From e821e88bf218c8e3934436590ef21026f112eb26 Mon Sep 17 00:00:00 2001 From: Tom Arild Jakobsen Date: Mon, 12 Aug 2024 09:30:52 +0200 Subject: [PATCH] Add support for Refresh Action Closes: #3 --- .changeset/two-seals-heal.md | 5 ++ .../resources/lib/turbo-streams/actions.ts | 60 ++++++++++++++----- src/main/resources/lib/turbo-streams/index.ts | 23 ++++++- 3 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 .changeset/two-seals-heal.md diff --git a/.changeset/two-seals-heal.md b/.changeset/two-seals-heal.md new file mode 100644 index 0000000..cf281b1 --- /dev/null +++ b/.changeset/two-seals-heal.md @@ -0,0 +1,5 @@ +--- +"@item-enonic-types/lib-turbo-streams": minor +--- + +Add Turbo Stream support for Refresh Action diff --git a/src/main/resources/lib/turbo-streams/actions.ts b/src/main/resources/lib/turbo-streams/actions.ts index ec503c5..179a441 100644 --- a/src/main/resources/lib/turbo-streams/actions.ts +++ b/src/main/resources/lib/turbo-streams/actions.ts @@ -1,4 +1,6 @@ -export interface TurboStreamChangeAction { +export const actionNames = ["append", "prepend", "replace", "update", "before", "after", "remove", "refresh"] as const; + +export type TurboStreamChangeAction = { /** * Action to perform */ @@ -18,9 +20,9 @@ export interface TurboStreamChangeAction { * The new content to insert into the dom */ readonly content: string; -} +}; -export interface TurboStreamRemoveAction { +export type TurboStreamRemoveAction = { /** * Action to perform */ @@ -35,12 +37,24 @@ export interface TurboStreamRemoveAction { * CSS Query selector to update */ readonly targets?: string; -} +}; + +export type TurboStreamRefreshAction = { + /** + * Action to perform + */ + readonly action: "refresh"; + + /** + * Dom ID to update + */ + readonly requestId?: string; +}; /** * Type that can be serialized into a turbo stream action frame */ -export type TurboStreamAction = TurboStreamChangeAction | TurboStreamRemoveAction; +export type TurboStreamAction = TurboStreamChangeAction | TurboStreamRemoveAction | TurboStreamRefreshAction; /** * Guard that verifies that an object is of type TurboStreamAction @@ -51,8 +65,8 @@ export function isTurboStreamAction(v: unknown): v is TurboStreamAction { return ( v !== undefined && v !== null && - ["append", "prepend", "replace", "update", "remove", "before", "after"].indexOf(value.action) !== -1 && - typeof value.target === "string" + actionNames.indexOf(value.action) !== -1 && + (value.action === "refresh" || typeof value.target === "string") ); } @@ -63,25 +77,41 @@ export function serialize(action: TurboStreamAction): string; export function serialize(actions: ReadonlyArray): string; export function serialize(actions: TurboStreamAction | ReadonlyArray): string; export function serialize(actions: TurboStreamAction | ReadonlyArray): string { - return actions instanceof Array ? actions.map(serializeOne).join("\n") : serializeOne(actions); + return Array.isArray(actions) ? actions.map(serializeOne).join("\n") : serializeOne(actions); } function serializeOne(action: TurboStreamAction): string { - return action.action === "remove" - ? action.target - ? `` - : `` - : action.target - ? ` + switch (action.action) { + case "remove": + return action.target + ? `` + : ``; + + case "refresh": + return action.requestId + ? `` + : ``; + + case "append": + case "prepend": + case "replace": + case "update": + case "before": + case "after": + return action.target + ? ` `.trim() - : ` + : ` `.trim(); + default: + return ""; + } } diff --git a/src/main/resources/lib/turbo-streams/index.ts b/src/main/resources/lib/turbo-streams/index.ts index e3feca1..8fb607c 100644 --- a/src/main/resources/lib/turbo-streams/index.ts +++ b/src/main/resources/lib/turbo-streams/index.ts @@ -1,5 +1,11 @@ import { sendByWebSocket, type SendByWebSocketTarget } from "./websockets"; -import { serialize, type TurboStreamRemoveAction, type TurboStreamChangeAction, TurboStreamAction } from "./actions"; +import { + serialize, + type TurboStreamRemoveAction, + type TurboStreamChangeAction, + TurboStreamAction, + TurboStreamRefreshAction, +} from "./actions"; import type { Request, Response } from "@item-enonic-types/global/controller"; /** @@ -121,6 +127,19 @@ export function after(params: TurboStreamsParams): void { ); } +/** + * Initiates a Page Refresh to render new content with morphing. + */ +export function refresh(params: TypeStreamsRefreshParams): void { + sendByWebSocket( + params, + serialize({ + action: "refresh", + requestId: params.requestId, + }), + ); +} + /** * Checks the request header if the response can be of mime type "text/vnd.turbo-stream.html" */ @@ -155,5 +174,7 @@ export type TurboStreamsParams = Omit & SendB */ export type TurboStreamsRemoveParams = Omit & SendByWebSocketTarget; +export type TypeStreamsRefreshParams = Omit & SendByWebSocketTarget; + export * from "./actions"; export { getUsersPersonalGroupName, getWebSocketUrl, SERVICE_NAME_TURBO_STREAMS } from "./websockets";