@preact/signals 0.0.4 → 1.0.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @preact/signals
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 2383684: Correctly replace props-value with peeked value
8
+ - Updated dependencies [5644c1f]
9
+ - @preact/signals-core@1.0.1
10
+
11
+ ## 1.0.1
12
+
13
+ ### Patch Changes
14
+
15
+ - c7c0d91: Add marker for devtools to `Text` that is created when a signal is passed into JSX
16
+
17
+ ## 1.0.0
18
+
19
+ ### Major Changes
20
+
21
+ - 2ee8489: The v1 release for the signals package, we'd to see the uses you all
22
+ come up with and are eager to see performance improvements in your
23
+ applications.
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies [ab22ec7]
28
+ - Updated dependencies [2ee8489]
29
+ - Updated dependencies [b56abf3]
30
+ - @preact/signals-core@1.0.0
31
+
3
32
  ## 0.0.4
4
33
 
5
34
  ### Patch Changes
package/dist/signals.js CHANGED
@@ -1,2 +1 @@
1
- var n,r,t,e=require("preact"),i=require("preact/hooks"),u=require("@preact/signals-core"),o=new WeakSet,f=new WeakSet,c=new WeakSet;function a(n,r){e.options[n]=r.bind(null,e.options[n]||function(){})}var v=new WeakMap;function s(n){t&&t(!0,!0),r=n,t=n&&n._()}function l(n){var r=u.signal(void 0);return r._c=!0,r._u=n,r}function b(n){var r=v.get(n);if(r)r.__.length=0;else{var t=[];(r=l(function(){for(var r=n.__e,e=n.props,i=0;i<t.length;i++){var u=t[i],o=e[u]._v;u in r?r[u]=o:o?r.setAttribute(u,o):r.removeAttribute(u)}})).__=t,v.set(n,r)}return r}function p(n,r,t){"object"!=typeof n||null==n||(Array.isArray(n)?n.forEach(p):n instanceof u.Signal&&(t[r]=e.createElement(h,{data:n})))}function h(n){var t=this,e=n.data,o=i.useMemo(function(){for(var n=t.__v;n=n.__;)if(n.__c){c.add(n.__c);break}return r._u=function(){t.base.data=o._v},u.computed(function(){var n=e.value;return 0===n?0:!0===n?"":n||""})},[]);return o.value}a("__b",function(n,r){if("string"==typeof r.type){var t,e=r.props;for(var i in e){var o=e[i];"children"===i?p(o,"children",e):o instanceof u.Signal&&(t||(t=b(r)),t.__.push(i))}s(t)}n(r)}),a("__r",function(r,t){var e,i=t.__c;i&&(o.delete(i),void 0===(e=v.get(i))&&(e=l(function(){o.add(i),i.setState({})}),v.set(i,e))),n=i,s(e),r(t)}),a("__e",function(r,t,e,i){s(),n=void 0,r(t,e,i)}),a("diffed",function(r,t){s(),n=void 0,r(t)}),a("unmount",function(n,r){var t=r.__c||r,e=v.get(t);if(e){v.delete(t);var i=e._d;i&&(i.forEach(function(n){return n._s.delete(e)}),i.clear())}n(r)}),a("__h",function(n,r,t,e){e<3&&f.add(r),n(r,t,e)}),e.Component.prototype.shouldComponentUpdate=function(n,r){var t,e=v.get(this);if(!(e&&0!==(null==(t=e._d)?void 0:t.size)||c.has(this)))return!0;if(o.has(this))return!0;if(f.has(this))return!0;for(var i in r)return!0;for(var u in n)if("__source"!==u&&n[u]!==this.props[u])return!0;for(var a in this.props)if(!(a in n))return!0;return!1},Object.defineProperty(exports,"Signal",{enumerable:!0,get:function(){return u.Signal}}),Object.defineProperty(exports,"batch",{enumerable:!0,get:function(){return u.batch}}),Object.defineProperty(exports,"computed",{enumerable:!0,get:function(){return u.computed}}),Object.defineProperty(exports,"effect",{enumerable:!0,get:function(){return u.effect}}),Object.defineProperty(exports,"signal",{enumerable:!0,get:function(){return u.signal}}),exports.useComputed=function(r){var t=i.useRef(r);return t.current=r,c.add(n),i.useMemo(function(){return u.computed(function(){return t.current()})},[])},exports.useSignal=function(n){return i.useMemo(function(){return u.signal(n)},[])};
2
- //# sourceMappingURL=signals.js.map
1
+ var n,r,t,i=require("preact"),e=require("preact/hooks"),o=require("@preact/signals-core"),u=new WeakSet,f=new WeakSet,a=new WeakSet;function c(n,r){i.options[n]=r.bind(null,i.options[n]||function(){})}var v=new WeakMap;function s(n){t&&t(!0,!0),r=n,t=n&&n._()}function p(n){var r=o.signal(void 0);return r._c=!0,r._u=n,r}function _(n){var r=v.get(n);if(r)r.__.length=0;else{var t=[];(r=p(function(){for(var r=n.__e,i=0;i<t.length;i++){var e=t[i],o=e.t,u=e.i._v;if(!r)return;o in r?r[o]=u:u?r.setAttribute(o,u):r.removeAttribute(o)}})).__=t,v.set(n,r)}return r}function l(n,r,t){"object"!=typeof n||null==n||(Array.isArray(n)?n.forEach(l):n instanceof o.Signal&&(t[r]=i.createElement(h,{data:n})))}function h(n){var t=this,i=n.data,u=e.useMemo(function(){for(var n=t.__v;n=n.__;)if(n.__c){a.add(n.__c);break}return r._u=function(){t.base.data=u._v},o.computed(function(){var n=i.value;return 0===n?0:!0===n?"":n||""})},[]);return u.value}h.displayName="_st",c("__b",function(n,r){if("string"==typeof r.type){var t,i=r.props;for(var e in i){var u=i[e];"children"===e?l(u,"children",i):u instanceof o.Signal&&function(){t||(t=_(r)),t.__.push({t:e,i:u});var n=t._u;if(u._u){var o=u._u;u._u=function(){n(),o()}}else u._u=n;i[e]=u.peek()}()}s(t)}n(r)}),c("__r",function(r,t){var i,e=t.__c;e&&(u.delete(e),void 0===(i=v.get(e))&&(i=p(function(){u.add(e),e.setState({})}),v.set(e,i))),n=e,s(i),r(t)}),c("__e",function(r,t,i,e){s(),n=void 0,r(t,i,e)}),c("diffed",function(r,t){s(),n=void 0,r(t)}),c("unmount",function(n,r){var t=r.__c||r,i=v.get(t);if(i){v.delete(t);var e=i._d;e&&(e.forEach(function(n){return n._s.delete(i)}),e.clear())}n(r)}),c("__h",function(n,r,t,i){i<3&&f.add(r),n(r,t,i)}),i.Component.prototype.shouldComponentUpdate=function(n,r){var t,i=v.get(this);if(!(i&&0!==(null==(t=i._d)?void 0:t.size)||a.has(this)))return!0;if(u.has(this))return!0;if(f.has(this))return!0;for(var e in r)return!0;for(var o in n)if("__source"!==o&&n[o]!==this.props[o])return!0;for(var c in this.props)if(!(c in n))return!0;return!1},exports.Signal=o.Signal,exports.batch=o.batch,exports.computed=o.computed,exports.effect=o.effect,exports.signal=o.signal,exports.useComputed=function(r){var t=e.useRef(r);return t.current=r,a.add(n),e.useMemo(function(){return o.computed(function(){return t.current()})},[])},exports.useSignal=function(n){return e.useMemo(function(){return o.signal(n)},[])};//# sourceMappingURL=signals.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signals.js","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: string[] = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\t\t\tlet props = vnode.props;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet prop = signalProps[i];\n\t\t\t\tlet value = props[prop]._value;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push(i);\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["currentComponent","currentUpdater","finishUpdate","hasPendingUpdate","WeakSet","hasHookState","hasComputeds","hook","hookName","hookFn","options","bind","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","signal","undefined","_canActivate","_updater","getElementUpdater","vnode","get","_props","length","signalProps","dom","__e","props","i","prop","value","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Signal","createElement","Text","data","_ref","_this","this","useMemo","v","__v","__","__c","add","base","computed","old","type","push","component","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","Component","prototype","shouldComponentUpdate","state","_updater$_deps","size","has","compute","$compute","useRef","current"],"mappings":"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"}
1
+ {"version":3,"file":"signals.js","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: Array<{ _key: string, _signal: Signal }> = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet { _key: prop, _signal: signal } = signalProps[i];\n\t\t\t\tlet value = signal._value;\n\t\t\t\tif (!dom) return;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\nText.displayName = \"_st\";\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push({ _key: i, _signal: value });\n\t\t\t\tlet newUpdater = updater._updater\n\t\t\t\tif (value._updater) {\n\t\t\t\t\tlet oldUpdater = value._updater\n\t\t\t\t\tvalue._updater = () => {\n\t\t\t\t\t\tnewUpdater();\n\t\t\t\t\t\toldUpdater();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvalue._updater = newUpdater\n\t\t\t\t}\n\t\t\t\tprops[i] = value.peek()\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["currentComponent","currentUpdater","finishUpdate","preact","require","hooks","signalsCore","hasPendingUpdate","WeakSet","hasComputeds","hook","hookName","hookFn","options","bind","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","s","signal","undefined","_canActivate","_updater","getElementUpdater","vnode","get","_props","length","signalProps","createUpdater","dom","__e","i","prop","_key","value","_signal","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Signal","createElement","Text","data","_ref","_this","this","useMemo","__v","v","__","__c","add","base","computed","displayName","old","type","props","push","oldUpdater","newUpdater","peek","component","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","hasHookState","Component","prototype","shouldComponentUpdate","state","_updater$_deps","size","has","_i","_i2","exports","batch","effect","useComputed","compute","$compute","useRef","current","useSignal"],"mappings":"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"}
@@ -1,2 +1 @@
1
- !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("preact"),require("preact/hooks"),require("@preact/signals-core")):"function"==typeof define&&define.amd?define(["exports","preact","preact/hooks","@preact/signals-core"],e):e((n||self).preactSignals={},n.preact,n.hooks,n.signalsCore)}(this,function(n,e,r,t){var i,u,o,f=new WeakSet,c=new WeakSet,a=new WeakSet;function s(n,r){e.options[n]=r.bind(null,e.options[n]||function(){})}var v=new WeakMap;function l(n){o&&o(!0,!0),u=n,o=n&&n._()}function d(n){var e=t.signal(void 0);return e._c=!0,e._u=n,e}function b(n){var e=v.get(n);if(e)e.__.length=0;else{var r=[];(e=d(function(){for(var e=n.__e,t=n.props,i=0;i<r.length;i++){var u=r[i],o=t[u]._v;u in e?e[u]=o:o?e.setAttribute(u,o):e.removeAttribute(u)}})).__=r,v.set(n,e)}return e}function p(n,r,i){"object"!=typeof n||null==n||(Array.isArray(n)?n.forEach(p):n instanceof t.Signal&&(i[r]=e.createElement(h,{data:n})))}function h(n){var e=this,i=n.data,o=r.useMemo(function(){for(var n=e.__v;n=n.__;)if(n.__c){a.add(n.__c);break}return u._u=function(){e.base.data=o._v},t.computed(function(){var n=i.value;return 0===n?0:!0===n?"":n||""})},[]);return o.value}s("__b",function(n,e){if("string"==typeof e.type){var r,i=e.props;for(var u in i){var o=i[u];"children"===u?p(o,"children",i):o instanceof t.Signal&&(r||(r=b(e)),r.__.push(u))}l(r)}n(e)}),s("__r",function(n,e){var r,t=e.__c;t&&(f.delete(t),void 0===(r=v.get(t))&&(r=d(function(){f.add(t),t.setState({})}),v.set(t,r))),i=t,l(r),n(e)}),s("__e",function(n,e,r,t){l(),i=void 0,n(e,r,t)}),s("diffed",function(n,e){l(),i=void 0,n(e)}),s("unmount",function(n,e){var r=e.__c||e,t=v.get(r);if(t){v.delete(r);var i=t._d;i&&(i.forEach(function(n){return n._s.delete(t)}),i.clear())}n(e)}),s("__h",function(n,e,r,t){t<3&&c.add(e),n(e,r,t)}),e.Component.prototype.shouldComponentUpdate=function(n,e){var r,t=v.get(this);if(!(t&&0!==(null==(r=t._d)?void 0:r.size)||a.has(this)))return!0;if(f.has(this))return!0;if(c.has(this))return!0;for(var i in e)return!0;for(var u in n)if("__source"!==u&&n[u]!==this.props[u])return!0;for(var o in this.props)if(!(o in n))return!0;return!1},Object.defineProperty(n,"Signal",{enumerable:!0,get:function(){return t.Signal}}),Object.defineProperty(n,"batch",{enumerable:!0,get:function(){return t.batch}}),Object.defineProperty(n,"computed",{enumerable:!0,get:function(){return t.computed}}),Object.defineProperty(n,"effect",{enumerable:!0,get:function(){return t.effect}}),Object.defineProperty(n,"signal",{enumerable:!0,get:function(){return t.signal}}),n.useComputed=function(n){var e=r.useRef(n);return e.current=n,a.add(i),r.useMemo(function(){return t.computed(function(){return e.current()})},[])},n.useSignal=function(n){return r.useMemo(function(){return t.signal(n)},[])}});
2
- //# sourceMappingURL=signals.min.js.map
1
+ !function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("preact"),require("preact/hooks"),require("@preact/signals-core")):"function"==typeof define&&define.amd?define(["exports","preact","preact/hooks","@preact/signals-core"],r):r((n||self).preactSignals={},n.preact,n.hooks,n.signalsCore)}(this,function(n,r,t,e){var i,o,f,u=new WeakSet,a=new WeakSet,c=new WeakSet;function s(n,t){r.options[n]=t.bind(null,r.options[n]||function(){})}var v=new WeakMap;function l(n){f&&f(!0,!0),o=n,f=n&&n._()}function d(n){var r=e.signal(void 0);return r._c=!0,r._u=n,r}function p(n){var r=v.get(n);if(r)r.__.length=0;else{var t=[];(r=d(function(){for(var r=n.__e,e=0;e<t.length;e++){var i=t[e],o=i.t,f=i.i._v;if(!r)return;o in r?r[o]=f:f?r.setAttribute(o,f):r.removeAttribute(o)}})).__=t,v.set(n,r)}return r}function h(n,t,i){"object"!=typeof n||null==n||(Array.isArray(n)?n.forEach(h):n instanceof e.Signal&&(i[t]=r.createElement(_,{data:n})))}function _(n){var r=this,i=n.data,f=t.useMemo(function(){for(var n=r.__v;n=n.__;)if(n.__c){c.add(n.__c);break}return o._u=function(){r.base.data=f._v},e.computed(function(){var n=i.value;return 0===n?0:!0===n?"":n||""})},[]);return f.value}_.displayName="_st",s("__b",function(n,r){if("string"==typeof r.type){var t,i=r.props;for(var o in i){var f=i[o];"children"===o?h(f,"children",i):f instanceof e.Signal&&function(){t||(t=p(r)),t.__.push({t:o,i:f});var n=t._u;if(f._u){var e=f._u;f._u=function(){n(),e()}}else f._u=n;i[o]=f.peek()}()}l(t)}n(r)}),s("__r",function(n,r){var t,e=r.__c;e&&(u.delete(e),void 0===(t=v.get(e))&&(t=d(function(){u.add(e),e.setState({})}),v.set(e,t))),i=e,l(t),n(r)}),s("__e",function(n,r,t,e){l(),i=void 0,n(r,t,e)}),s("diffed",function(n,r){l(),i=void 0,n(r)}),s("unmount",function(n,r){var t=r.__c||r,e=v.get(t);if(e){v.delete(t);var i=e._d;i&&(i.forEach(function(n){return n._s.delete(e)}),i.clear())}n(r)}),s("__h",function(n,r,t,e){e<3&&a.add(r),n(r,t,e)}),r.Component.prototype.shouldComponentUpdate=function(n,r){var t,e=v.get(this);if(!(e&&0!==(null==(t=e._d)?void 0:t.size)||c.has(this)))return!0;if(u.has(this))return!0;if(a.has(this))return!0;for(var i in r)return!0;for(var o in n)if("__source"!==o&&n[o]!==this.props[o])return!0;for(var f in this.props)if(!(f in n))return!0;return!1},n.Signal=e.Signal,n.batch=e.batch,n.computed=e.computed,n.effect=e.effect,n.signal=e.signal,n.useComputed=function(n){var r=t.useRef(n);return r.current=n,c.add(i),t.useMemo(function(){return e.computed(function(){return r.current()})},[])},n.useSignal=function(n){return t.useMemo(function(){return e.signal(n)},[])}});//# sourceMappingURL=signals.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signals.min.js","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: string[] = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\t\t\tlet props = vnode.props;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet prop = signalProps[i];\n\t\t\t\tlet value = props[prop]._value;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push(i);\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["currentComponent","currentUpdater","finishUpdate","hasPendingUpdate","WeakSet","hasHookState","hasComputeds","hook","hookName","hookFn","options","bind","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","signal","undefined","_canActivate","_updater","getElementUpdater","vnode","get","_props","length","signalProps","dom","__e","props","i","prop","value","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Signal","createElement","Text","data","_ref","_this","this","useMemo","v","__v","__","__c","add","base","computed","old","type","push","component","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","Component","prototype","shouldComponentUpdate","state","_updater$_deps","size","has","compute","$compute","useRef","current"],"mappings":"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"}
1
+ {"version":3,"file":"signals.min.js","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: Array<{ _key: string, _signal: Signal }> = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet { _key: prop, _signal: signal } = signalProps[i];\n\t\t\t\tlet value = signal._value;\n\t\t\t\tif (!dom) return;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\nText.displayName = \"_st\";\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push({ _key: i, _signal: value });\n\t\t\t\tlet newUpdater = updater._updater\n\t\t\t\tif (value._updater) {\n\t\t\t\t\tlet oldUpdater = value._updater\n\t\t\t\t\tvalue._updater = () => {\n\t\t\t\t\t\tnewUpdater();\n\t\t\t\t\t\toldUpdater();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvalue._updater = newUpdater\n\t\t\t\t}\n\t\t\t\tprops[i] = value.peek()\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["g","f","exports","module","require","define","amd","globalThis","self","preactSignals","preact","hooks","signalsCore","this","currentComponent","currentUpdater","finishUpdate","hasPendingUpdate","WeakSet","hasComputeds","hook","hookName","hookFn","options","bind","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","s","signal","undefined","_canActivate","_updater","getElementUpdater","vnode","get","_props","length","signalProps","createUpdater","dom","__e","i","prop","_key","value","_signal","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Signal","createElement","Text","data","_ref","_this","useMemo","__v","v","__","__c","add","base","computed","displayName","old","type","props","push","oldUpdater","newUpdater","peek","component","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","hasHookState","Component","prototype","shouldComponentUpdate","state","_updater$_deps","size","has","_i","_i2","batch","effect","useComputed","compute","$compute","useRef","current","useSignal"],"mappings":"CAsBA,SAAAA,EAAAC,GAAA,iBAAAC,SAAA,oBAAAC,OAAAF,EAAAC,QAAAE,QAAA,UAAAA,QAAA,gBAAAA,QAAA,yBAAA,mBAAAC,QAAAA,OAAAC,IAAAD,OAAA,CAAA,UAAA,SAAA,eAAA,wBAAAJ,GAAAA,GAAAD,EAAA,oBAAAO,WAAAA,WAAAP,GAAAQ,MAAAC,cAAA,CAAA,EAAAT,EAAAU,OAAAV,EAAAW,MAAAX,EAAAY,YAAA,CAAA,CAAAC,KAAA,SAAAX,EAAAQ,EAAAC,EAAAC,GAAA,IAcAE,EACIC,EACJC,EAhBsBC,EAAG,IAAIC,UAGR,IAArBA,QAGMC,EAAe,IAArBD,QAGA,SAASE,EAA6BC,EAAaC,GAElDC,EAAOA,QAACF,GAAYC,EAAOE,KAAK,KAAMD,EAAOA,QAACF,IAAc,WAAxC,EACpB,CAKD,IAAMI,EAAsB,IAAIC,QAEhC,SAAAC,EAA2BC,GAEtBZ,GAAcA,GAAa,GAAM,GAErCD,EAAiBa,EACjBZ,EAAeY,GAAWA,EAAQC,GAClC,CAED,WAAuBD,GACtB,IAAME,EAAIC,cAAOC,GAGjB,OAFAF,EAAEG,IAAe,EACjBH,EAAEI,GAAWN,EAEbE,CAAA,CAGD,SAASK,EAAkBC,GAC1B,IAAWR,EAAGH,EAAoBY,IAAID,GACtC,GAAKR,EAsBJA,EAAQU,GAAOC,OAAS,MAtBX,CACb,IAAIC,EAAwD,IAC5DZ,EAAUa,EAAc,WAGvB,IAFA,IAAIC,EAAMN,EAAMO,IAENC,EAAG,EAAGA,EAAIJ,EAAYD,OAAQK,IAAK,CAC5C,IAAsCJ,EAAAA,EAAYI,GAAtCC,EAANC,EAAAA,EACGC,EADSC,EAAAA,EACCC,GACnB,IAAKP,EAAK,OACNG,KAAQH,EAEXA,EAAIG,GAAQE,EACFA,EACVL,EAAIQ,aAAaL,EAAME,GAEvBL,EAAIS,gBAAgBN,EAErB,CACD,IACOP,GAASE,EACjBf,EAAoB2B,IAAIhB,EAAOR,EAC/B,CAGD,OAAOA,CACP,CAYD,SAAAyB,EAA0BC,EAAYV,EAAYW,GAC5B,iBAAjBD,GAAsC,MAATA,IAEtBE,MAAMC,QAAQH,GACxBA,EAAMI,QAAQL,GACJC,aAAJK,EAAAA,SAENJ,EAAIX,GAAKgB,gBAAcC,EAAM,CAAEC,KAAMR,KAEtC,CAMD,SAASO,EAAoDE,GAAA,IAAAC,EAAAnD,KAAAiD,EAAAC,EAAxBD,KAG9BhC,EAAImC,EAAOA,QAAC,WAGjB,IADA,MAAQD,EAAKE,IACLC,EAAIA,EAAEC,IACb,GAAID,EAAEE,IAAK,CACVlD,EAAamD,IAAIH,EAAEE,KACnB,KACA,CAQF,OAJAtD,EAAgBmB,GAAW,WACzB8B,EAAKO,KAAcT,KAAOhC,EAAEmB,EAC7B,EAEcuB,WAAC,WACf,IAAK1C,EAAGgC,EAAKf,MACb,OAAa,IAANjB,EAAU,GAAU,IAANA,EAAa,GAAKA,GAAK,EAC5C,EACD,EAAE,IAEH,OAAOA,EAAEiB,KACT,CACDc,EAAKY,YAAc,MAGnBrD,QAAwB,SAACsD,EAAKtC,GAC7B,GAA0B,iBAAfA,EAAMuC,KAAmB,CAEnC,IACI/C,EADAgD,EAAQxC,EAAMwC,MAGlB,IAAK,IAAIhC,KAAKgC,EAAO,CACpB,IAAI7B,EAAQ6B,EAAMhC,GACR,aAANA,EACHS,EAAcN,EAAO,WAAY6B,GACvB7B,aAAJY,EAAAA,QAEN,WAAK/B,IAASA,EAAUO,EAAkBC,IAE1CR,EAAQU,GAAOuC,KAAK,CAAE/B,EAAMF,EAAGI,EAASD,IACxC,MAAiBnB,EAAQM,GACzB,GAAIa,EAAMb,GAAU,CACnB,IAAc4C,EAAG/B,EAAMb,GACvBa,EAAMb,GAAW,WAChB6C,IACAD,GACA,CACD,MACA/B,EAAMb,GAAW6C,EAElBH,EAAMhC,GAAKG,EAAMiC,MAfkB,CAEnC,EAeD,CAEDrD,EAAkBC,EAClB,CAED8C,EAAItC,EACJ,GAGDhB,QAA0B,SAACsD,EAAKtC,GAC/B,IAAIR,EAESqD,EAAG7C,EAAMiC,IAClBY,IACHhE,EAAA,OAAwBgE,QAGRjD,KADhBJ,EAAUH,EAAoBY,IAAI4C,MAEjCrD,EAAUa,EAAc,WACvBxB,EAAiBqD,IAAIW,GACrBA,EAAUC,SAAS,CAAnB,EACA,GACDzD,EAAoB2B,IAAI6B,EAAWrD,KAIrCd,EAAmBmE,EACnBtD,EAAkBC,GAClB8C,EAAItC,EACJ,GAGDhB,EAAI,MAA2B,SAACsD,EAAKS,EAAO/C,EAAOgD,GAClDzD,IACAb,OAAmBkB,EACnB0C,EAAIS,EAAO/C,EAAOgD,EAClB,GAGDhE,WAA0B,SAACsD,EAAKtC,GAC/BT,IACAb,OAAmBkB,EACnB0C,EAAItC,EACJ,GAGDhB,YAA2B,SAACsD,EAAKtC,GAChC,IAASiD,EAAGjD,EAAMiC,KAAOjC,EACZR,EAAGH,EAAoBY,IAAIgD,GACxC,GAAIzD,EAAS,CACZH,EAAA,OAA2B4D,GAC3B,IAAMC,EAAU1D,EAAQ2D,GACpBD,IACHA,EAAQ5B,QAAQ,SAAA3B,GAAUA,OAAAA,EAAOyD,GAAa5D,OAAAA,EAAxB,GACtB0D,EAAQG,QAET,CACDf,EAAItC,EACJ,GAGDhB,EAAI,MAAoB,SAACsD,EAAKO,EAAWS,EAAOf,GAC3CA,EAAO,GAAGgB,EAAarB,IAAIW,GAC/BP,EAAIO,EAAWS,EAAOf,EACtB,GAMDiB,EAASA,UAACC,UAAUC,sBAAwB,SAAUlB,EAAOmB,GAAK,IAAAC,EAE3DpE,EAAUH,EAAoBY,IAAIxB,MA2BxC,KAzBmBe,GAAmC,KAATqE,OAAfrE,EAAAA,EAAQ2D,SAAOU,EAAAA,EAAAA,OAyBzB9E,EAAa+E,IAAIrF,OAAO,OAAO,EAGnD,GAAII,EAAiBiF,IAAIrF,MAAO,OAAO,EAGvC,GAAI8E,EAAaO,IAAIrF,MAAO,SAC5B,IAAK,IAAI+B,KAAKmD,EAAO,OAArB,EAGA,IAAK,IAALI,KAAAvB,EACC,GAAU,aAANhC,GAAoBgC,EAAMhC,KAAO/B,KAAK+D,MAAMhC,GAAI,OACpD,EACD,IAAK,IAALwD,KAAmBxB,KAAAA,MAAO,KAAMhC,KAAKgC,GAAQ,OAA7C,EAGA,OAAO,CACP,EAWA1E,EAAAyD,OAAA/C,EAAA+C,OAAAzD,EAAAmG,MAAAzF,EAAAyF,MAAAnG,EAAAsE,SAAA5D,EAAA4D,SAAAtE,EAAAoG,OAAA1F,EAAA0F,OAAApG,EAAA6B,OAAAnB,EAAAmB,OAAA7B,EAAAqG,YALeA,SAAeC,GAC9B,IAAcC,EAAGC,EAAMA,OAACF,GAGxB,OAFAC,EAASE,QAAUH,EACnBrF,EAAamD,IAAIxD,GACVmD,UAAQ,WAAA,OAAcO,EAAAA,SAAI,kBAAciC,EAACE,SAAf,EAAlB,EAA6C,GAC5D,EAAAzG,EAAA0G,UATK,SAAuB7D,GAC5B,OAAckB,EAAAA,QAAC,kBAAYlC,EAAAA,OAAIgB,EAAhB,EAAwB,GACvC,CAOA"}
package/dist/signals.mjs CHANGED
@@ -1,2 +1 @@
1
- import{Component as t,options as n,createElement as e}from"preact";import{useMemo as r,useRef as i}from"preact/hooks";import{Signal as o,signal as f,computed as c}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";const u=new WeakSet,l=new WeakSet,s=new WeakSet;function a(t,e){n[t]=e.bind(null,n[t]||(()=>{}))}let h,p,d;const _=new WeakMap;function m(t){d&&d(!0,!0),p=t,d=t&&t._()}function k(t){const n=f(void 0);return n._c=!0,n._u=t,n}function v(t){let n=_.get(t);if(n)n.__.length=0;else{let e=[];n=k(()=>{let n=t.__e,r=t.props;for(let t=0;t<e.length;t++){let i=e[t],o=r[i]._v;i in n?n[i]=o:o?n.setAttribute(i,o):n.removeAttribute(i)}}),n.__=e,_.set(t,n)}return n}function g(t,n,r){"object"!=typeof t||null==t||(Array.isArray(t)?t.forEach(g):t instanceof o&&(r[n]=e(b,{data:t})))}function b({data:t}){const n=r(()=>{let e=this.__v;for(;e=e.__;)if(e.__c){s.add(e.__c);break}return p._u=()=>{this.base.data=n._v},c(()=>{let n=t.value;return 0===n?0:!0===n?"":n||""})},[]);return n.value}function w(t){return r(()=>f(t),[])}function S(t){const n=i(t);return n.current=t,s.add(h),r(()=>c(()=>n.current()),[])}a("__b",(t,n)=>{if("string"==typeof n.type){let t,e=n.props;for(let r in e){let i=e[r];"children"===r?g(i,"children",e):i instanceof o&&(t||(t=v(n)),t.__.push(r))}m(t)}t(n)}),a("__r",(t,n)=>{let e,r=n.__c;r&&(u.delete(r),e=_.get(r),void 0===e&&(e=k(()=>{u.add(r),r.setState({})}),_.set(r,e))),h=r,m(e),t(n)}),a("__e",(t,n,e,r)=>{m(),h=void 0,t(n,e,r)}),a("diffed",(t,n)=>{m(),h=void 0,t(n)}),a("unmount",(t,n)=>{let e=n.__c||n;const r=_.get(e);if(r){_.delete(e);const t=r._d;t&&(t.forEach(t=>t._s.delete(r)),t.clear())}t(n)}),a("__h",(t,n,e,r)=>{r<3&&l.add(n),t(n,e,r)}),t.prototype.shouldComponentUpdate=function(t,n){var e;const r=_.get(this);if(!(r&&0!==(null==(e=r._d)?void 0:e.size)||s.has(this)))return!0;if(u.has(this))return!0;if(l.has(this))return!0;for(let t in n)return!0;for(let n in t)if("__source"!==n&&t[n]!==this.props[n])return!0;for(let n in this.props)if(!(n in t))return!0;return!1};export{S as useComputed,w as useSignal};
2
- //# sourceMappingURL=signals.mjs.map
1
+ import{Component as t,options as e,createElement as n}from"preact";import{useMemo as r,useRef as i}from"preact/hooks";import{Signal as o,signal as f,computed as l}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";const c=new WeakSet,s=new WeakSet,u=new WeakSet;function a(t,n){e[t]=n.bind(null,e[t]||(()=>{}))}let _,h,p;const d=new WeakMap;function m(t){p&&p(!0,!0),h=t,p=t&&t._()}function k(t){const e=f(void 0);return e._c=!0,e._u=t,e}function g(t){let e=d.get(t);if(e)e.__.length=0;else{let n=[];e=k(()=>{let e=t.__e;for(let t=0;t<n.length;t++){let{t:r,i}=n[t],o=i._v;if(!e)return;r in e?e[r]=o:o?e.setAttribute(r,o):e.removeAttribute(r)}}),e.__=n,d.set(t,e)}return e}function v(t,e,r){"object"!=typeof t||null==t||(Array.isArray(t)?t.forEach(v):t instanceof o&&(r[e]=n(y,{data:t})))}function y({data:t}){const e=r(()=>{let n=this.__v;for(;n=n.__;)if(n.__c){u.add(n.__c);break}return h._u=()=>{this.base.data=e._v},l(()=>{let e=t.value;return 0===e?0:!0===e?"":e||""})},[]);return e.value}function b(t){return r(()=>f(t),[])}function w(t){const e=i(t);return e.current=t,u.add(_),r(()=>l(()=>e.current()),[])}y.displayName="_st",a("__b",(t,e)=>{if("string"==typeof e.type){let t,n=e.props;for(let r in n){let i=n[r];if("children"===r)v(i,"children",n);else if(i instanceof o){t||(t=g(e)),t.__.push({t:r,i});let o=t._u;if(i._u){let t=i._u;i._u=()=>{o(),t()}}else i._u=o;n[r]=i.peek()}}m(t)}t(e)}),a("__r",(t,e)=>{let n,r=e.__c;r&&(c.delete(r),n=d.get(r),void 0===n&&(n=k(()=>{c.add(r),r.setState({})}),d.set(r,n))),_=r,m(n),t(e)}),a("__e",(t,e,n,r)=>{m(),_=void 0,t(e,n,r)}),a("diffed",(t,e)=>{m(),_=void 0,t(e)}),a("unmount",(t,e)=>{let n=e.__c||e;const r=d.get(n);if(r){d.delete(n);const t=r._d;t&&(t.forEach(t=>t._s.delete(r)),t.clear())}t(e)}),a("__h",(t,e,n,r)=>{r<3&&s.add(e),t(e,n,r)}),t.prototype.shouldComponentUpdate=function(t,e){var n;const r=d.get(this);if(!(r&&0!==(null==(n=r._d)?void 0:n.size)||u.has(this)))return!0;if(c.has(this))return!0;if(s.has(this))return!0;for(let t in e)return!0;for(let e in t)if("__source"!==e&&t[e]!==this.props[e])return!0;for(let e in this.props)if(!(e in t))return!0;return!1};export{w as useComputed,b as useSignal};//# sourceMappingURL=signals.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"signals.mjs","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: string[] = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\t\t\tlet props = vnode.props;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet prop = signalProps[i];\n\t\t\t\tlet value = props[prop]._value;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push(i);\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["hasPendingUpdate","WeakSet","hasHookState","hasComputeds","hook","hookName","hookFn","options","bind","currentComponent","currentUpdater","finishUpdate","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","signal","undefined","_canActivate","_updater","getElementUpdater","vnode","get","_props","length","signalProps","dom","__e","props","i","prop","value","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Signal","createElement","Text","data","useMemo","v","this","__v","__","__c","add","base","computed","useSignal","useComputed","compute","$compute","useRef","current","old","type","push","component","delete","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","Component","prototype","shouldComponentUpdate","state","_updater$_deps","size","has"],"mappings":"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"}
1
+ {"version":3,"file":"signals.mjs","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: Array<{ _key: string, _signal: Signal }> = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet { _key: prop, _signal: signal } = signalProps[i];\n\t\t\t\tlet value = signal._value;\n\t\t\t\tif (!dom) return;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\nText.displayName = \"_st\";\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push({ _key: i, _signal: value });\n\t\t\t\tlet newUpdater = updater._updater\n\t\t\t\tif (value._updater) {\n\t\t\t\t\tlet oldUpdater = value._updater\n\t\t\t\t\tvalue._updater = () => {\n\t\t\t\t\t\tnewUpdater();\n\t\t\t\t\t\toldUpdater();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvalue._updater = newUpdater\n\t\t\t\t}\n\t\t\t\tprops[i] = value.peek()\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["Component","options","createElement","useMemo","useRef","Signal","signal","computed","batch","effect","hasPendingUpdate","WeakSet","hasComputeds","hook","hookName","hookFn","bind","currentComponent","currentUpdater","finishUpdate","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","undefined","_canActivate","_updater","getElementUpdater","vnode","updaterForComponent","get","_props","length","dom","__e","i","signalProps","_key","prop","_signal","value","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Text","data","v","this","__v","__","__c","add","base","useSignal","useComputed","compute","$compute","current","displayName","old","type","props","push","newUpdater","oldUpdater","peek","component","delete","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","hasHookState","prototype","shouldComponentUpdate","state","_updater$_deps","size","has"],"mappings":"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"}
@@ -1,2 +1 @@
1
- import{Component as n,options as r,createElement as t}from"preact";import{useMemo as i,useRef as o}from"preact/hooks";import{Signal as e,signal as f,computed as u}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";var a,c,v,s=new WeakSet,l=new WeakSet,p=new WeakSet;function h(n,t){r[n]=t.bind(null,r[n]||function(){})}var d=new WeakMap;function _(n){v&&v(!0,!0),c=n,v=n&&n._()}function m(n){var r=f(void 0);return r._c=!0,r._u=n,r}function k(n){var r=d.get(n);if(r)r.__.length=0;else{var t=[];(r=m(function(){for(var r=n.__e,i=n.props,o=0;o<t.length;o++){var e=t[o],f=i[e]._v;e in r?r[e]=f:f?r.setAttribute(e,f):r.removeAttribute(e)}})).__=t,d.set(n,r)}return r}function g(n,r,i){"object"!=typeof n||null==n||(Array.isArray(n)?n.forEach(g):n instanceof e&&(i[r]=t(b,{data:n})))}function b(n){var r=this,t=n.data,o=i(function(){for(var n=r.__v;n=n.__;)if(n.__c){p.add(n.__c);break}return c._u=function(){r.base.data=o._v},u(function(){var n=t.value;return 0===n?0:!0===n?"":n||""})},[]);return o.value}function w(n){return i(function(){return f(n)},[])}function S(n){var r=o(n);return r.current=n,p.add(a),i(function(){return u(function(){return r.current()})},[])}h("__b",function(n,r){if("string"==typeof r.type){var t,i=r.props;for(var o in i){var f=i[o];"children"===o?g(f,"children",i):f instanceof e&&(t||(t=k(r)),t.__.push(o))}_(t)}n(r)}),h("__r",function(n,r){var t,i=r.__c;i&&(s.delete(i),void 0===(t=d.get(i))&&(t=m(function(){s.add(i),i.setState({})}),d.set(i,t))),a=i,_(t),n(r)}),h("__e",function(n,r,t,i){_(),a=void 0,n(r,t,i)}),h("diffed",function(n,r){_(),a=void 0,n(r)}),h("unmount",function(n,r){var t=r.__c||r,i=d.get(t);if(i){d.delete(t);var o=i._d;o&&(o.forEach(function(n){return n._s.delete(i)}),o.clear())}n(r)}),h("__h",function(n,r,t,i){i<3&&l.add(r),n(r,t,i)}),n.prototype.shouldComponentUpdate=function(n,r){var t,i=d.get(this);if(!(i&&0!==(null==(t=i._d)?void 0:t.size)||p.has(this)))return!0;if(s.has(this))return!0;if(l.has(this))return!0;for(var o in r)return!0;for(var e in n)if("__source"!==e&&n[e]!==this.props[e])return!0;for(var f in this.props)if(!(f in n))return!0;return!1};export{S as useComputed,w as useSignal};
2
- //# sourceMappingURL=signals.module.js.map
1
+ import{Component as n,options as r,createElement as t}from"preact";import{useMemo as i,useRef as o}from"preact/hooks";import{Signal as e,signal as f,computed as u}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";var a,c,v,s=new WeakSet,l=new WeakSet,p=new WeakSet;function _(n,t){r[n]=t.bind(null,r[n]||function(){})}var h=new WeakMap;function d(n){v&&v(!0,!0),c=n,v=n&&n._()}function m(n){var r=f(void 0);return r._c=!0,r._u=n,r}function k(n){var r=h.get(n);if(r)r.__.length=0;else{var t=[];(r=m(function(){for(var r=n.__e,i=0;i<t.length;i++){var o=t[i],e=o.t,f=o.i._v;if(!r)return;e in r?r[e]=f:f?r.setAttribute(e,f):r.removeAttribute(e)}})).__=t,h.set(n,r)}return r}function g(n,r,i){"object"!=typeof n||null==n||(Array.isArray(n)?n.forEach(g):n instanceof e&&(i[r]=t(b,{data:n})))}function b(n){var r=this,t=n.data,o=i(function(){for(var n=r.__v;n=n.__;)if(n.__c){p.add(n.__c);break}return c._u=function(){r.base.data=o._v},u(function(){var n=t.value;return 0===n?0:!0===n?"":n||""})},[]);return o.value}function w(n){return i(function(){return f(n)},[])}function y(n){var r=o(n);return r.current=n,p.add(a),i(function(){return u(function(){return r.current()})},[])}b.displayName="_st",_("__b",function(n,r){if("string"==typeof r.type){var t,i=r.props;for(var o in i){var f=i[o];"children"===o?g(f,"children",i):f instanceof e&&function(){t||(t=k(r)),t.__.push({t:o,i:f});var n=t._u;if(f._u){var e=f._u;f._u=function(){n(),e()}}else f._u=n;i[o]=f.peek()}()}d(t)}n(r)}),_("__r",function(n,r){var t,i=r.__c;i&&(s.delete(i),void 0===(t=h.get(i))&&(t=m(function(){s.add(i),i.setState({})}),h.set(i,t))),a=i,d(t),n(r)}),_("__e",function(n,r,t,i){d(),a=void 0,n(r,t,i)}),_("diffed",function(n,r){d(),a=void 0,n(r)}),_("unmount",function(n,r){var t=r.__c||r,i=h.get(t);if(i){h.delete(t);var o=i._d;o&&(o.forEach(function(n){return n._s.delete(i)}),o.clear())}n(r)}),_("__h",function(n,r,t,i){i<3&&l.add(r),n(r,t,i)}),n.prototype.shouldComponentUpdate=function(n,r){var t,i=h.get(this);if(!(i&&0!==(null==(t=i._d)?void 0:t.size)||p.has(this)))return!0;if(s.has(this))return!0;if(l.has(this))return!0;for(var o in r)return!0;for(var e in n)if("__source"!==e&&n[e]!==this.props[e])return!0;for(var f in this.props)if(!(f in n))return!0;return!1};export{y as useComputed,w as useSignal};//# sourceMappingURL=signals.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signals.module.js","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: string[] = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\t\t\tlet props = vnode.props;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet prop = signalProps[i];\n\t\t\t\tlet value = props[prop]._value;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push(i);\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["currentComponent","currentUpdater","finishUpdate","hasPendingUpdate","WeakSet","hasHookState","hasComputeds","hook","hookName","hookFn","options","bind","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","signal","undefined","_canActivate","_updater","getElementUpdater","vnode","get","_props","length","signalProps","dom","__e","props","i","prop","value","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Signal","createElement","Text","data","_ref","_this","this","useMemo","v","__v","__","__c","add","base","computed","useSignal","useComputed","compute","$compute","useRef","current","old","type","push","component","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","Component","prototype","shouldComponentUpdate","state","_updater$_deps","size","has"],"mappings":"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"}
1
+ {"version":3,"file":"signals.module.js","sources":["../src/index.ts"],"sourcesContent":["import { options, Component, createElement } from \"preact\";\nimport { useRef, useMemo } from \"preact/hooks\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport {\n\tVNode,\n\tComponentType,\n\tOptionsTypes,\n\tHookFn,\n\tUpdater,\n\tElementUpdater,\n} from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n// Components that have a pending Signal update: (used to bypass default sCU:false)\nconst hasPendingUpdate = new WeakSet<Component>();\n\n// Components that have useState()/useReducer() hooks:\nconst hasHookState = new WeakSet<Component>();\n\n// Components that have useComputed():\nconst hasComputeds = new WeakSet<Component>();\n\n// Install a Preact options hook\nfunction hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {\n\t// @ts-ignore-next-line private options hooks usage\n\toptions[hookName] = hookFn.bind(null, options[hookName] || (() => {}));\n}\n\nlet currentComponent: Component | undefined;\nlet currentUpdater: Updater | undefined;\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<Component | VNode, Updater>();\n\nfunction setCurrentUpdater(updater?: Updater) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate(true, true);\n\t// start tracking the new update:\n\tcurrentUpdater = updater;\n\tfinishUpdate = updater && updater._setCurrent();\n}\n\nfunction createUpdater(updater: () => void) {\n\tconst s = signal(undefined) as Updater;\n\ts._canActivate = true;\n\ts._updater = updater;\n\treturn s;\n}\n\n// Get a (cached) Signal property updater for an element VNode\nfunction getElementUpdater(vnode: VNode) {\n\tlet updater = updaterForComponent.get(vnode) as ElementUpdater;\n\tif (!updater) {\n\t\tlet signalProps: Array<{ _key: string, _signal: Signal }> = [];\n\t\tupdater = createUpdater(() => {\n\t\t\tlet dom = vnode.__e as Element;\n\n\t\t\tfor (let i = 0; i < signalProps.length; i++) {\n\t\t\t\tlet { _key: prop, _signal: signal } = signalProps[i];\n\t\t\t\tlet value = signal._value;\n\t\t\t\tif (!dom) return;\n\t\t\t\tif (prop in dom) {\n\t\t\t\t\t// @ts-ignore-next-line silly\n\t\t\t\t\tdom[prop] = value;\n\t\t\t\t} else if (value) {\n\t\t\t\t\tdom.setAttribute(prop, value);\n\t\t\t\t} else {\n\t\t\t\t\tdom.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}) as ElementUpdater;\n\t\tupdater._props = signalProps;\n\t\tupdaterForComponent.set(vnode, updater);\n\t} else {\n\t\tupdater._props.length = 0;\n\t}\n\treturn updater;\n}\n\n/** @todo This may be needed for complex prop value detection. */\n// function isSignalValue(value: any): value is Signal {\n// \tif (typeof value !== \"object\" || value == null) return false;\n// \tif (value instanceof Signal) return true;\n// \t// @TODO: uncomment this when we land Reactive (ideally behind a brand check)\n// \t// for (let i in value) if (value[i] instanceof Signal) return true;\n// \treturn false;\n// }\n\n/** Convert Signals within (nested) props.children into Text components */\nfunction childToSignal<T>(child: any, i: keyof T, arr: T) {\n\tif (typeof child !== \"object\" || child == null) {\n\t\t// can't be a signal\n\t} else if (Array.isArray(child)) {\n\t\tchild.forEach(childToSignal);\n\t} else if (child instanceof Signal) {\n\t\t// @ts-ignore-next-line yes, arr can accept VNodes:\n\t\tarr[i] = createElement(Text, { data: child });\n\t}\n}\n\n/**\n * A wrapper component that renders a Signal directly as a Text node.\n * @todo: in Preact 11, just decorate Signal with `type:null`\n */\nfunction Text(this: ComponentType, { data }: { data: Signal }) {\n\t// hasComputeds.add(this);\n\n\tconst s = useMemo(() => {\n\t\t// mark the parent component as having computeds so it gets optimized\n\t\tlet v = this.__v;\n\t\twhile ((v = v.__!)) {\n\t\t\tif (v.__c) {\n\t\t\t\thasComputeds.add(v.__c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Replace this component's vdom updater with a direct text one:\n\t\tcurrentUpdater!._updater = () => {\n\t\t\t(this.base as Text).data = s._value;\n\t\t};\n\n\t\treturn computed(() => {\n\t\t\tlet s = data.value;\n\t\t\treturn s === 0 ? 0 : s === true ? \"\" : s || \"\";\n\t\t});\n\t}, []);\n\n\treturn s.value;\n}\nText.displayName = \"_st\";\n\n/** Inject low-level property/attribute bindings for Signals into Preact's diff */\nhook(OptionsTypes.DIFF, (old, vnode) => {\n\tif (typeof vnode.type === \"string\") {\n\t\t// let orig = vnode.__o || vnode;\n\t\tlet props = vnode.props;\n\t\tlet updater;\n\n\t\tfor (let i in props) {\n\t\t\tlet value = props[i];\n\t\t\tif (i === \"children\") {\n\t\t\t\tchildToSignal(value, \"children\", props);\n\t\t\t} else if (value instanceof Signal) {\n\t\t\t\t// first Signal prop triggers creation/cleanup of the updater:\n\t\t\t\tif (!updater) updater = getElementUpdater(vnode);\n\t\t\t\t// track which props are Signals for precise updates:\n\t\t\t\tupdater._props.push({ _key: i, _signal: value });\n\t\t\t\tlet newUpdater = updater._updater\n\t\t\t\tif (value._updater) {\n\t\t\t\t\tlet oldUpdater = value._updater\n\t\t\t\t\tvalue._updater = () => {\n\t\t\t\t\t\tnewUpdater();\n\t\t\t\t\t\toldUpdater();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvalue._updater = newUpdater\n\t\t\t\t}\n\t\t\t\tprops[i] = value.peek()\n\t\t\t}\n\t\t}\n\n\t\tsetCurrentUpdater(updater);\n\t}\n\n\told(vnode);\n});\n\n/** Set up Updater before rendering a component */\nhook(OptionsTypes.RENDER, (old, vnode) => {\n\tlet updater;\n\n\tlet component = vnode.__c;\n\tif (component) {\n\t\thasPendingUpdate.delete(component);\n\n\t\tupdater = updaterForComponent.get(component);\n\t\tif (updater === undefined) {\n\t\t\tupdater = createUpdater(() => {\n\t\t\t\thasPendingUpdate.add(component);\n\t\t\t\tcomponent.setState({});\n\t\t\t});\n\t\t\tupdaterForComponent.set(component, updater);\n\t\t}\n\t}\n\n\tcurrentComponent = component;\n\tsetCurrentUpdater(updater);\n\told(vnode);\n});\n\n/** Finish current updater if a component errors */\nhook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(error, vnode, oldVNode);\n});\n\n/** Finish current updater after rendering any VNode */\nhook(OptionsTypes.DIFFED, (old, vnode) => {\n\tsetCurrentUpdater();\n\tcurrentComponent = undefined;\n\told(vnode);\n});\n\n/** Unsubscribe from Signals when unmounting components/vnodes */\nhook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {\n\tlet thing = vnode.__c || vnode;\n\tconst updater = updaterForComponent.get(thing);\n\tif (updater) {\n\t\tupdaterForComponent.delete(thing);\n\t\tconst signals = updater._deps;\n\t\tif (signals) {\n\t\t\tsignals.forEach(signal => signal._subs.delete(updater));\n\t\t\tsignals.clear();\n\t\t}\n\t}\n\told(vnode);\n});\n\n/** Mark components that use hook state so we can skip sCU optimization. */\nhook(OptionsTypes.HOOK, (old, component, index, type) => {\n\tif (type < 3) hasHookState.add(component);\n\told(component, index, type);\n});\n\n/**\n * Auto-memoize components that use Signals/Computeds.\n * Note: Does _not_ optimize components that use hook/class state.\n */\nComponent.prototype.shouldComponentUpdate = function (props, state) {\n\t// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:\n\tconst updater = updaterForComponent.get(this);\n\n\tconst hasSignals = updater && updater._deps?.size !== 0;\n\n\t// let reason;\n\t// if (!hasSignals && !hasComputeds.has(this)) {\n\t// \treason = \"no signals or computeds\";\n\t// } else if (hasPendingUpdate.has(this)) {\n\t// \treason = \"has pending update\";\n\t// } else if (hasHookState.has(this)) {\n\t// \treason = \"has hook state\";\n\t// }\n\t// if (reason) {\n\t// \tif (!this) reason += \" (`this` bug)\";\n\t// \tconsole.log(\"not optimizing\", this?.constructor?.name, \": \", reason, {\n\t// \t\tdetails: {\n\t// \t\t\thasSignals,\n\t// \t\t\thasComputeds: hasComputeds.has(this),\n\t// \t\t\thasPendingUpdate: hasPendingUpdate.has(this),\n\t// \t\t\thasHookState: hasHookState.has(this),\n\t// \t\t\tdeps: Array.from(updater._deps),\n\t// \t\t\tupdater,\n\t// \t\t},\n\t// \t});\n\t// }\n\n\t// if this component used no signals or computeds, update:\n\tif (!hasSignals && !hasComputeds.has(this)) return true;\n\n\t// if there is a pending re-render triggered from Signals, update:\n\tif (hasPendingUpdate.has(this)) return true;\n\n\t// if there is hook or class state, update:\n\tif (hasHookState.has(this)) return true;\n\tfor (let i in state) return true;\n\n\t// if any non-Signal props changed, update:\n\tfor (let i in props) {\n\t\tif (i !== \"__source\" && props[i] !== this.props[i]) return true;\n\t}\n\tfor (let i in this.props) if (!(i in props)) return true;\n\n\t// this is a purely Signal-driven component, don't update:\n\treturn false;\n};\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), []);\n}\n\nexport function useComputed<T>(compute: () => T) {\n\tconst $compute = useRef(compute);\n\t$compute.current = compute;\n\thasComputeds.add(currentComponent!);\n\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n\n/**\n * @todo Determine which Reactive implementation we'll be using.\n * @internal\n */\n// export function useReactive<T extends object>(value: T): Reactive<T> {\n// \treturn useMemo(() => reactive<T>(value), []);\n// }\n\n/**\n * @internal\n * Update a Reactive's using the properties of an object or other Reactive.\n * Also works for Signals.\n * @example\n * // Update a Reactive with Object.assign()-like syntax:\n * const r = reactive({ name: \"Alice\" });\n * update(r, { name: \"Bob\" });\n * update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'\n * update(r, 2); // '2' has no properties in common with '{ name?: string }'\n * console.log(r.name.value); // \"Bob\"\n *\n * @example\n * // Update a Reactive with the properties of another Reactive:\n * const A = reactive({ name: \"Alice\" });\n * const B = reactive({ name: \"Bob\", age: 42 });\n * update(A, B);\n * console.log(`${A.name} is ${A.age}`); // \"Bob is 42\"\n *\n * @example\n * // Update a signal with assign()-like syntax:\n * const s = signal(42);\n * update(s, \"hi\"); // Argument type 'string' not assignable to type 'number'\n * update(s, {}); // Argument type '{}' not assignable to type 'number'\n * update(s, 43);\n * console.log(s.value); // 43\n *\n * @param obj The Reactive or Signal to be updated\n * @param update The value, Signal, object or Reactive to update `obj` to match\n * @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`\n */\n/*\nexport function update<T extends SignalOrReactive>(\n\tobj: T,\n\tupdate: Partial<Unwrap<T>>,\n\toverwrite = false\n) {\n\tif (obj instanceof Signal) {\n\t\tobj.value = peekValue(update);\n\t} else {\n\t\tfor (let i in update) {\n\t\t\tif (i in obj) {\n\t\t\t\tobj[i].value = peekValue(update[i]);\n\t\t\t} else {\n\t\t\t\tlet sig = signal(peekValue(update[i]));\n\t\t\t\tsig[KEY] = i;\n\t\t\t\tobj[i] = sig;\n\t\t\t}\n\t\t}\n\t\tif (overwrite) {\n\t\t\tfor (let i in obj) {\n\t\t\t\tif (!(i in update)) {\n\t\t\t\t\tobj[i].value = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"],"names":["Component","options","createElement","useMemo","useRef","Signal","signal","computed","batch","effect","currentComponent","currentUpdater","finishUpdate","hasPendingUpdate","WeakSet","hasComputeds","hook","hookName","hookFn","bind","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","s","undefined","_canActivate","_updater","getElementUpdater","vnode","get","_props","length","signalProps","createUpdater","dom","__e","i","prop","_key","value","_signal","_value","setAttribute","removeAttribute","set","childToSignal","child","arr","Array","isArray","forEach","Text","data","_ref","_this","this","__v","v","__","__c","add","base","useSignal","useComputed","compute","$compute","current","displayName","old","type","props","push","oldUpdater","newUpdater","peek","component","setState","error","oldVNode","thing","signals","_deps","_subs","clear","index","hasHookState","prototype","shouldComponentUpdate","state","_updater$_deps","size","has","_i","_i2"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preact/signals",
3
- "version": "0.0.4",
3
+ "version": "1.0.2",
4
4
  "license": "MIT",
5
5
  "description": "",
6
6
  "keywords": [],
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "mangle": "../../mangle.json",
33
33
  "dependencies": {
34
- "@preact/signals-core": "^0.0.5"
34
+ "@preact/signals-core": "^1.0.1"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "preact": "10.x"
package/src/index.ts CHANGED
@@ -58,14 +58,14 @@ function createUpdater(updater: () => void) {
58
58
  function getElementUpdater(vnode: VNode) {
59
59
  let updater = updaterForComponent.get(vnode) as ElementUpdater;
60
60
  if (!updater) {
61
- let signalProps: string[] = [];
61
+ let signalProps: Array<{ _key: string, _signal: Signal }> = [];
62
62
  updater = createUpdater(() => {
63
63
  let dom = vnode.__e as Element;
64
- let props = vnode.props;
65
64
 
66
65
  for (let i = 0; i < signalProps.length; i++) {
67
- let prop = signalProps[i];
68
- let value = props[prop]._value;
66
+ let { _key: prop, _signal: signal } = signalProps[i];
67
+ let value = signal._value;
68
+ if (!dom) return;
69
69
  if (prop in dom) {
70
70
  // @ts-ignore-next-line silly
71
71
  dom[prop] = value;
@@ -135,6 +135,7 @@ function Text(this: ComponentType, { data }: { data: Signal }) {
135
135
 
136
136
  return s.value;
137
137
  }
138
+ Text.displayName = "_st";
138
139
 
139
140
  /** Inject low-level property/attribute bindings for Signals into Preact's diff */
140
141
  hook(OptionsTypes.DIFF, (old, vnode) => {
@@ -151,7 +152,18 @@ hook(OptionsTypes.DIFF, (old, vnode) => {
151
152
  // first Signal prop triggers creation/cleanup of the updater:
152
153
  if (!updater) updater = getElementUpdater(vnode);
153
154
  // track which props are Signals for precise updates:
154
- updater._props.push(i);
155
+ updater._props.push({ _key: i, _signal: value });
156
+ let newUpdater = updater._updater
157
+ if (value._updater) {
158
+ let oldUpdater = value._updater
159
+ value._updater = () => {
160
+ newUpdater();
161
+ oldUpdater();
162
+ }
163
+ } else {
164
+ value._updater = newUpdater
165
+ }
166
+ props[i] = value.peek()
155
167
  }
156
168
  }
157
169
 
package/src/internal.d.ts CHANGED
@@ -18,7 +18,7 @@ export interface ComponentType extends Component {
18
18
  export type Updater = Signal<unknown>;
19
19
 
20
20
  export interface ElementUpdater extends Updater {
21
- _props: string[];
21
+ _props: Array<{ _key: string, _signal: Signal }>;
22
22
  }
23
23
 
24
24
  export const enum OptionsTypes {
@@ -3,6 +3,8 @@ import { h, render } from "preact";
3
3
  import { useMemo } from "preact/hooks";
4
4
  import { setupRerender } from "preact/test-utils";
5
5
 
6
+ const sleep = (ms?: number) => new Promise(r => setTimeout(r, ms));
7
+
6
8
  describe("@preact/signals", () => {
7
9
  let scratch: HTMLDivElement;
8
10
  let rerender: () => void;
@@ -146,4 +148,85 @@ describe("@preact/signals", () => {
146
148
  expect(scratch.textContent).to.equal("bar");
147
149
  });
148
150
  });
151
+
152
+ describe("prop bindings", () => {
153
+ it("should set the initial value of the checked property", () => {
154
+ const s = signal(true);
155
+ // @ts-ignore
156
+ render(h("input", { checked: s }), scratch);
157
+
158
+ expect(scratch.firstChild).to.have.property("checked", true);
159
+ expect(s.value).to.equal(true);
160
+ });
161
+
162
+ it("should update the checked property on change", () => {
163
+ const s = signal(true);
164
+ // @ts-ignore
165
+ render(h("input", { checked: s }), scratch);
166
+
167
+ expect(scratch.firstChild).to.have.property("checked", true);
168
+
169
+ s.value = false;
170
+
171
+ expect(scratch.firstChild).to.have.property("checked", false);
172
+ });
173
+
174
+ it("should update props without re-rendering", async () => {
175
+ const s = signal("initial");
176
+ const spy = sinon.spy();
177
+ function Wrap() {
178
+ spy();
179
+ // @ts-ignore
180
+ return h("input", { value: s });
181
+ }
182
+ render(h(Wrap, {}), scratch);
183
+ spy.resetHistory();
184
+
185
+ expect(scratch.firstChild).to.have.property("value", "initial");
186
+
187
+ s.value = "updated";
188
+
189
+ expect(scratch.firstChild).to.have.property("value", "updated");
190
+
191
+ // ensure the component was never re-rendered: (even after a tick)
192
+ await sleep();
193
+ expect(spy).not.to.have.been.called;
194
+
195
+ s.value = "second update";
196
+
197
+ expect(scratch.firstChild).to.have.property("value", "second update");
198
+
199
+ // ensure the component was never re-rendered: (even after a tick)
200
+ await sleep();
201
+ expect(spy).not.to.have.been.called;
202
+ });
203
+
204
+ it("should set and update string style property", async () => {
205
+ const style = signal("left: 10px");
206
+ const spy = sinon.spy();
207
+ function Wrap() {
208
+ spy();
209
+ // @ts-ignore
210
+ return h("div", { style });
211
+ }
212
+ render(h(Wrap, {}), scratch);
213
+ spy.resetHistory();
214
+
215
+ const div = scratch.firstChild as HTMLDivElement;
216
+
217
+ expect(div.style).to.have.property("left", "10px");
218
+
219
+ // ensure the component was never re-rendered: (even after a tick)
220
+ await sleep();
221
+ expect(spy).not.to.have.been.called;
222
+
223
+ style.value = "left: 20px;";
224
+
225
+ expect(div.style).to.have.property("left", "20px");
226
+
227
+ // ensure the component was never re-rendered: (even after a tick)
228
+ await sleep();
229
+ expect(spy).not.to.have.been.called;
230
+ });
231
+ });
149
232
  });