diff --git a/types/hotwired__turbo/hotwired__turbo-tests.ts b/types/hotwired__turbo/hotwired__turbo-tests.ts index 5e3f6a582d3f63..f41a07a13381c1 100644 --- a/types/hotwired__turbo/hotwired__turbo-tests.ts +++ b/types/hotwired__turbo/hotwired__turbo-tests.ts @@ -16,6 +16,8 @@ import { StreamMessage, StreamSource, TurboHistory, + TurboStreamAction, + TurboStreamActions, Visit, visit, VisitOptions, @@ -102,6 +104,19 @@ StreamActions.log = function() { console.log(this.getAttribute("message")); }; +// Test TurboStreamActions / TurboStreamAction exports +// $ExpectType TurboStreamActions +StreamActions; + +const customStreamAction: TurboStreamAction = function() { + // $ExpectType StreamElement + this; +}; +StreamActions.custom = customStreamAction; + +const allStreamActions: TurboStreamActions = StreamActions; +allStreamActions.log; + document.addEventListener("turbo:before-fetch-request", function(event) { // $ExpectType FetchRequestHeaders const headers = event.detail.fetchOptions.headers; @@ -272,6 +287,12 @@ turboStream.templateElement = document.createElement("template"); // @ts-expect-error - templateContent is readonly turboStream.templateContent = document.createDocumentFragment(); +// Test StreamElement.targetElements +// $ExpectType Element[] +turboStream.targetElements; +// @ts-expect-error - targetElements is readonly +turboStream.targetElements = []; + const eventSource = new EventSource("https://example.com/stream"); const webSocket = new WebSocket("wss://example.com/stream"); diff --git a/types/hotwired__turbo/index.d.ts b/types/hotwired__turbo/index.d.ts index fa0c1ce206aec8..2169414fc32b8b 100644 --- a/types/hotwired__turbo/index.d.ts +++ b/types/hotwired__turbo/index.d.ts @@ -51,6 +51,13 @@ export class StreamElement extends HTMLElement { * Gets a cloned copy of the template's content. */ readonly templateContent: DocumentFragment; + + /** + * Gets the list of elements the stream action will be applied to, + * resolved from the `target` (an element ID) or `targets` (a CSS + * selector) attribute. + */ + readonly targetElements: Element[]; } export class StreamSourceElement extends HTMLElement { @@ -299,9 +306,19 @@ export interface TurboSession { readonly restorationIdentifier: string; } -export const StreamActions: { - [action: string]: (this: StreamElement) => void; -}; +/** + * A stream action callback. Invoked with the matched `StreamElement` as + * `this`, allowing access to its attributes and target elements. + */ +export type TurboStreamAction = (this: StreamElement) => void; + +/** + * A map of action names to their {@link TurboStreamAction} callbacks, as + * used by {@link StreamActions}. + */ +export type TurboStreamActions = Record; + +export const StreamActions: TurboStreamActions; export type Action = "advance" | "replace" | "restore"; export interface VisitOptions { @@ -457,9 +474,7 @@ export interface TurboGlobal { navigator: Navigator; cache: Cache; config: TurboConfig; - StreamActions: { - [action: string]: (this: StreamElement) => void; - }; + StreamActions: TurboStreamActions; } declare global {