@preact/signals-react 0.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 ADDED
@@ -0,0 +1,8 @@
1
+ # @preact/signals-react
2
+
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [702a9c5]
8
+ - @preact/signals-core@0.0.5
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022-present Preact Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ import { signal, computed, batch, effect, Signal, type ReadonlySignal } from "@preact/signals-core";
2
+ export { signal, computed, batch, effect, Signal, type ReadonlySignal };
3
+ export declare function useSignal<T>(value: T): Signal<T>;
4
+ export declare function useComputed<T>(compute: () => T): ReadonlySignal<T>;
@@ -0,0 +1 @@
1
+ var r=require("react"),n=require("@preact/signals-core");function t(r){return r&&"object"==typeof r&&"default"in r?r.default:r}var e,u=/*#__PURE__*/t(r),o=u.createElement;u.createElement=function(r,t){if("string"==typeof r&&t)for(var e in t){var u=t[e];"children"!==e&&u instanceof n.Signal&&(t[e]=u.value)}return o.apply(this,arguments)};var i=new WeakMap;function a(r){e&&e(!0,!0),e=r&&r._()}function c(r){var t=n.signal(void 0);return t._c=!0,t._u=r,t}var f=o("a").$$typeof;Object.defineProperties(n.Signal.prototype,{$$typeof:{value:f},type:{value:function(r){return r.data.value}},props:{get:function(){return{data:this}}},ref:{value:null}});var v,s=!1,p=function(){return{}};Object.defineProperty(r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher,"current",{get:function(){return v},set:function(n){if(v=n,!s)if(n&&!x(n)){s=!0;var t=n.useReducer(p,{})[1];s=!1;var e=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner.current,u=i.get(e);u||(u=c(t),i.set(e,u)),a(u)}else a()}});var l=new Map;function x(r){var n=l.get(r);if(void 0!==n)return n;var t=r.useCallback.length<2||/warnInvalidHookAccess/.test(r.useCallback);return l.set(r,t),t}exports.Signal=n.Signal,exports.batch=n.batch,exports.computed=n.computed,exports.effect=n.effect,exports.signal=n.signal,exports.useComputed=function(t){var e=r.useRef(t);return e.current=t,r.useMemo(function(){return n.computed(function(){return e.current()})},[])},exports.useSignal=function(t){return r.useMemo(function(){return n.signal(t)},[])};//# sourceMappingURL=signals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\t// @ts-ignore-next-line\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as internals,\n} from \"react\";\nimport React from \"react\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport { Updater, ReactOwner, ReactDispatcher } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n/**\n * Install a middleware into React.createElement to replace any Signals in props with their value.\n * @todo this likely needs to be duplicated for jsx()...\n */\nconst createElement = React.createElement;\n// @ts-ignore-next-line\nReact.createElement = function (type, props) {\n\tif (typeof type === \"string\" && props) {\n\t\tfor (let i in props) {\n\t\t\tlet v = props[i];\n\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t// createPropUpdater(props, i, v);\n\t\t\t\tprops[i] = v.value;\n\t\t\t}\n\t\t}\n\t}\n\t// @ts-ignore-next-line\n\treturn createElement.apply(this, arguments);\n};\n\n/*\n// This breaks React's controlled components implementation\nfunction createPropUpdater(props: any, prop: string, signal: Signal) {\n\tlet ref = props.ref;\n\tif (!ref) ref = props.ref = React.createRef();\n\teffect(() => {\n\t\tif (props) props[prop] = signal.value;\n\t\tlet el = ref.current;\n\t\tif (!el) return; // unsubscribe\n\t\t(el as any)[prop] = signal.value;\n\t});\n\tprops = null;\n}\n*/\n\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<ReactOwner, 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\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/**\n * A wrapper component that renders a Signal's value directly as a Text node.\n */\nfunction Text({ data }: { data: Signal }) {\n\treturn data.value;\n}\n\n// Decorate Signals so React renders them as <Text> components.\n//@ts-ignore-next-line\nconst $$typeof = createElement(\"a\").$$typeof;\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { value: $$typeof },\n\ttype: { value: Text },\n\tprops: {\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { value: null },\n});\n\n// Track the current owner (roughly equiv to current vnode)\n// let currentOwner: ReactOwner;\n// Object.defineProperty(internals.ReactCurrentOwner, \"current\", {\n// \tget() { return currentOwner; },\n// \tset(owner) { currentOwner = owner; },\n// });\n\n// Track the current dispatcher (roughly equiv to current component impl)\nlet lock = false;\nconst UPDATE = () => ({});\nlet currentDispatcher: ReactDispatcher;\nObject.defineProperty(internals.ReactCurrentDispatcher, \"current\", {\n\tget() {\n\t\treturn currentDispatcher;\n\t},\n\tset(api) {\n\t\tcurrentDispatcher = api;\n\t\tif (lock) return;\n\t\tif (api && !isInvalidHookAccessor(api)) {\n\t\t\t// prevent re-injecting useReducer when the Dispatcher\n\t\t\t// context changes to run the reducer callback:\n\t\t\tlock = true;\n\t\t\tconst rerender = api.useReducer(UPDATE, {})[1];\n\t\t\tlock = false;\n\t\t\tconst currentOwner = internals.ReactCurrentOwner.current;\n\t\t\tlet updater = updaterForComponent.get(currentOwner);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(currentOwner, updater);\n\t\t\t}\n\t\t\tsetCurrentUpdater(updater);\n\t\t} else {\n\t\t\tsetCurrentUpdater();\n\t\t}\n\t},\n});\n\n// We inject a useReducer into every function component via CurrentDispatcher.\n// This prevents injecting into anything other than a function component render.\nconst invalidHookAccessors = new Map();\nfunction isInvalidHookAccessor(api: ReactDispatcher) {\n\tconst cached = invalidHookAccessors.get(api);\n\tif (cached !== undefined) return cached;\n\t// we only want the real implementation, not the warning ones\n\tconst invalid =\n\t\tapi.useCallback.length < 2 ||\n\t\t/warnInvalidHookAccess/.test(api.useCallback as any);\n\tinvalidHookAccessors.set(api, invalid);\n\treturn invalid;\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\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n"],"names":["finishUpdate","createElement","React","type","props","i","v","Signal","value","apply","this","arguments","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","signal","undefined","_canActivate","_updater","$$typeof","Object","defineProperties","prototype","_ref","data","get","ref","currentDispatcher","UPDATE","defineProperty","internals","__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","ReactCurrentDispatcher","set","api","lock","isInvalidHookAccessor","useReducer","currentOwner","ReactCurrentOwner","current","rerender","invalidHookAccessors","Map","cached","invalid","useCallback","length","test","exports","signalsCore","batch","computed","effect","useComputed","compute","$compute","useRef","useMemo","useSignal"],"mappings":"mIAuDAA,sBA/BmBC,EAAGC,EAAMD,cAE5BC,EAAMD,cAAgB,SAAUE,EAAMC,GACrC,GAAoB,iBAAhBD,GAA4BC,EAC/B,IAAK,IAALC,KAAAD,EAAqB,CACpB,IAAKE,EAAGF,EAAMC,GACJ,aAANA,GAAoBC,aAAxBC,EAAAA,SAECH,EAAMC,GAAKC,EAAEE,MAEd,CAGF,OAAOP,EAAcQ,MAAMC,KAAMC,UACjC,EAkBD,IAAMC,EAAsB,IAA5BC,QAEA,SAASC,EAAkBC,GAEtBf,GAAcA,GAAa,GAAM,GAErCA,EAAee,GAAWA,EAAQC,GAClC,CAED,SAASC,EAAcF,GACtB,IAAMG,EAAIC,EAAMA,YAACC,GAGjB,OAFAF,EAAEG,IAAe,EACjBH,EAAEI,GAAWP,EAEbG,CAAA,CAWD,IAAMK,EAAWtB,EAAc,KAAKsB,SACpCC,OAAOC,iBAAiBlB,EAAAA,OAAOmB,UAAW,CACzCH,SAAU,CAAEf,MAAOe,GACnBpB,KAAM,CAAEK,MATT,SAAwCmB,GACvC,OADuCA,EAAxBC,KACHpB,KACZ,GAQAJ,MAAO,CACNyB,IADM,WAEL,MAAO,CAAED,KAAMlB,KACf,GAEFoB,IAAK,CAAEtB,MAAO,QAWf,IAEIuB,KAFO,EACCC,EAAG,WAAO,MAAA,CAAP,CAAA,EAEfR,OAAOS,eAAeC,EAASC,mDAACC,uBAAwB,UAAW,CAClEP,IADkE,WAEjE,QACA,EACDQ,IAJkE,SAI9DC,GAEH,GADAP,EAAoBO,GAChBC,EACJ,GAAID,IAAQE,EAAsBF,GAAM,CAGvCC,GAAO,EACP,MAAiBD,EAAIG,WAAWT,EAAQ,CAAvB,GAA2B,GAC5CO,GAAO,EACP,IAAMG,EAAeR,EAASC,mDAACQ,kBAAkBC,QACtC7B,EAAGH,EAAoBiB,IAAIa,GACjC3B,IACJA,EAAUE,EAAc4B,GACxBjC,EAAoByB,IAAIK,EAAc3B,IAEvCD,EAAkBC,EAClB,MACAD,GAED,IAKF,IAAMgC,EAAuB,IAA7BC,IACA,SAASP,EAAsBF,GAC9B,IAAMU,EAASF,EAAqBjB,IAAIS,GACxC,QAAelB,IAAX4B,EAAsB,OAAAA,EAE1B,IAAMC,EACLX,EAAIY,YAAYC,OAAS,GACzB,wBAAwBC,KAAKd,EAAIY,aAElC,OADAJ,EAAqBT,IAAIC,EAAKW,GACvBA,CACP,CAUAI,QAAA9C,OAAA+C,EAAA/C,OAAA8C,QAAAE,MAAAD,EAAAC,MAAAF,QAAAG,SAAAF,EAAAE,SAAAH,QAAAI,OAAAH,EAAAG,OAAAJ,QAAAlC,OAAAmC,EAAAnC,OAAAkC,QAAAK,YAJeA,SAAeC,GAC9B,IAAMC,EAAWC,EAAMA,OAACF,GAExB,OADAC,EAAShB,QAAUe,EACZG,EAAAA,QAAQ,WAAA,OAAcN,EAAAA,SAAI,WAAMI,OAAAA,EAAShB,SAAf,EAAlB,EAA6C,GAC5D,EAAAS,QAAAU,UAReA,SAAavD,GAC5B,OAAOsD,EAAOA,QAAC,WAAA,OAAY3C,EAAAA,OAAIX,EAAhB,EAAwB,GACvC"}
@@ -0,0 +1 @@
1
+ !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("@preact/signals-core")):"function"==typeof define&&define.amd?define(["exports","react","@preact/signals-core"],e):e((n||self).reactSignals={},n.react,n.signalsCore)}(this,function(n,e,r){function t(n){return n&&"object"==typeof n&&"default"in n?n.default:n}var i,u=/*#__PURE__*/t(e),o=u.createElement;u.createElement=function(n,e){if("string"==typeof n&&e)for(var t in e){var i=e[t];"children"!==t&&i instanceof r.Signal&&(e[t]=i.value)}return o.apply(this,arguments)};var f=new WeakMap;function a(n){i&&i(!0,!0),i=n&&n._()}function c(n){var e=r.signal(void 0);return e._c=!0,e._u=n,e}var s=o("a").$$typeof;Object.defineProperties(r.Signal.prototype,{$$typeof:{value:s},type:{value:function(n){return n.data.value}},props:{get:function(){return{data:this}}},ref:{value:null}});var v,l=!1,p=function(){return{}};Object.defineProperty(e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher,"current",{get:function(){return v},set:function(n){if(v=n,!l)if(n&&!y(n)){l=!0;var r=n.useReducer(p,{})[1];l=!1;var t=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner.current,i=f.get(t);i||(i=c(r),f.set(t,i)),a(i)}else a()}});var d=new Map;function y(n){var e=d.get(n);if(void 0!==e)return e;var r=n.useCallback.length<2||/warnInvalidHookAccess/.test(n.useCallback);return d.set(n,r),r}n.Signal=r.Signal,n.batch=r.batch,n.computed=r.computed,n.effect=r.effect,n.signal=r.signal,n.useComputed=function(n){var t=e.useRef(n);return t.current=n,e.useMemo(function(){return r.computed(function(){return t.current()})},[])},n.useSignal=function(n){return e.useMemo(function(){return r.signal(n)},[])}});//# sourceMappingURL=signals.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.min.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\t// @ts-ignore-next-line\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as internals,\n} from \"react\";\nimport React from \"react\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport { Updater, ReactOwner, ReactDispatcher } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n/**\n * Install a middleware into React.createElement to replace any Signals in props with their value.\n * @todo this likely needs to be duplicated for jsx()...\n */\nconst createElement = React.createElement;\n// @ts-ignore-next-line\nReact.createElement = function (type, props) {\n\tif (typeof type === \"string\" && props) {\n\t\tfor (let i in props) {\n\t\t\tlet v = props[i];\n\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t// createPropUpdater(props, i, v);\n\t\t\t\tprops[i] = v.value;\n\t\t\t}\n\t\t}\n\t}\n\t// @ts-ignore-next-line\n\treturn createElement.apply(this, arguments);\n};\n\n/*\n// This breaks React's controlled components implementation\nfunction createPropUpdater(props: any, prop: string, signal: Signal) {\n\tlet ref = props.ref;\n\tif (!ref) ref = props.ref = React.createRef();\n\teffect(() => {\n\t\tif (props) props[prop] = signal.value;\n\t\tlet el = ref.current;\n\t\tif (!el) return; // unsubscribe\n\t\t(el as any)[prop] = signal.value;\n\t});\n\tprops = null;\n}\n*/\n\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<ReactOwner, 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\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/**\n * A wrapper component that renders a Signal's value directly as a Text node.\n */\nfunction Text({ data }: { data: Signal }) {\n\treturn data.value;\n}\n\n// Decorate Signals so React renders them as <Text> components.\n//@ts-ignore-next-line\nconst $$typeof = createElement(\"a\").$$typeof;\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { value: $$typeof },\n\ttype: { value: Text },\n\tprops: {\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { value: null },\n});\n\n// Track the current owner (roughly equiv to current vnode)\n// let currentOwner: ReactOwner;\n// Object.defineProperty(internals.ReactCurrentOwner, \"current\", {\n// \tget() { return currentOwner; },\n// \tset(owner) { currentOwner = owner; },\n// });\n\n// Track the current dispatcher (roughly equiv to current component impl)\nlet lock = false;\nconst UPDATE = () => ({});\nlet currentDispatcher: ReactDispatcher;\nObject.defineProperty(internals.ReactCurrentDispatcher, \"current\", {\n\tget() {\n\t\treturn currentDispatcher;\n\t},\n\tset(api) {\n\t\tcurrentDispatcher = api;\n\t\tif (lock) return;\n\t\tif (api && !isInvalidHookAccessor(api)) {\n\t\t\t// prevent re-injecting useReducer when the Dispatcher\n\t\t\t// context changes to run the reducer callback:\n\t\t\tlock = true;\n\t\t\tconst rerender = api.useReducer(UPDATE, {})[1];\n\t\t\tlock = false;\n\t\t\tconst currentOwner = internals.ReactCurrentOwner.current;\n\t\t\tlet updater = updaterForComponent.get(currentOwner);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(currentOwner, updater);\n\t\t\t}\n\t\t\tsetCurrentUpdater(updater);\n\t\t} else {\n\t\t\tsetCurrentUpdater();\n\t\t}\n\t},\n});\n\n// We inject a useReducer into every function component via CurrentDispatcher.\n// This prevents injecting into anything other than a function component render.\nconst invalidHookAccessors = new Map();\nfunction isInvalidHookAccessor(api: ReactDispatcher) {\n\tconst cached = invalidHookAccessors.get(api);\n\tif (cached !== undefined) return cached;\n\t// we only want the real implementation, not the warning ones\n\tconst invalid =\n\t\tapi.useCallback.length < 2 ||\n\t\t/warnInvalidHookAccess/.test(api.useCallback as any);\n\tinvalidHookAccessors.set(api, invalid);\n\treturn invalid;\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\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n"],"names":["finishUpdate","createElement","React","type","props","i","v","Signal","value","apply","this","arguments","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","signal","undefined","_canActivate","_updater","$$typeof","Object","defineProperties","prototype","_ref","data","get","ref","currentDispatcher","UPDATE","defineProperty","internals","__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","ReactCurrentDispatcher","set","api","lock","isInvalidHookAccessor","useReducer","currentOwner","ReactCurrentOwner","current","rerender","invalidHookAccessors","Map","cached","invalid","useCallback","length","test","exports","signalsCore","batch","computed","effect","useComputed","compute","$compute","useRef","useMemo","useSignal"],"mappings":"0ZAuDAA,sBA/BmBC,EAAGC,EAAMD,cAE5BC,EAAMD,cAAgB,SAAUE,EAAMC,GACrC,GAAoB,iBAAhBD,GAA4BC,EAC/B,IAAK,IAALC,KAAAD,EAAqB,CACpB,IAAKE,EAAGF,EAAMC,GACJ,aAANA,GAAoBC,aAAxBC,EAAAA,SAECH,EAAMC,GAAKC,EAAEE,MAEd,CAGF,OAAOP,EAAcQ,MAAMC,KAAMC,UACjC,EAkBD,IAAMC,EAAsB,IAA5BC,QAEA,SAASC,EAAkBC,GAEtBf,GAAcA,GAAa,GAAM,GAErCA,EAAee,GAAWA,EAAQC,GAClC,CAED,SAASC,EAAcF,GACtB,IAAMG,EAAIC,EAAMA,YAACC,GAGjB,OAFAF,EAAEG,IAAe,EACjBH,EAAEI,GAAWP,EAEbG,CAAA,CAWD,IAAMK,EAAWtB,EAAc,KAAKsB,SACpCC,OAAOC,iBAAiBlB,EAAAA,OAAOmB,UAAW,CACzCH,SAAU,CAAEf,MAAOe,GACnBpB,KAAM,CAAEK,MATT,SAAwCmB,GACvC,OADuCA,EAAxBC,KACHpB,KACZ,GAQAJ,MAAO,CACNyB,IADM,WAEL,MAAO,CAAED,KAAMlB,KACf,GAEFoB,IAAK,CAAEtB,MAAO,QAWf,IAEIuB,KAFO,EACCC,EAAG,WAAO,MAAA,CAAP,CAAA,EAEfR,OAAOS,eAAeC,EAASC,mDAACC,uBAAwB,UAAW,CAClEP,IADkE,WAEjE,QACA,EACDQ,IAJkE,SAI9DC,GAEH,GADAP,EAAoBO,GAChBC,EACJ,GAAID,IAAQE,EAAsBF,GAAM,CAGvCC,GAAO,EACP,MAAiBD,EAAIG,WAAWT,EAAQ,CAAvB,GAA2B,GAC5CO,GAAO,EACP,IAAMG,EAAeR,EAASC,mDAACQ,kBAAkBC,QACtC7B,EAAGH,EAAoBiB,IAAIa,GACjC3B,IACJA,EAAUE,EAAc4B,GACxBjC,EAAoByB,IAAIK,EAAc3B,IAEvCD,EAAkBC,EAClB,MACAD,GAED,IAKF,IAAMgC,EAAuB,IAA7BC,IACA,SAASP,EAAsBF,GAC9B,IAAMU,EAASF,EAAqBjB,IAAIS,GACxC,QAAelB,IAAX4B,EAAsB,OAAAA,EAE1B,IAAMC,EACLX,EAAIY,YAAYC,OAAS,GACzB,wBAAwBC,KAAKd,EAAIY,aAElC,OADAJ,EAAqBT,IAAIC,EAAKW,GACvBA,CACP,CAUAI,EAAA9C,OAAA+C,EAAA/C,OAAA8C,EAAAE,MAAAD,EAAAC,MAAAF,EAAAG,SAAAF,EAAAE,SAAAH,EAAAI,OAAAH,EAAAG,OAAAJ,EAAAlC,OAAAmC,EAAAnC,OAAAkC,EAAAK,YAJeA,SAAeC,GAC9B,IAAMC,EAAWC,EAAMA,OAACF,GAExB,OADAC,EAAShB,QAAUe,EACZG,EAAAA,QAAQ,WAAA,OAAcN,EAAAA,SAAI,WAAMI,OAAAA,EAAShB,SAAf,EAAlB,EAA6C,GAC5D,EAAAS,EAAAU,UAReA,SAAavD,GAC5B,OAAOsD,EAAOA,QAAC,WAAA,OAAY3C,EAAAA,OAAIX,EAAhB,EAAwB,GACvC,CAMA"}
@@ -0,0 +1 @@
1
+ import t,{__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as n,useMemo as e,useRef as o}from"react";import{Signal as r,signal as c,computed as i}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";const s=t.createElement;let a;t.createElement=function(t,n){if("string"==typeof t&&n)for(let t in n){let e=n[t];"children"!==t&&e instanceof r&&(n[t]=e.value)}return s.apply(this,arguments)};const f=new WeakMap;function u(t){a&&a(!0,!0),a=t&&t._()}function l(t){const n=c(void 0);return n._c=!0,n._u=t,n}const p=s("a").$$typeof;Object.defineProperties(r.prototype,{$$typeof:{value:p},type:{value:function({data:t}){return t.value}},props:{get(){return{data:this}}},ref:{value:null}});let d=!1;const g=()=>({});let m;Object.defineProperty(n.ReactCurrentDispatcher,"current",{get:()=>m,set(t){if(m=t,!d)if(t&&!h(t)){d=!0;const e=t.useReducer(g,{})[1];d=!1;const o=n.ReactCurrentOwner.current;let r=f.get(o);r||(r=l(e),f.set(o,r)),u(r)}else u()}});const v=new Map;function h(t){const n=v.get(t);if(void 0!==n)return n;const e=t.useCallback.length<2||/warnInvalidHookAccess/.test(t.useCallback);return v.set(t,e),e}function b(t){return e(()=>c(t),[])}function w(t){const n=o(t);return n.current=t,e(()=>i(()=>n.current()),[])}export{w as useComputed,b as useSignal};//# sourceMappingURL=signals.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.mjs","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\t// @ts-ignore-next-line\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as internals,\n} from \"react\";\nimport React from \"react\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport { Updater, ReactOwner, ReactDispatcher } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n/**\n * Install a middleware into React.createElement to replace any Signals in props with their value.\n * @todo this likely needs to be duplicated for jsx()...\n */\nconst createElement = React.createElement;\n// @ts-ignore-next-line\nReact.createElement = function (type, props) {\n\tif (typeof type === \"string\" && props) {\n\t\tfor (let i in props) {\n\t\t\tlet v = props[i];\n\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t// createPropUpdater(props, i, v);\n\t\t\t\tprops[i] = v.value;\n\t\t\t}\n\t\t}\n\t}\n\t// @ts-ignore-next-line\n\treturn createElement.apply(this, arguments);\n};\n\n/*\n// This breaks React's controlled components implementation\nfunction createPropUpdater(props: any, prop: string, signal: Signal) {\n\tlet ref = props.ref;\n\tif (!ref) ref = props.ref = React.createRef();\n\teffect(() => {\n\t\tif (props) props[prop] = signal.value;\n\t\tlet el = ref.current;\n\t\tif (!el) return; // unsubscribe\n\t\t(el as any)[prop] = signal.value;\n\t});\n\tprops = null;\n}\n*/\n\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<ReactOwner, 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\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/**\n * A wrapper component that renders a Signal's value directly as a Text node.\n */\nfunction Text({ data }: { data: Signal }) {\n\treturn data.value;\n}\n\n// Decorate Signals so React renders them as <Text> components.\n//@ts-ignore-next-line\nconst $$typeof = createElement(\"a\").$$typeof;\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { value: $$typeof },\n\ttype: { value: Text },\n\tprops: {\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { value: null },\n});\n\n// Track the current owner (roughly equiv to current vnode)\n// let currentOwner: ReactOwner;\n// Object.defineProperty(internals.ReactCurrentOwner, \"current\", {\n// \tget() { return currentOwner; },\n// \tset(owner) { currentOwner = owner; },\n// });\n\n// Track the current dispatcher (roughly equiv to current component impl)\nlet lock = false;\nconst UPDATE = () => ({});\nlet currentDispatcher: ReactDispatcher;\nObject.defineProperty(internals.ReactCurrentDispatcher, \"current\", {\n\tget() {\n\t\treturn currentDispatcher;\n\t},\n\tset(api) {\n\t\tcurrentDispatcher = api;\n\t\tif (lock) return;\n\t\tif (api && !isInvalidHookAccessor(api)) {\n\t\t\t// prevent re-injecting useReducer when the Dispatcher\n\t\t\t// context changes to run the reducer callback:\n\t\t\tlock = true;\n\t\t\tconst rerender = api.useReducer(UPDATE, {})[1];\n\t\t\tlock = false;\n\t\t\tconst currentOwner = internals.ReactCurrentOwner.current;\n\t\t\tlet updater = updaterForComponent.get(currentOwner);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(currentOwner, updater);\n\t\t\t}\n\t\t\tsetCurrentUpdater(updater);\n\t\t} else {\n\t\t\tsetCurrentUpdater();\n\t\t}\n\t},\n});\n\n// We inject a useReducer into every function component via CurrentDispatcher.\n// This prevents injecting into anything other than a function component render.\nconst invalidHookAccessors = new Map();\nfunction isInvalidHookAccessor(api: ReactDispatcher) {\n\tconst cached = invalidHookAccessors.get(api);\n\tif (cached !== undefined) return cached;\n\t// we only want the real implementation, not the warning ones\n\tconst invalid =\n\t\tapi.useCallback.length < 2 ||\n\t\t/warnInvalidHookAccess/.test(api.useCallback as any);\n\tinvalidHookAccessors.set(api, invalid);\n\treturn invalid;\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\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n"],"names":["createElement","React","finishUpdate","type","props","i","v","Signal","value","apply","this","arguments","updaterForComponent","WeakMap","updater","_setCurrent","createUpdater","signal","undefined","s","_canActivate","_updater","$$typeof","Object","defineProperties","prototype","data","get","ref","lock","UPDATE","currentDispatcher","defineProperty","internals","ReactCurrentDispatcher","set","api","isInvalidHookAccessor","useReducer","currentOwner","ReactCurrentOwner","current","rerender","setCurrentUpdater","invalidHookAccessors","Map","cached","invalid","useCallback","length","test","useSignal","useMemo","useComputed","compute","$compute","useRef","computed"],"mappings":"qPAwBA,MAAmBA,EAAGC,EAAMD,cA+B5B,IAAIE,EA7BJD,EAAMD,cAAgB,SAAUG,EAAMC,GACrC,GAAoB,iBAAhBD,GAA4BC,EAC/B,IAAK,IAALC,KAAAD,EAAqB,CACpB,IAAKE,EAAGF,EAAMC,GACJ,aAANA,GAAoBC,aAAxBC,IAECH,EAAMC,GAAKC,EAAEE,MAEd,CAGF,OAAoBR,EAACS,MAAMC,KAAMC,UACjC,EAkBD,MAAyBC,EAAG,IAAIC,QAEhC,WAA2BC,GAEtBZ,GAAcA,GAAa,GAAM,GAErCA,EAAeY,GAAWA,EAAQC,GAClC,CAED,SAAAC,EAAuBF,GACtB,QAAUG,OAAOC,GAGjB,OAFAC,EAAEC,IAAe,EACjBD,EAAEE,GAAWP,EACNK,CACP,CAWD,MAAcG,EAAGtB,EAAc,KAAKsB,SACpCC,OAAOC,iBAAiBjB,EAAOkB,UAAW,CACzCH,SAAU,CAAEd,MAAOc,GACnBnB,KAAM,CAAEK,MATT,UAAckB,KAAEA,IACf,SAAYlB,KACZ,GAQAJ,MAAO,CACNuB,MACC,MAAO,CAAED,KAAMhB,KACf,GAEFkB,IAAK,CAAEpB,MAAO,QAWf,IAAIqB,GAAO,EACX,MAAYC,EAAG,KAAA,CAAA,GACf,IAAIC,EACJR,OAAOS,eAAeC,EAAUC,uBAAwB,UAAW,CAClEP,IAAG,MAGHQ,IAAIC,GAEH,GADAL,EAAoBK,GAChBP,EACJ,GAAIO,IAAQC,EAAsBD,GAAM,CAGvCP,GAAO,EACP,QAAiBO,EAAIE,WAAWR,EAAQ,CAAA,GAAI,GAC5CD,GAAO,EACP,MAAMU,EAAeN,EAAUO,kBAAkBC,QACjD,IAAW3B,EAAGF,EAAoBe,IAAIY,GACjCzB,IACJA,EAAUE,EAAc0B,GACxB9B,EAAoBuB,IAAII,EAAczB,IAEvC6B,EAAkB7B,EAClB,MACA6B,GAED,IAKF,MAA0BC,EAAG,IAAIC,IACjC,SAAAR,EAA+BD,GAC9B,MAAYU,EAAGF,EAAqBjB,IAAIS,GACxC,QAAelB,IAAX4B,EAAsB,OAAAA,EAE1B,MAAMC,EACLX,EAAIY,YAAYC,OAAS,GACzB,wBAAwBC,KAAKd,EAAIY,aAElC,OADAJ,EAAqBT,IAAIC,EAAKW,GACvBA,CACP,CAEeI,SAAAA,EAAa3C,GAC5B,OAAO4C,EAAQ,IAAMnC,EAAUT,GAAQ,GACvC,CAEK,SAAA6C,EAAyBC,GAC9B,MAAMC,EAAWC,EAAOF,GAExB,OADAC,EAASd,QAAUa,EACZF,EAAQ,IAAMK,EAAY,IAAMF,EAASd,WAAY,GAC5D,QAAAY,iBAAAF"}
@@ -0,0 +1 @@
1
+ import r,{__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as n,useMemo as t,useRef as e}from"react";import{Signal as a,signal as i,computed as o}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";var u,c=r.createElement;r.createElement=function(r,n){if("string"==typeof r&&n)for(var t in n){var e=n[t];"children"!==t&&e instanceof a&&(n[t]=e.value)}return c.apply(this,arguments)};var f=new WeakMap;function v(r){u&&u(!0,!0),u=r&&r._()}function p(r){var n=i(void 0);return n._c=!0,n._u=r,n}var s=c("a").$$typeof;Object.defineProperties(a.prototype,{$$typeof:{value:s},type:{value:function(r){return r.data.value}},props:{get:function(){return{data:this}}},ref:{value:null}});var l,g=!1,d=function(){return{}};Object.defineProperty(n.ReactCurrentDispatcher,"current",{get:function(){return l},set:function(r){if(l=r,!g)if(r&&!h(r)){g=!0;var t=r.useReducer(d,{})[1];g=!1;var e=n.ReactCurrentOwner.current,a=f.get(e);a||(a=p(t),f.set(e,a)),v(a)}else v()}});var m=new Map;function h(r){var n=m.get(r);if(void 0!==n)return n;var t=r.useCallback.length<2||/warnInvalidHookAccess/.test(r.useCallback);return m.set(r,t),t}function b(r){return t(function(){return i(r)},[])}function w(r){var n=e(r);return n.current=r,t(function(){return o(function(){return n.current()})},[])}export{w as useComputed,b as useSignal};//# sourceMappingURL=signals.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.module.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\t// @ts-ignore-next-line\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as internals,\n} from \"react\";\nimport React from \"react\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport { Updater, ReactOwner, ReactDispatcher } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\n/**\n * Install a middleware into React.createElement to replace any Signals in props with their value.\n * @todo this likely needs to be duplicated for jsx()...\n */\nconst createElement = React.createElement;\n// @ts-ignore-next-line\nReact.createElement = function (type, props) {\n\tif (typeof type === \"string\" && props) {\n\t\tfor (let i in props) {\n\t\t\tlet v = props[i];\n\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t// createPropUpdater(props, i, v);\n\t\t\t\tprops[i] = v.value;\n\t\t\t}\n\t\t}\n\t}\n\t// @ts-ignore-next-line\n\treturn createElement.apply(this, arguments);\n};\n\n/*\n// This breaks React's controlled components implementation\nfunction createPropUpdater(props: any, prop: string, signal: Signal) {\n\tlet ref = props.ref;\n\tif (!ref) ref = props.ref = React.createRef();\n\teffect(() => {\n\t\tif (props) props[prop] = signal.value;\n\t\tlet el = ref.current;\n\t\tif (!el) return; // unsubscribe\n\t\t(el as any)[prop] = signal.value;\n\t});\n\tprops = null;\n}\n*/\n\nlet finishUpdate: ReturnType<Updater[\"_setCurrent\"]> | undefined;\nconst updaterForComponent = new WeakMap<ReactOwner, 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\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/**\n * A wrapper component that renders a Signal's value directly as a Text node.\n */\nfunction Text({ data }: { data: Signal }) {\n\treturn data.value;\n}\n\n// Decorate Signals so React renders them as <Text> components.\n//@ts-ignore-next-line\nconst $$typeof = createElement(\"a\").$$typeof;\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { value: $$typeof },\n\ttype: { value: Text },\n\tprops: {\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { value: null },\n});\n\n// Track the current owner (roughly equiv to current vnode)\n// let currentOwner: ReactOwner;\n// Object.defineProperty(internals.ReactCurrentOwner, \"current\", {\n// \tget() { return currentOwner; },\n// \tset(owner) { currentOwner = owner; },\n// });\n\n// Track the current dispatcher (roughly equiv to current component impl)\nlet lock = false;\nconst UPDATE = () => ({});\nlet currentDispatcher: ReactDispatcher;\nObject.defineProperty(internals.ReactCurrentDispatcher, \"current\", {\n\tget() {\n\t\treturn currentDispatcher;\n\t},\n\tset(api) {\n\t\tcurrentDispatcher = api;\n\t\tif (lock) return;\n\t\tif (api && !isInvalidHookAccessor(api)) {\n\t\t\t// prevent re-injecting useReducer when the Dispatcher\n\t\t\t// context changes to run the reducer callback:\n\t\t\tlock = true;\n\t\t\tconst rerender = api.useReducer(UPDATE, {})[1];\n\t\t\tlock = false;\n\t\t\tconst currentOwner = internals.ReactCurrentOwner.current;\n\t\t\tlet updater = updaterForComponent.get(currentOwner);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(currentOwner, updater);\n\t\t\t}\n\t\t\tsetCurrentUpdater(updater);\n\t\t} else {\n\t\t\tsetCurrentUpdater();\n\t\t}\n\t},\n});\n\n// We inject a useReducer into every function component via CurrentDispatcher.\n// This prevents injecting into anything other than a function component render.\nconst invalidHookAccessors = new Map();\nfunction isInvalidHookAccessor(api: ReactDispatcher) {\n\tconst cached = invalidHookAccessors.get(api);\n\tif (cached !== undefined) return cached;\n\t// we only want the real implementation, not the warning ones\n\tconst invalid =\n\t\tapi.useCallback.length < 2 ||\n\t\t/warnInvalidHookAccess/.test(api.useCallback as any);\n\tinvalidHookAccessors.set(api, invalid);\n\treturn invalid;\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\treturn useMemo(() => computed<T>(() => $compute.current()), []);\n}\n"],"names":["finishUpdate","createElement","React","type","props","i","v","Signal","value","apply","this","arguments","updaterForComponent","WeakMap","setCurrentUpdater","updater","_setCurrent","createUpdater","s","signal","undefined","_canActivate","_updater","$$typeof","Object","defineProperties","prototype","_ref","data","get","ref","currentDispatcher","UPDATE","defineProperty","internals","ReactCurrentDispatcher","set","api","lock","isInvalidHookAccessor","useReducer","currentOwner","ReactCurrentOwner","current","rerender","invalidHookAccessors","Map","cached","invalid","useCallback","length","test","useSignal","useMemo","useComputed","compute","$compute","useRef","computed"],"mappings":"qPAwBA,IA+BAA,EA/BmBC,EAAGC,EAAMD,cAE5BC,EAAMD,cAAgB,SAAUE,EAAMC,GACrC,GAAoB,iBAAhBD,GAA4BC,EAC/B,IAAK,IAALC,KAAAD,EAAqB,CACpB,IAAKE,EAAGF,EAAMC,GACJ,aAANA,GAAoBC,aAAxBC,IAECH,EAAMC,GAAKC,EAAEE,MAEd,CAGF,OAAOP,EAAcQ,MAAMC,KAAMC,UACjC,EAkBD,IAAMC,EAAsB,IAA5BC,QAEA,SAASC,EAAkBC,GAEtBf,GAAcA,GAAa,GAAM,GAErCA,EAAee,GAAWA,EAAQC,GAClC,CAED,SAASC,EAAcF,GACtB,IAAMG,EAAIC,OAAOC,GAGjB,OAFAF,EAAEG,IAAe,EACjBH,EAAEI,GAAWP,EAEbG,CAAA,CAWD,IAAMK,EAAWtB,EAAc,KAAKsB,SACpCC,OAAOC,iBAAiBlB,EAAOmB,UAAW,CACzCH,SAAU,CAAEf,MAAOe,GACnBpB,KAAM,CAAEK,MATT,SAAwCmB,GACvC,OADuCA,EAAxBC,KACHpB,KACZ,GAQAJ,MAAO,CACNyB,IADM,WAEL,MAAO,CAAED,KAAMlB,KACf,GAEFoB,IAAK,CAAEtB,MAAO,QAWf,IAEIuB,KAFO,EACCC,EAAG,WAAO,MAAA,CAAP,CAAA,EAEfR,OAAOS,eAAeC,EAAUC,uBAAwB,UAAW,CAClEN,IADkE,WAEjE,QACA,EACDO,IAJkE,SAI9DC,GAEH,GADAN,EAAoBM,GAChBC,EACJ,GAAID,IAAQE,EAAsBF,GAAM,CAGvCC,GAAO,EACP,MAAiBD,EAAIG,WAAWR,EAAQ,CAAvB,GAA2B,GAC5CM,GAAO,EACP,IAAMG,EAAeP,EAAUQ,kBAAkBC,QACtC5B,EAAGH,EAAoBiB,IAAIY,GACjC1B,IACJA,EAAUE,EAAc2B,GACxBhC,EAAoBwB,IAAIK,EAAc1B,IAEvCD,EAAkBC,EAClB,MACAD,GAED,IAKF,IAAM+B,EAAuB,IAA7BC,IACA,SAASP,EAAsBF,GAC9B,IAAMU,EAASF,EAAqBhB,IAAIQ,GACxC,QAAejB,IAAX2B,EAAsB,OAAAA,EAE1B,IAAMC,EACLX,EAAIY,YAAYC,OAAS,GACzB,wBAAwBC,KAAKd,EAAIY,aAElC,OADAJ,EAAqBT,IAAIC,EAAKW,GACvBA,CACP,CAEeI,SAAAA,EAAa5C,GAC5B,OAAO6C,EAAQ,WAAA,OAAYlC,EAAIX,EAAhB,EAAwB,GACvC,CAEe8C,SAAAA,EAAeC,GAC9B,IAAMC,EAAWC,EAAOF,GAExB,OADAC,EAASb,QAAUY,EACZF,EAAQ,WAAA,OAAcK,EAAI,WAAMF,OAAAA,EAASb,SAAf,EAAlB,EAA6C,GAC5D,QAAAW,iBAAAF"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@preact/signals-react",
3
+ "version": "0.0.2",
4
+ "license": "MIT",
5
+ "description": "",
6
+ "keywords": [],
7
+ "authors": [
8
+ "The Preact Authors (https://github.com/preactjs/signals/contributors)"
9
+ ],
10
+ "repository": "preactjs/signals",
11
+ "bugs": "https://github.com/preactjs/signals/issues",
12
+ "homepage": "https://preactjs.com",
13
+ "funding": {
14
+ "type": "opencollective",
15
+ "url": "https://opencollective.com/preact"
16
+ },
17
+ "amdName": "reactSignals",
18
+ "main": "dist/signals.js",
19
+ "module": "dist/signals.module.js",
20
+ "unpkg": "dist/signals.min.js",
21
+ "types": "dist/signals.d.ts",
22
+ "source": "src/index.ts",
23
+ "exports": {
24
+ ".": {
25
+ "browser": "./dist/signals.module.js",
26
+ "umd": "./dist/signals.umd.js",
27
+ "import": "./dist/signals.mjs",
28
+ "require": "./dist/signals.js",
29
+ "types": "./dist/signals.d.ts"
30
+ }
31
+ },
32
+ "mangle": "../../mangle.json",
33
+ "dependencies": {
34
+ "@preact/signals-core": "^0.0.5"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "17.x | 18.x"
38
+ },
39
+ "devDependencies": {
40
+ "react": "^18.2.0",
41
+ "react-dom": "^18.2.0",
42
+ "@types/react": "^18.0.18",
43
+ "@types/react-dom": "^18.0.6"
44
+ },
45
+ "scripts": {}
46
+ }
package/src/index.ts ADDED
@@ -0,0 +1,153 @@
1
+ import {
2
+ useRef,
3
+ useMemo,
4
+ // @ts-ignore-next-line
5
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
+ __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as internals,
7
+ } from "react";
8
+ import React from "react";
9
+ import {
10
+ signal,
11
+ computed,
12
+ batch,
13
+ effect,
14
+ Signal,
15
+ type ReadonlySignal,
16
+ } from "@preact/signals-core";
17
+ import { Updater, ReactOwner, ReactDispatcher } from "./internal";
18
+
19
+ export { signal, computed, batch, effect, Signal, type ReadonlySignal };
20
+
21
+ /**
22
+ * Install a middleware into React.createElement to replace any Signals in props with their value.
23
+ * @todo this likely needs to be duplicated for jsx()...
24
+ */
25
+ const createElement = React.createElement;
26
+ // @ts-ignore-next-line
27
+ React.createElement = function (type, props) {
28
+ if (typeof type === "string" && props) {
29
+ for (let i in props) {
30
+ let v = props[i];
31
+ if (i !== "children" && v instanceof Signal) {
32
+ // createPropUpdater(props, i, v);
33
+ props[i] = v.value;
34
+ }
35
+ }
36
+ }
37
+ // @ts-ignore-next-line
38
+ return createElement.apply(this, arguments);
39
+ };
40
+
41
+ /*
42
+ // This breaks React's controlled components implementation
43
+ function createPropUpdater(props: any, prop: string, signal: Signal) {
44
+ let ref = props.ref;
45
+ if (!ref) ref = props.ref = React.createRef();
46
+ effect(() => {
47
+ if (props) props[prop] = signal.value;
48
+ let el = ref.current;
49
+ if (!el) return; // unsubscribe
50
+ (el as any)[prop] = signal.value;
51
+ });
52
+ props = null;
53
+ }
54
+ */
55
+
56
+ let finishUpdate: ReturnType<Updater["_setCurrent"]> | undefined;
57
+ const updaterForComponent = new WeakMap<ReactOwner, Updater>();
58
+
59
+ function setCurrentUpdater(updater?: Updater) {
60
+ // end tracking for the current update:
61
+ if (finishUpdate) finishUpdate(true, true);
62
+ // start tracking the new update:
63
+ finishUpdate = updater && updater._setCurrent();
64
+ }
65
+
66
+ function createUpdater(updater: () => void) {
67
+ const s = signal(undefined) as Updater;
68
+ s._canActivate = true;
69
+ s._updater = updater;
70
+ return s;
71
+ }
72
+
73
+ /**
74
+ * A wrapper component that renders a Signal's value directly as a Text node.
75
+ */
76
+ function Text({ data }: { data: Signal }) {
77
+ return data.value;
78
+ }
79
+
80
+ // Decorate Signals so React renders them as <Text> components.
81
+ //@ts-ignore-next-line
82
+ const $$typeof = createElement("a").$$typeof;
83
+ Object.defineProperties(Signal.prototype, {
84
+ $$typeof: { value: $$typeof },
85
+ type: { value: Text },
86
+ props: {
87
+ get() {
88
+ return { data: this };
89
+ },
90
+ },
91
+ ref: { value: null },
92
+ });
93
+
94
+ // Track the current owner (roughly equiv to current vnode)
95
+ // let currentOwner: ReactOwner;
96
+ // Object.defineProperty(internals.ReactCurrentOwner, "current", {
97
+ // get() { return currentOwner; },
98
+ // set(owner) { currentOwner = owner; },
99
+ // });
100
+
101
+ // Track the current dispatcher (roughly equiv to current component impl)
102
+ let lock = false;
103
+ const UPDATE = () => ({});
104
+ let currentDispatcher: ReactDispatcher;
105
+ Object.defineProperty(internals.ReactCurrentDispatcher, "current", {
106
+ get() {
107
+ return currentDispatcher;
108
+ },
109
+ set(api) {
110
+ currentDispatcher = api;
111
+ if (lock) return;
112
+ if (api && !isInvalidHookAccessor(api)) {
113
+ // prevent re-injecting useReducer when the Dispatcher
114
+ // context changes to run the reducer callback:
115
+ lock = true;
116
+ const rerender = api.useReducer(UPDATE, {})[1];
117
+ lock = false;
118
+ const currentOwner = internals.ReactCurrentOwner.current;
119
+ let updater = updaterForComponent.get(currentOwner);
120
+ if (!updater) {
121
+ updater = createUpdater(rerender);
122
+ updaterForComponent.set(currentOwner, updater);
123
+ }
124
+ setCurrentUpdater(updater);
125
+ } else {
126
+ setCurrentUpdater();
127
+ }
128
+ },
129
+ });
130
+
131
+ // We inject a useReducer into every function component via CurrentDispatcher.
132
+ // This prevents injecting into anything other than a function component render.
133
+ const invalidHookAccessors = new Map();
134
+ function isInvalidHookAccessor(api: ReactDispatcher) {
135
+ const cached = invalidHookAccessors.get(api);
136
+ if (cached !== undefined) return cached;
137
+ // we only want the real implementation, not the warning ones
138
+ const invalid =
139
+ api.useCallback.length < 2 ||
140
+ /warnInvalidHookAccess/.test(api.useCallback as any);
141
+ invalidHookAccessors.set(api, invalid);
142
+ return invalid;
143
+ }
144
+
145
+ export function useSignal<T>(value: T) {
146
+ return useMemo(() => signal<T>(value), []);
147
+ }
148
+
149
+ export function useComputed<T>(compute: () => T) {
150
+ const $compute = useRef(compute);
151
+ $compute.current = compute;
152
+ return useMemo(() => computed<T>(() => $compute.current()), []);
153
+ }
@@ -0,0 +1,11 @@
1
+ import { Signal } from "@preact/signals-core";
2
+
3
+ export interface ReactOwner {
4
+ _: never;
5
+ }
6
+
7
+ export interface ReactDispatcher {
8
+ useCallback(): unknown;
9
+ }
10
+
11
+ export type Updater = Signal<unknown>;
@@ -0,0 +1,18 @@
1
+ import * as core from "@preact/signals-core";
2
+ import * as adapter from "@preact/signals-react";
3
+
4
+ describe("@preact/signals-react", () => {
5
+ describe("exports", () => {
6
+ it("should re-export core", () => {
7
+ const keys = Object.keys(core);
8
+
9
+ for (let i = 0; i < keys.length; i++) {
10
+ const key = keys[i];
11
+ expect(key in adapter).to.equal(
12
+ true,
13
+ `"${key}" is not exported from react adapter`
14
+ );
15
+ }
16
+ });
17
+ });
18
+ });
@@ -0,0 +1,162 @@
1
+ // @ts-ignore-next-line
2
+ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
3
+
4
+ import { signal, useComputed } from "@preact/signals-react";
5
+ import { createElement as h, useMemo } from "react";
6
+ import { createRoot, Root } from "react-dom/client";
7
+ import { act } from "react-dom/test-utils";
8
+
9
+ describe("@preact/signals-react", () => {
10
+ let scratch: HTMLDivElement;
11
+ let root: Root;
12
+ function render(element: Parameters<Root["render"]>[0]) {
13
+ act(() => root.render(element));
14
+ }
15
+
16
+ beforeEach(() => {
17
+ scratch = document.createElement("div");
18
+ root = createRoot(scratch);
19
+ });
20
+
21
+ afterEach(() => {
22
+ act(() => root.unmount());
23
+ });
24
+
25
+ describe("Text bindings", () => {
26
+ it("should render text without signals", () => {
27
+ render(h("span", null, "test"));
28
+ const span = scratch.firstChild;
29
+ const text = span?.firstChild;
30
+ expect(text).to.have.property("data", "test");
31
+ });
32
+
33
+ it("should render Signals as Text", () => {
34
+ const sig = signal("test");
35
+ render(h("span", null, sig));
36
+ const span = scratch.firstChild;
37
+ expect(span).to.have.property("firstChild").that.is.an.instanceOf(Text);
38
+ const text = span?.firstChild;
39
+ expect(text).to.have.property("data", "test");
40
+ });
41
+
42
+ it("should update Signal-based Text (no parent component)", () => {
43
+ const sig = signal("test");
44
+ render(h("span", null, sig));
45
+
46
+ const text = scratch.firstChild!.firstChild!;
47
+ expect(text).to.have.property("data", "test");
48
+
49
+ act(() => {
50
+ sig.value = "changed";
51
+ });
52
+
53
+ // should not remount/replace Text
54
+ expect(scratch.firstChild!.firstChild!).to.equal(text);
55
+ // should update the text in-place
56
+ expect(text).to.have.property("data", "changed");
57
+ });
58
+
59
+ it("should update Signal-based Text (in a parent component)", () => {
60
+ const sig = signal("test");
61
+ function App({ x }: { x: typeof sig }) {
62
+ return h("span", null, x);
63
+ }
64
+ render(h(App, { x: sig }));
65
+
66
+ const text = scratch.firstChild!.firstChild!;
67
+ expect(text).to.have.property("data", "test");
68
+
69
+ act(() => {
70
+ sig.value = "changed";
71
+ });
72
+
73
+ // should not remount/replace Text
74
+ expect(scratch.firstChild!.firstChild!).to.equal(text);
75
+ // should update the text in-place
76
+ expect(text).to.have.property("data", "changed");
77
+ });
78
+ });
79
+
80
+ describe("Component bindings", () => {
81
+ it("should subscribe to signals", () => {
82
+ const sig = signal("foo");
83
+
84
+ function App() {
85
+ const value = sig.value;
86
+ return h("p", null, value);
87
+ }
88
+
89
+ render(h(App, {}));
90
+ expect(scratch.textContent).to.equal("foo");
91
+
92
+ act(() => {
93
+ sig.value = "bar";
94
+ });
95
+ expect(scratch.textContent).to.equal("bar");
96
+ });
97
+
98
+ it("should activate signal accessed in render", () => {
99
+ const sig = signal(null);
100
+
101
+ function App() {
102
+ const arr = useComputed(() => {
103
+ // trigger read
104
+ sig.value;
105
+
106
+ return [];
107
+ });
108
+
109
+ const str = arr.value.join(", ");
110
+ return h("p", null, str);
111
+ }
112
+
113
+ const fn = () => render(h(App, {}));
114
+ expect(fn).not.to.throw;
115
+ });
116
+
117
+ it("should not subscribe to child signals", () => {
118
+ const sig = signal("foo");
119
+
120
+ function Child() {
121
+ const value = sig.value;
122
+ return h("p", null, value);
123
+ }
124
+
125
+ const spy = sinon.spy();
126
+ function App() {
127
+ spy();
128
+ return h(Child, null);
129
+ }
130
+
131
+ render(h(App, {}));
132
+ expect(scratch.textContent).to.equal("foo");
133
+
134
+ act(() => {
135
+ sig.value = "bar";
136
+ });
137
+ expect(spy).to.be.calledOnce;
138
+ });
139
+
140
+ it("should update memo'ed component via signals", async () => {
141
+ const sig = signal("foo");
142
+
143
+ function Inner() {
144
+ const value = sig.value;
145
+ return h("p", null, value);
146
+ }
147
+
148
+ function App() {
149
+ sig.value;
150
+ return useMemo(() => h(Inner, { foo: 1 }), []);
151
+ }
152
+
153
+ render(h(App, {}));
154
+ expect(scratch.textContent).to.equal("foo");
155
+
156
+ act(() => {
157
+ sig.value = "bar";
158
+ });
159
+ expect(scratch.textContent).to.equal("bar");
160
+ });
161
+ });
162
+ });