isomorfeus-preact 10.8.0 → 10.9.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/isomorfeus_preact/preact/function_component/api.rb +24 -0
  3. data/lib/preact/version.rb +1 -1
  4. data/node_modules/.package-lock.json +5 -7
  5. data/node_modules/preact/compat/dist/compat.js +2 -2
  6. data/node_modules/preact/compat/dist/compat.js.map +1 -1
  7. data/node_modules/preact/compat/dist/compat.mjs +2 -2
  8. data/node_modules/preact/compat/dist/compat.module.js +2 -2
  9. data/node_modules/preact/compat/dist/compat.module.js.map +1 -1
  10. data/node_modules/preact/compat/dist/compat.umd.js +2 -2
  11. data/node_modules/preact/compat/dist/compat.umd.js.map +1 -1
  12. data/node_modules/preact/compat/src/index.d.ts +164 -155
  13. data/node_modules/preact/compat/src/index.js +223 -187
  14. data/node_modules/preact/compat/src/render.js +238 -238
  15. data/node_modules/preact/debug/dist/debug.js +2 -2
  16. data/node_modules/preact/debug/dist/debug.js.map +1 -1
  17. data/node_modules/preact/debug/dist/debug.mjs +2 -2
  18. data/node_modules/preact/debug/dist/debug.module.js +2 -2
  19. data/node_modules/preact/debug/dist/debug.module.js.map +1 -1
  20. data/node_modules/preact/debug/dist/debug.umd.js +2 -2
  21. data/node_modules/preact/debug/dist/debug.umd.js.map +1 -1
  22. data/node_modules/preact/debug/src/debug.js +437 -444
  23. data/node_modules/preact/devtools/dist/devtools.js +2 -2
  24. data/node_modules/preact/devtools/dist/devtools.js.map +1 -1
  25. data/node_modules/preact/devtools/dist/devtools.mjs +2 -2
  26. data/node_modules/preact/devtools/dist/devtools.module.js +2 -2
  27. data/node_modules/preact/devtools/dist/devtools.module.js.map +1 -1
  28. data/node_modules/preact/devtools/dist/devtools.umd.js +2 -2
  29. data/node_modules/preact/devtools/dist/devtools.umd.js.map +1 -1
  30. data/node_modules/preact/devtools/src/devtools.js +10 -10
  31. data/node_modules/preact/hooks/dist/hooks.js +2 -2
  32. data/node_modules/preact/hooks/dist/hooks.js.map +1 -1
  33. data/node_modules/preact/hooks/dist/hooks.mjs +2 -2
  34. data/node_modules/preact/hooks/dist/hooks.module.js +2 -2
  35. data/node_modules/preact/hooks/dist/hooks.module.js.map +1 -1
  36. data/node_modules/preact/hooks/dist/hooks.umd.js +2 -2
  37. data/node_modules/preact/hooks/dist/hooks.umd.js.map +1 -1
  38. data/node_modules/preact/hooks/src/index.js +417 -404
  39. data/node_modules/preact/hooks/src/internal.d.ts +3 -0
  40. data/node_modules/preact/package.json +304 -304
  41. data/node_modules/preact/src/jsx.d.ts +1014 -1013
  42. data/package.json +1 -1
  43. metadata +4 -4
@@ -1,404 +1,417 @@
1
- import { options } from 'preact';
2
-
3
- /** @type {number} */
4
- let currentIndex;
5
-
6
- /** @type {import('./internal').Component} */
7
- let currentComponent;
8
-
9
- /** @type {import('./internal').Component} */
10
- let previousComponent;
11
-
12
- /** @type {number} */
13
- let currentHook = 0;
14
-
15
- /** @type {Array<import('./internal').Component>} */
16
- let afterPaintEffects = [];
17
-
18
- let oldBeforeDiff = options._diff;
19
- let oldBeforeRender = options._render;
20
- let oldAfterDiff = options.diffed;
21
- let oldCommit = options._commit;
22
- let oldBeforeUnmount = options.unmount;
23
-
24
- const RAF_TIMEOUT = 100;
25
- let prevRaf;
26
-
27
- options._diff = vnode => {
28
- currentComponent = null;
29
- if (oldBeforeDiff) oldBeforeDiff(vnode);
30
- };
31
-
32
- options._render = vnode => {
33
- if (oldBeforeRender) oldBeforeRender(vnode);
34
-
35
- currentComponent = vnode._component;
36
- currentIndex = 0;
37
-
38
- const hooks = currentComponent.__hooks;
39
- if (hooks) {
40
- if (previousComponent === currentComponent) {
41
- hooks._pendingEffects = [];
42
- currentComponent._renderCallbacks = [];
43
- hooks._list.forEach(hookItem => {
44
- if (hookItem._args) hookItem._args = undefined;
45
- });
46
- } else {
47
- hooks._pendingEffects.forEach(invokeCleanup);
48
- hooks._pendingEffects.forEach(invokeEffect);
49
- hooks._pendingEffects = [];
50
- }
51
- }
52
- previousComponent = currentComponent;
53
- };
54
-
55
- options.diffed = vnode => {
56
- if (oldAfterDiff) oldAfterDiff(vnode);
57
-
58
- const c = vnode._component;
59
- if (c && c.__hooks && c.__hooks._pendingEffects.length) {
60
- afterPaint(afterPaintEffects.push(c));
61
- }
62
- currentComponent = null;
63
- previousComponent = null;
64
- };
65
-
66
- options._commit = (vnode, commitQueue) => {
67
- commitQueue.some(component => {
68
- try {
69
- component._renderCallbacks.forEach(invokeCleanup);
70
- component._renderCallbacks = component._renderCallbacks.filter(cb =>
71
- cb._value ? invokeEffect(cb) : true
72
- );
73
- } catch (e) {
74
- commitQueue.some(c => {
75
- if (c._renderCallbacks) c._renderCallbacks = [];
76
- });
77
- commitQueue = [];
78
- options._catchError(e, component._vnode);
79
- }
80
- });
81
-
82
- if (oldCommit) oldCommit(vnode, commitQueue);
83
- };
84
-
85
- options.unmount = vnode => {
86
- if (oldBeforeUnmount) oldBeforeUnmount(vnode);
87
-
88
- const c = vnode._component;
89
- if (c && c.__hooks) {
90
- let hasErrored;
91
- c.__hooks._list.forEach(s => {
92
- try {
93
- invokeCleanup(s);
94
- } catch (e) {
95
- hasErrored = e;
96
- }
97
- });
98
- if (hasErrored) options._catchError(hasErrored, c._vnode);
99
- }
100
- };
101
-
102
- /**
103
- * Get a hook's state from the currentComponent
104
- * @param {number} index The index of the hook to get
105
- * @param {number} type The index of the hook to get
106
- * @returns {any}
107
- */
108
- function getHookState(index, type) {
109
- if (options._hook) {
110
- options._hook(currentComponent, index, currentHook || type);
111
- }
112
- currentHook = 0;
113
-
114
- // Largely inspired by:
115
- // * https://github.com/michael-klein/funcy.js/blob/f6be73468e6ec46b0ff5aa3cc4c9baf72a29025a/src/hooks/core_hooks.mjs
116
- // * https://github.com/michael-klein/funcy.js/blob/650beaa58c43c33a74820a3c98b3c7079cf2e333/src/renderer.mjs
117
- // Other implementations to look at:
118
- // * https://codesandbox.io/s/mnox05qp8
119
- const hooks =
120
- currentComponent.__hooks ||
121
- (currentComponent.__hooks = {
122
- _list: [],
123
- _pendingEffects: []
124
- });
125
-
126
- if (index >= hooks._list.length) {
127
- hooks._list.push({});
128
- }
129
- return hooks._list[index];
130
- }
131
-
132
- /**
133
- * @param {import('./index').StateUpdater<any>} [initialState]
134
- */
135
- export function useState(initialState) {
136
- currentHook = 1;
137
- return useReducer(invokeOrReturn, initialState);
138
- }
139
-
140
- /**
141
- * @param {import('./index').Reducer<any, any>} reducer
142
- * @param {import('./index').StateUpdater<any>} initialState
143
- * @param {(initialState: any) => void} [init]
144
- * @returns {[ any, (state: any) => void ]}
145
- */
146
- export function useReducer(reducer, initialState, init) {
147
- /** @type {import('./internal').ReducerHookState} */
148
- const hookState = getHookState(currentIndex++, 2);
149
- hookState._reducer = reducer;
150
- if (!hookState._component) {
151
- hookState._value = [
152
- !init ? invokeOrReturn(undefined, initialState) : init(initialState),
153
-
154
- action => {
155
- const nextValue = hookState._reducer(hookState._value[0], action);
156
- if (hookState._value[0] !== nextValue) {
157
- hookState._value = [nextValue, hookState._value[1]];
158
- hookState._component.setState({});
159
- }
160
- }
161
- ];
162
-
163
- hookState._component = currentComponent;
164
- }
165
-
166
- return hookState._value;
167
- }
168
-
169
- /**
170
- * @param {import('./internal').Effect} callback
171
- * @param {any[]} args
172
- */
173
- export function useEffect(callback, args) {
174
- /** @type {import('./internal').EffectHookState} */
175
- const state = getHookState(currentIndex++, 3);
176
- if (!options._skipEffects && argsChanged(state._args, args)) {
177
- state._value = callback;
178
- state._args = args;
179
-
180
- currentComponent.__hooks._pendingEffects.push(state);
181
- }
182
- }
183
-
184
- /**
185
- * @param {import('./internal').Effect} callback
186
- * @param {any[]} args
187
- */
188
- export function useLayoutEffect(callback, args) {
189
- /** @type {import('./internal').EffectHookState} */
190
- const state = getHookState(currentIndex++, 4);
191
- if (!options._skipEffects && argsChanged(state._args, args)) {
192
- state._value = callback;
193
- state._args = args;
194
-
195
- currentComponent._renderCallbacks.push(state);
196
- }
197
- }
198
-
199
- export function useRef(initialValue) {
200
- currentHook = 5;
201
- return useMemo(() => ({ current: initialValue }), []);
202
- }
203
-
204
- /**
205
- * @param {object} ref
206
- * @param {() => object} createHandle
207
- * @param {any[]} args
208
- */
209
- export function useImperativeHandle(ref, createHandle, args) {
210
- currentHook = 6;
211
- useLayoutEffect(
212
- () => {
213
- if (typeof ref == 'function') {
214
- ref(createHandle());
215
- return () => ref(null);
216
- } else if (ref) {
217
- ref.current = createHandle();
218
- return () => (ref.current = null);
219
- }
220
- },
221
- args == null ? args : args.concat(ref)
222
- );
223
- }
224
-
225
- /**
226
- * @param {() => any} factory
227
- * @param {any[]} args
228
- */
229
- export function useMemo(factory, args) {
230
- /** @type {import('./internal').MemoHookState} */
231
- const state = getHookState(currentIndex++, 7);
232
- if (argsChanged(state._args, args)) {
233
- state._value = factory();
234
- state._args = args;
235
- state._factory = factory;
236
- }
237
-
238
- return state._value;
239
- }
240
-
241
- /**
242
- * @param {() => void} callback
243
- * @param {any[]} args
244
- */
245
- export function useCallback(callback, args) {
246
- currentHook = 8;
247
- return useMemo(() => callback, args);
248
- }
249
-
250
- /**
251
- * @param {import('./internal').PreactContext} context
252
- */
253
- export function useContext(context) {
254
- const provider = currentComponent.context[context._id];
255
- // We could skip this call here, but than we'd not call
256
- // `options._hook`. We need to do that in order to make
257
- // the devtools aware of this hook.
258
- /** @type {import('./internal').ContextHookState} */
259
- const state = getHookState(currentIndex++, 9);
260
- // The devtools needs access to the context object to
261
- // be able to pull of the default value when no provider
262
- // is present in the tree.
263
- state._context = context;
264
- if (!provider) return context._defaultValue;
265
- // This is probably not safe to convert to "!"
266
- if (state._value == null) {
267
- state._value = true;
268
- provider.sub(currentComponent);
269
- }
270
- return provider.props.value;
271
- }
272
-
273
- /**
274
- * Display a custom label for a custom hook for the devtools panel
275
- * @type {<T>(value: T, cb?: (value: T) => string | number) => void}
276
- */
277
- export function useDebugValue(value, formatter) {
278
- if (options.useDebugValue) {
279
- options.useDebugValue(formatter ? formatter(value) : value);
280
- }
281
- }
282
-
283
- /**
284
- * @param {(error: any) => void} cb
285
- */
286
- export function useErrorBoundary(cb) {
287
- /** @type {import('./internal').ErrorBoundaryHookState} */
288
- const state = getHookState(currentIndex++, 10);
289
- const errState = useState();
290
- state._value = cb;
291
- if (!currentComponent.componentDidCatch) {
292
- currentComponent.componentDidCatch = err => {
293
- if (state._value) state._value(err);
294
- errState[1](err);
295
- };
296
- }
297
- return [
298
- errState[0],
299
- () => {
300
- errState[1](undefined);
301
- }
302
- ];
303
- }
304
-
305
- /**
306
- * After paint effects consumer.
307
- */
308
- function flushAfterPaintEffects() {
309
- let component;
310
- while ((component = afterPaintEffects.shift())) {
311
- if (!component._parentDom) continue;
312
- try {
313
- component.__hooks._pendingEffects.forEach(invokeCleanup);
314
- component.__hooks._pendingEffects.forEach(invokeEffect);
315
- component.__hooks._pendingEffects = [];
316
- } catch (e) {
317
- component.__hooks._pendingEffects = [];
318
- options._catchError(e, component._vnode);
319
- }
320
- }
321
- }
322
-
323
- let HAS_RAF = typeof requestAnimationFrame == 'function';
324
-
325
- /**
326
- * Schedule a callback to be invoked after the browser has a chance to paint a new frame.
327
- * Do this by combining requestAnimationFrame (rAF) + setTimeout to invoke a callback after
328
- * the next browser frame.
329
- *
330
- * Also, schedule a timeout in parallel to the the rAF to ensure the callback is invoked
331
- * even if RAF doesn't fire (for example if the browser tab is not visible)
332
- *
333
- * @param {() => void} callback
334
- */
335
- function afterNextFrame(callback) {
336
- const done = () => {
337
- clearTimeout(timeout);
338
- if (HAS_RAF) cancelAnimationFrame(raf);
339
- setTimeout(callback);
340
- };
341
- const timeout = setTimeout(done, RAF_TIMEOUT);
342
-
343
- let raf;
344
- if (HAS_RAF) {
345
- raf = requestAnimationFrame(done);
346
- }
347
- }
348
-
349
- // Note: if someone used options.debounceRendering = requestAnimationFrame,
350
- // then effects will ALWAYS run on the NEXT frame instead of the current one, incurring a ~16ms delay.
351
- // Perhaps this is not such a big deal.
352
- /**
353
- * Schedule afterPaintEffects flush after the browser paints
354
- * @param {number} newQueueLength
355
- */
356
- function afterPaint(newQueueLength) {
357
- if (newQueueLength === 1 || prevRaf !== options.requestAnimationFrame) {
358
- prevRaf = options.requestAnimationFrame;
359
- (prevRaf || afterNextFrame)(flushAfterPaintEffects);
360
- }
361
- }
362
-
363
- /**
364
- * @param {import('./internal').EffectHookState} hook
365
- */
366
- function invokeCleanup(hook) {
367
- // A hook cleanup can introduce a call to render which creates a new root, this will call options.vnode
368
- // and move the currentComponent away.
369
- const comp = currentComponent;
370
- let cleanup = hook._cleanup;
371
- if (typeof cleanup == 'function') {
372
- hook._cleanup = undefined;
373
- cleanup();
374
- }
375
- currentComponent = comp;
376
- }
377
-
378
- /**
379
- * Invoke a Hook's effect
380
- * @param {import('./internal').EffectHookState} hook
381
- */
382
- function invokeEffect(hook) {
383
- // A hook call can introduce a call to render which creates a new root, this will call options.vnode
384
- // and move the currentComponent away.
385
- const comp = currentComponent;
386
- hook._cleanup = hook._value();
387
- currentComponent = comp;
388
- }
389
-
390
- /**
391
- * @param {any[]} oldArgs
392
- * @param {any[]} newArgs
393
- */
394
- function argsChanged(oldArgs, newArgs) {
395
- return (
396
- !oldArgs ||
397
- oldArgs.length !== newArgs.length ||
398
- newArgs.some((arg, index) => arg !== oldArgs[index])
399
- );
400
- }
401
-
402
- function invokeOrReturn(arg, f) {
403
- return typeof f == 'function' ? f(arg) : f;
404
- }
1
+ import { options } from 'preact';
2
+
3
+ /** @type {number} */
4
+ let currentIndex;
5
+
6
+ /** @type {import('./internal').Component} */
7
+ let currentComponent;
8
+
9
+ /** @type {import('./internal').Component} */
10
+ let previousComponent;
11
+
12
+ /** @type {number} */
13
+ let currentHook = 0;
14
+
15
+ /** @type {Array<import('./internal').Component>} */
16
+ let afterPaintEffects = [];
17
+
18
+ let EMPTY = [];
19
+
20
+ let oldBeforeDiff = options._diff;
21
+ let oldBeforeRender = options._render;
22
+ let oldAfterDiff = options.diffed;
23
+ let oldCommit = options._commit;
24
+ let oldBeforeUnmount = options.unmount;
25
+
26
+ const RAF_TIMEOUT = 100;
27
+ let prevRaf;
28
+
29
+ options._diff = vnode => {
30
+ currentComponent = null;
31
+ if (oldBeforeDiff) oldBeforeDiff(vnode);
32
+ };
33
+
34
+ options._render = vnode => {
35
+ if (oldBeforeRender) oldBeforeRender(vnode);
36
+
37
+ currentComponent = vnode._component;
38
+ currentIndex = 0;
39
+
40
+ const hooks = currentComponent.__hooks;
41
+ if (hooks) {
42
+ if (previousComponent === currentComponent) {
43
+ hooks._pendingEffects = [];
44
+ currentComponent._renderCallbacks = [];
45
+ hooks._list.forEach(hookItem => {
46
+ hookItem._pendingValue = EMPTY;
47
+ hookItem._pendingArgs = undefined;
48
+ });
49
+ } else {
50
+ hooks._pendingEffects.forEach(invokeCleanup);
51
+ hooks._pendingEffects.forEach(invokeEffect);
52
+ hooks._pendingEffects = [];
53
+ }
54
+ }
55
+ previousComponent = currentComponent;
56
+ };
57
+
58
+ options.diffed = vnode => {
59
+ if (oldAfterDiff) oldAfterDiff(vnode);
60
+
61
+ const c = vnode._component;
62
+ if (c && c.__hooks) {
63
+ if (c.__hooks._pendingEffects.length) afterPaint(afterPaintEffects.push(c));
64
+ c.__hooks._list.forEach(hookItem => {
65
+ if (hookItem._pendingArgs) {
66
+ hookItem._args = hookItem._pendingArgs;
67
+ }
68
+ if (hookItem._pendingValue !== EMPTY) {
69
+ hookItem._value = hookItem._pendingValue;
70
+ }
71
+ hookItem._pendingArgs = undefined;
72
+ hookItem._pendingValue = EMPTY;
73
+ });
74
+ }
75
+ previousComponent = currentComponent = null;
76
+ };
77
+
78
+ options._commit = (vnode, commitQueue) => {
79
+ commitQueue.some(component => {
80
+ try {
81
+ component._renderCallbacks.forEach(invokeCleanup);
82
+ component._renderCallbacks = component._renderCallbacks.filter(cb =>
83
+ cb._value ? invokeEffect(cb) : true
84
+ );
85
+ } catch (e) {
86
+ commitQueue.some(c => {
87
+ if (c._renderCallbacks) c._renderCallbacks = [];
88
+ });
89
+ commitQueue = [];
90
+ options._catchError(e, component._vnode);
91
+ }
92
+ });
93
+
94
+ if (oldCommit) oldCommit(vnode, commitQueue);
95
+ };
96
+
97
+ options.unmount = vnode => {
98
+ if (oldBeforeUnmount) oldBeforeUnmount(vnode);
99
+
100
+ const c = vnode._component;
101
+ if (c && c.__hooks) {
102
+ let hasErrored;
103
+ c.__hooks._list.forEach(s => {
104
+ try {
105
+ invokeCleanup(s);
106
+ } catch (e) {
107
+ hasErrored = e;
108
+ }
109
+ });
110
+ if (hasErrored) options._catchError(hasErrored, c._vnode);
111
+ }
112
+ };
113
+
114
+ /**
115
+ * Get a hook's state from the currentComponent
116
+ * @param {number} index The index of the hook to get
117
+ * @param {number} type The index of the hook to get
118
+ * @returns {any}
119
+ */
120
+ function getHookState(index, type) {
121
+ if (options._hook) {
122
+ options._hook(currentComponent, index, currentHook || type);
123
+ }
124
+ currentHook = 0;
125
+
126
+ // Largely inspired by:
127
+ // * https://github.com/michael-klein/funcy.js/blob/f6be73468e6ec46b0ff5aa3cc4c9baf72a29025a/src/hooks/core_hooks.mjs
128
+ // * https://github.com/michael-klein/funcy.js/blob/650beaa58c43c33a74820a3c98b3c7079cf2e333/src/renderer.mjs
129
+ // Other implementations to look at:
130
+ // * https://codesandbox.io/s/mnox05qp8
131
+ const hooks =
132
+ currentComponent.__hooks ||
133
+ (currentComponent.__hooks = {
134
+ _list: [],
135
+ _pendingEffects: []
136
+ });
137
+
138
+ if (index >= hooks._list.length) {
139
+ hooks._list.push({ _pendingValue: EMPTY });
140
+ }
141
+ return hooks._list[index];
142
+ }
143
+
144
+ /**
145
+ * @param {import('./index').StateUpdater<any>} [initialState]
146
+ */
147
+ export function useState(initialState) {
148
+ currentHook = 1;
149
+ return useReducer(invokeOrReturn, initialState);
150
+ }
151
+
152
+ /**
153
+ * @param {import('./index').Reducer<any, any>} reducer
154
+ * @param {import('./index').StateUpdater<any>} initialState
155
+ * @param {(initialState: any) => void} [init]
156
+ * @returns {[ any, (state: any) => void ]}
157
+ */
158
+ export function useReducer(reducer, initialState, init) {
159
+ /** @type {import('./internal').ReducerHookState} */
160
+ const hookState = getHookState(currentIndex++, 2);
161
+ hookState._reducer = reducer;
162
+ if (!hookState._component) {
163
+ hookState._value = [
164
+ !init ? invokeOrReturn(undefined, initialState) : init(initialState),
165
+
166
+ action => {
167
+ const nextValue = hookState._reducer(hookState._value[0], action);
168
+ if (hookState._value[0] !== nextValue) {
169
+ hookState._value = [nextValue, hookState._value[1]];
170
+ hookState._component.setState({});
171
+ }
172
+ }
173
+ ];
174
+
175
+ hookState._component = currentComponent;
176
+ }
177
+
178
+ return hookState._value;
179
+ }
180
+
181
+ /**
182
+ * @param {import('./internal').Effect} callback
183
+ * @param {any[]} args
184
+ */
185
+ export function useEffect(callback, args) {
186
+ /** @type {import('./internal').EffectHookState} */
187
+ const state = getHookState(currentIndex++, 3);
188
+ if (!options._skipEffects && argsChanged(state._args, args)) {
189
+ state._value = callback;
190
+ state._pendingArgs = args;
191
+
192
+ currentComponent.__hooks._pendingEffects.push(state);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * @param {import('./internal').Effect} callback
198
+ * @param {any[]} args
199
+ */
200
+ export function useLayoutEffect(callback, args) {
201
+ /** @type {import('./internal').EffectHookState} */
202
+ const state = getHookState(currentIndex++, 4);
203
+ if (!options._skipEffects && argsChanged(state._args, args)) {
204
+ state._value = callback;
205
+ state._pendingArgs = args;
206
+
207
+ currentComponent._renderCallbacks.push(state);
208
+ }
209
+ }
210
+
211
+ export function useRef(initialValue) {
212
+ currentHook = 5;
213
+ return useMemo(() => ({ current: initialValue }), []);
214
+ }
215
+
216
+ /**
217
+ * @param {object} ref
218
+ * @param {() => object} createHandle
219
+ * @param {any[]} args
220
+ */
221
+ export function useImperativeHandle(ref, createHandle, args) {
222
+ currentHook = 6;
223
+ useLayoutEffect(
224
+ () => {
225
+ if (typeof ref == 'function') {
226
+ ref(createHandle());
227
+ return () => ref(null);
228
+ } else if (ref) {
229
+ ref.current = createHandle();
230
+ return () => (ref.current = null);
231
+ }
232
+ },
233
+ args == null ? args : args.concat(ref)
234
+ );
235
+ }
236
+
237
+ /**
238
+ * @param {() => any} factory
239
+ * @param {any[]} args
240
+ */
241
+ export function useMemo(factory, args) {
242
+ /** @type {import('./internal').MemoHookState} */
243
+ const state = getHookState(currentIndex++, 7);
244
+ if (argsChanged(state._args, args)) {
245
+ state._pendingValue = factory();
246
+ state._pendingArgs = args;
247
+ state._factory = factory;
248
+ return state._pendingValue;
249
+ }
250
+
251
+ return state._value;
252
+ }
253
+
254
+ /**
255
+ * @param {() => void} callback
256
+ * @param {any[]} args
257
+ */
258
+ export function useCallback(callback, args) {
259
+ currentHook = 8;
260
+ return useMemo(() => callback, args);
261
+ }
262
+
263
+ /**
264
+ * @param {import('./internal').PreactContext} context
265
+ */
266
+ export function useContext(context) {
267
+ const provider = currentComponent.context[context._id];
268
+ // We could skip this call here, but than we'd not call
269
+ // `options._hook`. We need to do that in order to make
270
+ // the devtools aware of this hook.
271
+ /** @type {import('./internal').ContextHookState} */
272
+ const state = getHookState(currentIndex++, 9);
273
+ // The devtools needs access to the context object to
274
+ // be able to pull of the default value when no provider
275
+ // is present in the tree.
276
+ state._context = context;
277
+ if (!provider) return context._defaultValue;
278
+ // This is probably not safe to convert to "!"
279
+ if (state._value == null) {
280
+ state._value = true;
281
+ provider.sub(currentComponent);
282
+ }
283
+ return provider.props.value;
284
+ }
285
+
286
+ /**
287
+ * Display a custom label for a custom hook for the devtools panel
288
+ * @type {<T>(value: T, cb?: (value: T) => string | number) => void}
289
+ */
290
+ export function useDebugValue(value, formatter) {
291
+ if (options.useDebugValue) {
292
+ options.useDebugValue(formatter ? formatter(value) : value);
293
+ }
294
+ }
295
+
296
+ /**
297
+ * @param {(error: any) => void} cb
298
+ */
299
+ export function useErrorBoundary(cb) {
300
+ /** @type {import('./internal').ErrorBoundaryHookState} */
301
+ const state = getHookState(currentIndex++, 10);
302
+ const errState = useState();
303
+ state._value = cb;
304
+ if (!currentComponent.componentDidCatch) {
305
+ currentComponent.componentDidCatch = err => {
306
+ if (state._value) state._value(err);
307
+ errState[1](err);
308
+ };
309
+ }
310
+ return [
311
+ errState[0],
312
+ () => {
313
+ errState[1](undefined);
314
+ }
315
+ ];
316
+ }
317
+
318
+ /**
319
+ * After paint effects consumer.
320
+ */
321
+ function flushAfterPaintEffects() {
322
+ let component;
323
+ while ((component = afterPaintEffects.shift())) {
324
+ if (!component._parentDom) continue;
325
+ try {
326
+ component.__hooks._pendingEffects.forEach(invokeCleanup);
327
+ component.__hooks._pendingEffects.forEach(invokeEffect);
328
+ component.__hooks._pendingEffects = [];
329
+ } catch (e) {
330
+ component.__hooks._pendingEffects = [];
331
+ options._catchError(e, component._vnode);
332
+ }
333
+ }
334
+ }
335
+
336
+ let HAS_RAF = typeof requestAnimationFrame == 'function';
337
+
338
+ /**
339
+ * Schedule a callback to be invoked after the browser has a chance to paint a new frame.
340
+ * Do this by combining requestAnimationFrame (rAF) + setTimeout to invoke a callback after
341
+ * the next browser frame.
342
+ *
343
+ * Also, schedule a timeout in parallel to the the rAF to ensure the callback is invoked
344
+ * even if RAF doesn't fire (for example if the browser tab is not visible)
345
+ *
346
+ * @param {() => void} callback
347
+ */
348
+ function afterNextFrame(callback) {
349
+ const done = () => {
350
+ clearTimeout(timeout);
351
+ if (HAS_RAF) cancelAnimationFrame(raf);
352
+ setTimeout(callback);
353
+ };
354
+ const timeout = setTimeout(done, RAF_TIMEOUT);
355
+
356
+ let raf;
357
+ if (HAS_RAF) {
358
+ raf = requestAnimationFrame(done);
359
+ }
360
+ }
361
+
362
+ // Note: if someone used options.debounceRendering = requestAnimationFrame,
363
+ // then effects will ALWAYS run on the NEXT frame instead of the current one, incurring a ~16ms delay.
364
+ // Perhaps this is not such a big deal.
365
+ /**
366
+ * Schedule afterPaintEffects flush after the browser paints
367
+ * @param {number} newQueueLength
368
+ */
369
+ function afterPaint(newQueueLength) {
370
+ if (newQueueLength === 1 || prevRaf !== options.requestAnimationFrame) {
371
+ prevRaf = options.requestAnimationFrame;
372
+ (prevRaf || afterNextFrame)(flushAfterPaintEffects);
373
+ }
374
+ }
375
+
376
+ /**
377
+ * @param {import('./internal').EffectHookState} hook
378
+ */
379
+ function invokeCleanup(hook) {
380
+ // A hook cleanup can introduce a call to render which creates a new root, this will call options.vnode
381
+ // and move the currentComponent away.
382
+ const comp = currentComponent;
383
+ let cleanup = hook._cleanup;
384
+ if (typeof cleanup == 'function') {
385
+ hook._cleanup = undefined;
386
+ cleanup();
387
+ }
388
+ currentComponent = comp;
389
+ }
390
+
391
+ /**
392
+ * Invoke a Hook's effect
393
+ * @param {import('./internal').EffectHookState} hook
394
+ */
395
+ function invokeEffect(hook) {
396
+ // A hook call can introduce a call to render which creates a new root, this will call options.vnode
397
+ // and move the currentComponent away.
398
+ const comp = currentComponent;
399
+ hook._cleanup = hook._value();
400
+ currentComponent = comp;
401
+ }
402
+
403
+ /**
404
+ * @param {any[]} oldArgs
405
+ * @param {any[]} newArgs
406
+ */
407
+ function argsChanged(oldArgs, newArgs) {
408
+ return (
409
+ !oldArgs ||
410
+ oldArgs.length !== newArgs.length ||
411
+ newArgs.some((arg, index) => arg !== oldArgs[index])
412
+ );
413
+ }
414
+
415
+ function invokeOrReturn(arg, f) {
416
+ return typeof f == 'function' ? f(arg) : f;
417
+ }