sinho 0.2.1 → 0.2.3
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/dist/bundle.d.ts +12 -5
- package/dist/bundle.js +80 -63
- package/dist/bundle.min.js +1 -1
- package/dist/scope.d.ts +12 -5
- package/dist/scope.js +80 -63
- package/dist/scope.js.map +1 -1
- package/package.json +1 -1
- package/src/scope.ts +102 -80
package/dist/bundle.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ interface Signal<out T> extends SignalLike<T> {
|
|
|
18
18
|
*/
|
|
19
19
|
peek(): T;
|
|
20
20
|
}
|
|
21
|
+
interface SignalOptions<T> extends SetSignalOptions {
|
|
22
|
+
/**
|
|
23
|
+
* A custom equality function to compare the new value with the old value.
|
|
24
|
+
*/
|
|
25
|
+
equals?: (a: T, b: T) => boolean;
|
|
26
|
+
}
|
|
21
27
|
interface SetSignalOptions {
|
|
22
28
|
/**
|
|
23
29
|
* Whether to force the update of the signal even if the new value has the
|
|
@@ -40,9 +46,10 @@ interface SubscopeOptions {
|
|
|
40
46
|
details?: object;
|
|
41
47
|
}
|
|
42
48
|
interface Effect {
|
|
49
|
+
_scope: Scope;
|
|
50
|
+
_pure: boolean;
|
|
43
51
|
_clean?: Cleanup;
|
|
44
52
|
_deps: Set<Signal<unknown>>;
|
|
45
|
-
_scope: Scope;
|
|
46
53
|
_run(): void;
|
|
47
54
|
}
|
|
48
55
|
/**
|
|
@@ -63,7 +70,7 @@ declare const useScope: <T = {}>() => Scope<T>;
|
|
|
63
70
|
* Creates a new signal with the given value.
|
|
64
71
|
* @returns A tuple with the signal and its setter.
|
|
65
72
|
*/
|
|
66
|
-
declare const useSignal: (<T>(value: T, opts?:
|
|
73
|
+
declare const useSignal: (<T>(value: T, opts?: SignalOptions<T>) => readonly [Signal<T>, SignalSetter<T>]) & (<T>(value?: T, opts?: SignalOptions<T | undefined>) => readonly [Signal<T | undefined>, SignalSetter<T | undefined>]);
|
|
67
74
|
/**
|
|
68
75
|
* Runs the given function in a batch.
|
|
69
76
|
*
|
|
@@ -71,13 +78,13 @@ declare const useSignal: (<T>(value: T, opts?: SetSignalOptions) => readonly [Si
|
|
|
71
78
|
* and updated at the same time.
|
|
72
79
|
*/
|
|
73
80
|
declare const useBatch: <T>(fn: () => T) => T;
|
|
74
|
-
declare
|
|
81
|
+
declare const flushBatch: () => void;
|
|
75
82
|
/**
|
|
76
83
|
* Creates a memoized signal.
|
|
77
84
|
*
|
|
78
85
|
* @param fn The computation function.
|
|
79
86
|
*/
|
|
80
|
-
declare const useMemo: <T>(fn: () => T, opts?:
|
|
87
|
+
declare const useMemo: <T>(fn: () => T, opts?: SignalOptions<T>) => Signal<T>;
|
|
81
88
|
/**
|
|
82
89
|
* Executes a function inside a subscope which can be manually destroyed.
|
|
83
90
|
*
|
|
@@ -106,7 +113,7 @@ interface RefSignalSetter<in T> {
|
|
|
106
113
|
/**
|
|
107
114
|
* Creates a new signal with write capabilities.
|
|
108
115
|
*/
|
|
109
|
-
declare const useRef: (<T>(value: T, opts?:
|
|
116
|
+
declare const useRef: (<T>(value: T, opts?: SignalOptions<T>) => RefSignal<T>) & (<T>(value?: T, opts?: SignalOptions<T | undefined>) => RefSignal<T | undefined>);
|
|
110
117
|
/**
|
|
111
118
|
* Represents a value that can be a signal or a constant value.
|
|
112
119
|
*
|
package/dist/bundle.js
CHANGED
|
@@ -52,24 +52,33 @@ const useSignal = (value, opts) => {
|
|
|
52
52
|
signal._effects = new Set();
|
|
53
53
|
signal.peek = () => value;
|
|
54
54
|
const setter = (arg, innerOpts) => {
|
|
55
|
-
|
|
55
|
+
const allOpts = { ...opts, ...innerOpts };
|
|
56
|
+
allOpts.equals ??= (a, b) => a === b;
|
|
56
57
|
if (currBatch) {
|
|
57
58
|
const newValue = typeof arg == "function"
|
|
58
59
|
? arg(signal.peek())
|
|
59
60
|
: arg;
|
|
60
|
-
if (
|
|
61
|
-
if (
|
|
61
|
+
if (allOpts?.force || !allOpts.equals(newValue, signal.peek())) {
|
|
62
|
+
if (allOpts?.force) {
|
|
62
63
|
value = newValue;
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
else {
|
|
66
|
+
currBatch._setters.push(() => (value = newValue));
|
|
67
|
+
}
|
|
68
|
+
if (!allOpts?.silent) {
|
|
69
|
+
signal._effects.forEach((effect) => {
|
|
70
|
+
if (effect._pure) {
|
|
71
|
+
currBatch._pureEffects.add(effect);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
currBatch._effects.add(effect);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
79
|
}
|
|
71
80
|
else {
|
|
72
|
-
useBatch(() => setter(arg,
|
|
81
|
+
useBatch(() => setter(arg, allOpts));
|
|
73
82
|
}
|
|
74
83
|
};
|
|
75
84
|
return [signal, setter];
|
|
@@ -81,50 +90,44 @@ const useSignal = (value, opts) => {
|
|
|
81
90
|
* and updated at the same time.
|
|
82
91
|
*/
|
|
83
92
|
const useBatch = (fn) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
if (currBatch)
|
|
94
|
+
return fn();
|
|
95
|
+
currBatch = {
|
|
96
|
+
_setters: [],
|
|
97
|
+
_effects: new Set(),
|
|
98
|
+
_pureEffects: new Set(),
|
|
99
|
+
};
|
|
100
|
+
try {
|
|
101
|
+
const result = fn();
|
|
89
102
|
flushBatch();
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
90
106
|
currBatch = undefined;
|
|
91
107
|
}
|
|
92
|
-
return result;
|
|
93
108
|
};
|
|
94
|
-
|
|
95
|
-
const mutatedSignals = new Set();
|
|
109
|
+
const flushBatch = () => {
|
|
96
110
|
while (currBatch &&
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
if (!silent) {
|
|
104
|
-
signal._effects.forEach((effect) => {
|
|
105
|
-
effect._clean?.();
|
|
106
|
-
effects.add(effect);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
111
|
+
currBatch._setters.length +
|
|
112
|
+
currBatch._effects.size +
|
|
113
|
+
currBatch._pureEffects.size >
|
|
114
|
+
0) {
|
|
115
|
+
// Clean effect subscope
|
|
116
|
+
currBatch._effects.forEach((effect) => effect._clean?.());
|
|
110
117
|
// Run signal updates
|
|
111
|
-
|
|
112
|
-
setter();
|
|
113
|
-
mutatedSignals.add(signal);
|
|
114
|
-
}
|
|
118
|
+
currBatch._setters.forEach((setter) => setter());
|
|
115
119
|
currBatch._setters = [];
|
|
116
|
-
// Run
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
currBatch._effects.add(effect);
|
|
124
|
-
}
|
|
120
|
+
// Run next effect
|
|
121
|
+
const effect = currBatch._pureEffects.values().next().value ??
|
|
122
|
+
currBatch._effects.values().next().value;
|
|
123
|
+
if (effect) {
|
|
124
|
+
effect._run();
|
|
125
|
+
currBatch._pureEffects.delete(effect);
|
|
126
|
+
currBatch._effects.delete(effect);
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
|
-
}
|
|
129
|
+
};
|
|
130
|
+
let pureEffectFlag = false;
|
|
128
131
|
/**
|
|
129
132
|
* Creates an effect which will rerun when any accessed signal changes.
|
|
130
133
|
*
|
|
@@ -134,6 +137,7 @@ const useEffect = (fn, deps) => {
|
|
|
134
137
|
const untracked = !!deps;
|
|
135
138
|
const effect = {
|
|
136
139
|
_scope: currScope,
|
|
140
|
+
_pure: pureEffectFlag,
|
|
137
141
|
_deps: new Set(),
|
|
138
142
|
_run() {
|
|
139
143
|
const prevEffect = currEffect;
|
|
@@ -180,12 +184,18 @@ const useEffect = (fn, deps) => {
|
|
|
180
184
|
* @param fn The computation function.
|
|
181
185
|
*/
|
|
182
186
|
const useMemo = (fn, opts) => {
|
|
183
|
-
const [memo, setMemo] = useSignal();
|
|
187
|
+
const [memo, setMemo] = useSignal(undefined, opts);
|
|
184
188
|
let firstTime = true;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
+
pureEffectFlag = true;
|
|
190
|
+
try {
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
setMemo(fn, firstTime ? { force: true } : {});
|
|
193
|
+
firstTime = false;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
pureEffectFlag = false;
|
|
198
|
+
}
|
|
189
199
|
return memo;
|
|
190
200
|
};
|
|
191
201
|
/**
|
|
@@ -195,30 +205,37 @@ const useMemo = (fn, opts) => {
|
|
|
195
205
|
* @returns A function to manually destroy the subscope.
|
|
196
206
|
*/
|
|
197
207
|
const useSubscope = (fn, opts) => {
|
|
208
|
+
const prevBatch = currBatch;
|
|
209
|
+
currBatch = undefined;
|
|
198
210
|
const parent = currScope;
|
|
199
211
|
const scope = createScope(parent);
|
|
200
212
|
Object.assign(scope._details, opts?.details);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
try {
|
|
214
|
+
parent._subscopes.push(scope);
|
|
215
|
+
const result = scope._run(fn);
|
|
216
|
+
return [
|
|
217
|
+
result,
|
|
218
|
+
() => {
|
|
219
|
+
const index = parent._subscopes.indexOf(scope);
|
|
220
|
+
if (index >= 0) {
|
|
221
|
+
parent._subscopes.splice(index, 1);
|
|
222
|
+
}
|
|
223
|
+
scope._cleanup();
|
|
224
|
+
},
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
currBatch = prevBatch;
|
|
229
|
+
}
|
|
213
230
|
};
|
|
214
231
|
/**
|
|
215
232
|
* Creates a new signal with write capabilities.
|
|
216
233
|
*/
|
|
217
|
-
const useRef = (value, opts) => {
|
|
234
|
+
const useRef = ((value, opts) => {
|
|
218
235
|
const [signal, setter] = useSignal(value, opts);
|
|
219
236
|
signal.set = setter;
|
|
220
237
|
return signal;
|
|
221
|
-
};
|
|
238
|
+
});
|
|
222
239
|
/**
|
|
223
240
|
* @namespace
|
|
224
241
|
*/
|
package/dist/bundle.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const t=t=>({t:t,o:[],i:[],l:{...t?.l},u(t){const n=o;o=this;try{return t()}finally{o=n}},h(){for(let t=this.i.length-1;t>=0;t--)this.i[t].h();this.i=[];for(let t=this.o.length-1;t>=0;t--){const n=this.o[t];n._?.(),n.u=()=>{},n.p.forEach((t=>t.o.delete(n))),n.p.clear()}this.o=[]}});let n,e,o=t(),s=!1;const r=()=>o,c=(t,o)=>{const r=()=>(!s&&n&&(n.p.add(r),r.o.add(n)),r.peek());r.o=new Set,r.peek=()=>t;const c=(n,s)=>{
|
|
1
|
+
const t=t=>({t:t,o:[],i:[],l:{...t?.l},u(t){const n=o;o=this;try{return t()}finally{o=n}},h(){for(let t=this.i.length-1;t>=0;t--)this.i[t].h();this.i=[];for(let t=this.o.length-1;t>=0;t--){const n=this.o[t];n._?.(),n.u=()=>{},n.p.forEach((t=>t.o.delete(n))),n.p.clear()}this.o=[]}});let n,e,o=t(),s=!1;const r=()=>o,c=(t,o)=>{const r=()=>(!s&&n&&(n.p.add(r),r.o.add(n)),r.peek());r.o=new Set,r.peek=()=>t;const c=(n,s)=>{const l={...o,...s};if(l.equals??=(t,n)=>t===n,e){const o="function"==typeof n?n(r.peek()):n;!l?.force&&l.equals(o,r.peek())||(l?.force?t=o:e.m.push((()=>t=o)),l?.silent||r.o.forEach((t=>{t.v?e.S.add(t):e.o.add(t)})))}else i((()=>c(n,l)))};return[r,c]},i=t=>{if(e)return t();e={m:[],o:new Set,S:new Set};try{const n=t();return l(),n}finally{e=void 0}},l=()=>{for(;e&&e.m.length+e.o.size+e.S.size>0;){e.o.forEach((t=>t._?.())),e.m.forEach((t=>t())),e.m=[];const t=e.S.values().next().value??e.o.values().next().value;t&&(t.u(),e.S.delete(t),e.o.delete(t))}};let u=!1;const f=(t,e)=>{const r=!!e,c={M:o,v:u,p:new Set,u(){const o=n,c=s;n=this;try{this.p.forEach((t=>t.o.delete(this))),this.p.clear(),e&&(s=!1,e.forEach((t=>t()))),s=r,this._?.();const n=this.M.u((()=>i(t)));this._=n?()=>{this.M.u((()=>i(n))),this._=null}:null}finally{n=o,s=c}}};o.o.push(c),c.u(),c.p.size||c._||o.o.pop()},a=(t,n)=>{const[e,o]=c(void 0,n);let s=!0;u=!0;try{f((()=>{o(t,s?{force:!0}:{}),s=!1}))}finally{u=!1}return e},d=(n,s)=>{const r=e;e=void 0;const c=o,i=t(c);Object.assign(i.l,s?.details);try{c.i.push(i);return[i.u(n),()=>{const t=c.i.indexOf(i);t>=0&&c.i.splice(t,1),i.h()}]}finally{e=r}},h=(t,n)=>{const[e,o]=c(t,n);return e.set=o,e},_={upgrade:t=>()=>_.get(t),get:t=>"function"==typeof t?t():t,peek(t){const n=s;s=!0;try{return this.get(t)}finally{s=n}}},p=(t={})=>({k:[],C(t){return this.N?.next().value??t()},...t}),m=()=>{const t=r();return t.l.j??=p()},y=(t,n)=>{const e=m(),o=p({...e,...t}),[s,r]=d(n,{details:{j:o}});return f((()=>r)),s},w=t=>(t[0]??"").toLowerCase()+t.slice(1).replace(/[A-Z]/g,(t=>"-"+t.toLowerCase())),b=t=>t.startsWith("on:")?t.slice(3):w(t.slice(2)),v=Symbol(),g=(t,n)=>({[v]:Math.random().toString(36).slice(2),H:t,L:n}),x=t=>!!t?.[v],S=(t,n,e)=>{n.addEventListener(t[v],(t=>{const n=_.get(e);void 0!==n&&(t.stopPropagation(),t.detail(n))}))},M=t=>{const n=m();return a((()=>{let e=t.H;return n.T?.dispatchEvent(new CustomEvent(t[v],{detail:t=>e=t,bubbles:!0,composed:!0})),e}))},k=(t,n)=>({A:"p",O:t,...n}),C=(t=CustomEvent)=>({A:"e",D:t}),E=Symbol();let N;const j=(t,n)=>{N?N.push([t,n]):f(t,n)},H=(t,n={},e={})=>{const o=[],s=new Map;for(const t in n){const e=n[t];if("p"==e.A&&e.attribute){"function"==typeof e.attribute&&(e.attribute={transform:e.attribute});const n=e.attribute={name:w(t),static:!1,transform:t=>t,...e.attribute};s.set(n.name,{name:t,meta:e}),n.static||o.push(n.name)}}e.shadow??={mode:"open"};class i extends HTMLElement{static[E]={I:t};static observedAttributes=o;props={};events={};[E]={};constructor(){super();for(const t in n){const e=n[t];if("p"==e.A){const n=x(e.O)?e.O:null,[o,s]=c(n?void 0:e.O);this.props[t]=o,n&&S(n,this,o),Object.defineProperty(this,t,{get:o.peek,set:t=>s((()=>t),{force:!0})})}else if("e"==e.A&&t.startsWith("on")){const n=b(t);this.events[t]=t=>this.dispatchEvent(new e.D(n,t))}}}connectedCallback(){const t=(n=this,e.shadow?n.shadowRoot??n.attachShadow(e.shadow):n);var n;this[E].$=d((()=>y({P:!1,T:this,N:t.childNodes.values()},(()=>{this[E].M=r();const n=N;N=[];try{t?.append(...this.render().build()),N.forEach((([t,n])=>f(t,n)))}finally{N=n}}))))[1]}disconnectedCallback(){this[E].$?.()}attributeChangedCallback(t,n,e){const o=s.get(t);o&&(this[o.name]=null!=e?o.meta.attribute.transform.call(this,e):x(o.meta.O)?void 0:o.meta.O)}}return i},L=t=>!!t?.[E],T=(...t)=>{const[n,e]="string"==typeof t[0]?[t[0],t.slice(1)]:["",t];for(const t of e)customElements.define(n+t[E].I,t)},A=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,O=(t,n,e)=>{"-"==n[0]?t.style.setProperty(n,""+e):t.style[n]=null==e?"":"number"!=typeof e||A.test(n)?""+e:e+"px"},D=(t,n,e,o)=>{const s=null==e||!1===e&&!n.includes("-");if(n.startsWith("prop:"))t[n.slice(5)]=e;else if(n.startsWith("attr:"))n=n.slice(5),s?t.removeAttribute(n):t.setAttribute(n,e);else if(!["innerHTML","outerHTML"].includes(n)){if(!["tabIndex","role",...o?["width","height","href","list","form","download","rowSpan","colSpan"]:[]].includes(n)&&n in t)try{return void(t[n]=e)}catch(t){}"function"==typeof e||(s?t.removeAttribute(n):t.setAttribute(n,e))}},I=t=>({build(){const n=t();return n.build?.()??n}}),$=({text:t,marker:n})=>I((()=>{const e=m(),o=n&&e.C((()=>document.createComment(""))),s=e.C((()=>document.createTextNode("")));return f((()=>{const n=""+(_.get(t)??"");s.textContent!=n&&(s.textContent=n)})),o?[o,s]:[s]})),z=({children:t})=>I((()=>Array.isArray(t)?t.flatMap((t=>z({children:t}).build())):null==t?[]:"object"==typeof t?t:$({text:t}))),P=(t,n,e,o)=>{const{ref:s,style:c,children:l,dangerouslySetInnerHTML:u,...a}=e;for(const n in c??{}){const e=c[n];f((()=>{O(t,n,_.get(e))}))}for(const n in a){const e=a[n];if(n.startsWith("on")){const o=r(),s=t=>{o.u((()=>i((()=>e(t)))))},c=b(n);f((()=>(t.addEventListener(c,s),()=>t.removeEventListener(c,s))))}else f((()=>{D(t,n,_.get(e),o)}))}return u&&f((()=>{const n=_.get(u).__html;t.innerHTML!=n&&(t.innerHTML=n)})),s&&f((()=>(s.set(t),()=>s.set(void 0)))),null!=e.children&&t.append(...y({P:n,N:t.childNodes.values()},(()=>z({children:e.children}).build()))),t},V=(t,n={},e)=>(null!=e&&(n.children=e),L(t)?((t,n)=>I((()=>{const e=m().C((()=>new t));return customElements.upgrade(e),P(e,!1,n),[e]})))(t,n):"function"==typeof t?I((()=>t(n))):((t,n={})=>I((()=>{const e=m(),o="svg"==t||!!e.P;return[P(e.C((()=>o?document.createElementNS("http://www.w3.org/2000/svg",t):document.createElement(t))),o,n,!0)]})))(t,n)),Z=new Proxy(V,{get:(t,n)=>(e,o)=>t(n,e,o)}),q=(t,n)=>{const[e,o]=c({V:[],Z:new Map});let s=new Map;return f((()=>{const e=[],r=s,c=((t,n)=>{const e=new Map;for(let o=0;o<t.length;o++){const s=n(t[o],o);if(e.has(s))throw Error(`Duplicate key '${s}'`);e.set(s,o)}return e})(t(),n),i=(t=NaN)=>e.map((t=>"r"==t.q?n=>n<t.B?n:n==t.B?NaN:n-1:"a"==t.q?n=>n<t.B?n:n+1:"m"==t.q?n=>t.F<=n&&n<t.G?n+1:n==t.G?t.F:n:t=>t)).reduce(((t,n)=>n(t)),t);for(const t of r.keys()){const n=i(r.get(t));c.has(t)||e.push({q:"r",J:t,B:n})}for(let o=0;o<t().length;o++){const s=n(t()[o],o),c=i(r.get(s));isNaN(c)?e.push({q:"a",J:s,B:o}):c!=o&&e.push({q:"m",J:s,G:c,F:o})}e.length>0&&o({V:e,Z:c}),s=c})),e},B=t=>I((()=>{const n=m(),e=_.upgrade(t.each??[]),o=n.C((()=>document.createComment(""))),s=t.key??((t,n)=>n),r=[o],i=new Map,l=q(e,s),u=t=>{for(let n=t-1;n>=0;n--){const n=s(e()[t-1],t-1),o=i.get(n)?.K??[];if(o.length>0)return o[o.length-1]}return o};return f((()=>{for(const n of l().V)if("r"==n.q){const{K:t=[],$:e}=i.get(n.J)??{};e?.();const o=r.indexOf(t[0]);o>0&&r.splice(o,t.length),t.forEach((t=>t.parentNode?.removeChild(t))),i.delete(n.J)}else if("a"==n.q){let o=[];const[,s]=d((()=>{const[s,i]=c(n.B),[a,d]=c(e()[n.B]);f((()=>{0<=s()&&s()<e().length&&d((()=>e()[s()]))})),f((()=>{const t=l().Z.get(n.J);null!=t&&i(t)})),o=t.children?.(a,s,e).build()??[];const h=u(n.B),_=r.indexOf(h);_>=0&&r.splice(_+1,0,...o),o.forEach((t=>h.parentNode?.insertBefore(t,h.nextSibling)))}));i.set(n.J,{K:o,$:s})}else if("m"==n.q){const{K:t=[]}=i.get(n.J)??{},e=r.indexOf(t[0]);e>=0&&r.splice(e,t.length);const o=u(n.F),s=r.indexOf(o);s>=0&&r.splice(s+1,0,...t),t.forEach((t=>o.parentNode?.insertBefore(t,o.nextSibling)))}}),[l]),r})),F=t=>(m().k=[],G({condition:t.condition,children:t.children})),G=t=>{const n=m(),e=n.k,o=a((()=>e.every((t=>!t()))&&_.get(t.condition)));return n.k=[...e,o],y({k:[]},(()=>I((()=>{const e=n.C((()=>document.createComment(""))),s=[e],r=a((()=>o()?z({children:t.children}):null));let c=[];return f((()=>{c.forEach((t=>t.parentNode?.removeChild(t))),s.length=1;const[,t]=d((()=>{c=r()?.build()??[],e.after(...c),s.push(...c)}));return t}),[r]),s}))))},J=({children:t})=>G({condition:!0,children:t}),K=({mount:t,children:n})=>I((()=>y({N:void 0},(()=>{const e=z({children:n}).build();return f((()=>(e.forEach((n=>t.appendChild(n))),()=>{e.forEach((t=>t.parentNode?.removeChild(t)))}))),[]})))),Q=Symbol(),R=new Map,U=t=>{const n=t.children;if("function"==typeof n){const e=V("style",{},$({text:n,marker:!1}));return t.light?K({mount:document.head,children:e}):e}if(n){const o=m(),s=t.light?document:o.T?.shadowRoot??document,r=((t,n,e)=>{if(!R.has(n)){const t=new CSSStyleSheet;t.replaceSync(n),R.set(n,{R:t,U:0})}const o=R.get(n);o.U++,t.has(n)||t.set(n,{R:o.R,U:0});const s=t.get(n);return s.U++,f((()=>()=>{--s.U||(t.delete(n),e()),--o.U||R.delete(n)})),s.R})((e=s,e[Q]??=new Map),n,(()=>{s.adoptedStyleSheets=s.adoptedStyleSheets.filter((t=>t!=r))}));s.adoptedStyleSheets.push(r)}var e;return z({})},W=(t,...n)=>{const e=()=>t.reduce(((t,e,o)=>t+e+(_.get(n[o])??"")),"");return n.some((t=>"function"==typeof t))?e:e()},X=(t,n,e)=>(n&&null!=e&&(n.key=e),V(t,n));export{H as Component,J as Else,G as ElseIf,B as For,z as Fragment,F as If,_ as MaybeSignal,K as Portal,U as Style,g as createContext,V as createElement,W as css,T as defineComponents,C as event,l as flushBatch,Z as h,L as isComponent,X as jsx,X as jsxDEV,X as jsxs,k as prop,i as useBatch,M as useContext,j as useEffect,a as useMemo,h as useRef,c as useSignal,d as useSubscope};
|
package/dist/scope.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ export interface Signal<out T> extends SignalLike<T> {
|
|
|
18
18
|
*/
|
|
19
19
|
peek(): T;
|
|
20
20
|
}
|
|
21
|
+
export interface SignalOptions<T> extends SetSignalOptions {
|
|
22
|
+
/**
|
|
23
|
+
* A custom equality function to compare the new value with the old value.
|
|
24
|
+
*/
|
|
25
|
+
equals?: (a: T, b: T) => boolean;
|
|
26
|
+
}
|
|
21
27
|
export interface SetSignalOptions {
|
|
22
28
|
/**
|
|
23
29
|
* Whether to force the update of the signal even if the new value has the
|
|
@@ -40,9 +46,10 @@ export interface SubscopeOptions {
|
|
|
40
46
|
details?: object;
|
|
41
47
|
}
|
|
42
48
|
interface Effect {
|
|
49
|
+
_scope: Scope;
|
|
50
|
+
_pure: boolean;
|
|
43
51
|
_clean?: Cleanup;
|
|
44
52
|
_deps: Set<Signal<unknown>>;
|
|
45
|
-
_scope: Scope;
|
|
46
53
|
_run(): void;
|
|
47
54
|
}
|
|
48
55
|
/**
|
|
@@ -63,7 +70,7 @@ export declare const useScope: <T = {}>() => Scope<T>;
|
|
|
63
70
|
* Creates a new signal with the given value.
|
|
64
71
|
* @returns A tuple with the signal and its setter.
|
|
65
72
|
*/
|
|
66
|
-
export declare const useSignal: (<T>(value: T, opts?:
|
|
73
|
+
export declare const useSignal: (<T>(value: T, opts?: SignalOptions<T>) => readonly [Signal<T>, SignalSetter<T>]) & (<T>(value?: T, opts?: SignalOptions<T | undefined>) => readonly [Signal<T | undefined>, SignalSetter<T | undefined>]);
|
|
67
74
|
/**
|
|
68
75
|
* Runs the given function in a batch.
|
|
69
76
|
*
|
|
@@ -71,7 +78,7 @@ export declare const useSignal: (<T>(value: T, opts?: SetSignalOptions) => reado
|
|
|
71
78
|
* and updated at the same time.
|
|
72
79
|
*/
|
|
73
80
|
export declare const useBatch: <T>(fn: () => T) => T;
|
|
74
|
-
export declare
|
|
81
|
+
export declare const flushBatch: () => void;
|
|
75
82
|
/**
|
|
76
83
|
* Creates an effect which will rerun when any accessed signal changes.
|
|
77
84
|
*
|
|
@@ -83,7 +90,7 @@ export declare const useEffect: (fn: () => Cleanup, deps?: SignalLike<unknown>[]
|
|
|
83
90
|
*
|
|
84
91
|
* @param fn The computation function.
|
|
85
92
|
*/
|
|
86
|
-
export declare const useMemo: <T>(fn: () => T, opts?:
|
|
93
|
+
export declare const useMemo: <T>(fn: () => T, opts?: SignalOptions<T>) => Signal<T>;
|
|
87
94
|
/**
|
|
88
95
|
* Executes a function inside a subscope which can be manually destroyed.
|
|
89
96
|
*
|
|
@@ -112,7 +119,7 @@ export interface RefSignalSetter<in T> {
|
|
|
112
119
|
/**
|
|
113
120
|
* Creates a new signal with write capabilities.
|
|
114
121
|
*/
|
|
115
|
-
export declare const useRef: (<T>(value: T, opts?:
|
|
122
|
+
export declare const useRef: (<T>(value: T, opts?: SignalOptions<T>) => RefSignal<T>) & (<T>(value?: T, opts?: SignalOptions<T | undefined>) => RefSignal<T | undefined>);
|
|
116
123
|
/**
|
|
117
124
|
* Represents a value that can be a signal or a constant value.
|
|
118
125
|
*
|
package/dist/scope.js
CHANGED
|
@@ -52,24 +52,33 @@ export const useSignal = (value, opts) => {
|
|
|
52
52
|
signal._effects = new Set();
|
|
53
53
|
signal.peek = () => value;
|
|
54
54
|
const setter = (arg, innerOpts) => {
|
|
55
|
-
|
|
55
|
+
const allOpts = { ...opts, ...innerOpts };
|
|
56
|
+
allOpts.equals ??= (a, b) => a === b;
|
|
56
57
|
if (currBatch) {
|
|
57
58
|
const newValue = typeof arg == "function"
|
|
58
59
|
? arg(signal.peek())
|
|
59
60
|
: arg;
|
|
60
|
-
if (
|
|
61
|
-
if (
|
|
61
|
+
if (allOpts?.force || !allOpts.equals(newValue, signal.peek())) {
|
|
62
|
+
if (allOpts?.force) {
|
|
62
63
|
value = newValue;
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
else {
|
|
66
|
+
currBatch._setters.push(() => (value = newValue));
|
|
67
|
+
}
|
|
68
|
+
if (!allOpts?.silent) {
|
|
69
|
+
signal._effects.forEach((effect) => {
|
|
70
|
+
if (effect._pure) {
|
|
71
|
+
currBatch._pureEffects.add(effect);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
currBatch._effects.add(effect);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
79
|
}
|
|
71
80
|
else {
|
|
72
|
-
useBatch(() => setter(arg,
|
|
81
|
+
useBatch(() => setter(arg, allOpts));
|
|
73
82
|
}
|
|
74
83
|
};
|
|
75
84
|
return [signal, setter];
|
|
@@ -81,50 +90,44 @@ export const useSignal = (value, opts) => {
|
|
|
81
90
|
* and updated at the same time.
|
|
82
91
|
*/
|
|
83
92
|
export const useBatch = (fn) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
if (currBatch)
|
|
94
|
+
return fn();
|
|
95
|
+
currBatch = {
|
|
96
|
+
_setters: [],
|
|
97
|
+
_effects: new Set(),
|
|
98
|
+
_pureEffects: new Set(),
|
|
99
|
+
};
|
|
100
|
+
try {
|
|
101
|
+
const result = fn();
|
|
89
102
|
flushBatch();
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
90
106
|
currBatch = undefined;
|
|
91
107
|
}
|
|
92
|
-
return result;
|
|
93
108
|
};
|
|
94
|
-
export
|
|
95
|
-
const mutatedSignals = new Set();
|
|
109
|
+
export const flushBatch = () => {
|
|
96
110
|
while (currBatch &&
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
if (!silent) {
|
|
104
|
-
signal._effects.forEach((effect) => {
|
|
105
|
-
effect._clean?.();
|
|
106
|
-
effects.add(effect);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
111
|
+
currBatch._setters.length +
|
|
112
|
+
currBatch._effects.size +
|
|
113
|
+
currBatch._pureEffects.size >
|
|
114
|
+
0) {
|
|
115
|
+
// Clean effect subscope
|
|
116
|
+
currBatch._effects.forEach((effect) => effect._clean?.());
|
|
110
117
|
// Run signal updates
|
|
111
|
-
|
|
112
|
-
setter();
|
|
113
|
-
mutatedSignals.add(signal);
|
|
114
|
-
}
|
|
118
|
+
currBatch._setters.forEach((setter) => setter());
|
|
115
119
|
currBatch._setters = [];
|
|
116
|
-
// Run
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
currBatch._effects.add(effect);
|
|
124
|
-
}
|
|
120
|
+
// Run next effect
|
|
121
|
+
const effect = currBatch._pureEffects.values().next().value ??
|
|
122
|
+
currBatch._effects.values().next().value;
|
|
123
|
+
if (effect) {
|
|
124
|
+
effect._run();
|
|
125
|
+
currBatch._pureEffects.delete(effect);
|
|
126
|
+
currBatch._effects.delete(effect);
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
|
-
}
|
|
129
|
+
};
|
|
130
|
+
let pureEffectFlag = false;
|
|
128
131
|
/**
|
|
129
132
|
* Creates an effect which will rerun when any accessed signal changes.
|
|
130
133
|
*
|
|
@@ -134,6 +137,7 @@ export const useEffect = (fn, deps) => {
|
|
|
134
137
|
const untracked = !!deps;
|
|
135
138
|
const effect = {
|
|
136
139
|
_scope: currScope,
|
|
140
|
+
_pure: pureEffectFlag,
|
|
137
141
|
_deps: new Set(),
|
|
138
142
|
_run() {
|
|
139
143
|
const prevEffect = currEffect;
|
|
@@ -180,12 +184,18 @@ export const useEffect = (fn, deps) => {
|
|
|
180
184
|
* @param fn The computation function.
|
|
181
185
|
*/
|
|
182
186
|
export const useMemo = (fn, opts) => {
|
|
183
|
-
const [memo, setMemo] = useSignal();
|
|
187
|
+
const [memo, setMemo] = useSignal(undefined, opts);
|
|
184
188
|
let firstTime = true;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
+
pureEffectFlag = true;
|
|
190
|
+
try {
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
setMemo(fn, firstTime ? { force: true } : {});
|
|
193
|
+
firstTime = false;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
pureEffectFlag = false;
|
|
198
|
+
}
|
|
189
199
|
return memo;
|
|
190
200
|
};
|
|
191
201
|
/**
|
|
@@ -195,30 +205,37 @@ export const useMemo = (fn, opts) => {
|
|
|
195
205
|
* @returns A function to manually destroy the subscope.
|
|
196
206
|
*/
|
|
197
207
|
export const useSubscope = (fn, opts) => {
|
|
208
|
+
const prevBatch = currBatch;
|
|
209
|
+
currBatch = undefined;
|
|
198
210
|
const parent = currScope;
|
|
199
211
|
const scope = createScope(parent);
|
|
200
212
|
Object.assign(scope._details, opts?.details);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
try {
|
|
214
|
+
parent._subscopes.push(scope);
|
|
215
|
+
const result = scope._run(fn);
|
|
216
|
+
return [
|
|
217
|
+
result,
|
|
218
|
+
() => {
|
|
219
|
+
const index = parent._subscopes.indexOf(scope);
|
|
220
|
+
if (index >= 0) {
|
|
221
|
+
parent._subscopes.splice(index, 1);
|
|
222
|
+
}
|
|
223
|
+
scope._cleanup();
|
|
224
|
+
},
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
currBatch = prevBatch;
|
|
229
|
+
}
|
|
213
230
|
};
|
|
214
231
|
/**
|
|
215
232
|
* Creates a new signal with write capabilities.
|
|
216
233
|
*/
|
|
217
|
-
export const useRef = (value, opts) => {
|
|
234
|
+
export const useRef = ((value, opts) => {
|
|
218
235
|
const [signal, setter] = useSignal(value, opts);
|
|
219
236
|
signal.set = setter;
|
|
220
237
|
return signal;
|
|
221
|
-
};
|
|
238
|
+
});
|
|
222
239
|
/**
|
|
223
240
|
* @namespace
|
|
224
241
|
*/
|
package/dist/scope.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/scope.ts
CHANGED
|
@@ -21,6 +21,13 @@ export interface Signal<out T> extends SignalLike<T> {
|
|
|
21
21
|
peek(): T;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export interface SignalOptions<T> extends SetSignalOptions {
|
|
25
|
+
/**
|
|
26
|
+
* A custom equality function to compare the new value with the old value.
|
|
27
|
+
*/
|
|
28
|
+
equals?: (a: T, b: T) => boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
export interface SetSignalOptions {
|
|
25
32
|
/**
|
|
26
33
|
* Whether to force the update of the signal even if the new value has the
|
|
@@ -46,9 +53,10 @@ export interface SubscopeOptions {
|
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
interface Effect {
|
|
56
|
+
_scope: Scope;
|
|
57
|
+
_pure: boolean;
|
|
49
58
|
_clean?: Cleanup;
|
|
50
59
|
_deps: Set<Signal<unknown>>;
|
|
51
|
-
_scope: Scope;
|
|
52
60
|
|
|
53
61
|
_run(): void;
|
|
54
62
|
}
|
|
@@ -113,12 +121,9 @@ let currUntracked: boolean = false;
|
|
|
113
121
|
let currEffect: Effect | undefined;
|
|
114
122
|
let currBatch:
|
|
115
123
|
| {
|
|
116
|
-
_setters: [
|
|
117
|
-
signal: Signal<unknown>,
|
|
118
|
-
setter: () => void,
|
|
119
|
-
silent?: boolean,
|
|
120
|
-
][];
|
|
124
|
+
_setters: (() => void)[];
|
|
121
125
|
_effects: Set<Effect>;
|
|
126
|
+
_pureEffects: Set<Effect>;
|
|
122
127
|
}
|
|
123
128
|
| undefined;
|
|
124
129
|
|
|
@@ -131,14 +136,14 @@ export const useScope = <T = {}>(): Scope<T> => currScope as Scope<T>;
|
|
|
131
136
|
*/
|
|
132
137
|
export const useSignal: (<T>(
|
|
133
138
|
value: T,
|
|
134
|
-
opts?:
|
|
139
|
+
opts?: SignalOptions<T>,
|
|
135
140
|
) => readonly [Signal<T>, SignalSetter<T>]) &
|
|
136
141
|
(<T>(
|
|
137
142
|
value?: T,
|
|
138
|
-
opts?:
|
|
143
|
+
opts?: SignalOptions<T | undefined>,
|
|
139
144
|
) => readonly [Signal<T | undefined>, SignalSetter<T | undefined>]) = <T>(
|
|
140
145
|
value: T,
|
|
141
|
-
opts?:
|
|
146
|
+
opts?: SignalOptions<T>,
|
|
142
147
|
): readonly [Signal<T>, SignalSetter<T>] => {
|
|
143
148
|
const signal: Signal<T> = () => {
|
|
144
149
|
if (!currUntracked && currEffect) {
|
|
@@ -153,7 +158,8 @@ export const useSignal: (<T>(
|
|
|
153
158
|
signal.peek = () => value;
|
|
154
159
|
|
|
155
160
|
const setter = (arg: T | ((value: T) => T), innerOpts?: SetSignalOptions) => {
|
|
156
|
-
|
|
161
|
+
const allOpts = { ...opts, ...innerOpts };
|
|
162
|
+
allOpts.equals ??= (a, b) => a === b;
|
|
157
163
|
|
|
158
164
|
if (currBatch) {
|
|
159
165
|
const newValue =
|
|
@@ -161,19 +167,25 @@ export const useSignal: (<T>(
|
|
|
161
167
|
? (arg as (value: T) => T)(signal.peek())
|
|
162
168
|
: arg;
|
|
163
169
|
|
|
164
|
-
if (
|
|
165
|
-
if (
|
|
170
|
+
if (allOpts?.force || !allOpts.equals(newValue, signal.peek())) {
|
|
171
|
+
if (allOpts?.force) {
|
|
166
172
|
value = newValue;
|
|
173
|
+
} else {
|
|
174
|
+
currBatch._setters.push(() => (value = newValue));
|
|
167
175
|
}
|
|
168
176
|
|
|
169
|
-
|
|
170
|
-
signal
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
177
|
+
if (!allOpts?.silent) {
|
|
178
|
+
signal._effects.forEach((effect) => {
|
|
179
|
+
if (effect._pure) {
|
|
180
|
+
currBatch!._pureEffects.add(effect);
|
|
181
|
+
} else {
|
|
182
|
+
currBatch!._effects.add(effect);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
174
186
|
}
|
|
175
187
|
} else {
|
|
176
|
-
useBatch(() => setter(arg,
|
|
188
|
+
useBatch(() => setter(arg, allOpts));
|
|
177
189
|
}
|
|
178
190
|
};
|
|
179
191
|
|
|
@@ -187,64 +199,55 @@ export const useSignal: (<T>(
|
|
|
187
199
|
* and updated at the same time.
|
|
188
200
|
*/
|
|
189
201
|
export const useBatch = <T>(fn: () => T): T => {
|
|
190
|
-
|
|
191
|
-
if (createBatch) currBatch = { _setters: [], _effects: new Set() };
|
|
202
|
+
if (currBatch) return fn();
|
|
192
203
|
|
|
193
|
-
|
|
204
|
+
currBatch = {
|
|
205
|
+
_setters: [],
|
|
206
|
+
_effects: new Set(),
|
|
207
|
+
_pureEffects: new Set(),
|
|
208
|
+
};
|
|
194
209
|
|
|
195
|
-
|
|
210
|
+
try {
|
|
211
|
+
const result = fn();
|
|
196
212
|
flushBatch();
|
|
213
|
+
return result;
|
|
214
|
+
} finally {
|
|
197
215
|
currBatch = undefined;
|
|
198
216
|
}
|
|
199
|
-
|
|
200
|
-
return result;
|
|
201
217
|
};
|
|
202
218
|
|
|
203
|
-
export
|
|
204
|
-
const mutatedSignals = new Set<Signal<unknown>>();
|
|
205
|
-
|
|
219
|
+
export const flushBatch = (): void => {
|
|
206
220
|
while (
|
|
207
221
|
currBatch &&
|
|
208
|
-
|
|
222
|
+
currBatch._setters.length +
|
|
223
|
+
currBatch._effects.size +
|
|
224
|
+
currBatch._pureEffects.size >
|
|
225
|
+
0
|
|
209
226
|
) {
|
|
210
|
-
|
|
211
|
-
const effects = currBatch._effects;
|
|
212
|
-
currBatch._effects = new Set();
|
|
213
|
-
|
|
214
|
-
// Collect and clean effects
|
|
215
|
-
|
|
216
|
-
for (const [signal, , silent] of currBatch._setters) {
|
|
217
|
-
if (!silent) {
|
|
218
|
-
signal._effects.forEach((effect) => {
|
|
219
|
-
effect._clean?.();
|
|
220
|
-
effects.add(effect);
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
227
|
+
// Clean effect subscope
|
|
224
228
|
|
|
225
|
-
|
|
229
|
+
currBatch._effects.forEach((effect) => effect._clean?.());
|
|
226
230
|
|
|
227
|
-
|
|
228
|
-
setter();
|
|
229
|
-
mutatedSignals.add(signal);
|
|
230
|
-
}
|
|
231
|
+
// Run signal updates
|
|
231
232
|
|
|
233
|
+
currBatch._setters.forEach((setter) => setter());
|
|
232
234
|
currBatch._setters = [];
|
|
233
235
|
|
|
234
|
-
// Run
|
|
236
|
+
// Run next effect
|
|
235
237
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
238
|
+
const effect: Effect | undefined =
|
|
239
|
+
currBatch._pureEffects.values().next().value ??
|
|
240
|
+
currBatch._effects.values().next().value;
|
|
241
|
+
|
|
242
|
+
if (effect) {
|
|
243
|
+
effect._run();
|
|
244
|
+
currBatch._pureEffects.delete(effect);
|
|
245
|
+
currBatch._effects.delete(effect);
|
|
245
246
|
}
|
|
246
247
|
}
|
|
247
|
-
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
let pureEffectFlag: boolean = false;
|
|
248
251
|
|
|
249
252
|
/**
|
|
250
253
|
* Creates an effect which will rerun when any accessed signal changes.
|
|
@@ -259,6 +262,7 @@ export const useEffect = (
|
|
|
259
262
|
|
|
260
263
|
const effect: Effect = {
|
|
261
264
|
_scope: currScope,
|
|
265
|
+
_pure: pureEffectFlag,
|
|
262
266
|
_deps: new Set(),
|
|
263
267
|
|
|
264
268
|
_run(): void {
|
|
@@ -319,16 +323,24 @@ export const useEffect = (
|
|
|
319
323
|
*
|
|
320
324
|
* @param fn The computation function.
|
|
321
325
|
*/
|
|
322
|
-
export const useMemo = <T>(fn: () => T, opts?:
|
|
323
|
-
const [memo, setMemo] = useSignal<T>(
|
|
326
|
+
export const useMemo = <T>(fn: () => T, opts?: SignalOptions<T>): Signal<T> => {
|
|
327
|
+
const [memo, setMemo] = useSignal<T>(
|
|
328
|
+
undefined,
|
|
329
|
+
opts as SignalOptions<T | undefined>,
|
|
330
|
+
);
|
|
324
331
|
|
|
325
332
|
let firstTime = true;
|
|
333
|
+
pureEffectFlag = true;
|
|
326
334
|
|
|
327
|
-
|
|
328
|
-
|
|
335
|
+
try {
|
|
336
|
+
useEffect(() => {
|
|
337
|
+
setMemo(fn, firstTime ? { force: true } : {});
|
|
329
338
|
|
|
330
|
-
|
|
331
|
-
|
|
339
|
+
firstTime = false;
|
|
340
|
+
});
|
|
341
|
+
} finally {
|
|
342
|
+
pureEffectFlag = false;
|
|
343
|
+
}
|
|
332
344
|
|
|
333
345
|
return memo as Signal<T>;
|
|
334
346
|
};
|
|
@@ -343,24 +355,31 @@ export const useSubscope = <T>(
|
|
|
343
355
|
fn: () => T,
|
|
344
356
|
opts?: SubscopeOptions,
|
|
345
357
|
): [T, () => void] => {
|
|
358
|
+
const prevBatch = currBatch;
|
|
359
|
+
currBatch = undefined;
|
|
360
|
+
|
|
346
361
|
const parent = currScope;
|
|
347
362
|
const scope = createScope(parent);
|
|
348
363
|
Object.assign(scope._details, opts?.details);
|
|
349
364
|
|
|
350
|
-
|
|
351
|
-
|
|
365
|
+
try {
|
|
366
|
+
parent._subscopes.push(scope);
|
|
367
|
+
const result = scope._run(fn);
|
|
352
368
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
369
|
+
return [
|
|
370
|
+
result,
|
|
371
|
+
() => {
|
|
372
|
+
const index = parent._subscopes.indexOf(scope);
|
|
373
|
+
if (index >= 0) {
|
|
374
|
+
parent._subscopes.splice(index, 1);
|
|
375
|
+
}
|
|
360
376
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
377
|
+
scope._cleanup();
|
|
378
|
+
},
|
|
379
|
+
];
|
|
380
|
+
} finally {
|
|
381
|
+
currBatch = prevBatch;
|
|
382
|
+
}
|
|
364
383
|
};
|
|
365
384
|
|
|
366
385
|
/**
|
|
@@ -386,15 +405,18 @@ export interface RefSignalSetter<in T> {
|
|
|
386
405
|
/**
|
|
387
406
|
* Creates a new signal with write capabilities.
|
|
388
407
|
*/
|
|
389
|
-
export const useRef: (<T>(value: T, opts?:
|
|
390
|
-
(<T>(
|
|
408
|
+
export const useRef: (<T>(value: T, opts?: SignalOptions<T>) => RefSignal<T>) &
|
|
409
|
+
(<T>(
|
|
410
|
+
value?: T,
|
|
411
|
+
opts?: SignalOptions<T | undefined>,
|
|
412
|
+
) => RefSignal<T | undefined>) = (<T>(
|
|
391
413
|
value?: T,
|
|
392
|
-
opts?:
|
|
414
|
+
opts?: SignalOptions<T | undefined>,
|
|
393
415
|
): RefSignal<T> & RefSignal<T | undefined> => {
|
|
394
416
|
const [signal, setter] = useSignal(value, opts);
|
|
395
417
|
(signal as RefSignal<T | undefined>).set = setter;
|
|
396
418
|
return signal as RefSignal<T> & RefSignal<T | undefined>;
|
|
397
|
-
};
|
|
419
|
+
}) as any;
|
|
398
420
|
|
|
399
421
|
/**
|
|
400
422
|
* Represents a value that can be a signal or a constant value.
|