react-fine-grained-signals 0.1.1 → 0.2.0
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.
- package/LICENSE-ALIEN-SIGNALS.txt +21 -0
- package/README.ja.md +17 -10
- package/README.md +18 -10
- package/dist/base-WD_74mfC.js +55 -0
- package/dist/base-WD_74mfC.js.map +1 -0
- package/dist/core-runtime-2jSE9Tz5.js +1354 -0
- package/dist/core-runtime-2jSE9Tz5.js.map +1 -0
- package/dist/index.d.ts +20 -25
- package/dist/index.js +4 -4
- package/dist/{jsx-Xp5q2y97.d.ts → jsx-BQGrTir3.d.ts} +40 -5
- package/dist/jsx-P6volZdr.js +1833 -0
- package/dist/jsx-P6volZdr.js.map +1 -0
- package/dist/jsx-dev-runtime.d.ts +3 -3
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-runtime.d.ts +4 -4
- package/dist/jsx-runtime.js +1 -1
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +2 -2
- package/dist/use-signals-C1K8-vJX.js +169 -0
- package/dist/use-signals-C1K8-vJX.js.map +1 -0
- package/dist/use-signals-CJYcdFdL.d.ts +11 -0
- package/dist/utils.d.ts +14 -15
- package/dist/utils.js +6 -6
- package/dist/utils.js.map +1 -1
- package/package.json +22 -18
- package/dist/base-BZTnpU8U.js +0 -286
- package/dist/base-BZTnpU8U.js.map +0 -1
- package/dist/hooks-BFIWh7AD.js +0 -914
- package/dist/hooks-BFIWh7AD.js.map +0 -1
- package/dist/jsx-D9U6dSwL.js +0 -730
- package/dist/jsx-D9U6dSwL.js.map +0 -1
- package/dist/render-tracking-DCzw57BW.js +0 -96
- package/dist/render-tracking-DCzw57BW.js.map +0 -1
- package/dist/use-signals-8i2B-94o.js +0 -173
- package/dist/use-signals-8i2B-94o.js.map +0 -1
- package/dist/use-signals-CBDbbAbV.d.ts +0 -24
package/dist/jsx-D9U6dSwL.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-D9U6dSwL.js","names":[],"sources":["../src/runtime/jsx.ts"],"sourcesContent":["import { effect, isSignal } from \"../core/index.js\";\nimport type { ReadonlySignal } from \"../core/index.js\";\nimport { useSignalValue } from \"../react/hooks.js\";\nimport { createElement, Fragment, useLayoutEffect, useRef } from \"react\";\nimport type * as React from \"react\";\n\n/** The small set of DOM properties that support direct signal bindings. */\nconst REACTIVE_PROP_NAMES = new Set([\n \"title\",\n \"id\",\n \"className\",\n \"hidden\",\n \"disabled\",\n \"style\",\n \"value\",\n \"checked\",\n]);\n\n// `value`/`checked` are two-way bound only on these tags — the ones where React\n// itself treats them as a controlled/uncontrolled input. Elsewhere (`<li value>`,\n// `<option value>`, `<meter value>`, ...) they are plain, write-only attributes,\n// so those keep the same peek-and-substitute treatment as `title`/`disabled`/etc.\nfunction isControlledTwoWayProp(tagName: string, name: string): boolean {\n if (name === \"value\") return tagName === \"input\" || tagName === \"textarea\" || tagName === \"select\";\n if (name === \"checked\") return tagName === \"input\";\n return false;\n}\n\n/**\n * The concrete strategy a direct binding is mounted with. Resolved once, in\n * `findHostBindings`, from the JSX tag string that is already on hand at\n * element-creation time — `\"select\"` needs `bindSelectValue`'s MutationObserver\n * workaround, `\"input\"`/`\"textarea\"` need `bindTextValue`'s IME handling, and\n * `<input checked>` is the only other two-way case — so `mountBinding` later\n * only has to dispatch on this already-known value instead of re-deriving the\n * same facts from the mounted DOM node's `tagName`. It is also half of a\n * binding's identity for `createReactiveHostBinder`'s re-render diff.\n */\ntype BindingKind = \"style\" | \"select-value\" | \"text-value\" | \"checked\" | \"prop\";\n\nfunction resolveBindingKind(tagName: string, name: string): BindingKind {\n if (name === \"style\") return \"style\";\n if (isControlledTwoWayProp(tagName, name)) {\n if (name === \"value\") return tagName === \"select\" ? \"select-value\" : \"text-value\";\n return \"checked\";\n }\n return \"prop\";\n}\n\nfunction isTwoWayBindingKind(kind: BindingKind): boolean {\n return kind === \"select-value\" || kind === \"text-value\" || kind === \"checked\";\n}\n\n// The uncontrolled counterpart React reads only at mount, used in place of the\n// controlled prop so React's own input reconciliation never re-asserts a stale\n// signal snapshot over what the direct-binding effect just wrote.\nconst UNCONTROLLED_PROP_NAMES: Record<string, string> = {\n value: \"defaultValue\",\n checked: \"defaultChecked\",\n};\n\n// CSS properties React also treats as unitless: a bound number is written as-is\n// instead of getting a \"px\" suffix. Not exhaustive (SVG-only properties are\n// omitted since style binding is HTML-host-only), but covers the common cases.\nconst UNITLESS_CSS_PROPERTIES = new Set([\n \"animationIterationCount\", \"aspectRatio\", \"borderImageOutset\", \"borderImageSlice\",\n \"borderImageWidth\", \"boxFlex\", \"boxFlexGroup\", \"boxOrdinalGroup\", \"columnCount\",\n \"columns\", \"flex\", \"flexGrow\", \"flexPositive\", \"flexShrink\", \"flexNegative\",\n \"flexOrder\", \"gridArea\", \"gridColumn\", \"gridColumnEnd\", \"gridColumnSpan\",\n \"gridColumnStart\", \"gridRow\", \"gridRowEnd\", \"gridRowSpan\", \"gridRowStart\",\n \"fontWeight\", \"lineClamp\", \"lineHeight\", \"opacity\", \"order\", \"orphans\",\n \"scale\", \"tabSize\", \"WebkitLineClamp\", \"widows\", \"zIndex\", \"zoom\",\n]);\n\n// SVG has a different property model (for example, className is an SVGAnimatedString).\n// Keeping it out of the host fast path makes the supported surface explicit.\nconst SVG_ELEMENTS = [\n \"svg\", \"animate\", \"animateMotion\", \"animateTransform\", \"circle\", \"clipPath\",\n \"defs\", \"desc\", \"ellipse\", \"feBlend\", \"feColorMatrix\", \"feComponentTransfer\",\n \"feComposite\", \"feConvolveMatrix\", \"feDiffuseLighting\", \"feDisplacementMap\",\n \"feDistantLight\", \"feDropShadow\", \"feFlood\", \"feFuncA\", \"feFuncB\", \"feFuncG\",\n \"feFuncR\", \"feGaussianBlur\", \"feImage\", \"feMerge\", \"feMergeNode\", \"feMorphology\",\n \"feOffset\", \"fePointLight\", \"feSpecularLighting\", \"feSpotLight\", \"feTile\",\n \"feTurbulence\", \"filter\", \"foreignObject\", \"g\", \"image\", \"line\", \"linearGradient\",\n \"marker\", \"mask\", \"metadata\", \"mpath\", \"path\", \"pattern\", \"polygon\", \"polyline\",\n \"radialGradient\", \"rect\", \"set\", \"stop\", \"switch\", \"symbol\", \"text\", \"textPath\",\n \"tspan\", \"use\", \"view\",\n] as const;\n\ntype SvgElement = (typeof SVG_ELEMENTS)[number];\n\n// MathML properties do not share the HTML DOM property model either. React\n// currently types only SVG separately, but custom JSX factories can still\n// receive these host tags at runtime.\nconst MATHML_ELEMENTS = [\n \"annotation\", \"annotation-xml\", \"maction\", \"math\", \"merror\", \"mfrac\",\n \"mi\", \"mmultiscripts\", \"mn\", \"mo\", \"mover\", \"mpadded\", \"mphantom\",\n \"mprescripts\", \"mroot\", \"mrow\", \"ms\", \"mspace\", \"msqrt\", \"mstyle\",\n \"msub\", \"msubsup\", \"msup\", \"mtable\", \"mtd\", \"mtext\", \"mtr\", \"munder\",\n \"munderover\", \"semantics\",\n] as const;\n\ntype MathMlElement = (typeof MATHML_ELEMENTS)[number];\ntype NonHtmlHostElement = SvgElement | MathMlElement;\nconst NON_HTML_HOST_ELEMENTS = new Set<string>([...SVG_ELEMENTS, ...MATHML_ELEMENTS]);\n\ntype SignalChild = React.ReactNode | ReadonlySignal<SignalChild> | readonly SignalChild[];\ntype HostProps = Record<string, unknown>;\ntype Binding = readonly [name: string, source: ReadonlySignal<unknown>, kind: BindingKind];\nconst HTML_NAMESPACE = \"http://www.w3.org/1999/xhtml\";\n\n/**\n * A leaf that lets React own reconciliation while its signal dependency stays\n * local to the leaf. A signal resolving to another signal/array is normalized\n * again so nested reactive children also work.\n */\nexport function SignalValue({ source }: { source: ReadonlySignal<SignalChild> }): React.ReactNode {\n return normalizeChild(useSignalValue(source));\n}\n\nfunction normalizeChild(value: unknown): React.ReactNode {\n if (isSignal(value)) {\n return createElement(SignalValue, { source: value as ReadonlySignal<SignalChild> });\n }\n\n if (Array.isArray(value)) {\n return value.map(normalizeChild);\n }\n\n return value as React.ReactNode;\n}\n\nfunction isReactiveHostProp(name: string, value: unknown): value is ReadonlySignal<unknown> {\n if (!isSignal(value)) return false;\n return REACTIVE_PROP_NAMES.has(name) || name.startsWith(\"data-\") || name.startsWith(\"aria-\");\n}\n\nfunction readInitialValue(source: ReadonlySignal<unknown>): unknown {\n return source.peek();\n}\n\n/**\n * Per-binding \"already reported this episode\" latch for `readBoundSignal`.\n * Owned by the same closure that already holds a binding's other local state\n * (`previousKeys`, `composing`, ...) — never module-level — so two bindings\n * failing independently each still get their own first-failure log instead of\n * one silencing the other.\n */\ntype FailureEpisode = { hasReported: boolean };\n\n/**\n * Reads a signal on behalf of one of this module's direct DOM bindings (see\n * the module doc: these write straight to the DOM from an `effect()` installed\n * alongside the element's ref, bypassing React's render, so the owning\n * component never re-renders). A `computed()` whose getter throws caches and\n * rethrows that error on every read (see `computed()` in src/core/base.ts) —\n * if `source` is such a computed and it starts failing after the binding is\n * already mounted, an unguarded read here would throw synchronously out of\n * `effect()`'s callback body. Since 41c77ea that no longer escapes the flush —\n * `effect()` catches it and routes it through `reportEffectError`\n * (src/core/base.ts), so the write that triggered it still completes and the\n * rest of the effect queue still runs. But that containment is whole-callback:\n * it abandons the remainder of this binding's callback for the cycle and\n * reports a generic \"an effect() callback threw\", with no idea which binding\n * failed or that the DOM was left mid-update.\n *\n * Catching here keeps a failure local to this one binding: the DOM write for\n * this cycle is skipped (the DOM is left at its last successful value) and\n * the failure is reported with `console.error(message, { cause: error })` —\n * assert against `mock.calls[i][1].cause` in tests, the same shape used by\n * `computed()`'s own error report (src/core/base.ts) and by\n * `render-tracking.ts`. Reporting is intentional here too: a direct binding\n * has no Error Boundary or other surface to fall back on, and silence would\n * mean a binding that mysteriously stops updating with zero trace.\n *\n * Reported at most once per contiguous run of failures (\"episode\"): `episode`\n * latches after the first report and is cleared the moment a read next\n * succeeds, so a later, distinct failure episode logs again. This keeps a\n * `computed()` that fails on every keystroke from spamming one `console.error`\n * per keystroke.\n */\nfunction readBoundSignal<T>(\n read: () => T,\n episode: FailureEpisode,\n): { ok: true; value: T } | { ok: false } {\n try {\n const value = read();\n episode.hasReported = false;\n return { ok: true, value };\n } catch (error) {\n if (!episode.hasReported) {\n episode.hasReported = true;\n console.error(\n \"react-fine-grained-signals: a direct signal binding's read threw; skipping this update and leaving the DOM at its last value.\",\n { cause: error },\n );\n }\n return { ok: false };\n }\n}\n\n/**\n * Reads via `readBoundSignal` and, on success, hands the value to `apply`; a\n * failed read is already reported by `readBoundSignal`, so this just skips\n * the write. Shared by every read-and-apply call site below, including the\n * one that isn't itself an `effect()` — the MutationObserver-triggered\n * re-apply in `bindSelectValue`, which reads outside the reactive graph via\n * `.peek()`.\n */\nfunction applyBoundSignal<T>(\n read: () => T,\n apply: (value: T) => void,\n episode: FailureEpisode,\n): void {\n const result = readBoundSignal(read, episode);\n if (result.ok) apply(result.value);\n}\n\n/**\n * The common case built on `applyBoundSignal`: subscribe to `source.value`\n * inside an `effect()` and re-run `apply` whenever it changes. Centralizes\n * the pattern that used to be hand-rolled at each binding site — declare an\n * `episode`, then `effect(() => { const read = readBoundSignal(...); if\n * (!read.ok) return; <apply the value> })` — so the read-and-skip contract\n * can't drift between sites. An `episode` may be passed in to share a\n * failure latch with a sibling read site (see `bindSelectValue`); otherwise\n * each binding gets its own.\n */\nfunction createBindingEffect<T>(\n source: ReadonlySignal<T>,\n apply: (value: T) => void,\n episode: FailureEpisode = { hasReported: false },\n): () => void {\n return effect(() => applyBoundSignal(() => source.value, apply, episode));\n}\n\nfunction setAttribute(node: Element, name: string, value: unknown): void {\n if (value == null) {\n node.removeAttribute(name);\n } else {\n node.setAttribute(name, String(value));\n }\n}\n\nfunction setDomProp(node: Element, name: string, value: unknown): void {\n // Tags such as `a`, `script`, `style`, and `title` exist in both HTML and\n // SVG. The JSX factory only sees the tag name, so defer the final namespace\n // decision until React gives us the actual DOM node.\n if (node.namespaceURI !== HTML_NAMESPACE) {\n setAttribute(node, name === \"className\" ? \"class\" : name, value);\n return;\n }\n\n switch (name) {\n case \"title\":\n (node as HTMLElement).title = value == null ? \"\" : String(value);\n return;\n case \"id\":\n (node as HTMLElement).id = value == null ? \"\" : String(value);\n return;\n case \"className\":\n (node as HTMLElement).className = value == null ? \"\" : String(value);\n return;\n case \"hidden\":\n // The `hidden` content attribute also accepts the DOM-native keyword\n // `\"until-found\"` (a collapsible, find-in-page-revealable hidden\n // state) — coercing every value through `Boolean(...)` and the\n // `.hidden` IDL property would turn that truthy string into a plain\n // `true`, downgrading it to a hard hide. Writing it as the attribute\n // directly instead preserves the keyword; every other value keeps\n // going through `.hidden` so `disabled`-style boolean semantics\n // (including the false/null/undefined-removes-the-attribute cases)\n // are unchanged.\n if (value === \"until-found\") setAttribute(node, \"hidden\", value);\n else (node as HTMLElement).hidden = Boolean(value);\n return;\n case \"disabled\":\n // Only controls expose this property, but the runtime remains safe when\n // JSX places it on another HTML element.\n if (\"disabled\" in node) (node as HTMLButtonElement).disabled = Boolean(value);\n else if (value == null || value === false) node.removeAttribute(name);\n else setAttribute(node, name, value);\n return;\n default:\n setAttribute(node, name, value);\n }\n}\n\n/**\n * Writes `value`/`checked` on a controlled-two-way element, skipping the DOM\n * write when it already holds the value being written. Effects re-run on\n * every keystroke (the signal changed because `onChange` just wrote it), so\n * without this guard every keystroke would re-set a property the DOM already\n * has, moving the caret and disrupting IME composition for no reason.\n */\nfunction setControlledProp(node: Element, name: string, value: unknown): void {\n if (name === \"value\") {\n const select = node as HTMLSelectElement;\n if (select.tagName === \"SELECT\" && select.multiple) {\n setMultiSelectValue(select, value);\n return;\n }\n const next = value == null ? \"\" : String(value);\n const input = node as HTMLInputElement | HTMLTextAreaElement;\n if (input.value !== next) input.value = next;\n return;\n }\n const next = Boolean(value);\n const input = node as HTMLInputElement;\n if (input.checked !== next) input.checked = next;\n}\n\n/**\n * `<select multiple>` does not support assigning `.value` directly — the DOM\n * setter only ever selects a single option, silently corrupting the\n * selection instead of erroring. Its documented API for a multi-value select\n * is per-`<option>` `.selected`, so an array-valued signal (React's own\n * typing for a multi-select) is applied that way instead.\n */\nfunction setMultiSelectValue(select: HTMLSelectElement, value: unknown): void {\n const values = new Set(\n Array.isArray(value) ? value.map(String) : value == null ? [] : [String(value)],\n );\n for (const option of select.options) {\n const selected = values.has(option.value);\n if (option.selected !== selected) option.selected = selected;\n }\n}\n\n/**\n * A `<select>` whose matching `<option>` does not exist yet (for example when\n * the options themselves are rendered from a signal or other state, mounted\n * after this one) silently ends up with nothing selected: the DOM neither\n * errors nor retroactively applies `.value`/`.selected` once a matching\n * `<option>` is later added. The per-value effect below only reruns when the\n * bound signal itself changes, so it cannot see that the option list changed\n * out from under it. A MutationObserver on the select's subtree re-applies\n * the signal's current value whenever its `<option>` list changes, closing\n * that gap without requiring the signal to change too.\n */\nfunction bindSelectValue(select: HTMLSelectElement, source: ReadonlySignal<unknown>): () => void {\n // Shared by both read sites below: an effect-triggered failure and a\n // MutationObserver-triggered failure are the same underlying computed\n // erroring, so they report as one episode, not two.\n const episode: FailureEpisode = { hasReported: false };\n const apply = (value: unknown) => setControlledProp(select, \"value\", value);\n const stopEffect = createBindingEffect(source, apply, episode);\n const observer = new MutationObserver(() => {\n applyBoundSignal(() => source.peek(), apply, episode);\n });\n observer.observe(select, { childList: true, subtree: true });\n return () => {\n stopEffect();\n observer.disconnect();\n };\n}\n\n/**\n * Forcing a `value` write while an IME composition is in progress can abort\n * the composition outright, independent of whether the string being written\n * happens to match what was typed — the write-skip guard in\n * `setControlledProp` only protects the same-value echo case, not this one.\n * `compositionstart`/`compositionend` listeners on the node itself track\n * composition state directly, regardless of whether the component declares\n * its own composition handlers, and a write requested while composing is\n * deferred until composition ends instead of applied immediately.\n */\nfunction bindTextValue(node: HTMLInputElement | HTMLTextAreaElement, source: ReadonlySignal<unknown>): () => void {\n let composing = false;\n let hasPending = false;\n let pending: unknown;\n const episode: FailureEpisode = { hasReported: false };\n\n const onCompositionStart = () => {\n composing = true;\n };\n const onCompositionEnd = () => {\n composing = false;\n if (hasPending) {\n hasPending = false;\n setControlledProp(node, \"value\", pending);\n }\n };\n\n node.addEventListener(\"compositionstart\", onCompositionStart);\n node.addEventListener(\"compositionend\", onCompositionEnd);\n\n // A failed read must bail out before this touches `pending`/`hasPending` —\n // a stale or garbage value must never latch in. `createBindingEffect`\n // already skips `apply` on a failed read, so that guard lives there once.\n const stopEffect = createBindingEffect(source, (next) => {\n if (composing) {\n hasPending = true;\n pending = next;\n return;\n }\n setControlledProp(node, \"value\", next);\n }, episode);\n\n return () => {\n stopEffect();\n node.removeEventListener(\"compositionstart\", onCompositionStart);\n node.removeEventListener(\"compositionend\", onCompositionEnd);\n };\n}\n\nfunction clearStyleProperty(style: CSSStyleDeclaration, key: string): void {\n if (key.startsWith(\"--\")) style.removeProperty(key);\n else (style as unknown as Record<string, string>)[key] = \"\";\n}\n\nfunction setStyleProperty(style: CSSStyleDeclaration, key: string, value: unknown): void {\n if (value == null) {\n clearStyleProperty(style, key);\n return;\n }\n if (key.startsWith(\"--\")) {\n style.setProperty(key, String(value));\n return;\n }\n const cssValue = typeof value === \"number\" && !UNITLESS_CSS_PROPERTIES.has(key)\n ? `${value}px`\n : String(value);\n (style as unknown as Record<string, string>)[key] = cssValue;\n}\n\n/**\n * Applies a whole style object to an element, clearing keys that were present\n * in a previous call but are absent from this one. Only the coarse\n * `style={signal}` form is bound this way — an object whose individual entries\n * are themselves signals is out of scope (see docs/direct-binding-value-checked-style.md).\n */\nfunction applyStyle(node: HTMLElement, value: unknown, previousKeys: readonly string[]): string[] {\n // A non-object value (an `any`-typed or otherwise unchecked caller passing\n // a string, for instance) would make `Object.keys` walk string indices\n // instead of CSS property names; treat anything that is not a plain object\n // as empty rather than writing garbage keys to the node's style.\n const nextStyle = (typeof value === \"object\" && value !== null && !Array.isArray(value) ? value : {}) as Record<string, unknown>;\n const nextKeys = Object.keys(nextStyle);\n const nextKeySet = new Set(nextKeys);\n\n for (const key of previousKeys) {\n if (!nextKeySet.has(key)) clearStyleProperty(node.style, key);\n }\n for (const key of nextKeys) {\n setStyleProperty(node.style, key, nextStyle[key]);\n }\n return nextKeys;\n}\n\ntype RefCleanup = void | (() => void);\ntype SupportedRef = React.Ref<Element> | undefined;\n\nfunction applyRef(ref: SupportedRef, node: Element | null): RefCleanup {\n if (typeof ref === \"function\") return ref(node);\n if (ref != null) ref.current = node;\n}\n\n/**\n * One live binding: the tuple it was mounted from, its teardown, and — for a\n * `\"style\"` binding only — a live accessor for the CSS property keys it has\n * actually applied to the node so far. `undefined` for every other kind.\n *\n * This is a getter, not a one-time snapshot, because a style binding's own\n * `previousKeys` keeps changing across its lifetime as its effect re-runs; a\n * rebuild reads it just before disposing the binding, so it sees whatever the\n * binding last actually wrote, not what it started with. See `syncBindings`.\n */\ntype MountedBinding = {\n readonly binding: Binding;\n readonly dispose: () => void;\n readonly getStyleKeys: (() => readonly string[]) | undefined;\n};\n\n/** A binding's identity for the re-render diff: same name, source, and kind. */\n// `b` is optional so callers can pass a positional lookup straight in: a\n// missing counterpart is simply not the same binding.\nfunction isSameBinding(a: Binding, b: Binding | undefined): boolean {\n return b !== undefined && a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\n}\n\n/** What `subscribeBinding` hands back to `mountBinding`. See `MountedBinding`. */\ntype Subscription = { readonly dispose: () => void; readonly getStyleKeys: (() => readonly string[]) | undefined };\n\n/**\n * Subscribes a single binding to `node` and returns its teardown. Split out of\n * the ref callback so `createReactiveHostBinder` can rebuild one binding on\n * its own, without disturbing the siblings that did not change.\n *\n * `initialStyleKeys` seeds a `\"style\"` binding's own `previousKeys` — passed\n * by `syncBindings` when this binding is replacing a disposed style binding,\n * so the fresh one starts already knowing which CSS properties are actually\n * on the node, instead of starting from an empty set and never clearing them.\n * Ignored for every other kind.\n */\nfunction subscribeBinding(\n node: Element,\n name: string,\n source: ReadonlySignal<unknown>,\n kind: BindingKind,\n initialStyleKeys: readonly string[] | undefined,\n): Subscription {\n switch (kind) {\n case \"style\": {\n let previousKeys: readonly string[] = initialStyleKeys ?? [];\n const dispose = createBindingEffect(source, (value) => {\n previousKeys = applyStyle(node as HTMLElement, value, previousKeys);\n });\n return { dispose, getStyleKeys: () => previousKeys };\n }\n case \"select-value\":\n return { dispose: bindSelectValue(node as HTMLSelectElement, source), getStyleKeys: undefined };\n case \"text-value\":\n return { dispose: bindTextValue(node as HTMLInputElement | HTMLTextAreaElement, source), getStyleKeys: undefined };\n case \"checked\":\n return { dispose: createBindingEffect(source, (value) => setControlledProp(node, name, value)), getStyleKeys: undefined };\n case \"prop\":\n return { dispose: createBindingEffect(source, (value) => setDomProp(node, name, value)), getStyleKeys: undefined };\n }\n}\n\nfunction mountBinding(node: Element, binding: Binding, initialStyleKeys?: readonly string[]): MountedBinding {\n const { dispose, getStyleKeys } = subscribeBinding(node, binding[0], binding[1], binding[2], initialStyleKeys);\n return { binding, dispose, getStyleKeys };\n}\n\ntype ReactiveHostBinder = {\n /** The one callback-ref identity React ever sees for this element. */\n readonly ref: (node: Element | null) => RefCleanup;\n /** Reconciles the attached node against the latest rendered inputs. */\n sync(bindings: readonly Binding[], userRef: SupportedRef): void;\n};\n\n/**\n * Owns everything one mounted `ReactiveHost` attaches to its DOM node: the\n * user's own ref, plus one live subscription per binding.\n *\n * The ref callback is created once per binder, and a binder is created once\n * per mounted `ReactiveHost`, so React only ever sees a single ref identity\n * for the lifetime of that element. That is load-bearing: React responds to a\n * *changed* callback-ref identity by detaching the old ref and attaching the\n * new one on the very same, unchanged DOM node. While the ref closure was\n * rebuilt on every render — which it was, since `transformProps` hands\n * `ReactiveHost` a freshly allocated `bindings` array each time — every\n * unrelated re-render of the owning component (any state, context, or parent\n * update anywhere above this element) silently disconnected and recreated\n * `bindSelectValue`'s `MutationObserver`, removed and re-added\n * `bindTextValue`'s composition listeners *along with the closure-local\n * `composing`/`pending` state they guard* — resetting `composing` to `false`\n * mid-composition and letting the next write stomp in-flight IME input —\n * resubscribed every binding's `effect()`, and called the user's own ref with\n * `null` and then the identical node again.\n *\n * Pinning the identity moves that reconciliation here: `sync` runs from\n * `ReactiveHost`'s layout effect after every commit and diffs the render's\n * bindings against the mounted ones by `(name, source, kind)`, tearing down\n * and rebuilding only the entries that actually changed. What is left in the\n * ref callback is exactly the part React's attach/detach protocol has to\n * drive: which node is current, and full teardown when there no longer is one.\n *\n * The split is safe because of how React orders a commit. A host element's ref\n * is attached during the layout phase *before* the layout effects of the\n * component that rendered it, so `sync` always finds the node already\n * attached; and a ref is only ever (re)attached on a fiber React re-rendered,\n * which is also the only way `ReactiveHost`'s dependency-less layout effect\n * can fail to re-run — so no attach can slip past a `sync`.\n */\nfunction createReactiveHostBinder(): ReactiveHostBinder {\n let node: Element | null = null;\n let mounted: MountedBinding[] = [];\n let attachedUserRef: SupportedRef;\n let userCleanup: RefCleanup;\n let activeCleanup: (() => void) | undefined;\n\n const attachUserRef = (target: Element, userRef: SupportedRef): void => {\n attachedUserRef = userRef;\n userCleanup = applyRef(userRef, target);\n };\n\n // React 19 callback refs may return a cleanup function; a user ref that did\n // is torn down through it instead of through the `null` call React 18 used.\n const detachUserRef = (): void => {\n const cleanup = userCleanup;\n const detached = attachedUserRef;\n userCleanup = undefined;\n attachedUserRef = undefined;\n if (typeof cleanup === \"function\") cleanup();\n else applyRef(detached, null);\n };\n\n const disposeActive = (): void => {\n const cleanup = activeCleanup;\n activeCleanup = undefined;\n cleanup?.();\n };\n\n const ref = (target: Element | null): RefCleanup => {\n // React 18 clears callback refs with `null`, while React 19 can invoke the\n // returned cleanup. A node replacement can use either order, so every\n // entry point first disposes whichever node is currently attached.\n disposeActive();\n\n if (target == null) {\n return;\n }\n\n node = target;\n\n let isDisposed = false;\n const cleanup = () => {\n if (isDisposed) return;\n isDisposed = true;\n if (activeCleanup === cleanup) activeCleanup = undefined;\n for (const binding of mounted) binding.dispose();\n mounted = [];\n detachUserRef();\n node = null;\n };\n\n activeCleanup = cleanup;\n return cleanup;\n };\n\n const syncBindings = (target: Element, bindings: readonly Binding[]): void => {\n // The overwhelmingly common case — a re-render that changed nothing about\n // the bindings — costs one walk and allocates nothing.\n if (\n mounted.length === bindings.length\n && mounted.every((entry, index) => isSameBinding(entry.binding, bindings[index]))\n ) {\n return;\n }\n\n // Keyed by prop name, which is unique per element: a binding whose source\n // or kind changed under the same name is a rebuild, not a reuse.\n const reusable = new Map<string, MountedBinding>();\n for (const entry of mounted) reusable.set(entry.binding[0], entry);\n\n const reused = bindings.map((binding) => {\n const candidate = reusable.get(binding[0]);\n if (candidate === undefined || !isSameBinding(candidate.binding, binding)) return undefined;\n reusable.delete(binding[0]);\n return candidate;\n });\n\n // A stale binding being replaced under the same prop name (its source or\n // kind changed — see `isSameBinding`) is disposed just below. For a\n // `\"style\"` binding specifically, that disposal would otherwise discard\n // the one thing that makes `applyStyle`'s clearing logic work: the CSS\n // property keys it actually last wrote to `node.style`. Nothing else\n // remembers that set — the node itself can hold keys today's rendered\n // value never mentions (an off-render signal write applied a value React\n // never saw), and the fresh binding about to replace this one would\n // otherwise start its own `previousKeys` at `[]`, with no memory of them\n // either. Snapshotting it here, before `dispose()` tears down the closure\n // that holds it, lets the replacement start already knowing what is\n // really on the node, so it can still clear it on its first write.\n const staleStyleKeys = new Map<string, readonly string[]>();\n for (const stale of reusable.values()) {\n if (stale.getStyleKeys !== undefined) staleStyleKeys.set(stale.binding[0], stale.getStyleKeys());\n }\n\n // Everything stale is disposed before anything replacing it is mounted, so\n // a rebuilt binding never briefly holds two live subscriptions on one node.\n for (const stale of reusable.values()) stale.dispose();\n mounted = bindings.map(\n (binding, index) => reused[index] ?? mountBinding(target, binding, staleStyleKeys.get(binding[0])),\n );\n };\n\n return {\n ref,\n sync(bindings, userRef) {\n const target = node;\n if (target == null) return;\n if (userRef !== attachedUserRef) {\n detachUserRef();\n attachUserRef(target, userRef);\n }\n syncBindings(target, bindings);\n },\n };\n}\n\n/**\n * Hands `ReactiveHost` its one stable ref callback and drives the binder's\n * post-commit reconciliation.\n *\n * The layout effect deliberately declares no dependency array and returns no\n * cleanup: it must run after every commit (that is what makes it impossible\n * for a ref attach to happen without a following `sync`), and its teardown\n * belongs to the ref callback, which React already invokes on unmount, on\n * node replacement, and on StrictMode's ref replay. Giving it a cleanup here\n * would tear the whole element down again on every re-render — precisely the\n * churn this exists to remove.\n */\nfunction useReactiveHostBinder(\n bindings: readonly Binding[],\n userRef: SupportedRef,\n): (node: Element | null) => RefCleanup {\n const binderRef = useRef<ReactiveHostBinder | undefined>(undefined);\n if (binderRef.current === undefined) {\n binderRef.current = createReactiveHostBinder();\n }\n const binder = binderRef.current;\n useLayoutEffect(() => {\n binder.sync(bindings, userRef);\n });\n return binder.ref;\n}\n\n/**\n * A host element with DOM-only signal subscriptions attached via its ref.\n *\n * The subscriptions themselves are owned by a per-instance binder\n * (`useReactiveHostBinder`) rather than rebuilt inline here, so this\n * component's ref prop keeps one identity for the element's whole lifetime\n * and an unrelated re-render costs nothing — see `createReactiveHostBinder`.\n *\n * `children` arrives as ReactiveHost's own top-level prop (see\n * `createJsxWrapper` below) rather than folded into `props`/`hostProps`,\n * purely so the *outer* `factory(ReactiveHost, { ..., children }, key)` call\n * that constructs this element — the very same real `jsx`/`jsxs`/`jsxDEV`\n * that would have validated the original host element's children had this\n * wrapper not intercepted it — runs React's dev-mode key validation on it.\n * That validation is a flag React stamps onto each child element itself\n * (`element._store.validated`), not onto the array or onto whichever\n * component currently holds it, so it survives being read back out of props\n * here and re-embedded via `createElement` below. Skip this indirection —\n * i.e. leave `children` folded into `hostProps` before any real jsx/jsxs call\n * ever sees it — and a signal-bound host element with 2+ static, unkeyed JSX\n * children spuriously trips React's \"missing key\" warning: `createElement`'s\n * children-as-prop path never validates children (only its children-as-rest-\n * args path does), and neither did the `factory(ReactiveHost, ...)` call\n * itself, since `children` wasn't its own prop at that call site.\n */\nexport function ReactiveHost({\n elementType,\n props,\n bindings,\n children,\n}: {\n elementType: string;\n props: HostProps;\n bindings: readonly Binding[];\n children?: React.ReactNode;\n}): React.ReactElement {\n const { ref: userRef, ...hostProps } = props;\n const ref = useReactiveHostBinder(bindings, userRef as SupportedRef);\n return createElement(elementType, {\n ...hostProps,\n // `elementType` is a runtime string, so this can't be written as JSX; the\n // lint rule assumes a literal `<Foo children={x}/>` authoring mistake,\n // which doesn't apply to a dynamic-host-element createElement call.\n // oxlint-disable-next-line react/no-children-prop\n children,\n ref,\n });\n}\n\ntype CreateElement = (type: React.ElementType, props: unknown, key?: React.Key) => React.ReactElement;\n\n/**\n * Scans a native host element's props for anything reactive (see\n * `isReactiveHostProp`). Kept separate from building the transformed props\n * copy in `transformHostProps` so that function can decide whether a copy is\n * needed at all before ever allocating one.\n */\nfunction findHostBindings(props: HostProps, tagName: string): Binding[] {\n const bindings: Binding[] = [];\n for (const [name, value] of Object.entries(props)) {\n if (isReactiveHostProp(name, value)) {\n bindings.push([name, value, resolveBindingKind(tagName, name)]);\n }\n }\n return bindings;\n}\n\n/**\n * Transforms a native host element's (`<div>`, `<svg>`, ...) props: replaces\n * any directly-bound prop with its initial, non-reactive value (`bindings`\n * carries the reactive ones for `ReactiveHost` to mount later — see\n * `createJsxWrapper`) and normalizes a signal/array `children` the same way\n * `Fragment` does.\n *\n * The overwhelmingly common host element has neither. Scanning first and only\n * allocating a copy when something is actually found means a plain\n * `<div className=\"card\">…</div>` costs one prop walk and zero extra\n * allocations — the original props object is returned as-is (see the\n * `bindings.length === 0 && !childrenNeedNormalization` branch below), and\n * `createJsxWrapper` passes it straight to `factory` unchanged.\n */\nfunction transformHostProps(type: string, input: unknown): { props: HostProps; bindings: Binding[] } {\n const inputProps = (input ?? {}) as HostProps;\n const isHtmlHost = !NON_HTML_HOST_ELEMENTS.has(type);\n const bindings = isHtmlHost ? findHostBindings(inputProps, type) : [];\n\n const rawChildren = inputProps.children;\n const childrenNeedNormalization =\n \"children\" in inputProps && (isSignal(rawChildren) || Array.isArray(rawChildren));\n\n if (bindings.length === 0 && !childrenNeedNormalization) {\n return { props: inputProps, bindings };\n }\n\n // Something needs to change, so — and only so — a copy is made; the\n // original `inputProps` (and, transitively, whatever object the caller\n // passed as `input`) is never mutated.\n const props: HostProps = { ...inputProps };\n if (childrenNeedNormalization) {\n props.children = normalizeChild(rawChildren);\n }\n for (const [name, value, kind] of bindings) {\n // A two-way kind is only ever derived from a `value`/`checked` name (see\n // `resolveBindingKind`), so the lookup always hits; should it ever not, the\n // prop is written directly, which is the pre-substitution behaviour.\n const uncontrolledName = isTwoWayBindingKind(kind) ? UNCONTROLLED_PROP_NAMES[name] : undefined;\n if (uncontrolledName !== undefined) {\n // Leaving the controlled prop in place would keep the element\n // React-controlled, so an unrelated re-render of the owner would\n // re-diff and potentially re-write this prop — work relying on an\n // internal React guard (skipping a same-value write) rather than a\n // documented one. Substituting the uncontrolled prop instead means\n // React only ever reads it once, at mount, and never touches this\n // property again — see docs/direct-binding-value-checked-style.md.\n delete props[name];\n props[uncontrolledName] = readInitialValue(value);\n } else {\n props[name] = readInitialValue(value);\n }\n }\n return { props, bindings };\n}\n\n/**\n * `Fragment`'s only prop worth transforming is `children`, and only when it\n * is itself a signal or array — `normalizeChild` is the identity for\n * anything else (see its definition) — so a plain `<>...</>` with ordinary\n * children is passed straight through, uncopied, the same way a custom\n * component is below.\n */\nfunction transformFragmentProps(input: unknown): unknown {\n const props = input as HostProps | null;\n if (\n props == null\n || !(\"children\" in props)\n || (!isSignal(props.children) && !Array.isArray(props.children))\n ) {\n return input;\n }\n return { ...props, children: normalizeChild(props.children) };\n}\n\n/** Creates a JSX wrapper while letting each module supply React's JSX factory. */\nexport function createJsxWrapper(factory: CreateElement): CreateElement {\n return (type, input, key) => {\n if (typeof type === \"string\") {\n const { props, bindings } = transformHostProps(type, input);\n if (bindings.length > 0) {\n // `children` is lifted out to be `factory`'s own top-level prop (see\n // the comment on ReactiveHost) instead of staying nested inside\n // `props`, so `factory` — the real jsx/jsxs/jsxDEV already correctly\n // wired to know whether this call site's children are a static JSX\n // list — validates them exactly as it would have for the\n // un-intercepted host element.\n const { children, ...hostProps } = props;\n return factory(ReactiveHost, { elementType: type, props: hostProps, bindings, children }, key);\n }\n return factory(type, props, key);\n }\n\n if (type === Fragment) {\n return factory(type, transformFragmentProps(input), key);\n }\n\n // Every other type — function/class components, `memo`, `forwardRef`,\n // Context.Provider/Consumer, Suspense, lazy, ... — receives its props\n // exactly as its caller passed them. None of these were ever touched by\n // children normalization or the reactive-prop scan above, even before\n // this fast path existed, so skipping the copy here changes nothing\n // observable and removes an allocation nothing downstream ever read.\n return factory(type, input, key);\n };\n}\n\ntype Signalable<T> = T | ReadonlySignal<T>;\ntype DirectSignalPropName = \"title\" | \"id\" | \"className\" | \"hidden\" | \"disabled\" | \"style\" | \"value\" | \"checked\";\ntype AriaPropName = `aria-${string}`;\ntype AddSignalChildren<P> = Omit<P, \"children\"> & {\n children?: SignalChild;\n};\ntype SignalizeKnownHtmlProps<P> = {\n [Name in keyof P as Name extends DirectSignalPropName | AriaPropName ? Name : never]: Signalable<P[Name]>;\n};\ntype AddHtmlSignalProps<P> = Omit<P, DirectSignalPropName | AriaPropName | \"children\"> & {\n [Name in keyof SignalizeKnownHtmlProps<P>]: SignalizeKnownHtmlProps<P>[Name];\n} & {\n [name: `data-${string}`]: Signalable<string | number | boolean | undefined>;\n} & AddSignalChildren<{}>;\n\n/** Types exposed by `jsxImportSource: \"react-fine-grained-signals\"`. */\nexport namespace JSX {\n export type ElementType = React.JSX.ElementType;\n export interface Element extends React.JSX.Element {}\n export interface ElementClass extends React.JSX.ElementClass {}\n export interface ElementAttributesProperty extends React.JSX.ElementAttributesProperty {}\n export interface ElementChildrenAttribute extends React.JSX.ElementChildrenAttribute {}\n export type LibraryManagedAttributes<C, P> = React.JSX.LibraryManagedAttributes<C, P>;\n export interface IntrinsicAttributes extends React.JSX.IntrinsicAttributes {}\n export interface IntrinsicClassAttributes<T> extends React.JSX.IntrinsicClassAttributes<T> {}\n export type IntrinsicElements = {\n [Tag in keyof React.JSX.IntrinsicElements]: Tag extends NonHtmlHostElement\n ? AddSignalChildren<React.JSX.IntrinsicElements[Tag]>\n : AddHtmlSignalProps<React.JSX.IntrinsicElements[Tag]>;\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
//#region src/core/render-tracking.ts
|
|
2
|
-
let activeRenderCollector;
|
|
3
|
-
/** Returns whether a React render is currently collecting signal reads. */
|
|
4
|
-
function hasActiveRenderCollector() {
|
|
5
|
-
return activeRenderCollector !== void 0;
|
|
6
|
-
}
|
|
7
|
-
/** Replaces the current render collector and returns the previous collector. */
|
|
8
|
-
function setActiveRenderCollector(collector) {
|
|
9
|
-
const previous = activeRenderCollector;
|
|
10
|
-
activeRenderCollector = collector;
|
|
11
|
-
return previous;
|
|
12
|
-
}
|
|
13
|
-
/** Records a dependency and reports whether render collection was active. */
|
|
14
|
-
function trackRenderDependency(dependency) {
|
|
15
|
-
if (activeRenderCollector === void 0) return false;
|
|
16
|
-
activeRenderCollector.add(dependency);
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
/** Runs a callback without adding its reads to the active React render. */
|
|
20
|
-
function untrackedRender(callback) {
|
|
21
|
-
const previous = setActiveRenderCollector();
|
|
22
|
-
try {
|
|
23
|
-
return callback();
|
|
24
|
-
} finally {
|
|
25
|
-
setActiveRenderCollector(previous);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/** A small versioned subscription surface shared by signals and computeds. */
|
|
29
|
-
var RenderSubscription = class {
|
|
30
|
-
#onFirstSubscriber;
|
|
31
|
-
#onLastSubscriber;
|
|
32
|
-
#listeners;
|
|
33
|
-
#version = 0;
|
|
34
|
-
constructor(onFirstSubscriber, onLastSubscriber) {
|
|
35
|
-
this.#onFirstSubscriber = onFirstSubscriber;
|
|
36
|
-
this.#onLastSubscriber = onLastSubscriber;
|
|
37
|
-
}
|
|
38
|
-
getRenderVersion() {
|
|
39
|
-
return this.#version;
|
|
40
|
-
}
|
|
41
|
-
subscribeRender(listener) {
|
|
42
|
-
const listeners = this.#listeners ??= /* @__PURE__ */ new Set();
|
|
43
|
-
const wasEmpty = listeners.size === 0;
|
|
44
|
-
listeners.add(listener);
|
|
45
|
-
if (wasEmpty) this.#onFirstSubscriber?.();
|
|
46
|
-
return () => {
|
|
47
|
-
const currentListeners = this.#listeners;
|
|
48
|
-
if (currentListeners === void 0 || !currentListeners.delete(listener)) return;
|
|
49
|
-
if (currentListeners.size === 0) {
|
|
50
|
-
this.#listeners = void 0;
|
|
51
|
-
this.#onLastSubscriber?.();
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
track() {
|
|
56
|
-
return trackRenderDependency(this);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Whether anything is currently subscribed on the React side. Used by
|
|
60
|
-
* `deepSignal`'s metadata pruning to tell a genuinely dead per-key version
|
|
61
|
-
* signal from one a mounted component still depends on — dropping the
|
|
62
|
-
* latter would strand that subscriber on a `RenderSubscription` the
|
|
63
|
-
* property map no longer reaches, so it would never be notified again.
|
|
64
|
-
*/
|
|
65
|
-
hasListeners() {
|
|
66
|
-
return this.#listeners !== void 0 && this.#listeners.size !== 0;
|
|
67
|
-
}
|
|
68
|
-
bumpVersion() {
|
|
69
|
-
this.#version = this.#version + 1 | 0;
|
|
70
|
-
}
|
|
71
|
-
notify() {
|
|
72
|
-
this.bumpVersion();
|
|
73
|
-
const listeners = this.#listeners;
|
|
74
|
-
if (listeners === void 0) return;
|
|
75
|
-
for (const listener of [...listeners]) notifyListener(listener);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
/**
|
|
79
|
-
* Invokes one subscription listener, keeping its failure from cancelling the
|
|
80
|
-
* listeners queued behind it. Without this, a single throwing subscriber
|
|
81
|
-
* aborts the rest of the notify cycle, so unrelated components silently miss
|
|
82
|
-
* the update that was being delivered. Reported the same way as the other
|
|
83
|
-
* background-callback failures in this codebase (`readBoundSignal` in
|
|
84
|
-
* src/runtime/jsx.ts): `console.error(message, { cause })`.
|
|
85
|
-
*/
|
|
86
|
-
function notifyListener(listener) {
|
|
87
|
-
try {
|
|
88
|
-
listener();
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.error("react-fine-grained-signals: a render-subscription listener threw; continuing with the remaining listeners.", { cause: error });
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
export { untrackedRender as a, setActiveRenderCollector as i, hasActiveRenderCollector as n, notifyListener as r, RenderSubscription as t };
|
|
95
|
-
|
|
96
|
-
//# sourceMappingURL=render-tracking-DCzw57BW.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"render-tracking-DCzw57BW.js","names":[],"sources":["../src/core/render-tracking.ts"],"sourcesContent":["/** Internal dependency contract used by the React render collector. */\nexport interface RenderDependency {\n getRenderVersion(): number;\n subscribeRender(listener: () => void): () => void;\n}\n\nexport interface RenderCollector {\n add(dependency: RenderDependency): void;\n}\n\nlet activeRenderCollector: RenderCollector | undefined;\n\n/** Returns whether a React render is currently collecting signal reads. */\nexport function hasActiveRenderCollector(): boolean {\n return activeRenderCollector !== undefined;\n}\n\n/** Replaces the current render collector and returns the previous collector. */\nexport function setActiveRenderCollector(\n collector?: RenderCollector,\n): RenderCollector | undefined {\n const previous = activeRenderCollector;\n activeRenderCollector = collector;\n return previous;\n}\n\n/** Records a dependency and reports whether render collection was active. */\nexport function trackRenderDependency(dependency: RenderDependency): boolean {\n if (activeRenderCollector === undefined) return false;\n activeRenderCollector.add(dependency);\n return true;\n}\n\n/** Runs a callback without adding its reads to the active React render. */\nexport function untrackedRender<T>(callback: () => T): T {\n const previous = setActiveRenderCollector();\n try {\n return callback();\n } finally {\n setActiveRenderCollector(previous);\n }\n}\n\n/** A small versioned subscription surface shared by signals and computeds. */\nexport class RenderSubscription implements RenderDependency {\n // Written slots, not absent ones: the hooks are `undefined` whenever the\n // constructor is called without them, and `#listeners` is cleared back to\n // `undefined` to release the Set once the last listener unsubscribes.\n readonly #onFirstSubscriber?: (() => void) | undefined;\n readonly #onLastSubscriber?: (() => void) | undefined;\n #listeners?: Set<() => void> | undefined;\n #version = 0;\n\n constructor(\n onFirstSubscriber?: () => void,\n onLastSubscriber?: () => void,\n ) {\n this.#onFirstSubscriber = onFirstSubscriber;\n this.#onLastSubscriber = onLastSubscriber;\n }\n\n getRenderVersion(): number {\n return this.#version;\n }\n\n subscribeRender(listener: () => void): () => void {\n const listeners = (this.#listeners ??= new Set());\n const wasEmpty = listeners.size === 0;\n listeners.add(listener);\n if (wasEmpty) this.#onFirstSubscriber?.();\n\n return () => {\n const currentListeners = this.#listeners;\n if (currentListeners === undefined || !currentListeners.delete(listener)) {\n return;\n }\n if (currentListeners.size === 0) {\n this.#listeners = undefined;\n this.#onLastSubscriber?.();\n }\n };\n }\n\n track(): boolean {\n return trackRenderDependency(this);\n }\n\n /**\n * Whether anything is currently subscribed on the React side. Used by\n * `deepSignal`'s metadata pruning to tell a genuinely dead per-key version\n * signal from one a mounted component still depends on — dropping the\n * latter would strand that subscriber on a `RenderSubscription` the\n * property map no longer reaches, so it would never be notified again.\n */\n hasListeners(): boolean {\n return this.#listeners !== undefined && this.#listeners.size !== 0;\n }\n\n bumpVersion(): void {\n this.#version = (this.#version + 1) | 0;\n }\n\n notify(): void {\n this.bumpVersion();\n const listeners = this.#listeners;\n if (listeners === undefined) return;\n // Snapshot before iterating: a listener may (un)subscribe synchronously.\n // oxlint-disable-next-line unicorn/no-useless-spread\n for (const listener of [...listeners]) notifyListener(listener);\n }\n}\n\n/**\n * Invokes one subscription listener, keeping its failure from cancelling the\n * listeners queued behind it. Without this, a single throwing subscriber\n * aborts the rest of the notify cycle, so unrelated components silently miss\n * the update that was being delivered. Reported the same way as the other\n * background-callback failures in this codebase (`readBoundSignal` in\n * src/runtime/jsx.ts): `console.error(message, { cause })`.\n */\nexport function notifyListener(listener: () => void): void {\n try {\n listener();\n } catch (error) {\n console.error(\n \"react-fine-grained-signals: a render-subscription listener threw; continuing with the remaining listeners.\",\n { cause: error },\n );\n }\n}\n"],"mappings":";AAUA,IAAI;;AAGJ,SAAgB,2BAAoC;CAClD,OAAO,0BAA0B,KAAA;AACnC;;AAGA,SAAgB,yBACd,WAC6B;CAC7B,MAAM,WAAW;CACjB,wBAAwB;CACxB,OAAO;AACT;;AAGA,SAAgB,sBAAsB,YAAuC;CAC3E,IAAI,0BAA0B,KAAA,GAAW,OAAO;CAChD,sBAAsB,IAAI,UAAU;CACpC,OAAO;AACT;;AAGA,SAAgB,gBAAmB,UAAsB;CACvD,MAAM,WAAW,yBAAyB;CAC1C,IAAI;EACF,OAAO,SAAS;CAClB,UAAU;EACR,yBAAyB,QAAQ;CACnC;AACF;;AAGA,IAAa,qBAAb,MAA4D;CAI1D;CACA;CACA;CACA,WAAW;CAEX,YACE,mBACA,kBACA;EACA,KAAK,qBAAqB;EAC1B,KAAK,oBAAoB;CAC3B;CAEA,mBAA2B;EACzB,OAAO,KAAK;CACd;CAEA,gBAAgB,UAAkC;EAChD,MAAM,YAAa,KAAK,+BAAe,IAAI,IAAI;EAC/C,MAAM,WAAW,UAAU,SAAS;EACpC,UAAU,IAAI,QAAQ;EACtB,IAAI,UAAU,KAAK,qBAAqB;EAExC,aAAa;GACX,MAAM,mBAAmB,KAAK;GAC9B,IAAI,qBAAqB,KAAA,KAAa,CAAC,iBAAiB,OAAO,QAAQ,GACrE;GAEF,IAAI,iBAAiB,SAAS,GAAG;IAC/B,KAAK,aAAa,KAAA;IAClB,KAAK,oBAAoB;GAC3B;EACF;CACF;CAEA,QAAiB;EACf,OAAO,sBAAsB,IAAI;CACnC;;;;;;;;CASA,eAAwB;EACtB,OAAO,KAAK,eAAe,KAAA,KAAa,KAAK,WAAW,SAAS;CACnE;CAEA,cAAoB;EAClB,KAAK,WAAY,KAAK,WAAW,IAAK;CACxC;CAEA,SAAe;EACb,KAAK,YAAY;EACjB,MAAM,YAAY,KAAK;EACvB,IAAI,cAAc,KAAA,GAAW;EAG7B,KAAK,MAAM,YAAY,CAAC,GAAG,SAAS,GAAG,eAAe,QAAQ;CAChE;AACF;;;;;;;;;AAUA,SAAgB,eAAe,UAA4B;CACzD,IAAI;EACF,SAAS;CACX,SAAS,OAAO;EACd,QAAQ,MACN,8GACA,EAAE,OAAO,MAAM,CACjB;CACF;AACF"}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { i as setActiveRenderCollector, r as notifyListener } from "./render-tracking-DCzw57BW.js";
|
|
2
|
-
import { useEffect, useLayoutEffect, useRef, useSyncExternalStore } from "react";
|
|
3
|
-
//#region src/react/use-signals.ts
|
|
4
|
-
const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
5
|
-
const resolvedPromise = Promise.resolve();
|
|
6
|
-
/**
|
|
7
|
-
* Module-global state backing the managed/best-effort render-scope
|
|
8
|
-
* boundary. At most one `RenderStore` is "current" at a time: a component's
|
|
9
|
-
* `.start()` (called at the top of `useSignalsImplementation`, before it
|
|
10
|
-
* reads any signals) opens it, and closing it is what stops later `.value`
|
|
11
|
-
* reads from being attributed to it — every read after a close belongs to
|
|
12
|
-
* whichever scope opens next, not a leftover one from earlier in the render
|
|
13
|
-
* pass.
|
|
14
|
-
*
|
|
15
|
-
* A scope is closed by whichever of these three paths reaches it first:
|
|
16
|
-
*
|
|
17
|
-
* 1. `start()`'s own pre-emptive close (see `shouldCloseCurrentScope`
|
|
18
|
-
* below) — the next component's `start()` finds a still-open scope
|
|
19
|
-
* that isn't a legitimate managed/managed nesting and force-closes it
|
|
20
|
-
* before opening its own, so a scope that outlives its owner's render
|
|
21
|
-
* can't leak reads into a sibling or the next component down.
|
|
22
|
-
* 2. The commit-phase layout effect (`useIsomorphicLayoutEffect` in
|
|
23
|
-
* `useSignalsImplementation`) — the normal, on-time close: the owning
|
|
24
|
-
* component's own scope, if nothing already closed it, is finished
|
|
25
|
-
* right before `store.commit()` subscribes to whatever it read.
|
|
26
|
-
* 3. The microtask scheduled by `ensureFinalCleanup` — the fallback for an
|
|
27
|
-
* unmanaged (`useSignals()`) scope that reaches neither path above, for
|
|
28
|
-
* example a component that reads signals during render but then
|
|
29
|
-
* throws, suspends, or is otherwise abandoned before committing.
|
|
30
|
-
* Managed scopes (`useManagedSignals()`) opt out of this fallback (see
|
|
31
|
-
* the `!managed` guard in `useSignalsImplementation`) because their
|
|
32
|
-
* owner is contractually responsible for calling `finish()`/`f()`
|
|
33
|
-
* itself, synchronously, before returning.
|
|
34
|
-
*/
|
|
35
|
-
let currentStore;
|
|
36
|
-
let finalCleanupScheduled = false;
|
|
37
|
-
/**
|
|
38
|
-
* The nesting rule for path 1 above: a still-open scope is left alone only
|
|
39
|
-
* when both it and the incoming `next` scope are managed. A managed scope's
|
|
40
|
-
* owner is contractually responsible for closing it itself, so two managed
|
|
41
|
-
* scopes overlapping is tolerated as a transient nesting rather than treated
|
|
42
|
-
* as one of them having been abandoned. Anything else overlapping a
|
|
43
|
-
* still-open scope — `next` is unmanaged, or the still-open scope itself is
|
|
44
|
-
* unmanaged — is not a rule-following nesting, so the leftover scope is
|
|
45
|
-
* force-closed before `next` starts.
|
|
46
|
-
*/
|
|
47
|
-
function shouldCloseCurrentScope(next, current) {
|
|
48
|
-
return !next.managed || !current.managed;
|
|
49
|
-
}
|
|
50
|
-
function cleanupTrailingStore() {
|
|
51
|
-
finalCleanupScheduled = false;
|
|
52
|
-
currentStore?.finish();
|
|
53
|
-
}
|
|
54
|
-
function ensureFinalCleanup() {
|
|
55
|
-
if (finalCleanupScheduled) return;
|
|
56
|
-
finalCleanupScheduled = true;
|
|
57
|
-
resolvedPromise.then(cleanupTrailingStore);
|
|
58
|
-
}
|
|
59
|
-
var RenderStore = class {
|
|
60
|
-
managed;
|
|
61
|
-
#reactListeners = /* @__PURE__ */ new Set();
|
|
62
|
-
#dependencySubscriptions = /* @__PURE__ */ new Map();
|
|
63
|
-
#pendingDependencies;
|
|
64
|
-
#finishCollection;
|
|
65
|
-
#disposeGeneration = 0;
|
|
66
|
-
#version = 0;
|
|
67
|
-
constructor(managed) {
|
|
68
|
-
this.managed = managed;
|
|
69
|
-
}
|
|
70
|
-
subscribe = (listener) => {
|
|
71
|
-
this.#disposeGeneration += 1;
|
|
72
|
-
this.#reactListeners.add(listener);
|
|
73
|
-
return () => {
|
|
74
|
-
this.#reactListeners.delete(listener);
|
|
75
|
-
if (this.#reactListeners.size !== 0) return;
|
|
76
|
-
const generation = ++this.#disposeGeneration;
|
|
77
|
-
resolvedPromise.then(() => {
|
|
78
|
-
if (generation === this.#disposeGeneration && this.#reactListeners.size === 0) {
|
|
79
|
-
this.#disposeDependencies();
|
|
80
|
-
this.#pendingDependencies = void 0;
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
getSnapshot = () => this.#version;
|
|
86
|
-
add(dependency) {
|
|
87
|
-
this.#pendingDependencies?.set(dependency, dependency.getRenderVersion());
|
|
88
|
-
}
|
|
89
|
-
start() {
|
|
90
|
-
if (this.#finishCollection !== void 0) this.finish();
|
|
91
|
-
if (currentStore !== void 0 && shouldCloseCurrentScope(this, currentStore)) currentStore.finish();
|
|
92
|
-
const previousStore = currentStore;
|
|
93
|
-
this.#pendingDependencies = /* @__PURE__ */ new Map();
|
|
94
|
-
const previousCollector = setActiveRenderCollector(this);
|
|
95
|
-
currentStore = this;
|
|
96
|
-
this.#finishCollection = () => {
|
|
97
|
-
setActiveRenderCollector(previousCollector);
|
|
98
|
-
if (currentStore === this) currentStore = previousStore;
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
finish() {
|
|
102
|
-
const finishCollection = this.#finishCollection;
|
|
103
|
-
this.#finishCollection = void 0;
|
|
104
|
-
finishCollection?.();
|
|
105
|
-
}
|
|
106
|
-
f() {
|
|
107
|
-
this.finish();
|
|
108
|
-
}
|
|
109
|
-
commit() {
|
|
110
|
-
const dependencies = this.#pendingDependencies;
|
|
111
|
-
this.#pendingDependencies = void 0;
|
|
112
|
-
if (dependencies === void 0) return;
|
|
113
|
-
for (const [dependency, unsubscribe] of this.#dependencySubscriptions) if (!dependencies.has(dependency)) {
|
|
114
|
-
unsubscribe();
|
|
115
|
-
this.#dependencySubscriptions.delete(dependency);
|
|
116
|
-
}
|
|
117
|
-
let changedDuringRender = false;
|
|
118
|
-
for (const [dependency, renderVersion] of dependencies) {
|
|
119
|
-
if (!this.#dependencySubscriptions.has(dependency)) this.#dependencySubscriptions.set(dependency, dependency.subscribeRender(this.#notifyReact));
|
|
120
|
-
if (dependency.getRenderVersion() !== renderVersion) changedDuringRender = true;
|
|
121
|
-
}
|
|
122
|
-
if (changedDuringRender) this.#notifyReact();
|
|
123
|
-
}
|
|
124
|
-
#notifyReact = () => {
|
|
125
|
-
this.#version = this.#version + 1 | 0;
|
|
126
|
-
for (const listener of [...this.#reactListeners]) notifyListener(listener);
|
|
127
|
-
};
|
|
128
|
-
#disposeDependencies() {
|
|
129
|
-
for (const unsubscribe of this.#dependencySubscriptions.values()) unsubscribe();
|
|
130
|
-
this.#dependencySubscriptions.clear();
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
/**
|
|
134
|
-
* Makes the component reactive to signals whose `.value` is read during render.
|
|
135
|
-
* Call this as the component's first hook and before those reads.
|
|
136
|
-
*/
|
|
137
|
-
function useSignalsImplementation(managed) {
|
|
138
|
-
if (!managed) ensureFinalCleanup();
|
|
139
|
-
const storeRef = useRef(void 0);
|
|
140
|
-
if (storeRef.current === void 0) storeRef.current = new RenderStore(managed);
|
|
141
|
-
const store = storeRef.current;
|
|
142
|
-
useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
143
|
-
store.start();
|
|
144
|
-
useIsomorphicLayoutEffect(() => {
|
|
145
|
-
cleanupTrailingStore();
|
|
146
|
-
store.commit();
|
|
147
|
-
});
|
|
148
|
-
return store;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Makes the component reactive to signals whose `.value` is read during render.
|
|
152
|
-
* Call this as the component's first hook and before those reads.
|
|
153
|
-
*
|
|
154
|
-
* The boundary is best-effort: tracking stays open until the next
|
|
155
|
-
* `useSignals()` call, the commit-phase layout effect, or a microtask — not the
|
|
156
|
-
* point the component returns. Every component that reads a signal during
|
|
157
|
-
* render must call this itself; a read from a sibling or descendant that does
|
|
158
|
-
* not can be attributed to another component's still-open boundary, and then
|
|
159
|
-
* silently stops updating the component that read it. Use the bundler
|
|
160
|
-
* plugin's default `transform: "managed"` for an exact boundary. See
|
|
161
|
-
* docs/design/use-signals-boundary-design.md.
|
|
162
|
-
*/
|
|
163
|
-
function useSignals() {
|
|
164
|
-
useSignalsImplementation(false);
|
|
165
|
-
}
|
|
166
|
-
/** Starts a managed render scope that must be closed synchronously with `finish()` (or its `f()` alias). */
|
|
167
|
-
function useManagedSignals() {
|
|
168
|
-
return useSignalsImplementation(true);
|
|
169
|
-
}
|
|
170
|
-
//#endregion
|
|
171
|
-
export { useSignals as n, useManagedSignals as t };
|
|
172
|
-
|
|
173
|
-
//# sourceMappingURL=use-signals-8i2B-94o.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-signals-8i2B-94o.js","names":[],"sources":["../src/react/use-signals.ts"],"sourcesContent":["import {\n useEffect,\n useLayoutEffect,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport {\n notifyListener,\n setActiveRenderCollector,\n type RenderCollector,\n type RenderDependency,\n} from \"../core/render-tracking.js\";\n\nconst useIsomorphicLayoutEffect =\n typeof window === \"undefined\" ? useEffect : useLayoutEffect;\nconst resolvedPromise = Promise.resolve();\n\n/**\n * Module-global state backing the managed/best-effort render-scope\n * boundary. At most one `RenderStore` is \"current\" at a time: a component's\n * `.start()` (called at the top of `useSignalsImplementation`, before it\n * reads any signals) opens it, and closing it is what stops later `.value`\n * reads from being attributed to it — every read after a close belongs to\n * whichever scope opens next, not a leftover one from earlier in the render\n * pass.\n *\n * A scope is closed by whichever of these three paths reaches it first:\n *\n * 1. `start()`'s own pre-emptive close (see `shouldCloseCurrentScope`\n * below) — the next component's `start()` finds a still-open scope\n * that isn't a legitimate managed/managed nesting and force-closes it\n * before opening its own, so a scope that outlives its owner's render\n * can't leak reads into a sibling or the next component down.\n * 2. The commit-phase layout effect (`useIsomorphicLayoutEffect` in\n * `useSignalsImplementation`) — the normal, on-time close: the owning\n * component's own scope, if nothing already closed it, is finished\n * right before `store.commit()` subscribes to whatever it read.\n * 3. The microtask scheduled by `ensureFinalCleanup` — the fallback for an\n * unmanaged (`useSignals()`) scope that reaches neither path above, for\n * example a component that reads signals during render but then\n * throws, suspends, or is otherwise abandoned before committing.\n * Managed scopes (`useManagedSignals()`) opt out of this fallback (see\n * the `!managed` guard in `useSignalsImplementation`) because their\n * owner is contractually responsible for calling `finish()`/`f()`\n * itself, synchronously, before returning.\n */\nlet currentStore: RenderStore | undefined;\nlet finalCleanupScheduled = false;\n\n/**\n * The nesting rule for path 1 above: a still-open scope is left alone only\n * when both it and the incoming `next` scope are managed. A managed scope's\n * owner is contractually responsible for closing it itself, so two managed\n * scopes overlapping is tolerated as a transient nesting rather than treated\n * as one of them having been abandoned. Anything else overlapping a\n * still-open scope — `next` is unmanaged, or the still-open scope itself is\n * unmanaged — is not a rule-following nesting, so the leftover scope is\n * force-closed before `next` starts.\n */\nfunction shouldCloseCurrentScope(next: RenderStore, current: RenderStore): boolean {\n return !next.managed || !current.managed;\n}\n\nfunction cleanupTrailingStore(): void {\n finalCleanupScheduled = false;\n currentStore?.finish();\n}\n\nfunction ensureFinalCleanup(): void {\n if (finalCleanupScheduled) return;\n finalCleanupScheduled = true;\n void resolvedPromise.then(cleanupTrailingStore);\n}\n\nclass RenderStore implements RenderCollector {\n readonly managed: boolean;\n readonly #reactListeners = new Set<() => void>();\n #dependencySubscriptions = new Map<RenderDependency, () => void>();\n // Both are cleared back to `undefined` rather than left absent — that is how\n // \"not collecting\" and \"collection already finished\" are represented — so\n // `undefined` belongs in the type, not just the absence of the slot.\n #pendingDependencies?: Map<RenderDependency, number> | undefined;\n #finishCollection?: (() => void) | undefined;\n #disposeGeneration = 0;\n #version = 0;\n\n constructor(managed: boolean) {\n this.managed = managed;\n }\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.#disposeGeneration += 1;\n this.#reactListeners.add(listener);\n\n return () => {\n this.#reactListeners.delete(listener);\n if (this.#reactListeners.size !== 0) return;\n\n const generation = ++this.#disposeGeneration;\n void resolvedPromise.then(() => {\n if (\n generation === this.#disposeGeneration &&\n this.#reactListeners.size === 0\n ) {\n this.#disposeDependencies();\n this.#pendingDependencies = undefined;\n }\n });\n };\n };\n\n readonly getSnapshot = (): number => this.#version;\n\n add(dependency: RenderDependency): void {\n this.#pendingDependencies?.set(\n dependency,\n dependency.getRenderVersion(),\n );\n }\n\n start(): void {\n // Close this store's own still-open scope first. `shouldCloseCurrentScope`\n // deliberately tolerates managed/managed overlap as legitimate nesting,\n // but legitimate nesting is always between *distinct* store instances —\n // each component owns its own `useRef` slot, so a store can never nest\n // inside itself. A self-overlap therefore always means the previous scope\n // was abandoned (e.g. the commit-phase layout effect threw between two\n // `start()` calls, reachable in dev on a hook-order violation). Without\n // this, `previousCollector`/`previousStore` would both capture `this`, and\n // the eventual `finish()` would restore the collector *to this store* —\n // leaving `activeRenderCollector` permanently non-undefined, so\n // `deepSignal`'s `track()` stops short-circuiting and allocates a version\n // signal for every property read anywhere in the app for the rest of the\n // page's life.\n if (this.#finishCollection !== undefined) this.finish();\n // See `shouldCloseCurrentScope` above for the nesting rule this enforces.\n if (currentStore !== undefined && shouldCloseCurrentScope(this, currentStore)) {\n currentStore.finish();\n }\n const previousStore = currentStore;\n this.#pendingDependencies = new Map();\n const previousCollector = setActiveRenderCollector(this);\n // Tracks the active collector across the module, not a scoping mistake.\n // oxlint-disable-next-line typescript/no-this-alias\n currentStore = this;\n this.#finishCollection = () => {\n setActiveRenderCollector(previousCollector);\n if (currentStore === this) currentStore = previousStore;\n };\n }\n\n finish(): void {\n const finishCollection = this.#finishCollection;\n this.#finishCollection = undefined;\n finishCollection?.();\n }\n\n f(): void {\n this.finish();\n }\n\n commit(): void {\n const dependencies = this.#pendingDependencies;\n this.#pendingDependencies = undefined;\n if (dependencies === undefined) return;\n\n // Diff against the previous commit's subscriptions instead of\n // unconditionally tearing everything down and resubscribing: a\n // dependency still read on this render keeps its existing subscription\n // alive. Unsubscribing a computed's render bridge only to immediately\n // resubscribe forces it through a cold first evaluation every commit,\n // which loses its Object.is memoization for any getter that returns a\n // new object/array identity each call (e.g. `.slice()`/`.filter()`) —\n // that cold read always looks \"changed\", which forced another commit,\n // forever. Keeping a continuously-read dependency's subscription intact\n // avoids that churn entirely.\n for (const [dependency, unsubscribe] of this.#dependencySubscriptions) {\n if (!dependencies.has(dependency)) {\n unsubscribe();\n this.#dependencySubscriptions.delete(dependency);\n }\n }\n\n let changedDuringRender = false;\n for (const [dependency, renderVersion] of dependencies) {\n if (!this.#dependencySubscriptions.has(dependency)) {\n this.#dependencySubscriptions.set(\n dependency,\n dependency.subscribeRender(this.#notifyReact),\n );\n }\n if (dependency.getRenderVersion() !== renderVersion) {\n changedDuringRender = true;\n }\n }\n\n if (changedDuringRender) this.#notifyReact();\n }\n\n readonly #notifyReact = (): void => {\n this.#version = (this.#version + 1) | 0;\n // Snapshot before iterating: a listener may (un)subscribe synchronously.\n // `notifyListener` isolates a throwing listener so it cannot cancel the\n // ones queued behind it in this same cycle.\n // oxlint-disable-next-line unicorn/no-useless-spread\n for (const listener of [...this.#reactListeners]) notifyListener(listener);\n };\n\n #disposeDependencies(): void {\n for (const unsubscribe of this.#dependencySubscriptions.values()) {\n unsubscribe();\n }\n this.#dependencySubscriptions.clear();\n }\n}\n\n/**\n * Makes the component reactive to signals whose `.value` is read during render.\n * Call this as the component's first hook and before those reads.\n */\nfunction useSignalsImplementation(managed: boolean): RenderStore {\n if (!managed) ensureFinalCleanup();\n const storeRef = useRef<RenderStore | undefined>(undefined);\n if (storeRef.current === undefined) storeRef.current = new RenderStore(managed);\n const store = storeRef.current;\n\n useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n store.start();\n useIsomorphicLayoutEffect(() => {\n cleanupTrailingStore();\n store.commit();\n });\n return store;\n}\n\n/**\n * Makes the component reactive to signals whose `.value` is read during render.\n * Call this as the component's first hook and before those reads.\n *\n * The boundary is best-effort: tracking stays open until the next\n * `useSignals()` call, the commit-phase layout effect, or a microtask — not the\n * point the component returns. Every component that reads a signal during\n * render must call this itself; a read from a sibling or descendant that does\n * not can be attributed to another component's still-open boundary, and then\n * silently stops updating the component that read it. Use the bundler\n * plugin's default `transform: \"managed\"` for an exact boundary. See\n * docs/design/use-signals-boundary-design.md.\n */\nexport function useSignals(): void {\n useSignalsImplementation(false);\n}\n\n/** The render-scope handle consumed by the source transform runtime. */\nexport interface ManagedSignalsStore {\n finish(): void;\n f(): void;\n}\n\n/** Starts a managed render scope that must be closed synchronously with `finish()` (or its `f()` alias). */\nexport function useManagedSignals(): ManagedSignalsStore {\n return useSignalsImplementation(true);\n}\n"],"mappings":"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"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
//#region src/react/use-signals.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Makes the component reactive to signals whose `.value` is read during render.
|
|
4
|
-
* Call this as the component's first hook and before those reads.
|
|
5
|
-
*
|
|
6
|
-
* The boundary is best-effort: tracking stays open until the next
|
|
7
|
-
* `useSignals()` call, the commit-phase layout effect, or a microtask — not the
|
|
8
|
-
* point the component returns. Every component that reads a signal during
|
|
9
|
-
* render must call this itself; a read from a sibling or descendant that does
|
|
10
|
-
* not can be attributed to another component's still-open boundary, and then
|
|
11
|
-
* silently stops updating the component that read it. Use the bundler
|
|
12
|
-
* plugin's default `transform: "managed"` for an exact boundary. See
|
|
13
|
-
* docs/design/use-signals-boundary-design.md.
|
|
14
|
-
*/
|
|
15
|
-
declare function useSignals(): void;
|
|
16
|
-
/** The render-scope handle consumed by the source transform runtime. */
|
|
17
|
-
interface ManagedSignalsStore {
|
|
18
|
-
finish(): void;
|
|
19
|
-
f(): void;
|
|
20
|
-
}
|
|
21
|
-
/** Starts a managed render scope that must be closed synchronously with `finish()` (or its `f()` alias). */
|
|
22
|
-
declare function useManagedSignals(): ManagedSignalsStore;
|
|
23
|
-
//#endregion
|
|
24
|
-
export { useManagedSignals as n, useSignals as r, ManagedSignalsStore as t };
|