@solidjs/web 2.0.0-beta.1 → 2.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,18 @@
1
+ /**
2
+ * Renders a component tree synchronously to an HTML string. Async reads inside
3
+ * `<Loading>` boundaries emit their `fallback` content; for full-graph
4
+ * resolution use `renderToStringAsync` instead.
5
+ *
6
+ * Pair the returned HTML with `hydrate()` on the client.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * import { renderToString } from "@solidjs/web";
11
+ *
12
+ * const html = renderToString(() => <App />);
13
+ * res.send(`<!doctype html><html><body><div id="root">${html}</div></body></html>`);
14
+ * ```
15
+ */
1
16
  export declare function renderToString<T>(fn: () => T, options?: {
2
17
  nonce?: string;
3
18
  renderId?: string;
@@ -12,6 +27,21 @@ export declare function renderToString<T>(fn: () => T, options?: {
12
27
  }>;
13
28
  onError?: (err: any) => void;
14
29
  }): string;
30
+ /**
31
+ * Renders a component tree to an HTML string and awaits all async reads in the
32
+ * subtree before resolving. The returned HTML reflects the fully-settled state
33
+ * — no `<Loading>` fallbacks appear in the output.
34
+ *
35
+ * Use this when you want a complete page in one round-trip. For incremental
36
+ * streaming with progressive boundary resolution, use `renderToStream`.
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * import { renderToStringAsync } from "@solidjs/web";
41
+ *
42
+ * const html = await renderToStringAsync(() => <App />);
43
+ * ```
44
+ */
15
45
  export declare function renderToStringAsync<T>(fn: () => T, options?: {
16
46
  timeoutMs?: number;
17
47
  nonce?: string;
@@ -27,6 +57,25 @@ export declare function renderToStringAsync<T>(fn: () => T, options?: {
27
57
  }>;
28
58
  onError?: (err: any) => void;
29
59
  }): Promise<string>;
60
+ /**
61
+ * Streams an HTML response, flushing the synchronous shell first and then
62
+ * progressively emitting async-resolved fragments as their `<Loading>`
63
+ * boundaries settle. Good for time-to-first-byte sensitive pages.
64
+ *
65
+ * Returns an object with `pipe`/`pipeTo` for piping to a Node `Writable` or
66
+ * a Web `WritableStream`, plus a `then` for awaiting full completion.
67
+ *
68
+ * @example
69
+ * ```tsx
70
+ * import { renderToStream } from "@solidjs/web";
71
+ *
72
+ * // Node:
73
+ * renderToStream(() => <App />).pipe(res);
74
+ *
75
+ * // Web (Workers / Deno):
76
+ * await renderToStream(() => <App />).pipeTo(stream.writable);
77
+ * ```
78
+ */
30
79
  export declare function renderToStream<T>(fn: () => T, options?: {
31
80
  nonce?: string;
32
81
  renderId?: string;
@@ -54,19 +103,59 @@ export declare function renderToStream<T>(fn: () => T, options?: {
54
103
  }) => void;
55
104
  pipeTo: (writable: WritableStream) => Promise<void>;
56
105
  };
106
+ /**
107
+ * Compiler primitive — emitted by JSX-DOM-Expressions for tagged-template
108
+ * SSR output. Not meant for hand-written code.
109
+ * @internal
110
+ */
57
111
  export declare function ssr(template: string[] | string, ...nodes: any[]): {
58
112
  t: string;
59
113
  };
114
+ /**
115
+ * Compiler primitive — emitted by JSX-DOM-Expressions for SSR element
116
+ * output. Not meant for hand-written code.
117
+ * @internal
118
+ */
60
119
  export declare function ssrElement(name: string, props: any, children: any, needsId: boolean): {
61
120
  t: string;
62
121
  };
122
+ /**
123
+ * Compiler primitive — serializes a classList object for SSR output. Not
124
+ * meant for hand-written code.
125
+ * @internal
126
+ */
63
127
  export declare function ssrClassList(value: {
64
128
  [k: string]: boolean;
65
129
  }): string;
130
+ /**
131
+ * Compiler primitive — serializes a style object for SSR output. Not meant
132
+ * for hand-written code.
133
+ * @internal
134
+ */
66
135
  export declare function ssrStyle(value: {
67
136
  [k: string]: string;
68
137
  }): string;
138
+ /**
139
+ * Compiler primitive — serializes a boolean attribute for SSR output. Not
140
+ * meant for hand-written code.
141
+ * @internal
142
+ */
69
143
  export declare function ssrAttribute(key: string, value: boolean): string;
144
+ /**
145
+ * Compiler primitive — generates the hydration-key attribute for SSR
146
+ * output. Not meant for hand-written code.
147
+ * @internal
148
+ */
70
149
  export declare function ssrHydrationKey(): string;
150
+ /**
151
+ * Compiler primitive — collapses an SSR-shaped node into its HTML string.
152
+ * Not meant for hand-written code.
153
+ * @internal
154
+ */
71
155
  export declare function resolveSSRNode(node: any): string;
156
+ /**
157
+ * Escapes a string for safe inclusion in HTML output. Used by the SSR
158
+ * runtime; not generally part of user code.
159
+ * @internal
160
+ */
72
161
  export declare function escape(html: string): string;
package/types/server.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import { JSX } from "./jsx.js";
2
- export const Properties: Set<string>;
3
2
  export const ChildProperties: Set<string>;
4
3
  export const DelegatedEvents: Set<string>;
5
4
  export const DOMElements: Set<string>;
6
5
  export const SVGElements: Set<string>;
7
- export const SVGNamespace: Record<string, string>;
6
+ export const MathMLElements: Set<string>;
7
+ export const VoidElements: Set<string>;
8
+ export const RawTextElements: Set<string>;
9
+ export const Namespaces: Record<string, string>;
8
10
 
9
11
  type MountableElement = Element | Document | ShadowRoot | DocumentFragment | Node;
10
12
 
@@ -15,7 +17,10 @@ export function renderToString<T>(
15
17
  renderId?: string;
16
18
  noScripts?: boolean;
17
19
  plugins?: any[];
18
- manifest?: Record<string, { file: string; css?: string[]; isEntry?: boolean; imports?: string[] }> & { _base?: string };
20
+ manifest?: Record<
21
+ string,
22
+ { file: string; css?: string[]; isEntry?: boolean; imports?: string[] }
23
+ > & { _base?: string };
19
24
  onError?: (err: any) => void;
20
25
  }
21
26
  ): string;
@@ -28,7 +33,10 @@ export function renderToStringAsync<T>(
28
33
  renderId?: string;
29
34
  noScripts?: boolean;
30
35
  plugins?: any[];
31
- manifest?: Record<string, { file: string; css?: string[]; isEntry?: boolean; imports?: string[] }> & { _base?: string };
36
+ manifest?: Record<
37
+ string,
38
+ { file: string; css?: string[]; isEntry?: boolean; imports?: string[] }
39
+ > & { _base?: string };
32
40
  onError?: (err: any) => void;
33
41
  }
34
42
  ): Promise<string>;
@@ -39,7 +47,10 @@ export function renderToStream<T>(
39
47
  renderId?: string;
40
48
  noScripts?: boolean;
41
49
  plugins?: any[];
42
- manifest?: Record<string, { file: string; css?: string[]; isEntry?: boolean; imports?: string[] }> & { _base?: string };
50
+ manifest?: Record<
51
+ string,
52
+ { file: string; css?: string[]; isEntry?: boolean; imports?: string[] }
53
+ > & { _base?: string };
43
54
  onCompleteShell?: (info: { write: (v: string) => void }) => void;
44
55
  onCompleteAll?: (info: { write: (v: string) => void }) => void;
45
56
  onError?: (err: any) => void;
@@ -65,17 +76,23 @@ export function ssrAttribute(key: string, value: any): string;
65
76
  export function ssrHydrationKey(): string;
66
77
  export function resolveSSRNode(node: any, result?: any, top?: boolean): any;
67
78
  export function escape(s: any, attr?: boolean): any;
68
- export function applyRef(r: ((element: any) => void) | ((element: any) => void)[], element: any): void;
79
+ export function applyRef(
80
+ r: ((element: any) => void) | ((element: any) => void)[],
81
+ element: any
82
+ ): void;
69
83
  export function useAssets(fn: () => JSX.Element): void;
70
84
  export function getAssets(): string;
71
85
  export function getHydrationKey(): string | undefined;
72
- export function effect<T>(fn: (prev?: T) => T, effect: (value: T, prev?: T) => void, init?: T): void;
86
+ export function effect<T>(fn: (prev?: T) => T, effect: (value: T, prev?: T) => void): void;
73
87
  export function memo<T>(fn: () => T, equal: boolean): () => T;
74
88
  export function createComponent<T>(Comp: (props: T) => JSX.Element, props: T): JSX.Element;
75
89
  export function mergeProps(...sources: unknown[]): unknown;
76
90
  export function getOwner(): unknown;
77
91
  export function ssrRunInScope(fn: () => void, owner: unknown): void;
78
- export function generateHydrationScript(options?: { nonce?: string; eventNames?: string[] }): string;
92
+ export function generateHydrationScript(options?: {
93
+ nonce?: string;
94
+ eventNames?: string[];
95
+ }): string;
79
96
  export declare const RequestContext: unique symbol;
80
97
  export interface RequestEvent {
81
98
  request: Request;
@@ -104,12 +121,7 @@ export function insert<T>(
104
121
  ): JSX.Element;
105
122
 
106
123
  /** @deprecated not supported on the server side */
107
- export function spread<T>(
108
- node: Element,
109
- accessor: T,
110
- isSVG?: Boolean,
111
- skipChildren?: Boolean
112
- ): void;
124
+ export function spread<T>(node: Element, accessor: T, skipChildren?: Boolean): void;
113
125
 
114
126
  /** @deprecated not supported on the server side */
115
127
  export function delegateEvents(eventNames: string[], d?: Document): void;
@@ -130,14 +142,20 @@ export function addEventListener(
130
142
 
131
143
  /** @deprecated not supported on the server side */
132
144
  export function render(code: () => JSX.Element, element: MountableElement): () => void;
133
- /** @deprecated not supported on the server side */
134
- export function template(html: string, isImportNode?: boolean, isSVG?: boolean, isMathML?: boolean): () => Element;
145
+ /**
146
+ * @deprecated not supported on the server side
147
+ * @param flag
148
+ * - `undefined` — clone the template as-is (uses `cloneNode`).
149
+ * - `1` — use `document.importNode` instead of `cloneNode`.
150
+ * - `2` — the template html is wrapped; the outer tag is stripped at clone time.
151
+ */
152
+ export function template(html: string, flag?: 1 | 2): () => Element;
135
153
  /** @deprecated not supported on the server side */
136
154
  export function setProperty(node: Element, name: string, value: any): void;
137
155
  /** @deprecated not supported on the server side */
138
156
  export function className(node: Element, value: string): void;
139
157
  /** @deprecated not supported on the server side */
140
- export function assign(node: Element, props: any, isSVG?: Boolean, skipChildren?: Boolean): void;
158
+ export function assign(node: Element, props: any, skipChildren?: Boolean): void;
141
159
 
142
160
  /** @deprecated not supported on the server side */
143
161
  export function hydrate(
@@ -0,0 +1,104 @@
1
+ import { JSX } from "./jsx.cjs";
2
+ export const DOMWithState: Record<string, Record<string, 1 | 2>>;
3
+ export const ChildProperties: Set<string>;
4
+ export const DelegatedEvents: Set<string>;
5
+ export const DOMElements: Set<string>;
6
+ export const SVGElements: Set<string>;
7
+ export const MathMLElements: Set<string>;
8
+ export const VoidElements: Set<string>;
9
+ export const RawTextElements: Set<string>;
10
+ export const Namespaces: Record<string, string>;
11
+
12
+ type MountableElement = Element | Document | ShadowRoot | DocumentFragment | Node;
13
+ export function render(
14
+ code: () => JSX.Element,
15
+ element: MountableElement,
16
+ init?: JSX.Element,
17
+ options?: { owner?: unknown }
18
+ ): () => void;
19
+ /**
20
+ * @param flag
21
+ * - `undefined` — clone the template as-is (uses `cloneNode`).
22
+ * - `1` — use `document.importNode` instead of `cloneNode`.
23
+ * - `2` — the template html is wrapped; the outer tag is stripped at clone time.
24
+ */
25
+ export function template(html: string, flag?: 1 | 2): () => Element;
26
+ export function effect<T>(fn: (prev?: T) => T, effect: (value: T, prev?: T) => void): void;
27
+ export function memo<T>(fn: () => T, equal: boolean): () => T;
28
+ export function untrack<T>(fn: () => T): T;
29
+ export function insert<T>(
30
+ parent: MountableElement,
31
+ accessor: (() => T) | T,
32
+ marker?: Node | null,
33
+ init?: JSX.Element
34
+ ): JSX.Element;
35
+ export function createComponent<T>(Comp: (props: T) => JSX.Element, props: T): JSX.Element;
36
+ export function delegateEvents(eventNames: string[], d?: Document): void;
37
+ export function clearDelegatedEvents(d?: Document): void;
38
+ export function spread<T>(node: Element, accessor: T, skipChildren?: Boolean): void;
39
+ export function assign(
40
+ node: Element,
41
+ props: any,
42
+ skipChildren?: Boolean,
43
+ prevProps?: any,
44
+ skipRef?: Boolean
45
+ ): void;
46
+ export function setAttribute(node: Element, name: string, value: string): void;
47
+ export function setAttributeNS(node: Element, namespace: string, name: string, value: string): void;
48
+ type ClassList =
49
+ | Record<string, boolean>
50
+ | Array<string | number | boolean | null | undefined | Record<string, boolean>>;
51
+ export function className(
52
+ node: Element,
53
+ value: string | ClassList,
54
+ prev?: string | ClassList
55
+ ): void;
56
+ export function setProperty(node: Element, name: string, value: any): void;
57
+ export function setStyleProperty(node: Element, name: string, value: any): void;
58
+ export function addEventListener(
59
+ node: Element,
60
+ name: string,
61
+ handler: EventListener | EventListenerObject | (EventListenerObject & AddEventListenerOptions),
62
+ delegate: boolean
63
+ ): void;
64
+ export function style(
65
+ node: Element,
66
+ value: { [k: string]: string },
67
+ prev?: { [k: string]: string }
68
+ ): void;
69
+ export function getOwner(): unknown;
70
+ export function mergeProps(...sources: unknown[]): unknown;
71
+ export function dynamicProperty(props: unknown, key: string): unknown;
72
+ export function applyRef(
73
+ r: ((element: Element) => void) | ((element: Element) => void)[],
74
+ element: Element
75
+ ): void;
76
+ export function ref(
77
+ fn: () => ((element: Element) => void) | ((element: Element) => void)[],
78
+ element: Element
79
+ ): void;
80
+
81
+ export function hydrate(
82
+ fn: () => JSX.Element,
83
+ node: MountableElement,
84
+ options?: { renderId?: string; owner?: unknown }
85
+ ): () => void;
86
+ export function getHydrationKey(): string | undefined;
87
+ export function getNextElement(template?: () => Element): Element;
88
+ export function getNextMatch(start: Node, elementName: string): Element;
89
+ export function getNextMarker(start: Node): [Node, Array<Node>];
90
+ export function useAssets(fn: () => JSX.Element): void;
91
+ export function getAssets(): string;
92
+ export function HydrationScript(props?: { nonce?: string; eventNames?: string[] }): JSX.Element;
93
+ export function generateHydrationScript(options?: {
94
+ nonce?: string;
95
+ eventNames?: string[];
96
+ }): string;
97
+ export function Assets(props: { children?: JSX.Element }): JSX.Element;
98
+ export interface RequestEvent {
99
+ request: Request;
100
+ locals: Record<string | number | symbol, any>;
101
+ }
102
+ export declare const RequestContext: unique symbol;
103
+ export function getRequestEvent(): RequestEvent | undefined;
104
+ export function runHydrationEvents(): void;
@@ -0,0 +1,3 @@
1
+ export { getOwner, runWithOwner, createComponent, createRoot as root, sharedConfig, untrack, merge as mergeProps, flatten, ssrHandleError, ssrRunInScope } from "solid-js";
2
+ export declare const effect: (fn: any, effectFn: any, options: any) => void;
3
+ export declare const memo: (fn: any) => import("solid-js").Accessor<any>;
@@ -0,0 +1,171 @@
1
+ import { hydrate as hydrateCore } from "./client.cjs";
2
+ import { Component } from "solid-js";
3
+ import type { JSX } from "./jsx.cjs";
4
+ export * from "./client.cjs";
5
+ export * from "./server-mock.cjs";
6
+ export type { JSX } from "./jsx.cjs";
7
+ export { For, Show, Switch, Match, Errored, Loading, Repeat, Reveal, NoHydration, Hydration } from "solid-js";
8
+ import { merge } from "solid-js";
9
+ /**
10
+ * Compiler-emitted prop-spread helper. The JSX transform (in
11
+ * `dom-expressions`) emits `mergeProps(...)` calls when compiling prop
12
+ * spreads on components — it is *not* a user-facing API. Application code
13
+ * should import `merge` from `solid-js` directly.
14
+ *
15
+ * @internal
16
+ */
17
+ export declare const mergeProps: typeof merge;
18
+ /**
19
+ * Build-time constant indicating whether code is running on the server. This
20
+ * client entry sets it to `false`; the matching server entry (`@solidjs/web`
21
+ * resolved through the `solid` server export condition) sets it to `true`.
22
+ *
23
+ * Bundlers can dead-code-eliminate branches gated on `isServer`, so guarding
24
+ * browser-only code with `if (!isServer) {…}` keeps it out of the SSR bundle
25
+ * entirely.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { isServer } from "@solidjs/web";
30
+ *
31
+ * if (!isServer) {
32
+ * // Browser-only: tree-shaken out of the SSR bundle.
33
+ * window.addEventListener("resize", onResize);
34
+ * }
35
+ * ```
36
+ */
37
+ export declare const isServer: boolean;
38
+ /**
39
+ * Build-time constant indicating whether code is running in a dev build.
40
+ * Replaced statically (`_SOLID_DEV_`) by the bundler integration, so guards
41
+ * like `if (isDev) {…}` are stripped from production builds.
42
+ *
43
+ * Use this to gate dev-only diagnostics, warnings, or expensive invariants
44
+ * that should never ship to production.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { isDev } from "@solidjs/web";
49
+ *
50
+ * if (isDev) {
51
+ * console.warn("debug-only path");
52
+ * }
53
+ * ```
54
+ */
55
+ export declare const isDev: boolean;
56
+ type MountableElement = Element | Document | ShadowRoot | DocumentFragment | Node;
57
+ export type IntrinsicElement = Extract<keyof JSX.IntrinsicElements, string>;
58
+ export type ValidComponent = IntrinsicElement | Component<any> | (string & {});
59
+ export type ComponentProps<T extends ValidComponent> = T extends Component<infer P> ? P : T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : Record<string, unknown>;
60
+ export type DynamicProps<T extends ValidComponent, P = ComponentProps<T>> = {
61
+ [K in keyof P]: P[K];
62
+ } & {
63
+ component: T | null | undefined | false;
64
+ };
65
+ /**
66
+ * Renders a component tree into a DOM element. Returns a dispose function
67
+ * that tears the tree down and cleans up reactive scopes when called.
68
+ *
69
+ * @example
70
+ * ```tsx
71
+ * import { render } from "@solidjs/web";
72
+ *
73
+ * const dispose = render(() => <App />, document.getElementById("root")!);
74
+ *
75
+ * // Later, to unmount:
76
+ * dispose();
77
+ * ```
78
+ *
79
+ * @remarks
80
+ * The top-level insert is queued via `insertOptions: { schedule: true }` so
81
+ * its initial DOM attach goes through the effect queue rather than executing
82
+ * inline. This lets the mount participate in transitions: if an uncaught
83
+ * async read surfaces during the initial render (no `Loading` ancestor
84
+ * absorbs it), the mount is held by the transition and attaches atomically
85
+ * once all pending settles. On the no-async happy path the tail `flush()`
86
+ * drains the queued callback so the attach is synchronous by the time
87
+ * `render()` returns. The dev enforcement window scopes
88
+ * `ASYNC_OUTSIDE_LOADING_BOUNDARY` to the initial mount only.
89
+ */
90
+ export declare function render(code: () => JSX.Element, element: MountableElement, init?: unknown, options?: {
91
+ renderId?: string;
92
+ }): () => void;
93
+ /**
94
+ * Resumes a server-rendered tree on the client, attaching event listeners
95
+ * and reactive bindings without reconstructing the DOM. Returns a `dispose`
96
+ * function that tears down reactive scopes (DOM nodes are left in place).
97
+ *
98
+ * Use this when the page HTML was produced by `renderToString`,
99
+ * `renderToStringAsync`, or `renderToStream`. For client-only apps, use
100
+ * `render` instead.
101
+ *
102
+ * Pass `options.renderId` to hydrate one of multiple roots emitted by a
103
+ * server render that used the same id.
104
+ *
105
+ * @example
106
+ * ```tsx
107
+ * import { hydrate } from "@solidjs/web";
108
+ *
109
+ * hydrate(() => <App />, document.getElementById("root")!);
110
+ * ```
111
+ */
112
+ export declare const hydrate: typeof hydrateCore;
113
+ /**
114
+ * Renders its children into a different part of the DOM (modal roots,
115
+ * tooltips, layers that need to escape an `overflow: hidden` ancestor).
116
+ *
117
+ * If `mount` is omitted, the portal attaches to `document.body`. The portal
118
+ * still participates in the parent's reactive scope and disposes when the
119
+ * parent does.
120
+ *
121
+ * @example
122
+ * ```tsx
123
+ * <Portal mount={document.getElementById("modal-root")!}>
124
+ * <Dialog />
125
+ * </Portal>
126
+ * ```
127
+ *
128
+ * @description https://docs.solidjs.com/reference/components/portal
129
+ */
130
+ export declare function Portal<T extends boolean = false, S extends boolean = false>(props: {
131
+ mount?: Element;
132
+ children: JSX.Element;
133
+ }): JSX.Element;
134
+ /**
135
+ * Returns a stable `Component` whose identity is driven by a reactive (and
136
+ * optionally async) `source`. The returned component can be used anywhere a
137
+ * normal component is used; children and props flow through JSX as usual.
138
+ *
139
+ * `source` may return a component, a native tag name (`'input'`, `'textarea'`,
140
+ * etc.), `undefined`, or a `Promise` of any of the above. A pending promise
141
+ * propagates as `NotReadyError` through the surrounding reactive scope, so
142
+ * async swaps compose with `<Loading>` boundaries the same way as `lazy`.
143
+ *
144
+ * @example
145
+ * ```tsx
146
+ * // `source` can return either a custom Component or a native tag
147
+ * // name — they're interchangeable, and the returned reference is a
148
+ * // stable Component you can use anywhere a normal one would go.
149
+ * const Field = dynamic(() => multiline() ? RichTextEditor : "input");
150
+ * return <Field value={value()} onInput={onInput} />;
151
+ * ```
152
+ *
153
+ * @description https://docs.solidjs.com/reference/components/dynamic
154
+ */
155
+ export declare function dynamic<T extends ValidComponent>(source: () => T | Promise<T> | null | undefined | false): Component<ComponentProps<T>>;
156
+ /**
157
+ * Renders an arbitrary custom or native component and forwards the other
158
+ * props. JSX form of `dynamic()` — same primitive, picked at the JSX site.
159
+ *
160
+ * @example
161
+ * ```tsx
162
+ * <Dynamic
163
+ * component={multiline() ? RichTextEditor : "input"}
164
+ * value={value()}
165
+ * onInput={onInput}
166
+ * />
167
+ * ```
168
+ *
169
+ * @description https://docs.solidjs.com/reference/components/dynamic
170
+ */
171
+ export declare function Dynamic<T extends ValidComponent>(props: DynamicProps<T>): JSX.Element;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared type-level helpers used to derive `prop:*` attribute typings from
3
+ * DOM element interfaces (e.g. `HTMLInputElement`, `HTMLButtonElement`).
4
+ *
5
+ * The wrapping of each value (`FunctionMaybe<T>` in `jsx-h.d.ts` vs. the
6
+ * raw value in `jsx.d.ts`) is applied by each consumer when composing its
7
+ * own `Properties<T>` mapped type. That way this file stays identical in
8
+ * both reactive and non-reactive contexts and only needs to exist once.
9
+ *
10
+ * originally from
11
+ * @url https://github.com/potahtml/pota
12
+ */
13
+
14
+ /** Base-class properties shared by all elements — skipped from `prop:*`. */
15
+ export type SkipPropsFrom = HTMLUnknownElement & HTMLElement & Element & Node;
16
+
17
+ /**
18
+ * Value types allowed on a `prop:*`. Primitives plus the writable
19
+ * non-primitive DOM-object props worth exposing:
20
+ *
21
+ * - `HTMLMediaElement.srcObject`
22
+ * - `HTMLButtonElement.popoverTargetElement` / `commandForElement` (and the same via
23
+ * `PopoverTargetAttributes` mixin on `HTMLInputElement`)
24
+ */
25
+ export type PropValue =
26
+ | string
27
+ | number
28
+ | boolean
29
+ | null
30
+ | MediaStream
31
+ | MediaSource
32
+ | Blob
33
+ | File
34
+ | Element;
35
+
36
+ /**
37
+ * Ergonomics widening for emitted `prop:*` value types:
38
+ *
39
+ * - general `string` → `string | number` (HTML coerces numbers)
40
+ * - string literal unions (`'on' | 'off'`) stay exact, so users still get autocomplete /
41
+ * narrowing
42
+ * - other types pass through unchanged
43
+ */
44
+ type WidenString<V> = string extends V ? string | number : V;
45
+ export type WidenPropValue<V> = [V] extends [string] ? WidenString<V> : V;
46
+
47
+ /**
48
+ * Structurally identical → `Y`; distinct → `N`. Used by `IsReadonlyKey` to detect
49
+ * readonly keys by comparing `Pick<T, K>` with `Readonly<Pick<T, K>>`.
50
+ */
51
+ export type IfEquals<A, B, Y = unknown, N = never> =
52
+ (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? Y : N;
53
+
54
+ /**
55
+ * True when `K` is readonly on `T`. Singleton-constant properties (e.g.
56
+ * `tagName: "INPUT"`, `nodeType: 1`) are always `readonly` in `lib.dom.d.ts`, so this
57
+ * single check covers both readonly and singleton-literal cases.
58
+ */
59
+ export type IsReadonlyKey<T, K extends keyof T> = IfEquals<
60
+ Pick<T, K>,
61
+ Readonly<Pick<T, K>>,
62
+ true,
63
+ false
64
+ >;
65
+
66
+ /**
67
+ * Resolves to the `prop:K` string literal when `K` is a writable, element-specific
68
+ * property suitable for a `prop:*` attribute; otherwise resolves to `never` so the
69
+ * key is filtered out of the resulting mapped type.
70
+ *
71
+ * Filters out:
72
+ *
73
+ * - base-class keys (via `SkipPropsFrom`)
74
+ * - aria-* keys (already typed via `AriaAttributes`)
75
+ * - readonly keys
76
+ * - keys whose value types fall outside `PropValue`
77
+ * - the generic `string` index signature (e.g. `HTMLFormElement[name: string]: any`),
78
+ * which would otherwise shadow every key with an `any`-typed `prop:*`
79
+ */
80
+ export type PropKey<T, K extends keyof T> = K extends keyof SkipPropsFrom
81
+ ? never
82
+ : K extends string
83
+ ? string extends K
84
+ ? never
85
+ : K extends `aria${string}`
86
+ ? never
87
+ : T[K] extends PropValue
88
+ ? IsReadonlyKey<T, K> extends true
89
+ ? never
90
+ : `prop:${K}`
91
+ : never
92
+ : never;