react-state-custom 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/extensions.json +5 -0
- package/.vscode/settings.json +8 -0
- package/.yarnrc.yml +1 -0
- package/README.md +57 -0
- package/dist/components/MyComponent.d.ts +7 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.es.js +1013 -0
- package/dist/index.umd.js +22 -0
- package/dist/state-utils/createRootCtx.d.ts +5 -0
- package/dist/state-utils/ctx.d.ts +94 -0
- package/dist/state-utils/useQuickSubscribe.d.ts +2 -0
- package/dist/state-utils/useQuickSubscribeV2.d.ts +2 -0
- package/dist/state-utils/useRefValue.d.ts +1 -0
- package/fix-vscode-yarn-pnp.sh +26 -0
- package/package.json +35 -0
- package/src/components/MyComponent.tsx +17 -0
- package/src/index.ts +19 -0
- package/src/state-utils/createRootCtx.tsx +56 -0
- package/src/state-utils/ctx.ts +308 -0
- package/src/state-utils/useQuickSubscribe.ts +115 -0
- package/src/state-utils/useQuickSubscribeV2.ts +93 -0
- package/src/state-utils/useRefValue.ts +8 -0
- package/tsconfig.json +18 -0
- package/vite.config.ts +33 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
(function(y,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],m):(y=typeof globalThis<"u"?globalThis:y||self,m(y.RState={},y.React))})(this,function(y,m){"use strict";var fr=Object.defineProperty;var cr=(y,m,W)=>m in y?fr(y,m,{enumerable:!0,configurable:!0,writable:!0,value:W}):y[m]=W;var ne=(y,m,W)=>cr(y,typeof m!="symbol"?m+"":m,W);function W(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var B={exports:{}},le;function Ae(){if(le)return B.exports;le=1;var e=typeof Reflect=="object"?Reflect:null,t=e&&typeof e.apply=="function"?e.apply:function(o,n,f){return Function.prototype.apply.call(o,n,f)},r;e&&typeof e.ownKeys=="function"?r=e.ownKeys:Object.getOwnPropertySymbols?r=function(o){return Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o))}:r=function(o){return Object.getOwnPropertyNames(o)};function u(s){console&&console.warn&&console.warn(s)}var c=Number.isNaN||function(o){return o!==o};function i(){i.init.call(this)}B.exports=i,B.exports.once=A,i.EventEmitter=i,i.prototype._events=void 0,i.prototype._eventsCount=0,i.prototype._maxListeners=void 0;var d=10;function h(s){if(typeof s!="function")throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof s)}Object.defineProperty(i,"defaultMaxListeners",{enumerable:!0,get:function(){return d},set:function(s){if(typeof s!="number"||s<0||c(s))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+s+".");d=s}}),i.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},i.prototype.setMaxListeners=function(o){if(typeof o!="number"||o<0||c(o))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+o+".");return this._maxListeners=o,this};function b(s){return s._maxListeners===void 0?i.defaultMaxListeners:s._maxListeners}i.prototype.getMaxListeners=function(){return b(this)},i.prototype.emit=function(o){for(var n=[],f=1;f<arguments.length;f++)n.push(arguments[f]);var l=o==="error",g=this._events;if(g!==void 0)l=l&&g.error===void 0;else if(!l)return!1;if(l){var v;if(n.length>0&&(v=n[0]),v instanceof Error)throw v;var j=new Error("Unhandled error."+(v?" ("+v.message+")":""));throw j.context=v,j}var M=g[o];if(M===void 0)return!1;if(typeof M=="function")t(M,this,n);else for(var re=M.length,K=F(M,re),f=0;f<re;++f)t(K[f],this,n);return!0};function _(s,o,n,f){var l,g,v;if(h(n),g=s._events,g===void 0?(g=s._events=Object.create(null),s._eventsCount=0):(g.newListener!==void 0&&(s.emit("newListener",o,n.listener?n.listener:n),g=s._events),v=g[o]),v===void 0)v=g[o]=n,++s._eventsCount;else if(typeof v=="function"?v=g[o]=f?[n,v]:[v,n]:f?v.unshift(n):v.push(n),l=b(s),l>0&&v.length>l&&!v.warned){v.warned=!0;var j=new Error("Possible EventEmitter memory leak detected. "+v.length+" "+String(o)+" listeners added. Use emitter.setMaxListeners() to increase limit");j.name="MaxListenersExceededWarning",j.emitter=s,j.type=o,j.count=v.length,u(j)}return s}i.prototype.addListener=function(o,n){return _(this,o,n,!1)},i.prototype.on=i.prototype.addListener,i.prototype.prependListener=function(o,n){return _(this,o,n,!0)};function O(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function w(s,o,n){var f={fired:!1,wrapFn:void 0,target:s,type:o,listener:n},l=O.bind(f);return l.listener=n,f.wrapFn=l,l}i.prototype.once=function(o,n){return h(n),this.on(o,w(this,o,n)),this},i.prototype.prependOnceListener=function(o,n){return h(n),this.prependListener(o,w(this,o,n)),this},i.prototype.removeListener=function(o,n){var f,l,g,v,j;if(h(n),l=this._events,l===void 0)return this;if(f=l[o],f===void 0)return this;if(f===n||f.listener===n)--this._eventsCount===0?this._events=Object.create(null):(delete l[o],l.removeListener&&this.emit("removeListener",o,f.listener||n));else if(typeof f!="function"){for(g=-1,v=f.length-1;v>=0;v--)if(f[v]===n||f[v].listener===n){j=f[v].listener,g=v;break}if(g<0)return this;g===0?f.shift():E(f,g),f.length===1&&(l[o]=f[0]),l.removeListener!==void 0&&this.emit("removeListener",o,j||n)}return this},i.prototype.off=i.prototype.removeListener,i.prototype.removeAllListeners=function(o){var n,f,l;if(f=this._events,f===void 0)return this;if(f.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):f[o]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete f[o]),this;if(arguments.length===0){var g=Object.keys(f),v;for(l=0;l<g.length;++l)v=g[l],v!=="removeListener"&&this.removeAllListeners(v);return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}if(n=f[o],typeof n=="function")this.removeListener(o,n);else if(n!==void 0)for(l=n.length-1;l>=0;l--)this.removeListener(o,n[l]);return this};function L(s,o,n){var f=s._events;if(f===void 0)return[];var l=f[o];return l===void 0?[]:typeof l=="function"?n?[l.listener||l]:[l]:n?S(l):F(l,l.length)}i.prototype.listeners=function(o){return L(this,o,!0)},i.prototype.rawListeners=function(o){return L(this,o,!1)},i.listenerCount=function(s,o){return typeof s.listenerCount=="function"?s.listenerCount(o):P.call(s,o)},i.prototype.listenerCount=P;function P(s){var o=this._events;if(o!==void 0){var n=o[s];if(typeof n=="function")return 1;if(n!==void 0)return n.length}return 0}i.prototype.eventNames=function(){return this._eventsCount>0?r(this._events):[]};function F(s,o){for(var n=new Array(o),f=0;f<o;++f)n[f]=s[f];return n}function E(s,o){for(;o+1<s.length;o++)s[o]=s[o+1];s.pop()}function S(s){for(var o=new Array(s.length),n=0;n<o.length;++n)o[n]=s[n].listener||s[n];return o}function A(s,o){return new Promise(function(n,f){function l(v){s.removeListener(o,g),f(v)}function g(){typeof s.removeListener=="function"&&s.removeListener("error",l),n([].slice.call(arguments))}U(s,o,g,{once:!0}),o!=="error"&&G(s,l,{once:!0})})}function G(s,o,n){typeof s.on=="function"&&U(s,"error",o,n)}function U(s,o,n,f){if(typeof s.on=="function")f.once?s.once(o,n):s.on(o,n);else if(typeof s.addEventListener=="function")s.addEventListener(o,function l(g){f.once&&s.removeEventListener(o,l),n(g)});else throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof s)}return B.exports}var Me=Ae();const De=W(Me);var Ie=typeof global=="object"&&global&&global.Object===Object&&global,ke=typeof self=="object"&&self&&self.Object===Object&&self,Q=Ie||ke||Function("return this")(),Z=Q.Symbol,de=Object.prototype,Fe=de.hasOwnProperty,We=de.toString,x=Z?Z.toStringTag:void 0;function ze(e){var t=Fe.call(e,x),r=e[x];try{e[x]=void 0;var u=!0}catch{}var c=We.call(e);return u&&(t?e[x]=r:delete e[x]),c}var Ye=Object.prototype,Ge=Ye.toString;function Ue(e){return Ge.call(e)}var Ve="[object Null]",xe="[object Undefined]",he=Z?Z.toStringTag:void 0;function pe(e){return e==null?e===void 0?xe:Ve:he&&he in Object(e)?ze(e):Ue(e)}function He(e){return e!=null&&typeof e=="object"}var Je="[object Symbol]";function Xe(e){return typeof e=="symbol"||He(e)&&pe(e)==Je}var Ke=/\s/;function Be(e){for(var t=e.length;t--&&Ke.test(e.charAt(t)););return t}var Qe=/^\s+/;function Ze(e){return e&&e.slice(0,Be(e)+1).replace(Qe,"")}function z(e){var t=typeof e;return e!=null&&(t=="object"||t=="function")}var ve=NaN,$e=/^[-+]0x[0-9a-f]+$/i,qe=/^0b[01]+$/i,et=/^0o[0-7]+$/i,tt=parseInt;function me(e){if(typeof e=="number")return e;if(Xe(e))return ve;if(z(e)){var t=typeof e.valueOf=="function"?e.valueOf():e;e=z(t)?t+"":t}if(typeof e!="string")return e===0?e:+e;e=Ze(e);var r=qe.test(e);return r||et.test(e)?tt(e.slice(2),r?2:8):$e.test(e)?ve:+e}var rt="[object AsyncFunction]",nt="[object Function]",ot="[object GeneratorFunction]",at="[object Proxy]";function it(e){if(!z(e))return!1;var t=pe(e);return t==nt||t==ot||t==rt||t==at}var oe=Q["__core-js_shared__"],be=function(){var e=/[^.]+$/.exec(oe&&oe.keys&&oe.keys.IE_PROTO||"");return e?"Symbol(src)_1."+e:""}();function st(e){return!!be&&be in e}var ut=Function.prototype,ft=ut.toString;function ct(e){if(e!=null){try{return ft.call(e)}catch{}try{return e+""}catch{}}return""}var lt=/[\\^$.*+?()[\]{}|]/g,dt=/^\[object .+?Constructor\]$/,ht=Function.prototype,pt=Object.prototype,vt=ht.toString,mt=pt.hasOwnProperty,bt=RegExp("^"+vt.call(mt).replace(lt,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function gt(e){if(!z(e)||st(e))return!1;var t=it(e)?bt:dt;return t.test(ct(e))}function _t(e,t){return e==null?void 0:e[t]}function ge(e,t){var r=_t(e,t);return gt(r)?r:void 0}function Et(e,t){return e===t||e!==e&&t!==t}var H=ge(Object,"create");function yt(){this.__data__=H?H(null):{},this.size=0}function Tt(e){var t=this.has(e)&&delete this.__data__[e];return this.size-=t?1:0,t}var Ot="__lodash_hash_undefined__",wt=Object.prototype,St=wt.hasOwnProperty;function Rt(e){var t=this.__data__;if(H){var r=t[e];return r===Ot?void 0:r}return St.call(t,e)?t[e]:void 0}var Ct=Object.prototype,jt=Ct.hasOwnProperty;function Lt(e){var t=this.__data__;return H?t[e]!==void 0:jt.call(t,e)}var Pt="__lodash_hash_undefined__";function Nt(e,t){var r=this.__data__;return this.size+=this.has(e)?0:1,r[e]=H&&t===void 0?Pt:t,this}function I(e){var t=-1,r=e==null?0:e.length;for(this.clear();++t<r;){var u=e[t];this.set(u[0],u[1])}}I.prototype.clear=yt,I.prototype.delete=Tt,I.prototype.get=Rt,I.prototype.has=Lt,I.prototype.set=Nt;function At(){this.__data__=[],this.size=0}function $(e,t){for(var r=e.length;r--;)if(Et(e[r][0],t))return r;return-1}var Mt=Array.prototype,Dt=Mt.splice;function It(e){var t=this.__data__,r=$(t,e);if(r<0)return!1;var u=t.length-1;return r==u?t.pop():Dt.call(t,r,1),--this.size,!0}function kt(e){var t=this.__data__,r=$(t,e);return r<0?void 0:t[r][1]}function Ft(e){return $(this.__data__,e)>-1}function Wt(e,t){var r=this.__data__,u=$(r,e);return u<0?(++this.size,r.push([e,t])):r[u][1]=t,this}function Y(e){var t=-1,r=e==null?0:e.length;for(this.clear();++t<r;){var u=e[t];this.set(u[0],u[1])}}Y.prototype.clear=At,Y.prototype.delete=It,Y.prototype.get=kt,Y.prototype.has=Ft,Y.prototype.set=Wt;var zt=ge(Q,"Map");function Yt(){this.size=0,this.__data__={hash:new I,map:new(zt||Y),string:new I}}function Gt(e){var t=typeof e;return t=="string"||t=="number"||t=="symbol"||t=="boolean"?e!=="__proto__":e===null}function q(e,t){var r=e.__data__;return Gt(t)?r[typeof t=="string"?"string":"hash"]:r.map}function Ut(e){var t=q(this,e).delete(e);return this.size-=t?1:0,t}function Vt(e){return q(this,e).get(e)}function xt(e){return q(this,e).has(e)}function Ht(e,t){var r=q(this,e),u=r.size;return r.set(e,t),this.size+=r.size==u?0:1,this}function k(e){var t=-1,r=e==null?0:e.length;for(this.clear();++t<r;){var u=e[t];this.set(u[0],u[1])}}k.prototype.clear=Yt,k.prototype.delete=Ut,k.prototype.get=Vt,k.prototype.has=xt,k.prototype.set=Ht;var Jt="Expected a function";function ae(e,t){if(typeof e!="function"||t!=null&&typeof t!="function")throw new TypeError(Jt);var r=function(){var u=arguments,c=t?t.apply(this,u):u[0],i=r.cache;if(i.has(c))return i.get(c);var d=e.apply(this,u);return r.cache=i.set(c,d)||i,d};return r.cache=new(ae.Cache||k),r}ae.Cache=k;var ie=function(){return Q.Date.now()},Xt="Expected a function",Kt=Math.max,Bt=Math.min;function ee(e,t,r){var u,c,i,d,h,b,_=0,O=!1,w=!1,L=!0;if(typeof e!="function")throw new TypeError(Xt);t=me(t)||0,z(r)&&(O=!!r.leading,w="maxWait"in r,i=w?Kt(me(r.maxWait)||0,t):i,L="trailing"in r?!!r.trailing:L);function P(n){var f=u,l=c;return u=c=void 0,_=n,d=e.apply(l,f),d}function F(n){return _=n,h=setTimeout(A,t),O?P(n):d}function E(n){var f=n-b,l=n-_,g=t-f;return w?Bt(g,i-l):g}function S(n){var f=n-b,l=n-_;return b===void 0||f>=t||f<0||w&&l>=i}function A(){var n=ie();if(S(n))return G(n);h=setTimeout(A,E(n))}function G(n){return h=void 0,L&&u?P(n):(u=c=void 0,d)}function U(){h!==void 0&&clearTimeout(h),_=0,u=b=c=h=void 0}function s(){return h===void 0?d:G(ie())}function o(){var n=ie(),f=S(n);if(u=arguments,c=this,b=n,f){if(h===void 0)return F(b);if(w)return clearTimeout(h),h=setTimeout(A,t),P(b)}return h===void 0&&(h=setTimeout(A,t)),d}return o.cancel=U,o.flush=s,o}var Qt="Expected a function";function Zt(e,t,r){var u=!0,c=!0;if(typeof e!="function")throw new TypeError(Qt);return z(r)&&(u="leading"in r?!!r.leading:u,c="trailing"in r?!!r.trailing:c),ee(e,t,{leading:u,maxWait:t,trailing:c})}class _e{constructor(t){ne(this,"event",new De.EventEmitter);ne(this,"data",{});ne(this,"registry",new Set);this.name=t,console.log("[CONTEXT] %s",t),this.event.setMaxListeners(100)}publish(t,r){r!=this.data[t]&&(this.data[t]=r,this.event.emit(String(t),{value:r}))}subscribe(t,r){const u=({value:c})=>{r(c)};return this.event.addListener(String(t),u),console.log("listenerCount:",String(t),this.event.listenerCount(String(t))),t in this.data&&r(this.data[t]),()=>(this.event.removeListener(String(t),u),void 0)}}const Ee=ae(e=>new _e(e)),se=(e="noname")=>m.useMemo(()=>Ee(e),[e]),ye=(e,...t)=>{const r=new Error("[ctx] useRegistryChecker failed "+JSON.stringify({names:t,ctx:(e==null?void 0:e.name)??"undefined"}));m.useEffect(()=>{if(e)return t.some(u=>e.registry.has(u))&&console.error(r),t.forEach(u=>e.registry.add(u)),()=>{t.forEach(u=>e.registry.delete(u))}},[e,t.length])},$t=(e,t,r)=>{m.useEffect(()=>{e&&e.data[t]!=r&&e.publish(t,r)},[t,r,e]),ye(e,t)},qt=(e,t,r=0)=>{const[{value:u},c]=m.useState(()=>{var i;return{value:(i=e==null?void 0:e.data)==null?void 0:i[t]}});return m.useEffect(()=>{if(e){let i=r==0?h=>c({value:h}):ee(h=>c({value:h}),r),d=e.subscribe(t,i);return u!=e.data[t]&&c({value:e.data[t]}),()=>{d()}}},[t,e]),e==null?void 0:e.data[t]},er=(e,t,r)=>{const[,u]=m.useState(0),c=m.useMemo(()=>r(e==null?void 0:e.data[t]),[r,e==null?void 0:e.data[t]]);return m.useEffect(()=>{if(e){let i=c,d=()=>{let b=r(e.data[t]);b!=i&&(i=b,u(_=>_+1))},h=e.subscribe(t,d);return d(),()=>h()}},[t,e]),c},Te=(e,...t)=>{m.useEffect(()=>{if(e)for(let[r,u]of t)e.data[r]!=u&&e.publish(r,u)},[e,...t.flat()]),ye(e,...t.map(r=>r[0]))},tr=(e,...t)=>{const[,r]=m.useState(0),u=t.map(c=>{var i;return(i=e==null?void 0:e.data)==null?void 0:i[c]});return m.useEffect(()=>{if(e){let c=u;const i=ee(()=>{let b=t.map(_=>{var O;return(O=e==null?void 0:e.data)==null?void 0:O[_]});t.some((_,O)=>c[O]!=b[O])&&(c=b,r(_=>_+1))},1);let d=t.map(b=>e.subscribe(b,i)),h=setTimeout(i,1);return()=>{clearTimeout(h),i.cancel(),d.forEach(b=>b())}}},[e,...t]),Object.fromEntries(t.map((c,i)=>[c,u[i]]))},rr=(e,t=100,...r)=>{const[,u]=m.useState(0),c=r.map(i=>{var d;return(d=e==null?void 0:e.data)==null?void 0:d[i]});return m.useEffect(()=>{if(e){let i=c;const d=Zt(()=>{let _=r.map(O=>{var w;return(w=e==null?void 0:e.data)==null?void 0:w[O]});r.some((O,w)=>i[w]!=_[w])&&(i=_,u(O=>O+1))},t);let h=r.map(_=>e.subscribe(_,d)),b=setTimeout(d,1);return()=>{clearTimeout(b),d.cancel(),h.forEach(_=>_())}}},[e,...r]),c};var te={exports:{}},J={};/**
|
|
2
|
+
* @license React
|
|
3
|
+
* react-jsx-runtime.production.js
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
6
|
+
*
|
|
7
|
+
* This source code is licensed under the MIT license found in the
|
|
8
|
+
* LICENSE file in the root directory of this source tree.
|
|
9
|
+
*/var Oe;function nr(){if(Oe)return J;Oe=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function r(u,c,i){var d=null;if(i!==void 0&&(d=""+i),c.key!==void 0&&(d=""+c.key),"key"in c){i={};for(var h in c)h!=="key"&&(i[h]=c[h])}else i=c;return c=i.ref,{$$typeof:e,type:u,key:d,ref:c!==void 0?c:null,props:i}}return J.Fragment=t,J.jsx=r,J.jsxs=r,J}var X={};/**
|
|
10
|
+
* @license React
|
|
11
|
+
* react-jsx-runtime.development.js
|
|
12
|
+
*
|
|
13
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
14
|
+
*
|
|
15
|
+
* This source code is licensed under the MIT license found in the
|
|
16
|
+
* LICENSE file in the root directory of this source tree.
|
|
17
|
+
*/var we;function or(){return we||(we=1,process.env.NODE_ENV!=="production"&&function(){function e(a){if(a==null)return null;if(typeof a=="function")return a.$$typeof===v?null:a.displayName||a.name||null;if(typeof a=="string")return a;switch(a){case E:return"Fragment";case A:return"Profiler";case S:return"StrictMode";case o:return"Suspense";case n:return"SuspenseList";case g:return"Activity"}if(typeof a=="object")switch(typeof a.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),a.$$typeof){case F:return"Portal";case U:return(a.displayName||"Context")+".Provider";case G:return(a._context.displayName||"Context")+".Consumer";case s:var p=a.render;return a=a.displayName,a||(a=p.displayName||p.name||"",a=a!==""?"ForwardRef("+a+")":"ForwardRef"),a;case f:return p=a.displayName||null,p!==null?p:e(a.type)||"Memo";case l:p=a._payload,a=a._init;try{return e(a(p))}catch{}}return null}function t(a){return""+a}function r(a){try{t(a);var p=!1}catch{p=!0}if(p){p=console;var T=p.error,R=typeof Symbol=="function"&&Symbol.toStringTag&&a[Symbol.toStringTag]||a.constructor.name||"Object";return T.call(p,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",R),t(a)}}function u(a){if(a===E)return"<>";if(typeof a=="object"&&a!==null&&a.$$typeof===l)return"<...>";try{var p=e(a);return p?"<"+p+">":"<...>"}catch{return"<...>"}}function c(){var a=j.A;return a===null?null:a.getOwner()}function i(){return Error("react-stack-top-frame")}function d(a){if(M.call(a,"key")){var p=Object.getOwnPropertyDescriptor(a,"key").get;if(p&&p.isReactWarning)return!1}return a.key!==void 0}function h(a,p){function T(){Ce||(Ce=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",p))}T.isReactWarning=!0,Object.defineProperty(a,"key",{get:T,configurable:!0})}function b(){var a=e(this.type);return je[a]||(je[a]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),a=this.props.ref,a!==void 0?a:null}function _(a,p,T,R,D,N,ue,fe){return T=N.ref,a={$$typeof:P,type:a,key:p,props:N,_owner:D},(T!==void 0?T:null)!==null?Object.defineProperty(a,"ref",{enumerable:!1,get:b}):Object.defineProperty(a,"ref",{enumerable:!1,value:null}),a._store={},Object.defineProperty(a._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(a,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(a,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:ue}),Object.defineProperty(a,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:fe}),Object.freeze&&(Object.freeze(a.props),Object.freeze(a)),a}function O(a,p,T,R,D,N,ue,fe){var C=p.children;if(C!==void 0)if(R)if(re(C)){for(R=0;R<C.length;R++)w(C[R]);Object.freeze&&Object.freeze(C)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else w(C);if(M.call(p,"key")){C=e(a);var V=Object.keys(p).filter(function(ur){return ur!=="key"});R=0<V.length?"{key: someKey, "+V.join(": ..., ")+": ...}":"{key: someKey}",Ne[C+R]||(V=0<V.length?"{"+V.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
18
|
+
let props = %s;
|
|
19
|
+
<%s {...props} />
|
|
20
|
+
React keys must be passed directly to JSX without using spread:
|
|
21
|
+
let props = %s;
|
|
22
|
+
<%s key={someKey} {...props} />`,R,C,V,C),Ne[C+R]=!0)}if(C=null,T!==void 0&&(r(T),C=""+T),d(p)&&(r(p.key),C=""+p.key),"key"in p){T={};for(var ce in p)ce!=="key"&&(T[ce]=p[ce])}else T=p;return C&&h(T,typeof a=="function"?a.displayName||a.name||"Unknown":a),_(a,C,N,D,c(),T,ue,fe)}function w(a){typeof a=="object"&&a!==null&&a.$$typeof===P&&a._store&&(a._store.validated=1)}var L=m,P=Symbol.for("react.transitional.element"),F=Symbol.for("react.portal"),E=Symbol.for("react.fragment"),S=Symbol.for("react.strict_mode"),A=Symbol.for("react.profiler"),G=Symbol.for("react.consumer"),U=Symbol.for("react.context"),s=Symbol.for("react.forward_ref"),o=Symbol.for("react.suspense"),n=Symbol.for("react.suspense_list"),f=Symbol.for("react.memo"),l=Symbol.for("react.lazy"),g=Symbol.for("react.activity"),v=Symbol.for("react.client.reference"),j=L.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,M=Object.prototype.hasOwnProperty,re=Array.isArray,K=console.createTask?console.createTask:function(){return null};L={"react-stack-bottom-frame":function(a){return a()}};var Ce,je={},Le=L["react-stack-bottom-frame"].bind(L,i)(),Pe=K(u(i)),Ne={};X.Fragment=E,X.jsx=function(a,p,T,R,D){var N=1e4>j.recentlyCreatedOwnerStacks++;return O(a,p,T,!1,R,D,N?Error("react-stack-top-frame"):Le,N?K(u(a)):Pe)},X.jsxs=function(a,p,T,R,D){var N=1e4>j.recentlyCreatedOwnerStacks++;return O(a,p,T,!0,R,D,N?Error("react-stack-top-frame"):Le,N?K(u(a)):Pe)}}()),X}var Se;function ar(){return Se||(Se=1,process.env.NODE_ENV==="production"?te.exports=nr():te.exports=or()),te.exports}var Re=ar();const ir=(e,t)=>{const r=c=>[e,...Object.entries(c??{}).sort((i,d)=>i[0].localeCompare(d[0])).flat()].join("-");let u=!1;return{Root:c=>{const i=se(r(c)),d=t(c),h=m.useMemo(()=>new Error().stack,[]);return Te(i,...Object.entries(d)),m.useEffect(()=>{if(u==!0){const b=new Error("RootContext "+r(c)+" are mounted more than once");throw b.stack=h,b}return u=!0,()=>{u=!1}}),Re.jsx(Re.Fragment,{})},useCtxState:c=>{const i=m.useMemo(()=>new Error().stack,[]);return m.useEffect(()=>{if(!u){const d=new Error("RootContext ["+r(c)+"] is not mounted");throw d.stack=i,d}},[u]),se(r(c))}}},sr=e=>{const[,t]=m.useState(0),{proxy:r,finalGetter:u,openGetter:c,clean:i}=m.useMemo(()=>{const d=new Set,h={},b=new Map,_=new Proxy(e==null?void 0:e.data,{get(E,S){if(O)return d.add(S),h[S]=E[S];throw new Error("now allow here")}});let O=!0,w=ee(()=>{[...d.values()].some(E=>{var S;return h[E]!=((S=e==null?void 0:e.data)==null?void 0:S[E])})&&t(E=>E+1)},0),L=()=>{O=!0,d.clear()},P=()=>{O=!1,[...d.values()].filter(E=>!b.has(E)).forEach(E=>{b.set(E,e==null?void 0:e.subscribe(E,w))}),[...b.keys()].filter(E=>!d.has(E)).forEach(E=>{let S=b.get(E);S==null||S(),b.delete(E)})};return{proxy:_,finalGetter:P,openGetter:L,clean:()=>{L(),P(),t(E=>E+1)}}},[]);return c(),setTimeout(u,0),m.useEffect(()=>()=>i(),[i]),r};y.Context=_e,y.createRootCtx=ir,y.getContext=Ee,y.useDataContext=se,y.useDataSource=$t,y.useDataSourceMultiple=Te,y.useDataSubscribe=qt,y.useDataSubscribeMultiple=tr,y.useDataSubscribeMultipleWithDebounce=rr,y.useDataSubscribeWithTransform=er,y.useQuickSubscribe=sr,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic context for managing shared state and event subscriptions.
|
|
3
|
+
* @template D - The shape of the data managed by the context.
|
|
4
|
+
*/
|
|
5
|
+
export declare class Context<D> {
|
|
6
|
+
name: string;
|
|
7
|
+
/**
|
|
8
|
+
* Create a new Context instance.
|
|
9
|
+
* @param name - The name of the context (for debugging).
|
|
10
|
+
*/
|
|
11
|
+
constructor(name: string);
|
|
12
|
+
private event;
|
|
13
|
+
/**
|
|
14
|
+
* The current data held by the context.
|
|
15
|
+
*/
|
|
16
|
+
data: Partial<D>;
|
|
17
|
+
/**
|
|
18
|
+
* Registry for tracking active keys (for duplicate detection).
|
|
19
|
+
*/
|
|
20
|
+
registry: Set<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Publish a value to the context and notify subscribers if it changed.
|
|
23
|
+
* @param key - The key to update.
|
|
24
|
+
* @param value - The new value.
|
|
25
|
+
*/
|
|
26
|
+
publish(key: keyof D, value: D[typeof key] | undefined): void;
|
|
27
|
+
/**
|
|
28
|
+
* Subscribe to changes for a specific key in the context.
|
|
29
|
+
* @param key - The key to subscribe to.
|
|
30
|
+
* @param listender - Callback invoked with the new value.
|
|
31
|
+
* @returns Unsubscribe function.
|
|
32
|
+
*/
|
|
33
|
+
subscribe(key: keyof D, listender: (e: D[typeof key] | undefined) => void): () => undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get or create a memoized Context instance by name.
|
|
37
|
+
* @param name - The context name.
|
|
38
|
+
* @returns The Context instance.
|
|
39
|
+
*/
|
|
40
|
+
export declare const getContext: ((name: string) => Context<any>) & import('lodash').MemoizedFunction;
|
|
41
|
+
/**
|
|
42
|
+
* Type alias for a function that returns a Context instance.
|
|
43
|
+
*/
|
|
44
|
+
export type getContext<D> = (e: string) => Context<D>;
|
|
45
|
+
/**
|
|
46
|
+
* React hook to get a typed Context instance by name.
|
|
47
|
+
* @param name - The context name.
|
|
48
|
+
* @returns The Context instance.
|
|
49
|
+
*/
|
|
50
|
+
export declare const useDataContext: <D>(name?: string) => Context<D>;
|
|
51
|
+
/**
|
|
52
|
+
* React hook to publish a value to the context when it changes.
|
|
53
|
+
* @param ctx - The context instance.
|
|
54
|
+
* @param key - The key to update.
|
|
55
|
+
* @param value - The new value.
|
|
56
|
+
*/
|
|
57
|
+
export declare const useDataSource: <D, K extends keyof D>(ctx: Context<D> | undefined, key: K, value: D[K] | undefined) => void;
|
|
58
|
+
/**
|
|
59
|
+
* React hook to subscribe to a context value, with optional debounce.
|
|
60
|
+
* @param ctx - The context instance.
|
|
61
|
+
* @param key - The key to subscribe to.
|
|
62
|
+
* @param debounceTime - Debounce time in ms (default 0).
|
|
63
|
+
* @returns The current value for the key.
|
|
64
|
+
*/
|
|
65
|
+
export declare const useDataSubscribe: <D, K extends keyof D>(ctx: Context<D> | undefined, key: K, debounceTime?: number) => D[K] | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* React hook to subscribe to a context value and transform it before returning.
|
|
68
|
+
* @param ctx - The context instance.
|
|
69
|
+
* @param key - The key to subscribe to.
|
|
70
|
+
* @param transform - Function to transform the value.
|
|
71
|
+
* @returns The transformed value.
|
|
72
|
+
*/
|
|
73
|
+
export declare const useDataSubscribeWithTransform: <D, K extends keyof D, E>(ctx: Context<D> | undefined, key: K, transform: (e: D[K] | undefined) => E) => E;
|
|
74
|
+
/**
|
|
75
|
+
* React hook to publish multiple values to the context.
|
|
76
|
+
* @param ctx - The context instance.
|
|
77
|
+
* @param entries - Array of [key, value] pairs to update.
|
|
78
|
+
*/
|
|
79
|
+
export declare const useDataSourceMultiple: <D, T extends readonly (keyof D)[]>(ctx: Context<D> | undefined, ...entries: { -readonly [P in keyof T]: [T[P], D[T[P]]]; }) => void;
|
|
80
|
+
/**
|
|
81
|
+
* React hook to subscribe to multiple context values.
|
|
82
|
+
* @param ctx - The context instance.
|
|
83
|
+
* @param keys - Keys to subscribe to.
|
|
84
|
+
* @returns An object with the current values for the keys.
|
|
85
|
+
*/
|
|
86
|
+
export declare const useDataSubscribeMultiple: <D, K extends keyof D>(ctx: Context<D> | undefined, ...keys: K[]) => Pick<D, K>;
|
|
87
|
+
/**
|
|
88
|
+
* React hook to subscribe to multiple context values with throttling.
|
|
89
|
+
* @param ctx - The context instance.
|
|
90
|
+
* @param debounceTime - Throttle time in ms (default 100).
|
|
91
|
+
* @param keys - Keys to subscribe to.
|
|
92
|
+
* @returns Array of current values for the keys.
|
|
93
|
+
*/
|
|
94
|
+
export declare const useDataSubscribeMultipleWithDebounce: <D, K extends (keyof D)[]>(ctx: Context<D> | undefined, debounceTime?: number, ...keys: K) => { [i in keyof K]: D[K[i]] | undefined; };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useRefValue: <T extends object>(e: T) => T;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Fix VS Code + Yarn PnP TypeScript/module resolution issues
|
|
3
|
+
|
|
4
|
+
# 1. Set Yarn to use Plug'n'Play (PnP)
|
|
5
|
+
yarn config set nodeLinker pnp
|
|
6
|
+
|
|
7
|
+
# 2. Install dependencies
|
|
8
|
+
yarn install
|
|
9
|
+
|
|
10
|
+
# 3. Install Yarn SDKs for editor support
|
|
11
|
+
yarn dlx @yarnpkg/sdks vscode
|
|
12
|
+
|
|
13
|
+
# 4. Create VS Code settings for TypeScript SDK
|
|
14
|
+
mkdir -p .vscode
|
|
15
|
+
cat > .vscode/settings.json <<EOL
|
|
16
|
+
{
|
|
17
|
+
"typescript.tsdk": ".yarn/sdks/typescript/lib",
|
|
18
|
+
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
19
|
+
"search.exclude": {
|
|
20
|
+
"**/.yarn": true,
|
|
21
|
+
"**/.pnp.*": true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
EOL
|
|
25
|
+
|
|
26
|
+
echo "VS Code + Yarn PnP fix complete! Reload VS Code for changes to take effect."
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-state-custom",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A React library built with Vite and TypeScript",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.umd.js",
|
|
7
|
+
"module": "dist/index.es.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "vite build",
|
|
11
|
+
"dev": "vite",
|
|
12
|
+
"test": "echo \"No tests specified\" && exit 0"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "Your Name",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"events": "^3.3.0",
|
|
19
|
+
"lodash-es": "^4.17.21",
|
|
20
|
+
"react-object-view-bigint": "^0.3.4",
|
|
21
|
+
"vite-plugin-dts": "^4.5.4"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/events": "^3",
|
|
25
|
+
"@types/lodash-es": "^4",
|
|
26
|
+
"@types/react": "19",
|
|
27
|
+
"@types/react-dom": "19",
|
|
28
|
+
"@vitejs/plugin-react": "^4.5.2",
|
|
29
|
+
"react": "19",
|
|
30
|
+
"react-dom": "19",
|
|
31
|
+
"typescript": "^5.8.3",
|
|
32
|
+
"vite": "^6.3.5"
|
|
33
|
+
},
|
|
34
|
+
"packageManager": "yarn@4.6.0+sha512.5383cc12567a95f1d668fbe762dfe0075c595b4bfff433be478dbbe24e05251a8e8c3eb992a986667c1d53b6c3a9c85b8398c35a960587fbd9fa3a0915406728"
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface MyComponentProps {
|
|
4
|
+
title: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const MyComponent: React.FC<MyComponentProps> = ({ title, description }) => {
|
|
9
|
+
return (
|
|
10
|
+
<div>
|
|
11
|
+
<h1>{title}</h1>
|
|
12
|
+
{description && <p>{description}</p>}
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default MyComponent;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// export { default as MyComponent } from './components/MyComponent';
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
Context,
|
|
5
|
+
getContext,
|
|
6
|
+
useDataContext,
|
|
7
|
+
useDataSource,
|
|
8
|
+
useDataSourceMultiple,
|
|
9
|
+
useDataSubscribe,
|
|
10
|
+
useDataSubscribeMultiple,
|
|
11
|
+
useDataSubscribeMultipleWithDebounce,
|
|
12
|
+
useDataSubscribeWithTransform
|
|
13
|
+
} from "./state-utils/ctx"
|
|
14
|
+
|
|
15
|
+
export { createRootCtx } from "./state-utils/createRootCtx"
|
|
16
|
+
|
|
17
|
+
export { useQuickSubscribeV2 as useQuickSubscribe } from "./state-utils/useQuickSubscribeV2"
|
|
18
|
+
|
|
19
|
+
// export { OBJView } from "./components/ObjectView"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useEffect, useMemo } from "react"
|
|
2
|
+
import { useDataContext, useDataSourceMultiple, type Context } from "./ctx"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export const createRootCtx = <U extends object, V extends object>(name: string, useFn: (e: U) => V) => {
|
|
7
|
+
|
|
8
|
+
const resolveCtxName = (e: U) => [
|
|
9
|
+
name,
|
|
10
|
+
...Object
|
|
11
|
+
.entries(e ?? {})
|
|
12
|
+
.sort((e, f) => e[0].localeCompare(f[0]))
|
|
13
|
+
.flat()
|
|
14
|
+
].join("-")
|
|
15
|
+
|
|
16
|
+
let isCtxMounted = false
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
Root: (e: U) => {
|
|
20
|
+
const ctx = useDataContext<V>(resolveCtxName(e))
|
|
21
|
+
const state = useFn(e)
|
|
22
|
+
const stack = useMemo(() => new Error().stack, [])
|
|
23
|
+
|
|
24
|
+
useDataSourceMultiple(
|
|
25
|
+
ctx,
|
|
26
|
+
...Object.entries(state) as any
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (isCtxMounted == true) {
|
|
31
|
+
const err = new Error("RootContext " + resolveCtxName(e) + " are mounted more than once")
|
|
32
|
+
err.stack = stack;
|
|
33
|
+
throw err
|
|
34
|
+
}
|
|
35
|
+
isCtxMounted = true;
|
|
36
|
+
return () => { isCtxMounted = false };
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return <></>
|
|
40
|
+
},
|
|
41
|
+
useCtxState: (e: U): Context<V> => {
|
|
42
|
+
|
|
43
|
+
const stack = useMemo(() => new Error().stack, [])
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!isCtxMounted) {
|
|
47
|
+
const err = new Error("RootContext [" + resolveCtxName(e) + "] is not mounted")
|
|
48
|
+
err.stack = stack;
|
|
49
|
+
throw err
|
|
50
|
+
}
|
|
51
|
+
}, [isCtxMounted])
|
|
52
|
+
|
|
53
|
+
return useDataContext<V>(resolveCtxName(e))
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import event from "events"
|
|
2
|
+
import { debounce, memoize, throttle } from "lodash-es"
|
|
3
|
+
import { useEffect, useMemo, useState } from "react"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generic context for managing shared state and event subscriptions.
|
|
9
|
+
* @template D - The shape of the data managed by the context.
|
|
10
|
+
*/
|
|
11
|
+
export class Context<D> {
|
|
12
|
+
/**
|
|
13
|
+
* Create a new Context instance.
|
|
14
|
+
* @param name - The name of the context (for debugging).
|
|
15
|
+
*/
|
|
16
|
+
constructor(public name: string) {
|
|
17
|
+
console.log("[CONTEXT] %s", name)
|
|
18
|
+
this.event.setMaxListeners(100)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private event = new event.EventEmitter()
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The current data held by the context.
|
|
25
|
+
*/
|
|
26
|
+
public data: Partial<D> = {}
|
|
27
|
+
/**
|
|
28
|
+
* Registry for tracking active keys (for duplicate detection).
|
|
29
|
+
*/
|
|
30
|
+
public registry = new Set<string>()
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Publish a value to the context and notify subscribers if it changed.
|
|
34
|
+
* @param key - The key to update.
|
|
35
|
+
* @param value - The new value.
|
|
36
|
+
*/
|
|
37
|
+
public publish(key: keyof D, value: D[typeof key] | undefined) {
|
|
38
|
+
|
|
39
|
+
if (value != this.data[key]) {
|
|
40
|
+
this.data[key] = value
|
|
41
|
+
// console.count("[COUNT] " + String(key))
|
|
42
|
+
this.event.emit(String(key), { value })
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Subscribe to changes for a specific key in the context.
|
|
48
|
+
* @param key - The key to subscribe to.
|
|
49
|
+
* @param listender - Callback invoked with the new value.
|
|
50
|
+
* @returns Unsubscribe function.
|
|
51
|
+
*/
|
|
52
|
+
public subscribe(key: keyof D, listender: (e: D[typeof key] | undefined) => void) {
|
|
53
|
+
const listener = ({ value }: any) => {
|
|
54
|
+
listender(value)
|
|
55
|
+
}
|
|
56
|
+
this.event.addListener(String(key), listener)
|
|
57
|
+
console.log("listenerCount:", String(key), this.event.listenerCount(String(key)))
|
|
58
|
+
|
|
59
|
+
if (key in this.data) listender(this.data[key])
|
|
60
|
+
|
|
61
|
+
return () => (this.event.removeListener(String(key), listener), undefined)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get or create a memoized Context instance by name.
|
|
68
|
+
* @param name - The context name.
|
|
69
|
+
* @returns The Context instance.
|
|
70
|
+
*/
|
|
71
|
+
export const getContext = memoize((name: string) => new Context<any>(name))
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Type alias for a function that returns a Context instance.
|
|
75
|
+
*/
|
|
76
|
+
export type getContext<D> = (e: string) => Context<D>
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* React hook to get a typed Context instance by name.
|
|
80
|
+
* @param name - The context name.
|
|
81
|
+
* @returns The Context instance.
|
|
82
|
+
*/
|
|
83
|
+
export const useDataContext = <D>(name: string = "noname") => {
|
|
84
|
+
|
|
85
|
+
const ctx = useMemo(() => getContext(name), [name])
|
|
86
|
+
|
|
87
|
+
return ctx as any as Context<D>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Internal hook to check for duplicate registry entries in a context.
|
|
92
|
+
* Warns if any of the provided names are already registered.
|
|
93
|
+
* @param ctx - The context instance.
|
|
94
|
+
* @param names - Names to check and register.
|
|
95
|
+
*/
|
|
96
|
+
const useRegistryChecker = (ctx: Context<any> | undefined, ...names: string[]) => {
|
|
97
|
+
// return;
|
|
98
|
+
const stack = new Error("[ctx] useRegistryChecker failed " + JSON.stringify({ names, ctx: ctx?.name ?? 'undefined' }))
|
|
99
|
+
|
|
100
|
+
useEffect(
|
|
101
|
+
() => {
|
|
102
|
+
if (ctx) {
|
|
103
|
+
if (names.some(name => ctx.registry.has(name))) {
|
|
104
|
+
console.error(stack)
|
|
105
|
+
}
|
|
106
|
+
names.forEach(e => ctx.registry.add(e))
|
|
107
|
+
|
|
108
|
+
// console.debug("[ctx] %s%s add datasource", componentId, ctx.name, names)
|
|
109
|
+
return () => {
|
|
110
|
+
// console.debug("[ctx] %s %s remove datasource", componentId, ctx.name, names)
|
|
111
|
+
|
|
112
|
+
names.forEach(e => ctx.registry.delete(e))
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
[ctx, names.length]
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* React hook to publish a value to the context when it changes.
|
|
123
|
+
* @param ctx - The context instance.
|
|
124
|
+
* @param key - The key to update.
|
|
125
|
+
* @param value - The new value.
|
|
126
|
+
*/
|
|
127
|
+
export const useDataSource = <D, K extends keyof D>(ctx: Context<D> | undefined, key: K, value: D[K] | undefined) => {
|
|
128
|
+
//@ts-check
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
if (ctx && ctx.data[key] != value) {
|
|
131
|
+
|
|
132
|
+
ctx.publish(key, value)
|
|
133
|
+
}
|
|
134
|
+
}, [key, value, ctx])
|
|
135
|
+
|
|
136
|
+
useRegistryChecker(ctx, key as any)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* React hook to subscribe to a context value, with optional debounce.
|
|
141
|
+
* @param ctx - The context instance.
|
|
142
|
+
* @param key - The key to subscribe to.
|
|
143
|
+
* @param debounceTime - Debounce time in ms (default 0).
|
|
144
|
+
* @returns The current value for the key.
|
|
145
|
+
*/
|
|
146
|
+
export const useDataSubscribe = <D, K extends keyof D>(ctx: Context<D> | undefined, key: K, debounceTime = 0): D[K] | undefined => {
|
|
147
|
+
//@ts-check
|
|
148
|
+
const [{ value }, setState] = useState(() => ({ value: ctx?.data?.[key] }))
|
|
149
|
+
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (ctx) {
|
|
152
|
+
let callback = debounceTime == 0 ? (value: any) => setState({ value } as any) : debounce((value: any) => setState({ value } as any), debounceTime)
|
|
153
|
+
let unsub = ctx.subscribe(key, callback)
|
|
154
|
+
value != ctx.data[key] && setState({ value: ctx.data[key] })
|
|
155
|
+
return () => {
|
|
156
|
+
unsub()
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}, [key, ctx])
|
|
160
|
+
|
|
161
|
+
return ctx?.data[key]
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* React hook to subscribe to a context value and transform it before returning.
|
|
166
|
+
* @param ctx - The context instance.
|
|
167
|
+
* @param key - The key to subscribe to.
|
|
168
|
+
* @param transform - Function to transform the value.
|
|
169
|
+
* @returns The transformed value.
|
|
170
|
+
*/
|
|
171
|
+
export const useDataSubscribeWithTransform = <D, K extends keyof D, E>(ctx: Context<D> | undefined, key: K, transform: (e: D[K] | undefined) => E): E => {
|
|
172
|
+
const [, setState] = useState(0)
|
|
173
|
+
const result = useMemo(
|
|
174
|
+
() => transform(ctx?.data[key]),
|
|
175
|
+
[transform, ctx?.data[key]]
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (ctx) {
|
|
180
|
+
let preValue = result
|
|
181
|
+
let callback = () => {
|
|
182
|
+
let newValue = transform(ctx.data[key])
|
|
183
|
+
if (newValue != preValue) {
|
|
184
|
+
preValue = newValue;
|
|
185
|
+
setState(e => e + 1)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
let unsub = ctx.subscribe(key, callback)
|
|
189
|
+
callback();
|
|
190
|
+
return () => unsub()
|
|
191
|
+
}
|
|
192
|
+
}, [key, ctx])
|
|
193
|
+
|
|
194
|
+
return result
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* React hook to publish multiple values to the context.
|
|
199
|
+
* @param ctx - The context instance.
|
|
200
|
+
* @param entries - Array of [key, value] pairs to update.
|
|
201
|
+
*/
|
|
202
|
+
export const useDataSourceMultiple = <D, T extends readonly (keyof D)[]>(
|
|
203
|
+
ctx: Context<D> | undefined,
|
|
204
|
+
...entries: { -readonly [P in keyof T]: [T[P], D[T[P]]] }
|
|
205
|
+
) => {
|
|
206
|
+
//@ts-check
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
if (ctx) {
|
|
209
|
+
for (let [key, value] of entries) {
|
|
210
|
+
ctx.data[key] != value && ctx.publish(key, value)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}, [ctx, ...entries.flat()])
|
|
214
|
+
|
|
215
|
+
useRegistryChecker(ctx, ...entries.map(e => e[0]) as any)
|
|
216
|
+
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* React hook to subscribe to multiple context values.
|
|
221
|
+
* @param ctx - The context instance.
|
|
222
|
+
* @param keys - Keys to subscribe to.
|
|
223
|
+
* @returns An object with the current values for the keys.
|
|
224
|
+
*/
|
|
225
|
+
export const useDataSubscribeMultiple = <D, K extends keyof D>(
|
|
226
|
+
ctx: Context<D> | undefined,
|
|
227
|
+
...keys: K[]
|
|
228
|
+
): Pick<D, K> => {
|
|
229
|
+
const [, setCounter] = useState(0)
|
|
230
|
+
|
|
231
|
+
const returnValues = keys.map(key => ctx?.data?.[key])
|
|
232
|
+
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
if (ctx) {
|
|
235
|
+
let prevValues = returnValues
|
|
236
|
+
const callback = debounce(() => {
|
|
237
|
+
let currentValues = keys.map(key => ctx?.data?.[key])
|
|
238
|
+
if (keys.some((key, i) => prevValues[i] != currentValues[i])) {
|
|
239
|
+
// console.log("DIFF", keys.filter((e, i) => prevValues[i] != currentValues[i]))
|
|
240
|
+
prevValues = currentValues
|
|
241
|
+
setCounter(c => c + 1)
|
|
242
|
+
}
|
|
243
|
+
}, 1)
|
|
244
|
+
|
|
245
|
+
let handles = keys.map(key => ctx.subscribe(key, callback))
|
|
246
|
+
|
|
247
|
+
let firstCall = setTimeout(callback, 1);
|
|
248
|
+
|
|
249
|
+
return () => {
|
|
250
|
+
clearTimeout(firstCall)
|
|
251
|
+
callback.cancel();
|
|
252
|
+
handles.forEach(unsub => unsub())
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
}, [ctx, ...keys])
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
return Object
|
|
260
|
+
.fromEntries(keys.map((key, index) => [key, returnValues[index]])) as any
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* React hook to subscribe to multiple context values with throttling.
|
|
265
|
+
* @param ctx - The context instance.
|
|
266
|
+
* @param debounceTime - Throttle time in ms (default 100).
|
|
267
|
+
* @param keys - Keys to subscribe to.
|
|
268
|
+
* @returns Array of current values for the keys.
|
|
269
|
+
*/
|
|
270
|
+
export const useDataSubscribeMultipleWithDebounce = <D, K extends (keyof D)[]>(
|
|
271
|
+
ctx: Context<D> | undefined,
|
|
272
|
+
debounceTime = 100,
|
|
273
|
+
...keys: K
|
|
274
|
+
): { [i in keyof K]: D[K[i]] | undefined } => {
|
|
275
|
+
//@ts-check
|
|
276
|
+
const [, setCounter] = useState(0)
|
|
277
|
+
|
|
278
|
+
const returnValues = keys.map(key => ctx?.data?.[key])
|
|
279
|
+
|
|
280
|
+
useEffect(() => {
|
|
281
|
+
if (ctx) {
|
|
282
|
+
let prevValues = returnValues
|
|
283
|
+
const callback = throttle(() => {
|
|
284
|
+
let currentValues = keys.map(key => ctx?.data?.[key])
|
|
285
|
+
if (keys.some((key, i) => prevValues[i] != currentValues[i])) {
|
|
286
|
+
prevValues = currentValues
|
|
287
|
+
setCounter(c => c + 1)
|
|
288
|
+
}
|
|
289
|
+
}, debounceTime)
|
|
290
|
+
|
|
291
|
+
let handles = keys.map(key => ctx.subscribe(key, callback))
|
|
292
|
+
|
|
293
|
+
let firstCall = setTimeout(callback, 1);
|
|
294
|
+
|
|
295
|
+
return () => {
|
|
296
|
+
clearTimeout(firstCall)
|
|
297
|
+
callback.cancel();
|
|
298
|
+
handles.forEach(unsub => unsub())
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
}
|
|
302
|
+
}, [ctx, ...keys])
|
|
303
|
+
|
|
304
|
+
return returnValues as any
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|