@takazudo/zfb 3.0.0 → 3.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/README.md +8 -7
- package/dist/config.d.ts +43 -9
- package/dist/config.js +23 -12
- package/dist/config.js.map +1 -1
- package/dist/content.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -1
- package/dist/island-boundary.d.ts +2 -2
- package/dist/island-boundary.js +4 -2
- package/dist/island-boundary.js.map +1 -1
- package/dist/island.d.ts +8 -4
- package/dist/island.js +1 -1
- package/dist/island.js.map +1 -1
- package/dist/jsx-types.d.ts +1 -1
- package/dist/jsx-types.js.map +1 -1
- package/dist/runtime.d.ts +7 -4
- package/dist/runtime.js +166 -28
- package/dist/runtime.js.map +1 -1
- package/dist/slugify.js.map +1 -1
- package/dist/zudo-react/description.d.ts +18 -0
- package/dist/zudo-react/description.js +41 -0
- package/dist/zudo-react/description.js.map +1 -1
- package/dist/zudo-react/dom-bindings.d.ts +2 -1
- package/dist/zudo-react/dom-bindings.js +16 -22
- package/dist/zudo-react/dom-bindings.js.map +1 -1
- package/dist/zudo-react/forms.js.map +1 -1
- package/dist/zudo-react/hydrate.js +27 -34
- package/dist/zudo-react/hydrate.js.map +1 -1
- package/dist/zudo-react/index.d.ts +2 -1
- package/dist/zudo-react/index.js.map +1 -1
- package/dist/zudo-react/jsx-dev-runtime.d.ts +2 -6
- package/dist/zudo-react/jsx-dev-runtime.js +3 -3
- package/dist/zudo-react/jsx-dev-runtime.js.map +1 -1
- package/dist/zudo-react/jsx-runtime.js +2 -2
- package/dist/zudo-react/jsx-runtime.js.map +1 -1
- package/dist/zudo-react/jsx-types.d.ts +80 -31
- package/dist/zudo-react/jsx-types.js.map +1 -1
- package/dist/zudo-react/props-transport.d.ts +2 -0
- package/dist/zudo-react/props-transport.js +42 -14
- package/dist/zudo-react/props-transport.js.map +1 -1
- package/dist/zudo-react/raw-html.d.ts +1 -0
- package/dist/zudo-react/raw-html.js +120 -0
- package/dist/zudo-react/raw-html.js.map +1 -0
- package/dist/zudo-react/reactive.js.map +1 -1
- package/dist/zudo-react/render-html.d.ts +11 -1
- package/dist/zudo-react/render-html.js +96 -71
- package/dist/zudo-react/render-html.js.map +1 -1
- package/dist/zudo-react/root.js +24 -1
- package/dist/zudo-react/root.js.map +1 -1
- package/dist/zudo-react/server.d.ts +2 -0
- package/dist/zudo-react/server.js.map +1 -1
- package/dist/zudo-react/structure.d.ts +2 -0
- package/dist/zudo-react/structure.js +14 -0
- package/dist/zudo-react/structure.js.map +1 -1
- package/dist/zudo-react/style.d.ts +10 -0
- package/dist/zudo-react/style.js +525 -0
- package/dist/zudo-react/style.js.map +1 -0
- package/dist/zudo-react/testing.d.ts +27 -0
- package/dist/zudo-react/testing.js +117 -0
- package/dist/zudo-react/testing.js.map +1 -0
- package/dist/zudo-react/vocabulary.d.ts +19 -0
- package/dist/zudo-react/vocabulary.js +155 -0
- package/dist/zudo-react/vocabulary.js.map +1 -0
- package/package.json +16 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactive.js","sourceRoot":"","sources":["../../src/zudo-react/reactive.ts"],"names":[],"mappings":"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","sourcesContent":["import { enqueue, type Job, type Phase } from \"./scheduler.js\";\nimport type { ReadonlySignal, Signal } from \"./reactive-types.js\";\n\ninterface Source {\n readonly subscribers: Set<Observer>;\n}\ninterface Observer {\n readonly id: string;\n readonly dependencies: Set<Source>;\n invalidate(): void;\n}\nlet currentObserver: Observer | null = null;\nlet evaluating = 0;\nconst evaluationStack: Computed<unknown>[] = [];\nlet nextId = 0;\n\n// The quoted own key is the retained runtime definition witness.\nconst core = { \"@takazudo/zfb/zudo-react/runtime-definition-v1\": true, nextId: () => ++nextId };\n\nfunction track(source: Source): void {\n if (!currentObserver) return;\n source.subscribers.add(currentObserver);\n currentObserver.dependencies.add(source);\n}\nfunction detach(observer: Observer): void {\n for (const source of observer.dependencies) source.subscribers.delete(observer);\n observer.dependencies.clear();\n}\nfunction untracked<T>(fn: () => T): T {\n const previous = currentObserver;\n currentObserver = null;\n try {\n return fn();\n } finally {\n currentObserver = previous;\n }\n}\nexport { untracked };\n\nclass Writable<T> implements Signal<T>, Source {\n readonly $$zudoReactive = \"zudo-react.reactive.v1\" as const;\n readonly $$zudoWritable = \"zudo-react.writable.v1\" as const;\n readonly subscribers = new Set<Observer>();\n constructor(private current: T) {\n if (!core[\"@takazudo/zfb/zudo-react/runtime-definition-v1\"])\n throw new Error(\"ZR_RUNTIME_DEFINITION\");\n }\n get value(): T {\n track(this);\n return this.current;\n }\n set value(value: T) {\n if (evaluating > 0) throw new Error(\"ZR_COMPUTED_WRITE: write during computed evaluation\");\n if (Object.is(value, this.current)) return;\n this.current = value;\n for (const observer of [...this.subscribers]) observer.invalidate();\n }\n}\n\nclass Computed<T> implements ReadonlySignal<T>, Source, Observer {\n readonly $$zudoReactive = \"zudo-react.reactive.v1\" as const;\n readonly id = `computed:${core.nextId()}`;\n readonly subscribers = new Set<Observer>();\n readonly dependencies = new Set<Source>();\n private cached!: T;\n private dirty = true;\n private evaluatingNow = false;\n constructor(private readonly read: () => T) {}\n get value(): T {\n if (this.evaluatingNow) {\n throw new Error(\n `ZR_COMPUTED_CYCLE: ${[...evaluationStack.map((entry) => entry.id), this.id].join(\" -> \")}`,\n );\n }\n if (this.dirty) this.evaluate();\n track(this);\n if (this.subscribers.size === 0) {\n detachAndRelease(this);\n this.dirty = true;\n }\n return this.cached;\n }\n private evaluate(): void {\n detachAndRelease(this);\n const previous = currentObserver;\n currentObserver = this;\n this.evaluatingNow = true;\n evaluationStack.push(this as Computed<unknown>);\n evaluating++;\n try {\n this.cached = this.read();\n this.dirty = false;\n } catch (error) {\n detachAndRelease(this);\n throw error;\n } finally {\n evaluating--;\n evaluationStack.pop();\n this.evaluatingNow = false;\n currentObserver = previous;\n }\n }\n invalidate(): void {\n if (this.dirty) return;\n this.dirty = true;\n for (const observer of [...this.subscribers]) observer.invalidate();\n }\n release(): void {\n if (this.subscribers.size === 0) {\n detachAndRelease(this);\n this.dirty = true;\n }\n }\n}\n\nfunction release(source: Source): void {\n if (source instanceof Computed) source.release();\n}\nfunction detachAndRelease(observer: Observer): void {\n const sources = [...observer.dependencies];\n detach(observer);\n for (const source of sources) release(source);\n}\n\nexport function signal<T>(initial: T): Signal<T> {\n return new Writable(initial);\n}\nexport function computed<T>(read: () => T): ReadonlySignal<T> {\n return new Computed(read);\n}\nexport function readSnapshot<T>(value: ReadonlySignal<T>): T {\n return untracked(() => value.value);\n}\n\nexport interface Subscription {\n readonly id: string;\n run(): void;\n dispose(): void;\n}\nexport function subscribe(\n callback: () => void,\n options: { phase?: Phase; id?: string; active?: () => boolean; report?: Job[\"report\"] } = {},\n): Subscription {\n let disposed = false;\n const observer: Observer = {\n id: options.id ?? `subscriber:${core.nextId()}`,\n dependencies: new Set(),\n invalidate() {\n enqueue(job);\n },\n };\n const job: Job = {\n id: observer.id,\n phase: options.phase ?? \"commit\",\n active: () => !disposed && (options.active?.() ?? true),\n run: () => subscription.run(),\n ...(options.report ? { report: options.report } : {}),\n };\n const subscription: Subscription = {\n id: observer.id,\n run() {\n if (!job.active()) return;\n detachAndRelease(observer);\n const previous = currentObserver;\n currentObserver = observer;\n try {\n callback();\n } finally {\n currentObserver = previous;\n }\n },\n dispose() {\n disposed = true;\n detachAndRelease(observer);\n },\n };\n return subscription;\n}\n\n/** Internal test introspection; absent from every public entry. */\nexport function subscriberCount(value: ReadonlySignal<unknown>): number {\n return value instanceof Writable || value instanceof Computed ? value.subscribers.size : 0;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reactive.js","sourceRoot":"","sources":["../../src/zudo-react/reactive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAwB,MAAM,gBAAgB,CAAC;AAW/D,IAAI,eAAe,GAAoB,IAAI,CAAC;AAC5C,IAAI,UAAU,GAAG,CAAC,CAAC;AACnB,MAAM,eAAe,GAAwB,EAAE,CAAC;AAChD,IAAI,MAAM,GAAG,CAAC,CAAC;AAEf,iEAAiE;AACjE,MAAM,IAAI,GAAG,EAAE,gDAAgD,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AAEhG,SAAS,KAAK,CAAC,MAAc;IAC3B,IAAI,CAAC,eAAe;QAAE,OAAO;IAC7B,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACxC,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AACD,SAAS,MAAM,CAAC,QAAkB;IAChC,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,YAAY;QAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChF,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;AAChC,CAAC;AACD,SAAS,SAAS,CAAI,EAAW;IAC/B,MAAM,QAAQ,GAAG,eAAe,CAAC;IACjC,eAAe,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,eAAe,GAAG,QAAQ,CAAC;IAC7B,CAAC;AACH,CAAC;AACD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,MAAM,QAAQ;IAIQ,OAAO;IAHlB,cAAc,GAAG,wBAAiC,CAAC;IACnD,cAAc,GAAG,wBAAiC,CAAC;IACnD,WAAW,GAAG,IAAI,GAAG,EAAY,CAAC;IAC3C,YAAoB,OAAU;uBAAV,OAAO;QACzB,IAAI,CAAC,IAAI,CAAC,gDAAgD,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,KAAK;QACP,KAAK,CAAC,IAAI,CAAC,CAAC;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,IAAI,KAAK,CAAC,KAAQ;QAChB,IAAI,UAAU,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QAC3F,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO;QAC3C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;YAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;IACtE,CAAC;CACF;AAED,MAAM,QAAQ;IAQiB,IAAI;IAPxB,cAAc,GAAG,wBAAiC,CAAC;IACnD,EAAE,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IACjC,WAAW,GAAG,IAAI,GAAG,EAAY,CAAC;IAClC,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,CAAK;IACX,KAAK,GAAG,IAAI,CAAC;IACb,aAAa,GAAG,KAAK,CAAC;IAC9B,YAA6B,IAAa;oBAAb,IAAI;IAAY,CAAC;IAC9C,IAAI,KAAK;QACP,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,sBAAsB,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAC5F,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,CAAC;QACZ,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAChC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IACO,QAAQ;QACd,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,QAAQ,GAAG,eAAe,CAAC;QACjC,eAAe,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,eAAe,CAAC,IAAI,CAAC,IAAyB,CAAC,CAAC;QAChD,UAAU,EAAE,CAAC;QACb,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACvB,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,UAAU,EAAE,CAAC;YACb,eAAe,CAAC,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;YAC3B,eAAe,GAAG,QAAQ,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,UAAU;QACR,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;YAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;IACtE,CAAC;IACD,OAAO;QACL,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAChC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;CACF;AAED,SAAS,OAAO,CAAC,MAAc;IAC7B,IAAI,MAAM,YAAY,QAAQ;QAAE,MAAM,CAAC,OAAO,EAAE,CAAC;AACnD,CAAC;AACD,SAAS,gBAAgB,CAAC,QAAkB;IAC1C,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC3C,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjB,KAAK,MAAM,MAAM,IAAI,OAAO;QAAE,OAAO,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,MAAM,CAAI,OAAU;IAClC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AACD,MAAM,UAAU,QAAQ,CAAI,IAAa;IACvC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AACD,MAAM,UAAU,YAAY,CAAI,KAAwB;IACtD,OAAO,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAOD,MAAM,UAAU,SAAS,CACvB,QAAoB,EACpB,OAAO,GAAmF,EAAE;IAE5F,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,QAAQ,GAAa;QACzB,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,cAAc,IAAI,CAAC,MAAM,EAAE,EAAE;QAC/C,YAAY,EAAE,IAAI,GAAG,EAAE;QACvB,UAAU;YACR,OAAO,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;KACF,CAAC;IACF,MAAM,GAAG,GAAQ;QACf,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,QAAQ;QAChC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC;QACvD,GAAG,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE;QAC7B,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;IACF,MAAM,YAAY,GAAiB;QACjC,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,GAAG;YACD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE;gBAAE,OAAO;YAC1B,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC3B,MAAM,QAAQ,GAAG,eAAe,CAAC;YACjC,eAAe,GAAG,QAAQ,CAAC;YAC3B,IAAI,CAAC;gBACH,QAAQ,EAAE,CAAC;YACb,CAAC;oBAAS,CAAC;gBACT,eAAe,GAAG,QAAQ,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,OAAO;YACL,QAAQ,GAAG,IAAI,CAAC;YAChB,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;IACF,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,KAA8B;IAC5D,OAAO,KAAK,YAAY,QAAQ,IAAI,KAAK,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7F,CAAC","sourcesContent":["import { enqueue, type Job, type Phase } from \"./scheduler.js\";\nimport type { ReadonlySignal, Signal } from \"./reactive-types.js\";\n\ninterface Source {\n readonly subscribers: Set<Observer>;\n}\ninterface Observer {\n readonly id: string;\n readonly dependencies: Set<Source>;\n invalidate(): void;\n}\nlet currentObserver: Observer | null = null;\nlet evaluating = 0;\nconst evaluationStack: Computed<unknown>[] = [];\nlet nextId = 0;\n\n// The quoted own key is the retained runtime definition witness.\nconst core = { \"@takazudo/zfb/zudo-react/runtime-definition-v1\": true, nextId: () => ++nextId };\n\nfunction track(source: Source): void {\n if (!currentObserver) return;\n source.subscribers.add(currentObserver);\n currentObserver.dependencies.add(source);\n}\nfunction detach(observer: Observer): void {\n for (const source of observer.dependencies) source.subscribers.delete(observer);\n observer.dependencies.clear();\n}\nfunction untracked<T>(fn: () => T): T {\n const previous = currentObserver;\n currentObserver = null;\n try {\n return fn();\n } finally {\n currentObserver = previous;\n }\n}\nexport { untracked };\n\nclass Writable<T> implements Signal<T>, Source {\n readonly $$zudoReactive = \"zudo-react.reactive.v1\" as const;\n readonly $$zudoWritable = \"zudo-react.writable.v1\" as const;\n readonly subscribers = new Set<Observer>();\n constructor(private current: T) {\n if (!core[\"@takazudo/zfb/zudo-react/runtime-definition-v1\"])\n throw new Error(\"ZR_RUNTIME_DEFINITION\");\n }\n get value(): T {\n track(this);\n return this.current;\n }\n set value(value: T) {\n if (evaluating > 0) throw new Error(\"ZR_COMPUTED_WRITE: write during computed evaluation\");\n if (Object.is(value, this.current)) return;\n this.current = value;\n for (const observer of [...this.subscribers]) observer.invalidate();\n }\n}\n\nclass Computed<T> implements ReadonlySignal<T>, Source, Observer {\n readonly $$zudoReactive = \"zudo-react.reactive.v1\" as const;\n readonly id = `computed:${core.nextId()}`;\n readonly subscribers = new Set<Observer>();\n readonly dependencies = new Set<Source>();\n private cached!: T;\n private dirty = true;\n private evaluatingNow = false;\n constructor(private readonly read: () => T) {}\n get value(): T {\n if (this.evaluatingNow) {\n throw new Error(\n `ZR_COMPUTED_CYCLE: ${[...evaluationStack.map((entry) => entry.id), this.id].join(\" -> \")}`,\n );\n }\n if (this.dirty) this.evaluate();\n track(this);\n if (this.subscribers.size === 0) {\n detachAndRelease(this);\n this.dirty = true;\n }\n return this.cached;\n }\n private evaluate(): void {\n detachAndRelease(this);\n const previous = currentObserver;\n currentObserver = this;\n this.evaluatingNow = true;\n evaluationStack.push(this as Computed<unknown>);\n evaluating++;\n try {\n this.cached = this.read();\n this.dirty = false;\n } catch (error) {\n detachAndRelease(this);\n throw error;\n } finally {\n evaluating--;\n evaluationStack.pop();\n this.evaluatingNow = false;\n currentObserver = previous;\n }\n }\n invalidate(): void {\n if (this.dirty) return;\n this.dirty = true;\n for (const observer of [...this.subscribers]) observer.invalidate();\n }\n release(): void {\n if (this.subscribers.size === 0) {\n detachAndRelease(this);\n this.dirty = true;\n }\n }\n}\n\nfunction release(source: Source): void {\n if (source instanceof Computed) source.release();\n}\nfunction detachAndRelease(observer: Observer): void {\n const sources = [...observer.dependencies];\n detach(observer);\n for (const source of sources) release(source);\n}\n\nexport function signal<T>(initial: T): Signal<T> {\n return new Writable(initial);\n}\nexport function computed<T>(read: () => T): ReadonlySignal<T> {\n return new Computed(read);\n}\nexport function readSnapshot<T>(value: ReadonlySignal<T>): T {\n return untracked(() => value.value);\n}\n\nexport interface Subscription {\n readonly id: string;\n run(): void;\n dispose(): void;\n}\nexport function subscribe(\n callback: () => void,\n options: { phase?: Phase; id?: string; active?: () => boolean; report?: Job[\"report\"] } = {},\n): Subscription {\n let disposed = false;\n const observer: Observer = {\n id: options.id ?? `subscriber:${core.nextId()}`,\n dependencies: new Set(),\n invalidate() {\n enqueue(job);\n },\n };\n const job: Job = {\n id: observer.id,\n phase: options.phase ?? \"commit\",\n active: () => !disposed && (options.active?.() ?? true),\n run: () => subscription.run(),\n ...(options.report ? { report: options.report } : {}),\n };\n const subscription: Subscription = {\n id: observer.id,\n run() {\n if (!job.active()) return;\n detachAndRelease(observer);\n const previous = currentObserver;\n currentObserver = observer;\n try {\n callback();\n } finally {\n currentObserver = previous;\n }\n },\n dispose() {\n disposed = true;\n detachAndRelease(observer);\n },\n };\n return subscription;\n}\n\n/** Internal test introspection; absent from every public entry. */\nexport function subscriberCount(value: ReadonlySignal<unknown>): number {\n return value instanceof Writable || value instanceof Computed ? value.subscribers.size : 0;\n}\n"]}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
import { type Child } from "./description.js";
|
|
1
|
+
import { type Child, type DescriptionSite } from "./description.js";
|
|
2
2
|
import type { RenderOptions } from "./server.js";
|
|
3
|
+
export interface RenderDiagnostic {
|
|
4
|
+
readonly code: string;
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly component: string;
|
|
7
|
+
readonly spelling?: {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly suggestion?: string;
|
|
10
|
+
};
|
|
11
|
+
readonly site?: DescriptionSite;
|
|
12
|
+
}
|
|
3
13
|
export declare function renderHtml(node: Child, options: RenderOptions): string;
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serializeStyle } from "./style.js";
|
|
2
|
+
import { Fragment, descriptionSite, isDescription, } from "./description.js";
|
|
2
3
|
import { escapeAttribute, escapeText } from "./escape.js";
|
|
4
|
+
import { rawHtmlReserved } from "./raw-html.js";
|
|
3
5
|
import { readSnapshot } from "./reactive.js";
|
|
4
6
|
import { createScope, withScope } from "./scope.js";
|
|
5
|
-
import {
|
|
7
|
+
import { emptyChildren, normalizeProps } from "./props-transport.js";
|
|
6
8
|
import { islandRootType } from "./island-root-type.js";
|
|
7
|
-
import {
|
|
9
|
+
import { isShowType, isForType, showProps, forProps, keyed, keyPayload, view, } from "./structure.js";
|
|
10
|
+
import { attributeError, attributeText, booleanAttrs, commonAttrs, dialectSuggestion, emptyIframeChildren, formProps, htmlAttrs, htmlTags, isDialectProp, reactiveModelSuggestion, svgAttrs, svgTags, voidTags, } from "./vocabulary.js";
|
|
8
11
|
const words = (value) => new Set(value.split(" "));
|
|
9
|
-
const voidTags = words("area base br col embed hr img input link meta param source track wbr");
|
|
10
|
-
const booleanAttrs = words("hidden inert readonly autofocus required disabled checked selected multiple open controls muted loop autoplay novalidate formnovalidate allowfullscreen");
|
|
11
|
-
const commonAttrs = words("id class title lang dir slot role style hidden inert contenteditable draggable spellcheck tabindex accesskey translate onclick onload onerror");
|
|
12
|
-
const htmlAttrs = words("href target rel download src alt width height type name value placeholder for charset datetime readonly autofocus required disabled checked selected multiple open controls muted loop autoplay novalidate formnovalidate maxlength minlength min max step pattern autocomplete accept accept-charset http-equiv content media method action enctype rows cols colspan rowspan scope cite poster loading decoding sizes srcset crossorigin referrerpolicy sandbox allow allowfullscreen");
|
|
13
|
-
const svgAttrs = words("width height viewBox preserveAspectRatio gradientUnits gradientTransform markerWidth markerHeight refX refY xlink:href xml:lang stroke-width fill-rule clip-rule stroke-linecap stroke-linejoin stop-color stop-opacity fill stroke d x y x1 x2 y1 y2 cx cy r rx ry points transform opacity offset");
|
|
14
|
-
const svgTags = words("svg g path circle ellipse rect line polyline polygon text tspan defs symbol use clipPath mask linearGradient radialGradient stop title desc foreignObject");
|
|
15
|
-
const htmlTags = words("html head body title base link meta style script div span p a br hr main header footer nav section article aside h1 h2 h3 h4 h5 h6 ul ol li dl dt dd blockquote pre code strong em b i small mark time figure figcaption img picture source video audio track canvas form label input button textarea select option optgroup fieldset legend output progress meter datalist table caption thead tbody tfoot tr th td col colgroup details summary dialog template slot iframe noscript address abbr bdi bdo cite data del dfn ins kbd map area object param q rp rt ruby s samp sub sup u var wbr embed xmp noembed noframes plaintext");
|
|
16
|
-
const dialect = words("className htmlFor charSet dateTime tabIndex readOnly strokeWidth dangerouslySetInnerHTML");
|
|
17
12
|
const reserved = words("key ref children rawHtml");
|
|
18
|
-
const forms = words("modelValue modelChecked defaultValue defaultChecked");
|
|
19
13
|
const sensitive = words("noscript xmp iframe noembed noframes plaintext");
|
|
20
14
|
const tableChildren = {
|
|
21
15
|
table: words("caption colgroup thead tbody tfoot"),
|
|
@@ -25,8 +19,19 @@ const tableChildren = {
|
|
|
25
19
|
tr: words("td th"),
|
|
26
20
|
colgroup: words("col"),
|
|
27
21
|
};
|
|
28
|
-
function fail(code, context, detail) {
|
|
29
|
-
|
|
22
|
+
function fail(code, context, detail, spelling) {
|
|
23
|
+
const component = context.identity?.component ?? "static render";
|
|
24
|
+
const site = context.node && descriptionSite(context.node);
|
|
25
|
+
const diagnostic = {
|
|
26
|
+
code,
|
|
27
|
+
path: context.path,
|
|
28
|
+
component,
|
|
29
|
+
...(spelling && { spelling }),
|
|
30
|
+
...(site && { site }),
|
|
31
|
+
};
|
|
32
|
+
throw Object.assign(new TypeError(`${code}: ${detail} at ${context.path} in ${component}`), {
|
|
33
|
+
diagnostic,
|
|
34
|
+
});
|
|
30
35
|
}
|
|
31
36
|
function reactive(value) {
|
|
32
37
|
return (typeof value === "object" &&
|
|
@@ -70,34 +75,26 @@ function renderText(value, context) {
|
|
|
70
75
|
fail("ZR_CHILD", context, `invalid scalar ${typeof value}`);
|
|
71
76
|
}
|
|
72
77
|
function style(value, context) {
|
|
73
|
-
|
|
74
|
-
return value;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
let result = "";
|
|
81
|
-
for (const [name, entry] of Object.entries(value)) {
|
|
82
|
-
if (!/^(--[a-zA-Z0-9_-]+|[a-z][a-z0-9-]*)$/.test(name) || /[A-Z]/.test(name))
|
|
83
|
-
fail("ZR_STYLE", context, `invalid property ${name}`);
|
|
84
|
-
if (entry == null)
|
|
85
|
-
continue;
|
|
86
|
-
if (typeof entry !== "string" && !(typeof entry === "number" && Number.isFinite(entry)))
|
|
87
|
-
fail("ZR_STYLE", context, `invalid value for ${name}`);
|
|
88
|
-
result += `${name}:${entry};`;
|
|
78
|
+
try {
|
|
79
|
+
return serializeStyle(value);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof TypeError)
|
|
83
|
+
fail("ZR_STYLE", context, error.message.replace(/^ZR_STYLE: /, ""));
|
|
84
|
+
throw error;
|
|
89
85
|
}
|
|
90
|
-
return result;
|
|
91
86
|
}
|
|
92
87
|
function attributes(tag, props, context, namespace, custom) {
|
|
93
88
|
let output = "";
|
|
94
89
|
for (const [name, original] of Object.entries(props)) {
|
|
95
90
|
if (reserved.has(name))
|
|
96
91
|
continue;
|
|
97
|
-
if (
|
|
92
|
+
if (formProps.has(name))
|
|
98
93
|
continue;
|
|
99
|
-
if (
|
|
100
|
-
|
|
94
|
+
if (isDialectProp(name, namespace, custom)) {
|
|
95
|
+
const suggestion = dialectSuggestion(name, namespace, custom);
|
|
96
|
+
fail("ZR_PROP_DIALECT", context, `${tag}.${name}${suggestion ? ` (use \`${suggestion}\` instead of \`${name}\`)` : ""}`, suggestion ? { name, suggestion } : { name });
|
|
97
|
+
}
|
|
101
98
|
if (name.startsWith("on:")) {
|
|
102
99
|
if (!/^on:[A-Za-z][A-Za-z0-9_-]*(?::capture)?$/.test(name))
|
|
103
100
|
fail("ZR_LISTENER", context, `${tag}.${name}`);
|
|
@@ -118,37 +115,32 @@ function attributes(tag, props, context, namespace, custom) {
|
|
|
118
115
|
!/^on[a-z]+$/.test(name))
|
|
119
116
|
fail("ZR_ATTRIBUTE", context, `${tag}.${name}`);
|
|
120
117
|
const value = read(original);
|
|
121
|
-
if ((name === "value" || name === "checked") && reactive(original))
|
|
122
|
-
|
|
118
|
+
if ((name === "value" || name === "checked") && reactive(original)) {
|
|
119
|
+
const suggestion = reactiveModelSuggestion(tag, name, String(read(props.type) ?? "text"), custom);
|
|
120
|
+
fail("ZR_MODEL_UNSUPPORTED", context, `${tag}.${name} requires ${suggestion ?? "a static value"}`);
|
|
121
|
+
}
|
|
122
|
+
if (/^on[a-z]/.test(name) && typeof value === "function")
|
|
123
|
+
fail("ZR_PROP_DIALECT", context, `${tag}.${name} must use on:${name.slice(2)}`, {
|
|
124
|
+
name,
|
|
125
|
+
suggestion: `on:${name.slice(2)}`,
|
|
126
|
+
});
|
|
127
|
+
const error = attributeError(name, value, custom);
|
|
128
|
+
if (error)
|
|
129
|
+
fail("ZR_ATTRIBUTE", context, `${tag}.${name} ${error}`);
|
|
123
130
|
if (value == null)
|
|
124
131
|
continue;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
output += ` style="${escapeAttribute(style(value, context))}"`;
|
|
131
|
-
else if (booleanAttrs.has(name)) {
|
|
132
|
-
if (typeof value !== "boolean")
|
|
133
|
-
fail("ZR_ATTRIBUTE", context, `${tag}.${name} requires a boolean`);
|
|
134
|
-
if (value)
|
|
135
|
-
output += ` ${name}`;
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
if (typeof value !== "string" &&
|
|
139
|
-
typeof value !== "boolean" &&
|
|
140
|
-
!(typeof value === "number" && Number.isFinite(value)))
|
|
141
|
-
fail("ZR_ATTRIBUTE", context, `${tag}.${name} requires a scalar`);
|
|
142
|
-
if (typeof value === "boolean" && !name.startsWith("aria-") && !name.startsWith("data-"))
|
|
143
|
-
fail("ZR_ATTRIBUTE", context, `${tag}.${name} requires a string`);
|
|
144
|
-
if (/^on[a-z]/.test(name) && typeof value !== "string")
|
|
145
|
-
fail("ZR_ATTRIBUTE", context, `${tag}.${name} requires a string`);
|
|
146
|
-
output += ` ${name}="${escapeAttribute(String(value))}"`;
|
|
147
|
-
}
|
|
132
|
+
const text = name === "style" ? style(value, context) : attributeText(name, value);
|
|
133
|
+
if (text === null)
|
|
134
|
+
continue;
|
|
135
|
+
output +=
|
|
136
|
+
booleanAttrs.has(name) && value === true ? ` ${name}` : ` ${name}="${escapeAttribute(text)}"`;
|
|
148
137
|
}
|
|
149
138
|
return output;
|
|
150
139
|
}
|
|
151
140
|
function restricted(value, context, namespace, parent) {
|
|
141
|
+
return tracked(value, context, () => restrictedValue(value, context, namespace, parent));
|
|
142
|
+
}
|
|
143
|
+
function restrictedValue(value, context, namespace, parent) {
|
|
152
144
|
if (value == null || typeof value === "boolean")
|
|
153
145
|
return "";
|
|
154
146
|
if (Array.isArray(value))
|
|
@@ -173,7 +165,7 @@ function element(description, context, namespace, parent) {
|
|
|
173
165
|
const childNamespace = tag === "foreignObject" ? "html" : elementNamespace;
|
|
174
166
|
if (elementNamespace === "svg" ? !svgTags.has(tag) : !custom && !htmlTags.has(tag))
|
|
175
167
|
fail("ZR_TAG", context, tag);
|
|
176
|
-
if (context.identity && (tag === "template" || sensitive.has(tag)))
|
|
168
|
+
if (context.identity && (tag === "template" || (tag !== "iframe" && sensitive.has(tag))))
|
|
177
169
|
fail("ZR_PARSER_CONTEXT", context, tag);
|
|
178
170
|
if (parent in tableChildren && !tableChildren[parent]?.has(tag))
|
|
179
171
|
fail("ZR_PARSER_CONTEXT", context, `${parent} > ${tag}`);
|
|
@@ -188,6 +180,12 @@ function element(description, context, namespace, parent) {
|
|
|
188
180
|
: `form:${context.nextFormId++}`;
|
|
189
181
|
const source = description.props;
|
|
190
182
|
const props = { ...source };
|
|
183
|
+
if (tag === "iframe") {
|
|
184
|
+
if (Object.hasOwn(props, "rawHtml"))
|
|
185
|
+
fail("ZR_RAW_HTML", context, "iframe forbids rawHtml");
|
|
186
|
+
if (!emptyIframeChildren(props.children))
|
|
187
|
+
fail("ZR_PARSER_CONTEXT", context, "iframe requires empty children");
|
|
188
|
+
}
|
|
191
189
|
const hasValue = source.modelValue !== undefined;
|
|
192
190
|
const hasChecked = source.modelChecked !== undefined;
|
|
193
191
|
if ((hasValue && hasChecked) ||
|
|
@@ -315,7 +313,7 @@ function element(description, context, namespace, parent) {
|
|
|
315
313
|
const payload = read(raw);
|
|
316
314
|
if (typeof payload !== "string")
|
|
317
315
|
fail("ZR_RAW_HTML", context, `${tag} requires string rawHtml`);
|
|
318
|
-
if (
|
|
316
|
+
if (rawHtmlReserved(payload, tag))
|
|
319
317
|
fail("ZR_RAW_HTML", context, "reserved boundary in rawHtml");
|
|
320
318
|
if ((tag === "script" && /<\/script/i.test(payload)) ||
|
|
321
319
|
(tag === "style" && /<\/style/i.test(payload)))
|
|
@@ -328,6 +326,9 @@ function element(description, context, namespace, parent) {
|
|
|
328
326
|
fail("ZR_MODEL_VALUE", context, "textarea requires string");
|
|
329
327
|
content = `${value.startsWith("\n") ? "\n" : ""}${escapeText(value)}`;
|
|
330
328
|
}
|
|
329
|
+
else if (tag === "iframe") {
|
|
330
|
+
// The shell has no owned children; srcdoc belongs to the browser's foreign document.
|
|
331
|
+
}
|
|
331
332
|
else if (tag === "script" || tag === "style") {
|
|
332
333
|
if (hasChildren)
|
|
333
334
|
fail("ZR_RAW_HTML", context, `${tag} requires rawHtml`);
|
|
@@ -363,10 +364,27 @@ function element(description, context, namespace, parent) {
|
|
|
363
364
|
}
|
|
364
365
|
else
|
|
365
366
|
content = children(props.children, context, childNamespace, tag);
|
|
367
|
+
if (tag === "pre" && raw === undefined && (content.startsWith("\n") || content.startsWith("\r")))
|
|
368
|
+
content = `\n${content}`;
|
|
366
369
|
context.formId = previousFormId;
|
|
367
370
|
return `<${tag}${attrs}>${voidTags.has(tag) ? "" : `${content}</${tag}>`}`;
|
|
368
371
|
}
|
|
372
|
+
// A failure is attributed only to the value being rendered: a description's own site,
|
|
373
|
+
// or no site at all for scalars, promises and other non-description children.
|
|
374
|
+
function tracked(value, context, fn) {
|
|
375
|
+
const prior = context.node;
|
|
376
|
+
context.node = isDescription(value) ? value : undefined;
|
|
377
|
+
try {
|
|
378
|
+
return fn();
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
context.node = prior;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
369
384
|
function render(value, context, namespace, parent) {
|
|
385
|
+
return tracked(value, context, () => renderValue(value, context, namespace, parent));
|
|
386
|
+
}
|
|
387
|
+
function renderValue(value, context, namespace, parent) {
|
|
370
388
|
if (value == null || typeof value === "boolean")
|
|
371
389
|
return "";
|
|
372
390
|
if (Array.isArray(value))
|
|
@@ -383,7 +401,7 @@ function render(value, context, namespace, parent) {
|
|
|
383
401
|
return island(value, context, namespace, parent);
|
|
384
402
|
if (value.type === Fragment)
|
|
385
403
|
return region(context, "f", () => children(value.props.children, context, namespace, parent));
|
|
386
|
-
if (value.type
|
|
404
|
+
if (isShowType(value.type)) {
|
|
387
405
|
if (parent in tableChildren ||
|
|
388
406
|
["select", "optgroup", "option", "title", "textarea", "script", "style"].includes(parent))
|
|
389
407
|
fail("ZR_PARSER_CONTEXT", context, parent);
|
|
@@ -410,7 +428,7 @@ function render(value, context, namespace, parent) {
|
|
|
410
428
|
}
|
|
411
429
|
});
|
|
412
430
|
}
|
|
413
|
-
if (value.type
|
|
431
|
+
if (isForType(value.type)) {
|
|
414
432
|
if (parent in tableChildren ||
|
|
415
433
|
["select", "optgroup", "option", "title", "textarea", "script", "style"].includes(parent))
|
|
416
434
|
fail("ZR_PARSER_CONTEXT", context, parent);
|
|
@@ -455,9 +473,6 @@ function render(value, context, namespace, parent) {
|
|
|
455
473
|
context.scope = prior;
|
|
456
474
|
}
|
|
457
475
|
}
|
|
458
|
-
function empty(value) {
|
|
459
|
-
return (value == null || typeof value === "boolean" || (Array.isArray(value) && value.every(empty)));
|
|
460
|
-
}
|
|
461
476
|
function island(description, context, namespace, parent) {
|
|
462
477
|
if (context.boundary)
|
|
463
478
|
fail("ZR_NESTED_ISLAND", context, "nested island");
|
|
@@ -472,13 +487,13 @@ function island(description, context, namespace, parent) {
|
|
|
472
487
|
const component = child.type.displayName ?? child.type.name;
|
|
473
488
|
if (component !== options.identity.component)
|
|
474
489
|
fail("ZR_ISLAND_IDENTITY", context, `expected ${options.identity.component}, got ${component}`);
|
|
475
|
-
if (Object.hasOwn(child.props, "children") && !
|
|
490
|
+
if (Object.hasOwn(child.props, "children") && !emptyChildren(child.props.children))
|
|
476
491
|
fail("ZR_ISLAND_CHILD", context, "nonempty children");
|
|
477
|
-
|
|
478
|
-
delete props.children;
|
|
492
|
+
let props;
|
|
479
493
|
let payload;
|
|
480
494
|
try {
|
|
481
|
-
|
|
495
|
+
props = normalizeProps(child.props);
|
|
496
|
+
payload = JSON.stringify(props);
|
|
482
497
|
}
|
|
483
498
|
catch (error) {
|
|
484
499
|
throw new TypeError(`ZR_ISLAND_PROPS ${component}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -488,8 +503,18 @@ function island(description, context, namespace, parent) {
|
|
|
488
503
|
(when === "media" && !options.media?.trim()) ||
|
|
489
504
|
(when !== "media" && options.media !== undefined))
|
|
490
505
|
fail("ZR_ISLAND_WHEN", context, when);
|
|
506
|
+
if (options.persist !== undefined &&
|
|
507
|
+
(typeof options.persist !== "string" ||
|
|
508
|
+
!options.persist.trim() ||
|
|
509
|
+
options.persist !== options.persist.trim() ||
|
|
510
|
+
/[\u0000-\u001f\u007f]/.test(options.persist)))
|
|
511
|
+
fail("ZR_ISLAND_PERSIST", context, "persist must be a nonempty string without surrounding whitespace or control characters");
|
|
512
|
+
if (options.persistProps !== undefined && typeof options.persistProps !== "boolean")
|
|
513
|
+
fail("ZR_ISLAND_PERSIST", context, "persistProps must be a boolean");
|
|
514
|
+
if (options.persistProps !== undefined && options.persist === undefined)
|
|
515
|
+
fail("ZR_ISLAND_PERSIST", context, "persistProps requires persist");
|
|
491
516
|
const marker = options.skipSsr ? "data-zfb-island-skip-ssr" : "data-zfb-island";
|
|
492
|
-
const attrs = ` ${marker}="${escapeAttribute(options.identity.component)}" data-when="${when}"${when === "media" ? ` data-media="${escapeAttribute(options.media)}"` : ""} data-zfb-transport="json/1" data-zfb-protocol="zudo-react/1" data-zfb-build="${escapeAttribute(options.identity.build)}" data-props="${escapeAttribute(payload)}"`;
|
|
517
|
+
const attrs = ` ${marker}="${escapeAttribute(options.identity.component)}" data-when="${when}"${when === "media" ? ` data-media="${escapeAttribute(options.media)}"` : ""} data-zfb-transport="json/1" data-zfb-protocol="zudo-react/1" data-zfb-build="${escapeAttribute(options.identity.build)}" data-props="${escapeAttribute(payload)}"${options.persist === undefined ? "" : ` data-zfb-transition-persist="${escapeAttribute(options.persist)}"`}${options.persistProps === true ? ' data-zfb-transition-persist-props="true"' : ""}`;
|
|
493
518
|
const local = {
|
|
494
519
|
radioGroups: new Map(),
|
|
495
520
|
radioNames: new Map(),
|