@preact/signals-react 1.1.1 → 1.2.1
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 +19 -0
- package/dist/signals.js +1 -1
- package/dist/signals.js.map +1 -1
- package/dist/signals.min.js +1 -1
- package/dist/signals.min.js.map +1 -1
- package/dist/signals.mjs +1 -1
- package/dist/signals.mjs.map +1 -1
- package/dist/signals.module.js +1 -1
- package/dist/signals.module.js.map +1 -1
- package/package.json +7 -5
- package/src/index.ts +171 -97
- package/src/internal.d.ts +6 -4
- package/test/index.test.tsx +42 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @preact/signals-react
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#238](https://github.com/preactjs/signals/pull/238) [`bcf4b0b`](https://github.com/preactjs/signals/commit/bcf4b0b25d774483ddafa29c2fa133c467668b8c) Thanks [@eddyw](https://github.com/eddyw)! - Fix ERR_UNSUPPORTED_DIR_IMPORT error when importing `use-sync-external-store/shim` from ESM build
|
|
8
|
+
|
|
9
|
+
## 1.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#219](https://github.com/preactjs/signals/pull/219) [`0621526`](https://github.com/preactjs/signals/commit/0621526dd59187f674557e6df42c71980b32efab) Thanks [@eddyw](https://github.com/eddyw)! - Replace useReducer with useSyncExternalStore
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#226](https://github.com/preactjs/signals/pull/226) [`ad29826`](https://github.com/preactjs/signals/commit/ad2982606a8894ea8562a0726d7777185987ad60) Thanks [@marvinhagemeister](https://github.com/marvinhagemeister)! - Fix hook names being mangled
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [[`aa4cb7b`](https://github.com/preactjs/signals/commit/aa4cb7bfad744e78952cacc37af5bd4a713f0d3f), [`3f652a7`](https://github.com/preactjs/signals/commit/3f652a77d2a125a02a0cfc29fe661c81beeda16d)]:
|
|
20
|
+
- @preact/signals-core@1.2.2
|
|
21
|
+
|
|
3
22
|
## 1.1.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/signals.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var r=require("react"),n=require("@preact/signals-core");function
|
|
1
|
+
var r=require("react"),n=require("react/jsx-runtime"),t=require("react/jsx-dev-runtime"),e=require("use-sync-external-store/shim/index.js"),u=require("@preact/signals-core");function o(r){return r&&"object"==typeof r&&"default"in r?r.default:r}var i=/*#__PURE__*/o(r),f=/*#__PURE__*/o(n),c=/*#__PURE__*/o(t),a=[],s=Symbol.for("react.element"),p=Symbol.for("react.memo"),l=new Map,v="function"==typeof Proxy,y={apply:function(n,t,u){var o=r.useMemo(b,a);e.useSyncExternalStore(o.subscribe,o.getSnapshot,o.getSnapshot);var i=o.updater.S();try{return n.apply(t,u)}catch(r){throw r}finally{i()}}};function x(r){return l.get(r)||function(r){if(v){var n=new Proxy(r,y);l.set(r,n);l.set(n,n);return n}var t=function(){return y.apply(r,void 0,arguments)};l.set(r,t);l.set(t,t);return t}(r)}function b(){var r,n,t=0,e=u.effect(function(){r=this});r.c=function(){t=t+1|0;if(n)n()};return{updater:r,subscribe:function(r){n=r;return function(){t=t+1|0;n=void 0;e()}},getSnapshot:function(){return t}}}function d(n){if("function"!=typeof n)return n;else return function(t,e){var o=[].slice.call(arguments,2);if("function"==typeof t&&!(t instanceof r.Component))return n.call.apply(n,[n,x(t),e].concat(o));if(t&&"object"==typeof t&&t.$$typeof===p){t.type=x(t.type);return n.call.apply(n,[n,t,e].concat(o))}if("string"==typeof t&&e)for(var i in e){var f=e[i];if("children"!==i&&f instanceof u.Signal)e[i]=f.value}return n.call.apply(n,[n,t,e].concat(o))}}var g=f,m=c;i.createElement=d(i.createElement);m.jsx&&(m.jsx=d(m.jsx));g.jsx&&(g.jsx=d(g.jsx));m.jsxs&&(m.jsxs=d(m.jsxs));g.jsxs&&(g.jsxs=d(g.jsxs));m.jsxDEV&&(m.jsxDEV=d(m.jsxDEV));g.jsxDEV&&(g.jsxDEV=d(g.jsxDEV));Object.defineProperties(u.Signal.prototype,{$$typeof:{configurable:!0,value:s},type:{configurable:!0,value:x(function(r){return r.data.value})},props:{configurable:!0,get:function(){return{data:this}}},ref:{configurable:!0,value:null}});exports.Signal=u.Signal;exports.batch=u.batch;exports.computed=u.computed;exports.effect=u.effect;exports.signal=u.signal;exports.useComputed=function(n){var t=r.useRef(n);t.current=n;return r.useMemo(function(){return u.computed(function(){return t.current()})},a)};exports.useSignal=function(n){return r.useMemo(function(){return u.signal(n)},a)};exports.useSignalEffect=function(n){var t=r.useRef(n);t.current=n;r.useEffect(function(){return u.effect(function(){return t.current()})},a)};//# sourceMappingURL=signals.js.map
|
package/dist/signals.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\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 { Effect, 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: (() => void) | undefined;\nconst updaterForComponent = new WeakMap<() => void, Effect>();\n\nfunction setCurrentUpdater(updater?: Effect) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate();\n\t// start tracking the new update:\n\tfinishUpdate = updater && updater._start();\n}\n\nfunction createUpdater(update: () => void) {\n\tlet updater!: Effect;\n\teffect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = update;\n\treturn updater;\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: { configurable: true, value: $$typeof },\n\ttype: { configurable: true, value: Text },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\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\n\t\t\tlet updater = updaterForComponent.get(rerender);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(rerender, updater);\n\t\t\t} else {\n\t\t\t\tupdater._callback = rerender;\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 || /Invalid/.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\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, []);\n}\n"],"names":["React","require","signalsCore","_interopDefaultLegacy","e","default","React__default","createElement","type","props","i","v","Signal","value","apply","this","arguments","updaterForComponent","WeakMap","updater","finishUpdate","_start","$$typeof","Object","defineProperties","prototype","configurable","_ref","data","get","ref","currentDispatcher","lock","UPDATE","defineProperty","internals","ReactCurrentDispatcher","set","api","cached","invalidHookAccessors","undefined","invalid","useCallback","length","test","isInvalidHookAccessor","rerender","useReducer","update","effect","_callback","createUpdater","setCurrentUpdater","Map","exports","batch","computed","signal","useComputed","compute","useRef","$compute","current","useMemo","useSignal","useSignalEffect","cb","callback","useEffect"],"mappings":"AAyBA,IAAAA,EAAAC,QAAA,SAAAC,EAAAD,QAAA,wBAAA,SAAAE,EAAAC,GAAA,OAAAA,GAAA,iBAAAA,GAAA,YAAAA,EAAAA,EAAAC,QAAAD,CAAA,CAAA,MAAAE,eAAAH,EAAAH,GAAmBO,EAAGP,EAAMO,cAE5BP,EAAMO,cAAgB,SAAUC,EAAMC,GACrC,GAAoB,iBAAhBD,GAA4BC,EAC/B,IAAK,IAALC,KAAAD,EAAqB,CACpB,IAAKE,EAAGF,EAAMC,GACd,GAAU,aAANA,GAAoBC,aAAaC,EAAAA,OAEpCH,EAAMC,GAAKC,EAAEE,KAEd,CAGF,OAAON,EAAcO,MAAMC,KAAMC,UACjC,EAkBD,IAAyBC,EAAG,IAAIC,QAEhC,WAA2BC,GAE1B,GAAIC,EAAcA,IAElBA,EAAeD,GAAWA,EAAQE,GAClC,CAoBD,IAAcC,EAAGf,EAAc,KAAKe,SACpCC,OAAOC,iBAAiBZ,SAAOa,UAAW,CACzCH,SAAU,CAAEI,cAAc,EAAMb,MAAOS,GACvCd,KAAM,CAAEkB,cAAc,EAAMb,MAT7B,SAAAc,GACC,OADeC,EAAAA,KACHf,KACZ,GAQAJ,MAAO,CACNiB,cAAc,EACdG,IAAG,WACF,MAAO,CAAED,KAAMb,KACf,GAEFe,IAAK,CAAEJ,cAAc,EAAMb,MAAO,QAInC,IAEIkB,EAFAC,GAAO,EACLC,EAAS,WAAA,MAAO,CAAP,CAAA,EAEfV,OAAOW,eAAeC,EAAAA,mDAAUC,uBAAwB,UAAW,CAClEP,IADkE,WAEjE,OAAOE,CACP,EACDM,IAJkE,SAI9DC,GACHP,EAAoBO,EACpB,IAAIN,EACJ,GAAIM,IAwBN,SAA+BA,GAC9B,IAAYC,EAAGC,EAAqBX,IAAIS,GACxC,QAAeG,IAAXF,EAAsB,OAAAA,EAE1B,IAAMG,EACLJ,EAAIK,YAAYC,OAAS,GAAK,UAAUC,KAAKP,EAAIK,aAClDH,EAAqBH,IAAIC,EAAKI,GAC9B,OACAA,CAAA,CAhCaI,CAAsBR,GAAM,CAGvCN,GAAO,EACP,IAAMe,EAAWT,EAAIU,WAAWf,EAAQ,CAAA,GAAI,GAC5CD,GAAO,EAEP,IAAIb,EAAUF,EAAoBY,IAAIkB,GACtC,IAAK5B,EAAS,CACbA,EAnDJ,SAAuB8B,GACtB,MACAC,EAAAA,OAAO,WACN/B,EAAUJ,IACV,GACDI,EAAQgC,EAAYF,EACpB,OAAO9B,CACP,CA4CaiC,CAAcL,GACxB9B,EAAoBoB,IAAIU,EAAU5B,EAClC,MACAA,EAAQgC,EAAYJ,EAErBM,EAAkBlC,EAClB,MACAkC,GAED,IAKF,MAA6B,IAA7BC,IA8BCC,QAAA3C,OAAAV,EAAAU,OAAA2C,QAAAC,MAAAtD,EAAAsD,MAAAD,QAAAE,SAAAvD,EAAAuD,SAAAF,QAAAL,OAAAhD,EAAAgD,OAAAK,QAAAG,OAAAxD,EAAAwD,OAAAH,QAAAI,YAfK,SAAyBC,GAC9B,MAAiBC,EAAAA,OAAOD,GACxBE,EAASC,QAAUH,EACnB,OAAOI,EAAOA,QAAC,WAAA,kBAAkB,WAAA,OAAcF,EAACC,SAAf,EAAlB,EAA6C,GAC5D,EAWAR,QAAAU,UAnBK,SAAuBpD,GAC5B,OAAcmD,EAAAA,QAAC,kBAAYN,EAAAA,OAAI7C,EAAhB,EAAwB,GACvC,EAiBA0C,QAAAW,gBATK,SAA0BC,GAC/B,IAAMC,EAAWP,EAAMA,OAACM,GACxBC,EAASL,QAAUI,EAEnBE,EAAAA,UAAU,WACT,OAAanB,EAAAA,OAAC,WACb,OAAekB,EAACL,SAChB,EACD,EAAE,GACH"}
|
|
1
|
+
{"version":3,"file":"signals.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\n\tComponent,\n\ttype FunctionComponent,\n} from \"react\";\nimport React from \"react\";\nimport jsxRuntime from \"react/jsx-runtime\";\nimport jsxRuntimeDev from \"react/jsx-dev-runtime\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport type { Effect, JsxRuntimeModule } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\nconst Empty = [] as const;\nconst ReactElemType = Symbol.for(\"react.element\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L15\nconst ReactMemoType = Symbol.for(\"react.memo\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L30\nconst ProxyInstance = new Map<FunctionComponent<any>, FunctionComponent<any>>();\nconst SupportsProxy = typeof Proxy === \"function\";\n\nconst ProxyHandlers = {\n\t/**\n\t * This is a function call trap for functional components.\n\t * When this is called, we know it means React did run 'Component()',\n\t * that means we can use any hooks here to setup our effect and store.\n\t *\n\t * With the native Proxy, all other calls such as access/setting to/of properties will\n\t * be forwarded to the target Component, so we don't need to copy the Component's\n\t * own or inherited properties.\n\t *\n\t * @see https://github.com/facebook/react/blob/2d80a0cd690bb5650b6c8a6c079a87b5dc42bd15/packages/react-reconciler/src/ReactFiberHooks.old.js#L460\n\t */\n\tapply(Component: FunctionComponent, thisArg: any, argumentsList: any) {\n\t\tconst store = useMemo(createEffectStore, Empty);\n\n\t\tuseSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n\n\t\tconst stop = store.updater._start();\n\n\t\ttry {\n\t\t\tconst children = Component.apply(thisArg, argumentsList);\n\t\t\treturn children;\n\t\t} catch (e) {\n\t\t\t// Re-throwing promises that'll be handled by suspense\n\t\t\t// or an actual error.\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\t// Stop effects in either case before return or throw,\n\t\t\t// Otherwise the effect will leak.\n\t\t\tstop();\n\t\t}\n\t},\n};\n\nfunction ProxyFunctionalComponent(Component: FunctionComponent<any>) {\n\treturn ProxyInstance.get(Component) || WrapWithProxy(Component);\n}\nfunction WrapWithProxy(Component: FunctionComponent<any>) {\n\tif (SupportsProxy) {\n\t\tconst ProxyComponent = new Proxy(Component, ProxyHandlers);\n\n\t\tProxyInstance.set(Component, ProxyComponent);\n\t\tProxyInstance.set(ProxyComponent, ProxyComponent);\n\n\t\treturn ProxyComponent;\n\t}\n\n\t/**\n\t * Emulate a Proxy if environment doesn't support it.\n\t *\n\t * @TODO - unlike Proxy, it's not possible to access the type/Component's\n\t * static properties this way. Not sure if we want to copy all statics here.\n\t * Omitting this for now.\n\t *\n\t * @example - works with Proxy, doesn't with wrapped function.\n\t * ```\n\t * const el = <SomeFunctionalComponent />\n\t * el.type.someOwnOrInheritedProperty;\n\t * el.type.defaultProps;\n\t * ```\n\t */\n\tconst WrappedComponent = function () {\n\t\treturn ProxyHandlers.apply(Component, undefined, arguments);\n\t};\n\tProxyInstance.set(Component, WrappedComponent);\n\tProxyInstance.set(WrappedComponent, WrappedComponent);\n\n\treturn WrappedComponent;\n}\n\n/**\n * A redux-like store whose store value is a positive 32bit integer (a 'version').\n *\n * React subscribes to this store and gets a snapshot of the current 'version',\n * whenever the 'version' changes, we tell React it's time to update the component (call 'onStoreChange').\n *\n * How we achieve this is by creating a binding with an 'effect', when the `effect._callback' is called,\n * we update our store version and tell React to re-render the component ([1] We don't really care when/how React does it).\n *\n * [1]\n * @see https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore\n * @see https://github.com/reactjs/rfcs/blob/main/text/0214-use-sync-external-store.md\n */\nfunction createEffectStore() {\n\tlet updater!: Effect;\n\tlet version = 0;\n\tlet onChangeNotifyReact: (() => void) | undefined;\n\n\tlet unsubscribe = effect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = function () {\n\t\tversion = (version + 1) | 0;\n\t\tif (onChangeNotifyReact) onChangeNotifyReact();\n\t};\n\n\treturn {\n\t\tupdater,\n\t\tsubscribe(onStoreChange: () => void) {\n\t\t\tonChangeNotifyReact = onStoreChange;\n\n\t\t\treturn function () {\n\t\t\t\t/**\n\t\t\t\t * Rotate to next version when unsubscribing to ensure that components are re-run\n\t\t\t\t * when subscribing again.\n\t\t\t\t *\n\t\t\t\t * In StrictMode, 'memo'-ed components seem to keep a stale snapshot version, so\n\t\t\t\t * don't re-run after subscribing again if the version is the same as last time.\n\t\t\t\t *\n\t\t\t\t * Because we unsubscribe from the effect, the version may not change. We simply\n\t\t\t\t * set a new initial version in case of stale snapshots here.\n\t\t\t\t */\n\t\t\t\tversion = (version + 1) | 0;\n\t\t\t\tonChangeNotifyReact = undefined;\n\t\t\t\tunsubscribe();\n\t\t\t};\n\t\t},\n\t\tgetSnapshot() {\n\t\t\treturn version;\n\t\t},\n\t};\n}\n\nfunction WrapJsx<T>(jsx: T): T {\n\tif (typeof jsx !== \"function\") return jsx;\n\n\treturn function (type: any, props: any, ...rest: any[]) {\n\t\tif (typeof type === \"function\" && !(type instanceof Component)) {\n\t\t\treturn jsx.call(jsx, ProxyFunctionalComponent(type), props, ...rest);\n\t\t}\n\n\t\tif (type && typeof type === \"object\" && type.$$typeof === ReactMemoType) {\n\t\t\ttype.type = ProxyFunctionalComponent(type.type);\n\t\t\treturn jsx.call(jsx, type, props, ...rest);\n\t\t}\n\n\t\tif (typeof type === \"string\" && props) {\n\t\t\tfor (let i in props) {\n\t\t\t\tlet v = props[i];\n\t\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t\tprops[i] = v.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jsx.call(jsx, type, props, ...rest);\n\t} as any as T;\n}\n\nconst JsxPro: JsxRuntimeModule = jsxRuntime;\nconst JsxDev: JsxRuntimeModule = jsxRuntimeDev;\n\n/**\n * createElement _may_ be called by jsx runtime as a fallback in certain cases,\n * so we need to wrap it regardless.\n *\n * The jsx exports depend on the `NODE_ENV` var to ensure the users' bundler doesn't\n * include both, so one of them will be set with `undefined` values.\n */\nReact.createElement = WrapJsx(React.createElement);\nJsxDev.jsx && /* */ (JsxDev.jsx = WrapJsx(JsxDev.jsx));\nJsxPro.jsx && /* */ (JsxPro.jsx = WrapJsx(JsxPro.jsx));\nJsxDev.jsxs && /* */ (JsxDev.jsxs = WrapJsx(JsxDev.jsxs));\nJsxPro.jsxs && /* */ (JsxPro.jsxs = WrapJsx(JsxPro.jsxs));\nJsxDev.jsxDEV && /**/ (JsxDev.jsxDEV = WrapJsx(JsxDev.jsxDEV));\nJsxPro.jsxDEV && /**/ (JsxPro.jsxDEV = WrapJsx(JsxPro.jsxDEV));\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.\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { configurable: true, value: ReactElemType },\n\ttype: { configurable: true, value: ProxyFunctionalComponent(Text) },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\n});\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), Empty);\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()), Empty);\n}\n\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, Empty);\n}\n"],"names":["Empty","Symbol","ReactMemoType","ProxyInstance","Map","SupportsProxy","Proxy","apply","Component","thisArg","argumentsList","useMemo","createEffectStore","useSyncExternalStore","store","subscribe","getSnapshot","updater","_start","e","stop","ProxyFunctionalComponent","get","ProxyComponent","ProxyHandlers","set","WrappedComponent","undefined","arguments","WrapWithProxy","onChangeNotifyReact","version","unsubscribe","effect","this","_callback","onStoreChange","WrapJsx","jsx","type","props","slice","call","rest","$$typeof","i","v","Signal","value","concat","JsxPro","jsxRuntime","JsxDev","jsxRuntimeDev","React","createElement","jsxs","jsxDEV","Object","defineProperties","prototype","configurable","ReactElemType","_ref","data","ref","exports","signalsCore","batch","computed","signal","useComputed","compute","$compute","useRef","current","useSignal","useSignalEffect","cb","callback","useEffect"],"mappings":"oTAuBWA,EAAG,KACQC,WAAW,iBACdC,EAAGD,OAAM,IAAK,cAC3BE,EAAgB,IAAIC,IACPC,EAAoB,mBAAjBC,QAEA,CAYrBC,MAZqB,SAYfC,EAA8BC,EAAcC,GACjD,MAAcC,EAAAA,QAAQC,EAAmBZ,GAEzCa,EAAoBA,qBAACC,EAAMC,UAAWD,EAAME,YAAaF,EAAME,aAE/D,MAAaF,EAAMG,QAAQC,IAE3B,IAEC,OADiBV,EAAUD,MAAME,EAASC,EAU1C,CARC,MAAOS,GAGR,MAAMA,CACN,CAPD,QAUCC,GACA,CACD,GAGF,SAASC,EAAyBb,GACjC,SAAqBc,IAAId,IAE1B,SAAuBA,GACtB,GAAIH,EAAe,CAClB,IAAMkB,EAAiB,IAAIjB,MAAME,EAAWgB,GAE5CrB,EAAcsB,IAAIjB,EAAWe,GAC7BpB,EAAcsB,IAAIF,EAAgBA,GAElC,OACAA,CAAA,CAgBD,IAAsBG,EAAG,WACxB,OAAoBF,EAACjB,MAAMC,OAAWmB,EAAWC,UACjD,EACDzB,EAAcsB,IAAIjB,EAAWkB,GAC7BvB,EAAcsB,IAAIC,EAAkBA,GAEpC,OAAOA,CACP,CAjCuCG,CAAcrB,EACrD,CA+CD,SAASI,IACR,IAAAK,EAEAa,EADIC,EAAU,EAGCC,EAAGC,SAAO,WACxBhB,EAAUiB,IACV,GACDjB,EAAQkB,EAAY,WACnBJ,EAAWA,EAAU,EAAK,EAC1B,GAAID,EAAqBA,GACzB,EAED,MAAO,CACNb,QAAAA,EACAF,UAAUqB,SAAAA,GACTN,EAAsBM,EAEtB,OAAO,WAWNL,EAAWA,EAAU,EAAK,EAC1BD,OAAsBH,EACtBK,GACA,CACD,EACDhB,YArBM,WAsBL,OAAOe,CACP,EAEF,CAED,SAAAM,EAAoBC,GACnB,GAAmB,mBAARA,EAAoB,OAAAA,OAE/B,OAAO,SAAUC,EAAWC,GAA0B,MACrD,GAAAC,MAAAC,KAAAd,UAAA,GAAA,GAAoB,mBAAhBW,KAAgCA,aAAF/B,EAAAA,WACjC,SAAWkC,KAAJJ,MAAAA,EAASA,CAAAA,EAAKjB,EAAyBkB,GAAOC,GAAUG,OAAAA,IAGhE,GAAIJ,GAAwB,oBAAYA,EAAKK,WAAa1C,EAAe,CACxEqC,EAAKA,KAAOlB,EAAyBkB,EAAKA,MAC1C,SAAWG,WAAJJ,EAAG,CAAMA,EAAKC,EAAMC,GAAUG,OAAAA,GACrC,CAED,GAAoB,iBAAhBJ,GAA4BC,EAC/B,IAAK,IAALK,OAAqB,CACpB,IAAKC,EAAGN,EAAMK,GACd,GAAU,aAANA,GAAoBC,aAAaC,EAAAA,OACpCP,EAAMK,GAAKC,EAAEE,KAEd,CAGF,OAAOV,EAAII,WAAJJ,EAAG,CAAMA,EAAKC,EAAMC,GAAjBS,OAA2BN,GACzB,CACb,CAED,IAAMO,EAA2BC,EACrBC,EAAqBC,EASjCC,EAAMC,cAAgBlB,EAAQiB,EAAMC,eACpCH,EAAOd,MAAgBc,EAAOd,IAAMD,EAAQe,EAAOd,MACnDY,EAAOZ,MAAgBY,EAAOZ,IAAMD,EAAQa,EAAOZ,MACnDc,EAAOI,OAAgBJ,EAAOI,KAAOnB,EAAQe,EAAOI,OACpDN,EAAOM,OAAgBN,EAAOM,KAAOnB,EAAQa,EAAOM,OACpDJ,EAAOK,SAAgBL,EAAOK,OAASpB,EAAQe,EAAOK,SACtDP,EAAOO,SAAgBP,EAAOO,OAASpB,EAAQa,EAAOO,SAUtDC,OAAOC,iBAAiBZ,EAAAA,OAAOa,UAAW,CACzChB,SAAU,CAAEiB,cAAc,EAAMb,MAAOc,GACvCvB,KAAM,CAAEsB,cAAc,EAAMb,MAAO3B,EAPpC,SAAA0C,GACC,OADuCA,EAAxBC,KACHhB,KACZ,IAMAR,MAAO,CACNqB,cAAc,EACdvC,eACC,MAAO,CAAE0C,KAAM9B,KACf,GAEF+B,IAAK,CAAEJ,cAAc,EAAMb,MAAO,QAsBlCkB,QAAAnB,OAAAoB,EAAApB,OAAAmB,QAAAE,MAAAD,EAAAC,MAAAF,QAAAG,SAAAF,EAAAE,SAAAH,QAAAjC,OAAAkC,EAAAlC,OAAAiC,QAAAI,OAAAH,EAAAG,OAAAJ,QAAAK,YAfK,SAAyBC,GAC9B,IAAcC,EAAGC,EAAMA,OAACF,GACxBC,EAASE,QAAUH,EACnB,OAAO7D,UAAQ,WAAM0D,OAAAA,EAAAA,SAAY,WAAA,OAAcI,EAACE,SAAf,EAAlB,EAA6C3E,EAC5D,EAWAkE,QAAAU,UAnBK,SAAuB5B,GAC5B,SAAcrC,QAAC,WAAA,gBAAgBqC,EAAhB,EAAwBhD,EACvC,EAiBAkE,QAAAW,gBATeA,SAAgBC,GAC/B,IAAMC,EAAWL,EAAMA,OAACI,GACxBC,EAASJ,QAAUG,EAEnBE,EAAAA,UAAU,WACT,OAAO/C,EAAAA,OAAO,WACb,OAAO8C,EAASJ,SAChB,EACD,EAAE3E,EACH"}
|
package/dist/signals.min.js
CHANGED
|
@@ -1 +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
|
|
1
|
+
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("react/jsx-runtime"),require("react/jsx-dev-runtime"),require("use-sync-external-store/shim/index.js"),require("@preact/signals-core")):"function"==typeof define&&define.amd?define(["exports","react","react/jsx-runtime","react/jsx-dev-runtime","use-sync-external-store/shim/index.js","@preact/signals-core"],e):e((n||self).reactSignals={},n.react,n.jsxRuntime,n.jsxRuntimeDev,n.index_js,n.signalsCore)}(this,function(n,e,r,t,u,i){function o(n){return n&&"object"==typeof n&&"default"in n?n.default:n}var f=/*#__PURE__*/o(e),c=/*#__PURE__*/o(r),a=/*#__PURE__*/o(t),s=[],l=Symbol.for("react.element"),p=Symbol.for("react.memo"),y=new Map,v="function"==typeof Proxy,d={apply:function(n,r,t){var i=e.useMemo(x,s);u.useSyncExternalStore(i.subscribe,i.getSnapshot,i.getSnapshot);var o=i.updater.S();try{return n.apply(r,t)}catch(n){throw n}finally{o()}}};function b(n){return y.get(n)||function(n){if(v){var e=new Proxy(n,d);y.set(n,e);y.set(e,e);return e}var r=function(){return d.apply(n,void 0,arguments)};y.set(n,r);y.set(r,r);return r}(n)}function x(){var n,e,r=0,t=i.effect(function(){n=this});n.c=function(){r=r+1|0;if(e)e()};return{updater:n,subscribe:function(n){e=n;return function(){r=r+1|0;e=void 0;t()}},getSnapshot:function(){return r}}}function m(n){if("function"!=typeof n)return n;else return function(r,t){var u=[].slice.call(arguments,2);if("function"==typeof r&&!(r instanceof e.Component))return n.call.apply(n,[n,b(r),t].concat(u));if(r&&"object"==typeof r&&r.$$typeof===p){r.type=b(r.type);return n.call.apply(n,[n,r,t].concat(u))}if("string"==typeof r&&t)for(var o in t){var f=t[o];if("children"!==o&&f instanceof i.Signal)t[o]=f.value}return n.call.apply(n,[n,r,t].concat(u))}}var g=c,h=a;f.createElement=m(f.createElement);h.jsx&&(h.jsx=m(h.jsx));g.jsx&&(g.jsx=m(g.jsx));h.jsxs&&(h.jsxs=m(h.jsxs));g.jsxs&&(g.jsxs=m(g.jsxs));h.jsxDEV&&(h.jsxDEV=m(h.jsxDEV));g.jsxDEV&&(g.jsxDEV=m(g.jsxDEV));Object.defineProperties(i.Signal.prototype,{$$typeof:{configurable:!0,value:l},type:{configurable:!0,value:b(function(n){return n.data.value})},props:{configurable:!0,get:function(){return{data:this}}},ref:{configurable:!0,value:null}});n.Signal=i.Signal;n.batch=i.batch;n.computed=i.computed;n.effect=i.effect;n.signal=i.signal;n.useComputed=function(n){var r=e.useRef(n);r.current=n;return e.useMemo(function(){return i.computed(function(){return r.current()})},s)};n.useSignal=function(n){return e.useMemo(function(){return i.signal(n)},s)};n.useSignalEffect=function(n){var r=e.useRef(n);r.current=n;e.useEffect(function(){return i.effect(function(){return r.current()})},s)}});//# sourceMappingURL=signals.min.js.map
|
package/dist/signals.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.min.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\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 { Effect, 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: (() => void) | undefined;\nconst updaterForComponent = new WeakMap<() => void, Effect>();\n\nfunction setCurrentUpdater(updater?: Effect) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate();\n\t// start tracking the new update:\n\tfinishUpdate = updater && updater._start();\n}\n\nfunction createUpdater(update: () => void) {\n\tlet updater!: Effect;\n\teffect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = update;\n\treturn updater;\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: { configurable: true, value: $$typeof },\n\ttype: { configurable: true, value: Text },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\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\n\t\t\tlet updater = updaterForComponent.get(rerender);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(rerender, updater);\n\t\t\t} else {\n\t\t\t\tupdater._callback = rerender;\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 || /Invalid/.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\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, []);\n}\n"],"names":["g","f","exports","module","require","define","amd","globalThis","self","reactSignals","react","signalsCore","this","React","_interopDefaultLegacy","e","default","React__default","createElement","type","props","i","v","Signal","value","apply","arguments","updaterForComponent","WeakMap","updater","finishUpdate","_start","$$typeof","Object","defineProperties","prototype","configurable","_ref","data","get","ref","currentDispatcher","lock","UPDATE","defineProperty","internals","ReactCurrentDispatcher","set","api","cached","invalidHookAccessors","undefined","invalid","useCallback","length","test","isInvalidHookAccessor","rerender","useReducer","update","effect","_callback","createUpdater","setCurrentUpdater","Map","batch","computed","signal","useComputed","compute","useRef","$compute","current","useMemo","useSignal","useSignalEffect","cb","callback","useEffect"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"signals.min.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\n\tComponent,\n\ttype FunctionComponent,\n} from \"react\";\nimport React from \"react\";\nimport jsxRuntime from \"react/jsx-runtime\";\nimport jsxRuntimeDev from \"react/jsx-dev-runtime\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport type { Effect, JsxRuntimeModule } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\nconst Empty = [] as const;\nconst ReactElemType = Symbol.for(\"react.element\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L15\nconst ReactMemoType = Symbol.for(\"react.memo\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L30\nconst ProxyInstance = new Map<FunctionComponent<any>, FunctionComponent<any>>();\nconst SupportsProxy = typeof Proxy === \"function\";\n\nconst ProxyHandlers = {\n\t/**\n\t * This is a function call trap for functional components.\n\t * When this is called, we know it means React did run 'Component()',\n\t * that means we can use any hooks here to setup our effect and store.\n\t *\n\t * With the native Proxy, all other calls such as access/setting to/of properties will\n\t * be forwarded to the target Component, so we don't need to copy the Component's\n\t * own or inherited properties.\n\t *\n\t * @see https://github.com/facebook/react/blob/2d80a0cd690bb5650b6c8a6c079a87b5dc42bd15/packages/react-reconciler/src/ReactFiberHooks.old.js#L460\n\t */\n\tapply(Component: FunctionComponent, thisArg: any, argumentsList: any) {\n\t\tconst store = useMemo(createEffectStore, Empty);\n\n\t\tuseSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n\n\t\tconst stop = store.updater._start();\n\n\t\ttry {\n\t\t\tconst children = Component.apply(thisArg, argumentsList);\n\t\t\treturn children;\n\t\t} catch (e) {\n\t\t\t// Re-throwing promises that'll be handled by suspense\n\t\t\t// or an actual error.\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\t// Stop effects in either case before return or throw,\n\t\t\t// Otherwise the effect will leak.\n\t\t\tstop();\n\t\t}\n\t},\n};\n\nfunction ProxyFunctionalComponent(Component: FunctionComponent<any>) {\n\treturn ProxyInstance.get(Component) || WrapWithProxy(Component);\n}\nfunction WrapWithProxy(Component: FunctionComponent<any>) {\n\tif (SupportsProxy) {\n\t\tconst ProxyComponent = new Proxy(Component, ProxyHandlers);\n\n\t\tProxyInstance.set(Component, ProxyComponent);\n\t\tProxyInstance.set(ProxyComponent, ProxyComponent);\n\n\t\treturn ProxyComponent;\n\t}\n\n\t/**\n\t * Emulate a Proxy if environment doesn't support it.\n\t *\n\t * @TODO - unlike Proxy, it's not possible to access the type/Component's\n\t * static properties this way. Not sure if we want to copy all statics here.\n\t * Omitting this for now.\n\t *\n\t * @example - works with Proxy, doesn't with wrapped function.\n\t * ```\n\t * const el = <SomeFunctionalComponent />\n\t * el.type.someOwnOrInheritedProperty;\n\t * el.type.defaultProps;\n\t * ```\n\t */\n\tconst WrappedComponent = function () {\n\t\treturn ProxyHandlers.apply(Component, undefined, arguments);\n\t};\n\tProxyInstance.set(Component, WrappedComponent);\n\tProxyInstance.set(WrappedComponent, WrappedComponent);\n\n\treturn WrappedComponent;\n}\n\n/**\n * A redux-like store whose store value is a positive 32bit integer (a 'version').\n *\n * React subscribes to this store and gets a snapshot of the current 'version',\n * whenever the 'version' changes, we tell React it's time to update the component (call 'onStoreChange').\n *\n * How we achieve this is by creating a binding with an 'effect', when the `effect._callback' is called,\n * we update our store version and tell React to re-render the component ([1] We don't really care when/how React does it).\n *\n * [1]\n * @see https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore\n * @see https://github.com/reactjs/rfcs/blob/main/text/0214-use-sync-external-store.md\n */\nfunction createEffectStore() {\n\tlet updater!: Effect;\n\tlet version = 0;\n\tlet onChangeNotifyReact: (() => void) | undefined;\n\n\tlet unsubscribe = effect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = function () {\n\t\tversion = (version + 1) | 0;\n\t\tif (onChangeNotifyReact) onChangeNotifyReact();\n\t};\n\n\treturn {\n\t\tupdater,\n\t\tsubscribe(onStoreChange: () => void) {\n\t\t\tonChangeNotifyReact = onStoreChange;\n\n\t\t\treturn function () {\n\t\t\t\t/**\n\t\t\t\t * Rotate to next version when unsubscribing to ensure that components are re-run\n\t\t\t\t * when subscribing again.\n\t\t\t\t *\n\t\t\t\t * In StrictMode, 'memo'-ed components seem to keep a stale snapshot version, so\n\t\t\t\t * don't re-run after subscribing again if the version is the same as last time.\n\t\t\t\t *\n\t\t\t\t * Because we unsubscribe from the effect, the version may not change. We simply\n\t\t\t\t * set a new initial version in case of stale snapshots here.\n\t\t\t\t */\n\t\t\t\tversion = (version + 1) | 0;\n\t\t\t\tonChangeNotifyReact = undefined;\n\t\t\t\tunsubscribe();\n\t\t\t};\n\t\t},\n\t\tgetSnapshot() {\n\t\t\treturn version;\n\t\t},\n\t};\n}\n\nfunction WrapJsx<T>(jsx: T): T {\n\tif (typeof jsx !== \"function\") return jsx;\n\n\treturn function (type: any, props: any, ...rest: any[]) {\n\t\tif (typeof type === \"function\" && !(type instanceof Component)) {\n\t\t\treturn jsx.call(jsx, ProxyFunctionalComponent(type), props, ...rest);\n\t\t}\n\n\t\tif (type && typeof type === \"object\" && type.$$typeof === ReactMemoType) {\n\t\t\ttype.type = ProxyFunctionalComponent(type.type);\n\t\t\treturn jsx.call(jsx, type, props, ...rest);\n\t\t}\n\n\t\tif (typeof type === \"string\" && props) {\n\t\t\tfor (let i in props) {\n\t\t\t\tlet v = props[i];\n\t\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t\tprops[i] = v.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jsx.call(jsx, type, props, ...rest);\n\t} as any as T;\n}\n\nconst JsxPro: JsxRuntimeModule = jsxRuntime;\nconst JsxDev: JsxRuntimeModule = jsxRuntimeDev;\n\n/**\n * createElement _may_ be called by jsx runtime as a fallback in certain cases,\n * so we need to wrap it regardless.\n *\n * The jsx exports depend on the `NODE_ENV` var to ensure the users' bundler doesn't\n * include both, so one of them will be set with `undefined` values.\n */\nReact.createElement = WrapJsx(React.createElement);\nJsxDev.jsx && /* */ (JsxDev.jsx = WrapJsx(JsxDev.jsx));\nJsxPro.jsx && /* */ (JsxPro.jsx = WrapJsx(JsxPro.jsx));\nJsxDev.jsxs && /* */ (JsxDev.jsxs = WrapJsx(JsxDev.jsxs));\nJsxPro.jsxs && /* */ (JsxPro.jsxs = WrapJsx(JsxPro.jsxs));\nJsxDev.jsxDEV && /**/ (JsxDev.jsxDEV = WrapJsx(JsxDev.jsxDEV));\nJsxPro.jsxDEV && /**/ (JsxPro.jsxDEV = WrapJsx(JsxPro.jsxDEV));\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.\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { configurable: true, value: ReactElemType },\n\ttype: { configurable: true, value: ProxyFunctionalComponent(Text) },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\n});\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), Empty);\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()), Empty);\n}\n\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, Empty);\n}\n"],"names":["Empty","Symbol","ReactMemoType","ProxyInstance","Map","SupportsProxy","Proxy","apply","Component","thisArg","argumentsList","useMemo","createEffectStore","useSyncExternalStore","store","subscribe","getSnapshot","updater","_start","e","stop","ProxyFunctionalComponent","get","ProxyComponent","ProxyHandlers","set","WrappedComponent","undefined","arguments","WrapWithProxy","onChangeNotifyReact","version","unsubscribe","effect","this","_callback","onStoreChange","WrapJsx","jsx","type","props","slice","call","rest","$$typeof","i","v","Signal","value","concat","JsxPro","jsxRuntime","JsxDev","jsxRuntimeDev","React","createElement","jsxs","jsxDEV","Object","defineProperties","prototype","configurable","ReactElemType","_ref","data","ref","exports","signalsCore","batch","computed","signal","useComputed","compute","$compute","useRef","current","useSignal","useSignalEffect","cb","callback","useEffect"],"mappings":"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"}
|
package/dist/signals.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import t,{
|
|
1
|
+
import t,{Component as n,useMemo as e,useRef as r,useEffect as o}from"react";import i from"react/jsx-runtime";import c from"react/jsx-dev-runtime";import{useSyncExternalStore as f}from"use-sync-external-store/shim/index.js";import{Signal as u,signal as a,computed as s,effect as l}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";const p=[],m=Symbol.for("react.element"),y=Symbol.for("react.memo"),b=new Map,g="function"==typeof Proxy,d={apply(t,n,r){const o=e(x,p);f(o.subscribe,o.getSnapshot,o.getSnapshot);const i=o.updater.S();try{return t.apply(n,r)}catch(t){throw t}finally{i()}}};function h(t){return b.get(t)||function(t){if(g){const n=new Proxy(t,d);b.set(t,n);b.set(n,n);return n}const n=function(){return d.apply(t,void 0,arguments)};b.set(t,n);b.set(n,n);return n}(t)}function x(){let t,n,e=0,r=l(function(){t=this});t.c=function(){e=e+1|0;if(n)n()};return{updater:t,subscribe(t){n=t;return function(){e=e+1|0;n=void 0;r()}},getSnapshot:()=>e}}function v(t){if("function"!=typeof t)return t;else return function(e,r,...o){if("function"==typeof e&&!(e instanceof n))return t.call(t,h(e),r,...o);if(e&&"object"==typeof e&&e.$$typeof===y){e.type=h(e.type);return t.call(t,e,r,...o)}if("string"==typeof e&&r)for(let t in r){let n=r[t];if("children"!==t&&n instanceof u)r[t]=n.value}return t.call(t,e,r,...o)}}const j=i,S=c;t.createElement=v(t.createElement);S.jsx&&(S.jsx=v(S.jsx));j.jsx&&(j.jsx=v(j.jsx));S.jsxs&&(S.jsxs=v(S.jsxs));j.jsxs&&(j.jsxs=v(j.jsxs));S.jsxDEV&&(S.jsxDEV=v(S.jsxDEV));j.jsxDEV&&(j.jsxDEV=v(j.jsxDEV));Object.defineProperties(u.prototype,{$$typeof:{configurable:!0,value:m},type:{configurable:!0,value:h(function({data:t}){return t.value})},props:{configurable:!0,get(){return{data:this}}},ref:{configurable:!0,value:null}});function useSignal(t){return e(()=>a(t),p)}function useComputed(t){const n=r(t);n.current=t;return e(()=>s(()=>n.current()),p)}function useSignalEffect(t){const n=r(t);n.current=t;o(()=>l(()=>n.current()),p)}export{useComputed,useSignal,useSignalEffect};//# sourceMappingURL=signals.mjs.map
|
package/dist/signals.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.mjs","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\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 { Effect, 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: (() => void) | undefined;\nconst updaterForComponent = new WeakMap<() => void, Effect>();\n\nfunction setCurrentUpdater(updater?: Effect) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate();\n\t// start tracking the new update:\n\tfinishUpdate = updater && updater._start();\n}\n\nfunction createUpdater(update: () => void) {\n\tlet updater!: Effect;\n\teffect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = update;\n\treturn updater;\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: { configurable: true, value: $$typeof },\n\ttype: { configurable: true, value: Text },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\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\n\t\t\tlet updater = updaterForComponent.get(rerender);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(rerender, updater);\n\t\t\t} else {\n\t\t\t\tupdater._callback = rerender;\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 || /Invalid/.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\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, []);\n}\n"],"names":["createElement","React","type","props","i","v","Signal","value","apply","this","arguments","finishUpdate","updaterForComponent","WeakMap","setCurrentUpdater","updater","_start","$$typeof","Object","defineProperties","prototype","configurable","data","get","ref","UPDATE","currentDispatcher","defineProperty","internals","ReactCurrentDispatcher","set","api","lock","cached","invalidHookAccessors","undefined","invalid","useCallback","length","test","isInvalidHookAccessor","useReducer","rerender","update","effect","_callback","createUpdater","Map","useSignal","signal","useComputed","compute","$compute","useRef","current","useMemo","computed","useSignalEffect","cb","callback","useEffect"],"mappings":"gRAyBA,MAAmBA,EAAGC,EAAMD,cAE5BC,EAAMD,cAAgB,SAAUE,EAAMC,GACrC,GAAoB,iBAATD,GAAqBC,EAC/B,IAAK,IAAIC,KAAKD,EAAO,CACpB,IAAIE,EAAIF,EAAMC,GACd,GAAU,aAANA,GAAoBC,aAAxBC,EAECH,EAAMC,GAAKC,EAAEE,KAEd,CAGF,OAAoBP,EAACQ,MAAMC,KAAMC,UACjC,EAiBD,IAAAC,EACA,MAAMC,EAAsB,IAA5BC,QAEA,SAAAC,EAA2BC,GAE1B,GAAIJ,EAAcA,IAElBA,EAAeI,GAAWA,EAAQC,GAClC,CAoBD,MAAMC,EAAWjB,EAAc,KAAKiB,SACpCC,OAAOC,iBAAiBb,EAAOc,UAAW,CACzCH,SAAU,CAAEI,cAAc,EAAMd,MAAOU,GACvCf,KAAM,CAAEmB,cAAc,EAAMd,MAT7B,UAAce,KAAEA,IACf,OAAOA,EAAKf,KACZ,GAQAJ,MAAO,CACNkB,cAAc,EACdE,MACC,MAAO,CAAED,KAAMb,KACf,GAEFe,IAAK,CAAEH,cAAc,EAAMd,MAAO,QAInC,OAAW,EACX,MAAYkB,EAAG,KAAO,CAAP,GACf,IAAAC,EACAR,OAAOS,eAAeC,EAAUC,uBAAwB,UAAW,CAClEN,IAAG,IAEFG,EACDI,IAAIC,GACHL,EAAoBK,EACpB,IAAIC,EACJ,GAAID,IAwBN,SAA+BA,GAC9B,MAAYE,EAAGC,EAAqBX,IAAIQ,GACxC,QAAeI,IAAXF,EAAsB,OAAAA,EAE1B,MAAMG,EACLL,EAAIM,YAAYC,OAAS,GAAK,UAAUC,KAAKR,EAAIM,aAClDH,EAAqBJ,IAAIC,EAAKK,GAC9B,OACAA,CAAA,CAhCaI,CAAsBT,GAAM,CAGvCC,GAAO,EACP,QAAiBD,EAAIU,WAAWhB,EAAQ,CAAvB,GAA2B,GAC5CO,GAAO,EAEP,IAAWjB,EAAGH,EAAoBW,IAAImB,GACtC,IAAK3B,EAAS,CACbA,EAnDJ,SAAuB4B,GACtB,IAAA5B,EACA6B,EAAO,WACN7B,EAAUN,IACV,GACDM,EAAQ8B,EAAYF,EACpB,OACA5B,CAAA,CA4Ca+B,CAAcJ,GACxB9B,EAAoBkB,IAAIY,EAAU3B,EAClC,MACAA,EAAQ8B,EAAYH,EAErB5B,EAAkBC,EAClB,MACAD,GAED,IAKF,MAAMoB,EAAuB,IAA7Ba,IAWM,SAAAC,EAAuBzC,GAC5B,SAAe,IAAM0C,EAAU1C,GAAQ,GACvC,CAEe2C,SAAAA,EAAeC,GAC9B,MAAcC,EAAGC,EAAOF,GACxBC,EAASE,QAAUH,EACnB,OAAcI,EAAC,IAAMC,EAAY,IAAMJ,EAASE,WAAY,GAC5D,CAEK,SAAAG,EAA0BC,GAC/B,MAAMC,EAAWN,EAAOK,GACxBC,EAASL,QAAUI,EAEnBE,EAAU,IACIhB,EAAC,IACEe,EAACL,WAEf,GACH,QAAAJ,iBAAAF,eAAAS"}
|
|
1
|
+
{"version":3,"file":"signals.mjs","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\n\tComponent,\n\ttype FunctionComponent,\n} from \"react\";\nimport React from \"react\";\nimport jsxRuntime from \"react/jsx-runtime\";\nimport jsxRuntimeDev from \"react/jsx-dev-runtime\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport type { Effect, JsxRuntimeModule } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\nconst Empty = [] as const;\nconst ReactElemType = Symbol.for(\"react.element\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L15\nconst ReactMemoType = Symbol.for(\"react.memo\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L30\nconst ProxyInstance = new Map<FunctionComponent<any>, FunctionComponent<any>>();\nconst SupportsProxy = typeof Proxy === \"function\";\n\nconst ProxyHandlers = {\n\t/**\n\t * This is a function call trap for functional components.\n\t * When this is called, we know it means React did run 'Component()',\n\t * that means we can use any hooks here to setup our effect and store.\n\t *\n\t * With the native Proxy, all other calls such as access/setting to/of properties will\n\t * be forwarded to the target Component, so we don't need to copy the Component's\n\t * own or inherited properties.\n\t *\n\t * @see https://github.com/facebook/react/blob/2d80a0cd690bb5650b6c8a6c079a87b5dc42bd15/packages/react-reconciler/src/ReactFiberHooks.old.js#L460\n\t */\n\tapply(Component: FunctionComponent, thisArg: any, argumentsList: any) {\n\t\tconst store = useMemo(createEffectStore, Empty);\n\n\t\tuseSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n\n\t\tconst stop = store.updater._start();\n\n\t\ttry {\n\t\t\tconst children = Component.apply(thisArg, argumentsList);\n\t\t\treturn children;\n\t\t} catch (e) {\n\t\t\t// Re-throwing promises that'll be handled by suspense\n\t\t\t// or an actual error.\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\t// Stop effects in either case before return or throw,\n\t\t\t// Otherwise the effect will leak.\n\t\t\tstop();\n\t\t}\n\t},\n};\n\nfunction ProxyFunctionalComponent(Component: FunctionComponent<any>) {\n\treturn ProxyInstance.get(Component) || WrapWithProxy(Component);\n}\nfunction WrapWithProxy(Component: FunctionComponent<any>) {\n\tif (SupportsProxy) {\n\t\tconst ProxyComponent = new Proxy(Component, ProxyHandlers);\n\n\t\tProxyInstance.set(Component, ProxyComponent);\n\t\tProxyInstance.set(ProxyComponent, ProxyComponent);\n\n\t\treturn ProxyComponent;\n\t}\n\n\t/**\n\t * Emulate a Proxy if environment doesn't support it.\n\t *\n\t * @TODO - unlike Proxy, it's not possible to access the type/Component's\n\t * static properties this way. Not sure if we want to copy all statics here.\n\t * Omitting this for now.\n\t *\n\t * @example - works with Proxy, doesn't with wrapped function.\n\t * ```\n\t * const el = <SomeFunctionalComponent />\n\t * el.type.someOwnOrInheritedProperty;\n\t * el.type.defaultProps;\n\t * ```\n\t */\n\tconst WrappedComponent = function () {\n\t\treturn ProxyHandlers.apply(Component, undefined, arguments);\n\t};\n\tProxyInstance.set(Component, WrappedComponent);\n\tProxyInstance.set(WrappedComponent, WrappedComponent);\n\n\treturn WrappedComponent;\n}\n\n/**\n * A redux-like store whose store value is a positive 32bit integer (a 'version').\n *\n * React subscribes to this store and gets a snapshot of the current 'version',\n * whenever the 'version' changes, we tell React it's time to update the component (call 'onStoreChange').\n *\n * How we achieve this is by creating a binding with an 'effect', when the `effect._callback' is called,\n * we update our store version and tell React to re-render the component ([1] We don't really care when/how React does it).\n *\n * [1]\n * @see https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore\n * @see https://github.com/reactjs/rfcs/blob/main/text/0214-use-sync-external-store.md\n */\nfunction createEffectStore() {\n\tlet updater!: Effect;\n\tlet version = 0;\n\tlet onChangeNotifyReact: (() => void) | undefined;\n\n\tlet unsubscribe = effect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = function () {\n\t\tversion = (version + 1) | 0;\n\t\tif (onChangeNotifyReact) onChangeNotifyReact();\n\t};\n\n\treturn {\n\t\tupdater,\n\t\tsubscribe(onStoreChange: () => void) {\n\t\t\tonChangeNotifyReact = onStoreChange;\n\n\t\t\treturn function () {\n\t\t\t\t/**\n\t\t\t\t * Rotate to next version when unsubscribing to ensure that components are re-run\n\t\t\t\t * when subscribing again.\n\t\t\t\t *\n\t\t\t\t * In StrictMode, 'memo'-ed components seem to keep a stale snapshot version, so\n\t\t\t\t * don't re-run after subscribing again if the version is the same as last time.\n\t\t\t\t *\n\t\t\t\t * Because we unsubscribe from the effect, the version may not change. We simply\n\t\t\t\t * set a new initial version in case of stale snapshots here.\n\t\t\t\t */\n\t\t\t\tversion = (version + 1) | 0;\n\t\t\t\tonChangeNotifyReact = undefined;\n\t\t\t\tunsubscribe();\n\t\t\t};\n\t\t},\n\t\tgetSnapshot() {\n\t\t\treturn version;\n\t\t},\n\t};\n}\n\nfunction WrapJsx<T>(jsx: T): T {\n\tif (typeof jsx !== \"function\") return jsx;\n\n\treturn function (type: any, props: any, ...rest: any[]) {\n\t\tif (typeof type === \"function\" && !(type instanceof Component)) {\n\t\t\treturn jsx.call(jsx, ProxyFunctionalComponent(type), props, ...rest);\n\t\t}\n\n\t\tif (type && typeof type === \"object\" && type.$$typeof === ReactMemoType) {\n\t\t\ttype.type = ProxyFunctionalComponent(type.type);\n\t\t\treturn jsx.call(jsx, type, props, ...rest);\n\t\t}\n\n\t\tif (typeof type === \"string\" && props) {\n\t\t\tfor (let i in props) {\n\t\t\t\tlet v = props[i];\n\t\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t\tprops[i] = v.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jsx.call(jsx, type, props, ...rest);\n\t} as any as T;\n}\n\nconst JsxPro: JsxRuntimeModule = jsxRuntime;\nconst JsxDev: JsxRuntimeModule = jsxRuntimeDev;\n\n/**\n * createElement _may_ be called by jsx runtime as a fallback in certain cases,\n * so we need to wrap it regardless.\n *\n * The jsx exports depend on the `NODE_ENV` var to ensure the users' bundler doesn't\n * include both, so one of them will be set with `undefined` values.\n */\nReact.createElement = WrapJsx(React.createElement);\nJsxDev.jsx && /* */ (JsxDev.jsx = WrapJsx(JsxDev.jsx));\nJsxPro.jsx && /* */ (JsxPro.jsx = WrapJsx(JsxPro.jsx));\nJsxDev.jsxs && /* */ (JsxDev.jsxs = WrapJsx(JsxDev.jsxs));\nJsxPro.jsxs && /* */ (JsxPro.jsxs = WrapJsx(JsxPro.jsxs));\nJsxDev.jsxDEV && /**/ (JsxDev.jsxDEV = WrapJsx(JsxDev.jsxDEV));\nJsxPro.jsxDEV && /**/ (JsxPro.jsxDEV = WrapJsx(JsxPro.jsxDEV));\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.\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { configurable: true, value: ReactElemType },\n\ttype: { configurable: true, value: ProxyFunctionalComponent(Text) },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\n});\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), Empty);\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()), Empty);\n}\n\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, Empty);\n}\n"],"names":["React","Component","useMemo","useRef","useEffect","jsxRuntime","jsxRuntimeDev","useSyncExternalStore","Signal","signal","computed","effect","batch","Empty","Symbol","for","ReactMemoType","ProxyInstance","Map","ProxyHandlers","apply","thisArg","argumentsList","store","createEffectStore","subscribe","getSnapshot","stop","updater","_start","e","get","SupportsProxy","ProxyComponent","Proxy","set","WrappedComponent","undefined","arguments","WrapWithProxy","onChangeNotifyReact","unsubscribe","this","_callback","version","onStoreChange","jsx","type","props","rest","call","ProxyFunctionalComponent","$$typeof","v","i","value","JsxDev","createElement","WrapJsx","JsxPro","jsxs","jsxDEV","Object","defineProperties","prototype","configurable","ReactElemType","data","ref","compute","$compute","current","useSignalEffect","cb","callback","useComputed","useSignal"],"mappings":"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"}
|
package/dist/signals.module.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import n,{
|
|
1
|
+
import n,{Component as r,useMemo as t,useRef as e,useEffect as o}from"react";import u from"react/jsx-runtime";import i from"react/jsx-dev-runtime";import{useSyncExternalStore as f}from"use-sync-external-store/shim/index.js";import{Signal as c,signal as a,computed as p,effect as l}from"@preact/signals-core";export{Signal,batch,computed,effect,signal}from"@preact/signals-core";var s=[],m=Symbol.for("react.element"),v=Symbol.for("react.memo"),y=new Map,b="function"==typeof Proxy,g={apply:function(n,r,e){var o=t(h,s);f(o.subscribe,o.getSnapshot,o.getSnapshot);var u=o.updater.S();try{return n.apply(r,e)}catch(n){throw n}finally{u()}}};function d(n){return y.get(n)||function(n){if(b){var r=new Proxy(n,g);y.set(n,r);y.set(r,r);return r}var t=function(){return g.apply(n,void 0,arguments)};y.set(n,t);y.set(t,t);return t}(n)}function h(){var n,r,t=0,e=l(function(){n=this});n.c=function(){t=t+1|0;if(r)r()};return{updater:n,subscribe:function(n){r=n;return function(){t=t+1|0;r=void 0;e()}},getSnapshot:function(){return t}}}function x(n){if("function"!=typeof n)return n;else return function(t,e){var o=[].slice.call(arguments,2);if("function"==typeof t&&!(t instanceof r))return n.call.apply(n,[n,d(t),e].concat(o));if(t&&"object"==typeof t&&t.$$typeof===v){t.type=d(t.type);return n.call.apply(n,[n,t,e].concat(o))}if("string"==typeof t&&e)for(var u in e){var i=e[u];if("children"!==u&&i instanceof c)e[u]=i.value}return n.call.apply(n,[n,t,e].concat(o))}}var j=u,S=i;n.createElement=x(n.createElement);S.jsx&&(S.jsx=x(S.jsx));j.jsx&&(j.jsx=x(j.jsx));S.jsxs&&(S.jsxs=x(S.jsxs));j.jsxs&&(j.jsxs=x(j.jsxs));S.jsxDEV&&(S.jsxDEV=x(S.jsxDEV));j.jsxDEV&&(j.jsxDEV=x(j.jsxDEV));Object.defineProperties(c.prototype,{$$typeof:{configurable:!0,value:m},type:{configurable:!0,value:d(function(n){return n.data.value})},props:{configurable:!0,get:function(){return{data:this}}},ref:{configurable:!0,value:null}});function useSignal(n){return t(function(){return a(n)},s)}function useComputed(n){var r=e(n);r.current=n;return t(function(){return p(function(){return r.current()})},s)}function useSignalEffect(n){var r=e(n);r.current=n;o(function(){return l(function(){return r.current()})},s)}export{useComputed,useSignal,useSignalEffect};//# sourceMappingURL=signals.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.module.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\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 { Effect, 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: (() => void) | undefined;\nconst updaterForComponent = new WeakMap<() => void, Effect>();\n\nfunction setCurrentUpdater(updater?: Effect) {\n\t// end tracking for the current update:\n\tif (finishUpdate) finishUpdate();\n\t// start tracking the new update:\n\tfinishUpdate = updater && updater._start();\n}\n\nfunction createUpdater(update: () => void) {\n\tlet updater!: Effect;\n\teffect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = update;\n\treturn updater;\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: { configurable: true, value: $$typeof },\n\ttype: { configurable: true, value: Text },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\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\n\t\t\tlet updater = updaterForComponent.get(rerender);\n\t\t\tif (!updater) {\n\t\t\t\tupdater = createUpdater(rerender);\n\t\t\t\tupdaterForComponent.set(rerender, updater);\n\t\t\t} else {\n\t\t\t\tupdater._callback = rerender;\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 || /Invalid/.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\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, []);\n}\n"],"names":["React","__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","useMemo","useRef","useEffect","Signal","effect","signal","computed","batch","createElement","type","props","i","v","value","apply","this","arguments","updaterForComponent","WeakMap","updater","finishUpdate","_start","$$typeof","Object","defineProperties","prototype","configurable","_ref","data","get","ref","currentDispatcher","lock","UPDATE","defineProperty","internals","ReactCurrentDispatcher","set","api","cached","invalidHookAccessors","undefined","invalid","useCallback","length","test","isInvalidHookAccessor","rerender","useReducer","update","_callback","createUpdater","setCurrentUpdater","Map","useSignal","useComputed","compute","$compute","current","useSignalEffect","cb","callback"],"mappings":"OAyBAA,yDAAAC,aAAAC,YAAAC,eAAAC,MAAA,yBAAAC,YAAAC,YAAAC,cAAAC,MAAA,8BAAAH,OAAAI,MAAAD,SAAAF,OAAAC,WAAA,uBAAA,MAAmBG,EAAGV,EAAMU,cAE5BV,EAAMU,cAAgB,SAAUC,EAAMC,GACrC,GAAoB,iBAAhBD,GAA4BC,EAC/B,IAAK,IAALC,KAAAD,EAAqB,CACpB,IAAKE,EAAGF,EAAMC,GACd,GAAU,aAANA,GAAoBC,aAAaT,EAEpCO,EAAMC,GAAKC,EAAEC,KAEd,CAGF,OAAOL,EAAcM,MAAMC,KAAMC,UACjC,EAkBD,IAAyBC,EAAG,IAAIC,QAEhC,WAA2BC,GAE1B,GAAIC,EAAcA,IAElBA,EAAeD,GAAWA,EAAQE,GAClC,CAoBD,IAAcC,EAAGd,EAAc,KAAKc,SACpCC,OAAOC,iBAAiBrB,EAAOsB,UAAW,CACzCH,SAAU,CAAEI,cAAc,EAAMb,MAAOS,GACvCb,KAAM,CAAEiB,cAAc,EAAMb,MAT7B,SAAAc,GACC,OADeC,EAAAA,KACHf,KACZ,GAQAH,MAAO,CACNgB,cAAc,EACdG,IAAG,WACF,MAAO,CAAED,KAAMb,KACf,GAEFe,IAAK,CAAEJ,cAAc,EAAMb,MAAO,QAInC,IAEIkB,EAFAC,GAAO,EACLC,EAAS,WAAA,MAAO,CAAP,CAAA,EAEfV,OAAOW,eAAeC,EAAUC,uBAAwB,UAAW,CAClEP,IADkE,WAEjE,OAAOE,CACP,EACDM,IAJkE,SAI9DC,GACHP,EAAoBO,EACpB,IAAIN,EACJ,GAAIM,IAwBN,SAA+BA,GAC9B,IAAYC,EAAGC,EAAqBX,IAAIS,GACxC,QAAeG,IAAXF,EAAsB,OAAAA,EAE1B,IAAMG,EACLJ,EAAIK,YAAYC,OAAS,GAAK,UAAUC,KAAKP,EAAIK,aAClDH,EAAqBH,IAAIC,EAAKI,GAC9B,OACAA,CAAA,CAhCaI,CAAsBR,GAAM,CAGvCN,GAAO,EACP,IAAMe,EAAWT,EAAIU,WAAWf,EAAQ,CAAA,GAAI,GAC5CD,GAAO,EAEP,IAAIb,EAAUF,EAAoBY,IAAIkB,GACtC,IAAK5B,EAAS,CACbA,EAnDJ,SAAuB8B,GACtB,MACA7C,EAAO,WACNe,EAAUJ,IACV,GACDI,EAAQ+B,EAAYD,EACpB,OAAO9B,CACP,CA4CagC,CAAcJ,GACxB9B,EAAoBoB,IAAIU,EAAU5B,EAClC,MACAA,EAAQ+B,EAAYH,EAErBK,EAAkBjC,EAClB,MACAiC,GAED,IAKF,MAA6B,IAA7BC,IAWM,SAAAC,EAAuBzC,GAC5B,OAAcb,EAAC,kBAAYK,EAAIQ,EAAhB,EAAwB,GACvC,CAEK,SAAA0C,EAAyBC,GAC9B,MAAiBvD,EAAOuD,GACxBC,EAASC,QAAUF,EACnB,OAAOxD,EAAQ,WAAA,SAAkB,WAAA,OAAcyD,EAACC,SAAf,EAAlB,EAA6C,GAC5D,CAEK,SAAAC,EAA0BC,GAC/B,IAAMC,EAAW5D,EAAO2D,GACxBC,EAASH,QAAUE,EAEnB1D,EAAU,WACT,OAAaE,EAAC,WACb,OAAeyD,EAACH,SAChB,EACD,EAAE,GACH,QAAAH,iBAAAD,eAAAK"}
|
|
1
|
+
{"version":3,"file":"signals.module.js","sources":["../src/index.ts"],"sourcesContent":["import {\n\tuseRef,\n\tuseMemo,\n\tuseEffect,\n\tComponent,\n\ttype FunctionComponent,\n} from \"react\";\nimport React from \"react\";\nimport jsxRuntime from \"react/jsx-runtime\";\nimport jsxRuntimeDev from \"react/jsx-dev-runtime\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport {\n\tsignal,\n\tcomputed,\n\tbatch,\n\teffect,\n\tSignal,\n\ttype ReadonlySignal,\n} from \"@preact/signals-core\";\nimport type { Effect, JsxRuntimeModule } from \"./internal\";\n\nexport { signal, computed, batch, effect, Signal, type ReadonlySignal };\n\nconst Empty = [] as const;\nconst ReactElemType = Symbol.for(\"react.element\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L15\nconst ReactMemoType = Symbol.for(\"react.memo\"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L30\nconst ProxyInstance = new Map<FunctionComponent<any>, FunctionComponent<any>>();\nconst SupportsProxy = typeof Proxy === \"function\";\n\nconst ProxyHandlers = {\n\t/**\n\t * This is a function call trap for functional components.\n\t * When this is called, we know it means React did run 'Component()',\n\t * that means we can use any hooks here to setup our effect and store.\n\t *\n\t * With the native Proxy, all other calls such as access/setting to/of properties will\n\t * be forwarded to the target Component, so we don't need to copy the Component's\n\t * own or inherited properties.\n\t *\n\t * @see https://github.com/facebook/react/blob/2d80a0cd690bb5650b6c8a6c079a87b5dc42bd15/packages/react-reconciler/src/ReactFiberHooks.old.js#L460\n\t */\n\tapply(Component: FunctionComponent, thisArg: any, argumentsList: any) {\n\t\tconst store = useMemo(createEffectStore, Empty);\n\n\t\tuseSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n\n\t\tconst stop = store.updater._start();\n\n\t\ttry {\n\t\t\tconst children = Component.apply(thisArg, argumentsList);\n\t\t\treturn children;\n\t\t} catch (e) {\n\t\t\t// Re-throwing promises that'll be handled by suspense\n\t\t\t// or an actual error.\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\t// Stop effects in either case before return or throw,\n\t\t\t// Otherwise the effect will leak.\n\t\t\tstop();\n\t\t}\n\t},\n};\n\nfunction ProxyFunctionalComponent(Component: FunctionComponent<any>) {\n\treturn ProxyInstance.get(Component) || WrapWithProxy(Component);\n}\nfunction WrapWithProxy(Component: FunctionComponent<any>) {\n\tif (SupportsProxy) {\n\t\tconst ProxyComponent = new Proxy(Component, ProxyHandlers);\n\n\t\tProxyInstance.set(Component, ProxyComponent);\n\t\tProxyInstance.set(ProxyComponent, ProxyComponent);\n\n\t\treturn ProxyComponent;\n\t}\n\n\t/**\n\t * Emulate a Proxy if environment doesn't support it.\n\t *\n\t * @TODO - unlike Proxy, it's not possible to access the type/Component's\n\t * static properties this way. Not sure if we want to copy all statics here.\n\t * Omitting this for now.\n\t *\n\t * @example - works with Proxy, doesn't with wrapped function.\n\t * ```\n\t * const el = <SomeFunctionalComponent />\n\t * el.type.someOwnOrInheritedProperty;\n\t * el.type.defaultProps;\n\t * ```\n\t */\n\tconst WrappedComponent = function () {\n\t\treturn ProxyHandlers.apply(Component, undefined, arguments);\n\t};\n\tProxyInstance.set(Component, WrappedComponent);\n\tProxyInstance.set(WrappedComponent, WrappedComponent);\n\n\treturn WrappedComponent;\n}\n\n/**\n * A redux-like store whose store value is a positive 32bit integer (a 'version').\n *\n * React subscribes to this store and gets a snapshot of the current 'version',\n * whenever the 'version' changes, we tell React it's time to update the component (call 'onStoreChange').\n *\n * How we achieve this is by creating a binding with an 'effect', when the `effect._callback' is called,\n * we update our store version and tell React to re-render the component ([1] We don't really care when/how React does it).\n *\n * [1]\n * @see https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore\n * @see https://github.com/reactjs/rfcs/blob/main/text/0214-use-sync-external-store.md\n */\nfunction createEffectStore() {\n\tlet updater!: Effect;\n\tlet version = 0;\n\tlet onChangeNotifyReact: (() => void) | undefined;\n\n\tlet unsubscribe = effect(function (this: Effect) {\n\t\tupdater = this;\n\t});\n\tupdater._callback = function () {\n\t\tversion = (version + 1) | 0;\n\t\tif (onChangeNotifyReact) onChangeNotifyReact();\n\t};\n\n\treturn {\n\t\tupdater,\n\t\tsubscribe(onStoreChange: () => void) {\n\t\t\tonChangeNotifyReact = onStoreChange;\n\n\t\t\treturn function () {\n\t\t\t\t/**\n\t\t\t\t * Rotate to next version when unsubscribing to ensure that components are re-run\n\t\t\t\t * when subscribing again.\n\t\t\t\t *\n\t\t\t\t * In StrictMode, 'memo'-ed components seem to keep a stale snapshot version, so\n\t\t\t\t * don't re-run after subscribing again if the version is the same as last time.\n\t\t\t\t *\n\t\t\t\t * Because we unsubscribe from the effect, the version may not change. We simply\n\t\t\t\t * set a new initial version in case of stale snapshots here.\n\t\t\t\t */\n\t\t\t\tversion = (version + 1) | 0;\n\t\t\t\tonChangeNotifyReact = undefined;\n\t\t\t\tunsubscribe();\n\t\t\t};\n\t\t},\n\t\tgetSnapshot() {\n\t\t\treturn version;\n\t\t},\n\t};\n}\n\nfunction WrapJsx<T>(jsx: T): T {\n\tif (typeof jsx !== \"function\") return jsx;\n\n\treturn function (type: any, props: any, ...rest: any[]) {\n\t\tif (typeof type === \"function\" && !(type instanceof Component)) {\n\t\t\treturn jsx.call(jsx, ProxyFunctionalComponent(type), props, ...rest);\n\t\t}\n\n\t\tif (type && typeof type === \"object\" && type.$$typeof === ReactMemoType) {\n\t\t\ttype.type = ProxyFunctionalComponent(type.type);\n\t\t\treturn jsx.call(jsx, type, props, ...rest);\n\t\t}\n\n\t\tif (typeof type === \"string\" && props) {\n\t\t\tfor (let i in props) {\n\t\t\t\tlet v = props[i];\n\t\t\t\tif (i !== \"children\" && v instanceof Signal) {\n\t\t\t\t\tprops[i] = v.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jsx.call(jsx, type, props, ...rest);\n\t} as any as T;\n}\n\nconst JsxPro: JsxRuntimeModule = jsxRuntime;\nconst JsxDev: JsxRuntimeModule = jsxRuntimeDev;\n\n/**\n * createElement _may_ be called by jsx runtime as a fallback in certain cases,\n * so we need to wrap it regardless.\n *\n * The jsx exports depend on the `NODE_ENV` var to ensure the users' bundler doesn't\n * include both, so one of them will be set with `undefined` values.\n */\nReact.createElement = WrapJsx(React.createElement);\nJsxDev.jsx && /* */ (JsxDev.jsx = WrapJsx(JsxDev.jsx));\nJsxPro.jsx && /* */ (JsxPro.jsx = WrapJsx(JsxPro.jsx));\nJsxDev.jsxs && /* */ (JsxDev.jsxs = WrapJsx(JsxDev.jsxs));\nJsxPro.jsxs && /* */ (JsxPro.jsxs = WrapJsx(JsxPro.jsxs));\nJsxDev.jsxDEV && /**/ (JsxDev.jsxDEV = WrapJsx(JsxDev.jsxDEV));\nJsxPro.jsxDEV && /**/ (JsxPro.jsxDEV = WrapJsx(JsxPro.jsxDEV));\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.\nObject.defineProperties(Signal.prototype, {\n\t$$typeof: { configurable: true, value: ReactElemType },\n\ttype: { configurable: true, value: ProxyFunctionalComponent(Text) },\n\tprops: {\n\t\tconfigurable: true,\n\t\tget() {\n\t\t\treturn { data: this };\n\t\t},\n\t},\n\tref: { configurable: true, value: null },\n});\n\nexport function useSignal<T>(value: T) {\n\treturn useMemo(() => signal<T>(value), Empty);\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()), Empty);\n}\n\nexport function useSignalEffect(cb: () => void | (() => void)) {\n\tconst callback = useRef(cb);\n\tcallback.current = cb;\n\n\tuseEffect(() => {\n\t\treturn effect(() => {\n\t\t\treturn callback.current();\n\t\t});\n\t}, Empty);\n}\n"],"names":["Empty","Symbol","ReactMemoType","ProxyInstance","Map","SupportsProxy","Proxy","apply","Component","thisArg","argumentsList","useMemo","createEffectStore","useSyncExternalStore","store","subscribe","getSnapshot","updater","_start","e","stop","ProxyFunctionalComponent","get","ProxyComponent","ProxyHandlers","set","WrappedComponent","undefined","arguments","WrapWithProxy","onChangeNotifyReact","version","unsubscribe","effect","this","_callback","onStoreChange","WrapJsx","jsx","type","props","slice","call","rest","$$typeof","i","v","Signal","value","concat","JsxPro","jsxRuntime","JsxDev","jsxRuntimeDev","React","createElement","jsxs","jsxDEV","Object","defineProperties","prototype","configurable","ReactElemType","_ref","data","ref","useComputed","compute","$compute","useRef","current","computed","useSignalEffect","cb","callback","useEffect","useSignal"],"mappings":"0XAuBA,IAAWA,EAAG,KACQC,WAAW,iBACdC,EAAGD,OAAM,IAAK,cAC3BE,EAAgB,IAAIC,IACPC,EAAoB,mBAAjBC,QAEA,CAYrBC,MAZqB,SAYfC,EAA8BC,EAAcC,GACjD,MAAcC,EAAQC,EAAmBZ,GAEzCa,EAAqBC,EAAMC,UAAWD,EAAME,YAAaF,EAAME,aAE/D,MAAaF,EAAMG,QAAQC,IAE3B,IAEC,OADiBV,EAAUD,MAAME,EAASC,EAU1C,CARC,MAAOS,GAGR,MAAMA,CACN,CAPD,QAUCC,GACA,CACD,GAGF,SAASC,EAAyBb,GACjC,SAAqBc,IAAId,IAE1B,SAAuBA,GACtB,GAAIH,EAAe,CAClB,IAAMkB,EAAiB,IAAIjB,MAAME,EAAWgB,GAE5CrB,EAAcsB,IAAIjB,EAAWe,GAC7BpB,EAAcsB,IAAIF,EAAgBA,GAElC,OACAA,CAAA,CAgBD,IAAsBG,EAAG,WACxB,OAAoBF,EAACjB,MAAMC,OAAWmB,EAAWC,UACjD,EACDzB,EAAcsB,IAAIjB,EAAWkB,GAC7BvB,EAAcsB,IAAIC,EAAkBA,GAEpC,OAAOA,CACP,CAjCuCG,CAAcrB,EACrD,CA+CD,SAASI,IACR,IAAAK,EAEAa,EADIC,EAAU,EAGCC,EAAGC,EAAO,WACxBhB,EAAUiB,IACV,GACDjB,EAAQkB,EAAY,WACnBJ,EAAWA,EAAU,EAAK,EAC1B,GAAID,EAAqBA,GACzB,EAED,MAAO,CACNb,QAAAA,EACAF,UAAUqB,SAAAA,GACTN,EAAsBM,EAEtB,OAAO,WAWNL,EAAWA,EAAU,EAAK,EAC1BD,OAAsBH,EACtBK,GACA,CACD,EACDhB,YArBM,WAsBL,OAAOe,CACP,EAEF,CAED,SAAAM,EAAoBC,GACnB,GAAmB,mBAARA,EAAoB,OAAAA,OAE/B,OAAO,SAAUC,EAAWC,GAA0B,MACrD,GAAAC,MAAAC,KAAAd,UAAA,GAAA,GAAoB,mBAAhBW,KAAgCA,aAAF/B,GACjC,SAAWkC,KAAJJ,MAAAA,EAASA,CAAAA,EAAKjB,EAAyBkB,GAAOC,GAAUG,OAAAA,IAGhE,GAAIJ,GAAwB,oBAAYA,EAAKK,WAAa1C,EAAe,CACxEqC,EAAKA,KAAOlB,EAAyBkB,EAAKA,MAC1C,SAAWG,WAAJJ,EAAG,CAAMA,EAAKC,EAAMC,GAAUG,OAAAA,GACrC,CAED,GAAoB,iBAAhBJ,GAA4BC,EAC/B,IAAK,IAALK,OAAqB,CACpB,IAAKC,EAAGN,EAAMK,GACd,GAAU,aAANA,GAAoBC,aAAaC,EACpCP,EAAMK,GAAKC,EAAEE,KAEd,CAGF,OAAOV,EAAII,WAAJJ,EAAG,CAAMA,EAAKC,EAAMC,GAAjBS,OAA2BN,GACzB,CACb,CAED,IAAMO,EAA2BC,EACrBC,EAAqBC,EASjCC,EAAMC,cAAgBlB,EAAQiB,EAAMC,eACpCH,EAAOd,MAAgBc,EAAOd,IAAMD,EAAQe,EAAOd,MACnDY,EAAOZ,MAAgBY,EAAOZ,IAAMD,EAAQa,EAAOZ,MACnDc,EAAOI,OAAgBJ,EAAOI,KAAOnB,EAAQe,EAAOI,OACpDN,EAAOM,OAAgBN,EAAOM,KAAOnB,EAAQa,EAAOM,OACpDJ,EAAOK,SAAgBL,EAAOK,OAASpB,EAAQe,EAAOK,SACtDP,EAAOO,SAAgBP,EAAOO,OAASpB,EAAQa,EAAOO,SAUtDC,OAAOC,iBAAiBZ,EAAOa,UAAW,CACzChB,SAAU,CAAEiB,cAAc,EAAMb,MAAOc,GACvCvB,KAAM,CAAEsB,cAAc,EAAMb,MAAO3B,EAPpC,SAAA0C,GACC,OADuCA,EAAxBC,KACHhB,KACZ,IAMAR,MAAO,CACNqB,cAAc,EACdvC,eACC,MAAO,CAAE0C,KAAM9B,KACf,GAEF+B,IAAK,CAAEJ,cAAc,EAAMb,MAAO,QAG7B,mBAAuBA,GAC5B,SAAe,WAAA,SAAgBA,EAAhB,EAAwBhD,EACvC,CAEK,SAAAkE,YAAyBC,GAC9B,IAAcC,EAAGC,EAAOF,GACxBC,EAASE,QAAUH,EACnB,OAAOxD,EAAQ,WAAM4D,OAAAA,EAAY,WAAA,OAAcH,EAACE,SAAf,EAAlB,EAA6CtE,EAC5D,CAEewE,SAAAA,gBAAgBC,GAC/B,IAAMC,EAAWL,EAAOI,GACxBC,EAASJ,QAAUG,EAEnBE,EAAU,WACT,OAAO1C,EAAO,WACb,OAAOyC,EAASJ,SAChB,EACD,EAAEtE,EACH,QAAAkE,YAAAU,UAAAJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@preact/signals-react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "",
|
|
6
6
|
"keywords": [],
|
|
@@ -35,16 +35,18 @@
|
|
|
35
35
|
},
|
|
36
36
|
"mangle": "../../mangle.json",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@preact/signals-core": "^1.2.
|
|
38
|
+
"@preact/signals-core": "^1.2.2",
|
|
39
|
+
"use-sync-external-store": "^1.2.0"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"react": "17.x || 18.x"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
|
-
"react": "^18.2.0",
|
|
45
|
-
"react-dom": "^18.2.0",
|
|
46
45
|
"@types/react": "^18.0.18",
|
|
47
|
-
"@types/react-dom": "^18.0.6"
|
|
46
|
+
"@types/react-dom": "^18.0.6",
|
|
47
|
+
"@types/use-sync-external-store": "^0.0.3",
|
|
48
|
+
"react": "^18.2.0",
|
|
49
|
+
"react-dom": "^18.2.0"
|
|
48
50
|
},
|
|
49
51
|
"scripts": {}
|
|
50
52
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,11 +2,13 @@ import {
|
|
|
2
2
|
useRef,
|
|
3
3
|
useMemo,
|
|
4
4
|
useEffect,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as internals,
|
|
5
|
+
Component,
|
|
6
|
+
type FunctionComponent,
|
|
8
7
|
} from "react";
|
|
9
8
|
import React from "react";
|
|
9
|
+
import jsxRuntime from "react/jsx-runtime";
|
|
10
|
+
import jsxRuntimeDev from "react/jsx-dev-runtime";
|
|
11
|
+
import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
|
|
10
12
|
import {
|
|
11
13
|
signal,
|
|
12
14
|
computed,
|
|
@@ -15,64 +17,183 @@ import {
|
|
|
15
17
|
Signal,
|
|
16
18
|
type ReadonlySignal,
|
|
17
19
|
} from "@preact/signals-core";
|
|
18
|
-
import { Effect,
|
|
20
|
+
import type { Effect, JsxRuntimeModule } from "./internal";
|
|
19
21
|
|
|
20
22
|
export { signal, computed, batch, effect, Signal, type ReadonlySignal };
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
const Empty = [] as const;
|
|
25
|
+
const ReactElemType = Symbol.for("react.element"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L15
|
|
26
|
+
const ReactMemoType = Symbol.for("react.memo"); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L30
|
|
27
|
+
const ProxyInstance = new Map<FunctionComponent<any>, FunctionComponent<any>>();
|
|
28
|
+
const SupportsProxy = typeof Proxy === "function";
|
|
29
|
+
|
|
30
|
+
const ProxyHandlers = {
|
|
31
|
+
/**
|
|
32
|
+
* This is a function call trap for functional components.
|
|
33
|
+
* When this is called, we know it means React did run 'Component()',
|
|
34
|
+
* that means we can use any hooks here to setup our effect and store.
|
|
35
|
+
*
|
|
36
|
+
* With the native Proxy, all other calls such as access/setting to/of properties will
|
|
37
|
+
* be forwarded to the target Component, so we don't need to copy the Component's
|
|
38
|
+
* own or inherited properties.
|
|
39
|
+
*
|
|
40
|
+
* @see https://github.com/facebook/react/blob/2d80a0cd690bb5650b6c8a6c079a87b5dc42bd15/packages/react-reconciler/src/ReactFiberHooks.old.js#L460
|
|
41
|
+
*/
|
|
42
|
+
apply(Component: FunctionComponent, thisArg: any, argumentsList: any) {
|
|
43
|
+
const store = useMemo(createEffectStore, Empty);
|
|
44
|
+
|
|
45
|
+
useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
46
|
+
|
|
47
|
+
const stop = store.updater._start();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const children = Component.apply(thisArg, argumentsList);
|
|
51
|
+
return children;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
// Re-throwing promises that'll be handled by suspense
|
|
54
|
+
// or an actual error.
|
|
55
|
+
throw e;
|
|
56
|
+
} finally {
|
|
57
|
+
// Stop effects in either case before return or throw,
|
|
58
|
+
// Otherwise the effect will leak.
|
|
59
|
+
stop();
|
|
36
60
|
}
|
|
37
|
-
}
|
|
38
|
-
// @ts-ignore-next-line
|
|
39
|
-
return createElement.apply(this, arguments);
|
|
61
|
+
},
|
|
40
62
|
};
|
|
41
63
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
function createPropUpdater(props: any, prop: string, signal: Signal) {
|
|
45
|
-
let ref = props.ref;
|
|
46
|
-
if (!ref) ref = props.ref = React.createRef();
|
|
47
|
-
effect(() => {
|
|
48
|
-
if (props) props[prop] = signal.value;
|
|
49
|
-
let el = ref.current;
|
|
50
|
-
if (!el) return; // unsubscribe
|
|
51
|
-
(el as any)[prop] = signal.value;
|
|
52
|
-
});
|
|
53
|
-
props = null;
|
|
64
|
+
function ProxyFunctionalComponent(Component: FunctionComponent<any>) {
|
|
65
|
+
return ProxyInstance.get(Component) || WrapWithProxy(Component);
|
|
54
66
|
}
|
|
55
|
-
|
|
67
|
+
function WrapWithProxy(Component: FunctionComponent<any>) {
|
|
68
|
+
if (SupportsProxy) {
|
|
69
|
+
const ProxyComponent = new Proxy(Component, ProxyHandlers);
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
71
|
+
ProxyInstance.set(Component, ProxyComponent);
|
|
72
|
+
ProxyInstance.set(ProxyComponent, ProxyComponent);
|
|
59
73
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
return ProxyComponent;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Emulate a Proxy if environment doesn't support it.
|
|
79
|
+
*
|
|
80
|
+
* @TODO - unlike Proxy, it's not possible to access the type/Component's
|
|
81
|
+
* static properties this way. Not sure if we want to copy all statics here.
|
|
82
|
+
* Omitting this for now.
|
|
83
|
+
*
|
|
84
|
+
* @example - works with Proxy, doesn't with wrapped function.
|
|
85
|
+
* ```
|
|
86
|
+
* const el = <SomeFunctionalComponent />
|
|
87
|
+
* el.type.someOwnOrInheritedProperty;
|
|
88
|
+
* el.type.defaultProps;
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
const WrappedComponent = function () {
|
|
92
|
+
return ProxyHandlers.apply(Component, undefined, arguments);
|
|
93
|
+
};
|
|
94
|
+
ProxyInstance.set(Component, WrappedComponent);
|
|
95
|
+
ProxyInstance.set(WrappedComponent, WrappedComponent);
|
|
96
|
+
|
|
97
|
+
return WrappedComponent;
|
|
65
98
|
}
|
|
66
99
|
|
|
67
|
-
|
|
100
|
+
/**
|
|
101
|
+
* A redux-like store whose store value is a positive 32bit integer (a 'version').
|
|
102
|
+
*
|
|
103
|
+
* React subscribes to this store and gets a snapshot of the current 'version',
|
|
104
|
+
* whenever the 'version' changes, we tell React it's time to update the component (call 'onStoreChange').
|
|
105
|
+
*
|
|
106
|
+
* How we achieve this is by creating a binding with an 'effect', when the `effect._callback' is called,
|
|
107
|
+
* we update our store version and tell React to re-render the component ([1] We don't really care when/how React does it).
|
|
108
|
+
*
|
|
109
|
+
* [1]
|
|
110
|
+
* @see https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore
|
|
111
|
+
* @see https://github.com/reactjs/rfcs/blob/main/text/0214-use-sync-external-store.md
|
|
112
|
+
*/
|
|
113
|
+
function createEffectStore() {
|
|
68
114
|
let updater!: Effect;
|
|
69
|
-
|
|
115
|
+
let version = 0;
|
|
116
|
+
let onChangeNotifyReact: (() => void) | undefined;
|
|
117
|
+
|
|
118
|
+
let unsubscribe = effect(function (this: Effect) {
|
|
70
119
|
updater = this;
|
|
71
120
|
});
|
|
72
|
-
updater._callback =
|
|
73
|
-
|
|
121
|
+
updater._callback = function () {
|
|
122
|
+
version = (version + 1) | 0;
|
|
123
|
+
if (onChangeNotifyReact) onChangeNotifyReact();
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
updater,
|
|
128
|
+
subscribe(onStoreChange: () => void) {
|
|
129
|
+
onChangeNotifyReact = onStoreChange;
|
|
130
|
+
|
|
131
|
+
return function () {
|
|
132
|
+
/**
|
|
133
|
+
* Rotate to next version when unsubscribing to ensure that components are re-run
|
|
134
|
+
* when subscribing again.
|
|
135
|
+
*
|
|
136
|
+
* In StrictMode, 'memo'-ed components seem to keep a stale snapshot version, so
|
|
137
|
+
* don't re-run after subscribing again if the version is the same as last time.
|
|
138
|
+
*
|
|
139
|
+
* Because we unsubscribe from the effect, the version may not change. We simply
|
|
140
|
+
* set a new initial version in case of stale snapshots here.
|
|
141
|
+
*/
|
|
142
|
+
version = (version + 1) | 0;
|
|
143
|
+
onChangeNotifyReact = undefined;
|
|
144
|
+
unsubscribe();
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
getSnapshot() {
|
|
148
|
+
return version;
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function WrapJsx<T>(jsx: T): T {
|
|
154
|
+
if (typeof jsx !== "function") return jsx;
|
|
155
|
+
|
|
156
|
+
return function (type: any, props: any, ...rest: any[]) {
|
|
157
|
+
if (typeof type === "function" && !(type instanceof Component)) {
|
|
158
|
+
return jsx.call(jsx, ProxyFunctionalComponent(type), props, ...rest);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (type && typeof type === "object" && type.$$typeof === ReactMemoType) {
|
|
162
|
+
type.type = ProxyFunctionalComponent(type.type);
|
|
163
|
+
return jsx.call(jsx, type, props, ...rest);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (typeof type === "string" && props) {
|
|
167
|
+
for (let i in props) {
|
|
168
|
+
let v = props[i];
|
|
169
|
+
if (i !== "children" && v instanceof Signal) {
|
|
170
|
+
props[i] = v.value;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return jsx.call(jsx, type, props, ...rest);
|
|
176
|
+
} as any as T;
|
|
74
177
|
}
|
|
75
178
|
|
|
179
|
+
const JsxPro: JsxRuntimeModule = jsxRuntime;
|
|
180
|
+
const JsxDev: JsxRuntimeModule = jsxRuntimeDev;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* createElement _may_ be called by jsx runtime as a fallback in certain cases,
|
|
184
|
+
* so we need to wrap it regardless.
|
|
185
|
+
*
|
|
186
|
+
* The jsx exports depend on the `NODE_ENV` var to ensure the users' bundler doesn't
|
|
187
|
+
* include both, so one of them will be set with `undefined` values.
|
|
188
|
+
*/
|
|
189
|
+
React.createElement = WrapJsx(React.createElement);
|
|
190
|
+
JsxDev.jsx && /* */ (JsxDev.jsx = WrapJsx(JsxDev.jsx));
|
|
191
|
+
JsxPro.jsx && /* */ (JsxPro.jsx = WrapJsx(JsxPro.jsx));
|
|
192
|
+
JsxDev.jsxs && /* */ (JsxDev.jsxs = WrapJsx(JsxDev.jsxs));
|
|
193
|
+
JsxPro.jsxs && /* */ (JsxPro.jsxs = WrapJsx(JsxPro.jsxs));
|
|
194
|
+
JsxDev.jsxDEV && /**/ (JsxDev.jsxDEV = WrapJsx(JsxDev.jsxDEV));
|
|
195
|
+
JsxPro.jsxDEV && /**/ (JsxPro.jsxDEV = WrapJsx(JsxPro.jsxDEV));
|
|
196
|
+
|
|
76
197
|
/**
|
|
77
198
|
* A wrapper component that renders a Signal's value directly as a Text node.
|
|
78
199
|
*/
|
|
@@ -81,11 +202,9 @@ function Text({ data }: { data: Signal }) {
|
|
|
81
202
|
}
|
|
82
203
|
|
|
83
204
|
// Decorate Signals so React renders them as <Text> components.
|
|
84
|
-
//@ts-ignore-next-line
|
|
85
|
-
const $$typeof = createElement("a").$$typeof;
|
|
86
205
|
Object.defineProperties(Signal.prototype, {
|
|
87
|
-
$$typeof: { configurable: true, value:
|
|
88
|
-
type: { configurable: true, value: Text },
|
|
206
|
+
$$typeof: { configurable: true, value: ReactElemType },
|
|
207
|
+
type: { configurable: true, value: ProxyFunctionalComponent(Text) },
|
|
89
208
|
props: {
|
|
90
209
|
configurable: true,
|
|
91
210
|
get() {
|
|
@@ -95,59 +214,14 @@ Object.defineProperties(Signal.prototype, {
|
|
|
95
214
|
ref: { configurable: true, value: null },
|
|
96
215
|
});
|
|
97
216
|
|
|
98
|
-
// Track the current dispatcher (roughly equiv to current component impl)
|
|
99
|
-
let lock = false;
|
|
100
|
-
const UPDATE = () => ({});
|
|
101
|
-
let currentDispatcher: ReactDispatcher;
|
|
102
|
-
Object.defineProperty(internals.ReactCurrentDispatcher, "current", {
|
|
103
|
-
get() {
|
|
104
|
-
return currentDispatcher;
|
|
105
|
-
},
|
|
106
|
-
set(api) {
|
|
107
|
-
currentDispatcher = api;
|
|
108
|
-
if (lock) return;
|
|
109
|
-
if (api && !isInvalidHookAccessor(api)) {
|
|
110
|
-
// prevent re-injecting useReducer when the Dispatcher
|
|
111
|
-
// context changes to run the reducer callback:
|
|
112
|
-
lock = true;
|
|
113
|
-
const rerender = api.useReducer(UPDATE, {})[1];
|
|
114
|
-
lock = false;
|
|
115
|
-
|
|
116
|
-
let updater = updaterForComponent.get(rerender);
|
|
117
|
-
if (!updater) {
|
|
118
|
-
updater = createUpdater(rerender);
|
|
119
|
-
updaterForComponent.set(rerender, updater);
|
|
120
|
-
} else {
|
|
121
|
-
updater._callback = rerender;
|
|
122
|
-
}
|
|
123
|
-
setCurrentUpdater(updater);
|
|
124
|
-
} else {
|
|
125
|
-
setCurrentUpdater();
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// We inject a useReducer into every function component via CurrentDispatcher.
|
|
131
|
-
// This prevents injecting into anything other than a function component render.
|
|
132
|
-
const invalidHookAccessors = new Map();
|
|
133
|
-
function isInvalidHookAccessor(api: ReactDispatcher) {
|
|
134
|
-
const cached = invalidHookAccessors.get(api);
|
|
135
|
-
if (cached !== undefined) return cached;
|
|
136
|
-
// we only want the real implementation, not the warning ones
|
|
137
|
-
const invalid =
|
|
138
|
-
api.useCallback.length < 2 || /Invalid/.test(api.useCallback as any);
|
|
139
|
-
invalidHookAccessors.set(api, invalid);
|
|
140
|
-
return invalid;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
217
|
export function useSignal<T>(value: T) {
|
|
144
|
-
return useMemo(() => signal<T>(value),
|
|
218
|
+
return useMemo(() => signal<T>(value), Empty);
|
|
145
219
|
}
|
|
146
220
|
|
|
147
221
|
export function useComputed<T>(compute: () => T) {
|
|
148
222
|
const $compute = useRef(compute);
|
|
149
223
|
$compute.current = compute;
|
|
150
|
-
return useMemo(() => computed<T>(() => $compute.current()),
|
|
224
|
+
return useMemo(() => computed<T>(() => $compute.current()), Empty);
|
|
151
225
|
}
|
|
152
226
|
|
|
153
227
|
export function useSignalEffect(cb: () => void | (() => void)) {
|
|
@@ -158,5 +232,5 @@ export function useSignalEffect(cb: () => void | (() => void)) {
|
|
|
158
232
|
return effect(() => {
|
|
159
233
|
return callback.current();
|
|
160
234
|
});
|
|
161
|
-
},
|
|
235
|
+
}, Empty);
|
|
162
236
|
}
|
package/src/internal.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export interface Effect {
|
|
|
7
7
|
_dispose(): void;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export interface ReactDispatcher {
|
|
11
|
-
useCallback(): unknown;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
10
|
export type Updater = Signal<unknown>;
|
|
11
|
+
|
|
12
|
+
export interface JsxRuntimeModule {
|
|
13
|
+
jsx?(type: any, ...rest: any[]): unknown;
|
|
14
|
+
jsxs?(type: any, ...rest: any[]): unknown;
|
|
15
|
+
jsxDEV?(type: any, ...rest: any[]): unknown;
|
|
16
|
+
}
|
package/test/index.test.tsx
CHANGED
|
@@ -4,6 +4,7 @@ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
|
4
4
|
import { signal, useComputed } from "@preact/signals-react";
|
|
5
5
|
import { createElement, useMemo, memo, StrictMode } from "react";
|
|
6
6
|
import { createRoot, Root } from "react-dom/client";
|
|
7
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
7
8
|
import { act } from "react-dom/test-utils";
|
|
8
9
|
|
|
9
10
|
describe("@preact/signals-react", () => {
|
|
@@ -162,6 +163,26 @@ describe("@preact/signals-react", () => {
|
|
|
162
163
|
it("should consistently rerender in strict mode", async () => {
|
|
163
164
|
const sig = signal<string>(null!);
|
|
164
165
|
|
|
166
|
+
const Test = () => <p>{sig.value}</p>;
|
|
167
|
+
const App = () => (
|
|
168
|
+
<StrictMode>
|
|
169
|
+
<Test />
|
|
170
|
+
</StrictMode>
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
for (let i = 0; i < 3; i++) {
|
|
174
|
+
const value = `${i}`;
|
|
175
|
+
|
|
176
|
+
act(() => {
|
|
177
|
+
sig.value = value;
|
|
178
|
+
render(<App />);
|
|
179
|
+
});
|
|
180
|
+
expect(scratch.textContent).to.equal(value);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
it("should consistently rerender in strict mode (with memo)", async () => {
|
|
184
|
+
const sig = signal<string>(null!);
|
|
185
|
+
|
|
165
186
|
const Test = memo(() => <p>{sig.value}</p>);
|
|
166
187
|
const App = () => (
|
|
167
188
|
<StrictMode>
|
|
@@ -179,5 +200,26 @@ describe("@preact/signals-react", () => {
|
|
|
179
200
|
expect(scratch.textContent).to.equal(value);
|
|
180
201
|
}
|
|
181
202
|
});
|
|
203
|
+
it("should render static markup of a component", async () => {
|
|
204
|
+
const count = signal(0);
|
|
205
|
+
|
|
206
|
+
const Test = () => {
|
|
207
|
+
return (
|
|
208
|
+
<pre>
|
|
209
|
+
{renderToStaticMarkup(<code>{count}</code>)}
|
|
210
|
+
{renderToStaticMarkup(<code>{count.value}</code>)}
|
|
211
|
+
</pre>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
for (let i = 0; i < 3; i++) {
|
|
215
|
+
act(() => {
|
|
216
|
+
count.value += 1;
|
|
217
|
+
render(<Test />);
|
|
218
|
+
});
|
|
219
|
+
expect(scratch.textContent).to.equal(
|
|
220
|
+
`<code>${count.value}</code><code>${count.value}</code>`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
182
224
|
});
|
|
183
225
|
});
|