hadars 0.1.28 → 0.1.29
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/cli.js +141 -3
- package/dist/slim-react/index.cjs +79 -5
- package/dist/slim-react/index.js +69 -5
- package/dist/ssr-render-worker.js +141 -3
- package/package.json +1 -1
- package/src/slim-react/dispatcher.ts +69 -0
- package/src/slim-react/render.ts +30 -3
- package/src/slim-react/renderContext.ts +14 -8
package/dist/cli.js
CHANGED
|
@@ -242,6 +242,9 @@ function pushComponentScope() {
|
|
|
242
242
|
function popComponentScope(saved) {
|
|
243
243
|
s().localIdCounter = saved;
|
|
244
244
|
}
|
|
245
|
+
function componentCalledUseId() {
|
|
246
|
+
return s().localIdCounter > 0;
|
|
247
|
+
}
|
|
245
248
|
function snapshotContext() {
|
|
246
249
|
const st = s();
|
|
247
250
|
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
@@ -251,6 +254,121 @@ function restoreContext(snap) {
|
|
|
251
254
|
st.currentTreeContext = { ...snap.tree };
|
|
252
255
|
st.localIdCounter = snap.localId;
|
|
253
256
|
}
|
|
257
|
+
function getTreeId() {
|
|
258
|
+
const { id, overflow } = s().currentTreeContext;
|
|
259
|
+
if (id === 1)
|
|
260
|
+
return overflow;
|
|
261
|
+
const stripped = (id & ~(1 << 31 - Math.clz32(id))).toString(32);
|
|
262
|
+
return stripped + overflow;
|
|
263
|
+
}
|
|
264
|
+
function makeId() {
|
|
265
|
+
const st = s();
|
|
266
|
+
const treeId = getTreeId();
|
|
267
|
+
const n = st.localIdCounter++;
|
|
268
|
+
let id = "\xAB" + st.idPrefix + "R" + treeId;
|
|
269
|
+
if (n > 0)
|
|
270
|
+
id += "H" + n.toString(32);
|
|
271
|
+
return id + "\xBB";
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/slim-react/hooks.ts
|
|
275
|
+
function useState(initialState) {
|
|
276
|
+
const value = typeof initialState === "function" ? initialState() : initialState;
|
|
277
|
+
return [value, () => {
|
|
278
|
+
}];
|
|
279
|
+
}
|
|
280
|
+
function useReducer(_reducer, initialState) {
|
|
281
|
+
return [initialState, () => {
|
|
282
|
+
}];
|
|
283
|
+
}
|
|
284
|
+
function useEffect(_effect, _deps) {
|
|
285
|
+
}
|
|
286
|
+
function useLayoutEffect(_effect, _deps) {
|
|
287
|
+
}
|
|
288
|
+
function useInsertionEffect(_effect, _deps) {
|
|
289
|
+
}
|
|
290
|
+
function useRef(initialValue) {
|
|
291
|
+
return { current: initialValue };
|
|
292
|
+
}
|
|
293
|
+
function useMemo(factory, _deps) {
|
|
294
|
+
return factory();
|
|
295
|
+
}
|
|
296
|
+
function useCallback(callback, _deps) {
|
|
297
|
+
return callback;
|
|
298
|
+
}
|
|
299
|
+
function useDebugValue(_value, _format) {
|
|
300
|
+
}
|
|
301
|
+
function useImperativeHandle(_ref, _createHandle, _deps) {
|
|
302
|
+
}
|
|
303
|
+
function useSyncExternalStore(_subscribe, getSnapshot, getServerSnapshot) {
|
|
304
|
+
return (getServerSnapshot || getSnapshot)();
|
|
305
|
+
}
|
|
306
|
+
function useTransition() {
|
|
307
|
+
return [false, (cb) => cb()];
|
|
308
|
+
}
|
|
309
|
+
function useDeferredValue(value) {
|
|
310
|
+
return value;
|
|
311
|
+
}
|
|
312
|
+
function useOptimistic(passthrough) {
|
|
313
|
+
return [passthrough, () => {
|
|
314
|
+
}];
|
|
315
|
+
}
|
|
316
|
+
function useActionState(_action, initialState, _permalink) {
|
|
317
|
+
return [initialState, () => {
|
|
318
|
+
}, false];
|
|
319
|
+
}
|
|
320
|
+
function use(usable) {
|
|
321
|
+
if (typeof usable === "object" && usable !== null && ("_currentValue" in usable || "_defaultValue" in usable)) {
|
|
322
|
+
return getContextValue(usable);
|
|
323
|
+
}
|
|
324
|
+
const promise = usable;
|
|
325
|
+
if (promise.status === "fulfilled")
|
|
326
|
+
return promise.value;
|
|
327
|
+
if (promise.status === "rejected")
|
|
328
|
+
throw promise.reason;
|
|
329
|
+
throw promise;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/slim-react/dispatcher.ts
|
|
333
|
+
import ReactPkg from "react";
|
|
334
|
+
var _internals = ReactPkg.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
335
|
+
var slimDispatcher = {
|
|
336
|
+
useId: makeId,
|
|
337
|
+
readContext: (ctx) => getContextValue(ctx),
|
|
338
|
+
useContext: (ctx) => getContextValue(ctx),
|
|
339
|
+
useState,
|
|
340
|
+
useReducer,
|
|
341
|
+
useEffect,
|
|
342
|
+
useLayoutEffect,
|
|
343
|
+
useInsertionEffect,
|
|
344
|
+
useRef,
|
|
345
|
+
useMemo,
|
|
346
|
+
useCallback,
|
|
347
|
+
useDebugValue,
|
|
348
|
+
useImperativeHandle,
|
|
349
|
+
useSyncExternalStore,
|
|
350
|
+
useTransition,
|
|
351
|
+
useDeferredValue,
|
|
352
|
+
useOptimistic,
|
|
353
|
+
useActionState,
|
|
354
|
+
use,
|
|
355
|
+
// React internals that compiled output may call
|
|
356
|
+
useMemoCache: (size) => new Array(size).fill(void 0),
|
|
357
|
+
useCacheRefresh: () => () => {
|
|
358
|
+
},
|
|
359
|
+
useHostTransitionStatus: () => false
|
|
360
|
+
};
|
|
361
|
+
function installDispatcher() {
|
|
362
|
+
if (!_internals)
|
|
363
|
+
return null;
|
|
364
|
+
const prev = _internals.H;
|
|
365
|
+
_internals.H = slimDispatcher;
|
|
366
|
+
return prev;
|
|
367
|
+
}
|
|
368
|
+
function restoreDispatcher(prev) {
|
|
369
|
+
if (_internals)
|
|
370
|
+
_internals.H = prev;
|
|
371
|
+
}
|
|
254
372
|
|
|
255
373
|
// src/slim-react/render.ts
|
|
256
374
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
@@ -655,6 +773,7 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
655
773
|
return;
|
|
656
774
|
}
|
|
657
775
|
let result;
|
|
776
|
+
const prevDispatcher = installDispatcher();
|
|
658
777
|
try {
|
|
659
778
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
660
779
|
const instance = new type(props);
|
|
@@ -668,12 +787,20 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
668
787
|
result = type(props);
|
|
669
788
|
}
|
|
670
789
|
} catch (e) {
|
|
790
|
+
restoreDispatcher(prevDispatcher);
|
|
671
791
|
popComponentScope(savedScope);
|
|
672
792
|
if (isProvider)
|
|
673
793
|
popContextValue(ctx, prevCtxValue);
|
|
674
794
|
throw e;
|
|
675
795
|
}
|
|
796
|
+
restoreDispatcher(prevDispatcher);
|
|
797
|
+
let savedIdTree;
|
|
798
|
+
if (!(result instanceof Promise) && componentCalledUseId()) {
|
|
799
|
+
savedIdTree = pushTreeContext(1, 0);
|
|
800
|
+
}
|
|
676
801
|
const finish = () => {
|
|
802
|
+
if (savedIdTree !== void 0)
|
|
803
|
+
popTreeContext(savedIdTree);
|
|
677
804
|
popComponentScope(savedScope);
|
|
678
805
|
if (isProvider)
|
|
679
806
|
popContextValue(ctx, prevCtxValue);
|
|
@@ -682,22 +809,33 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
682
809
|
const m = captureMap();
|
|
683
810
|
return result.then((resolved) => {
|
|
684
811
|
swapContextMap(m);
|
|
812
|
+
let asyncSavedIdTree;
|
|
813
|
+
if (componentCalledUseId()) {
|
|
814
|
+
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
815
|
+
}
|
|
816
|
+
const asyncFinish = () => {
|
|
817
|
+
if (asyncSavedIdTree !== void 0)
|
|
818
|
+
popTreeContext(asyncSavedIdTree);
|
|
819
|
+
popComponentScope(savedScope);
|
|
820
|
+
if (isProvider)
|
|
821
|
+
popContextValue(ctx, prevCtxValue);
|
|
822
|
+
};
|
|
685
823
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
686
824
|
if (r2 && typeof r2.then === "function") {
|
|
687
825
|
const m2 = captureMap();
|
|
688
826
|
return r2.then(
|
|
689
827
|
() => {
|
|
690
828
|
swapContextMap(m2);
|
|
691
|
-
|
|
829
|
+
asyncFinish();
|
|
692
830
|
},
|
|
693
831
|
(e) => {
|
|
694
832
|
swapContextMap(m2);
|
|
695
|
-
|
|
833
|
+
asyncFinish();
|
|
696
834
|
throw e;
|
|
697
835
|
}
|
|
698
836
|
);
|
|
699
837
|
}
|
|
700
|
-
|
|
838
|
+
asyncFinish();
|
|
701
839
|
}, (e) => {
|
|
702
840
|
swapContextMap(m);
|
|
703
841
|
finish();
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/slim-react/index.ts
|
|
@@ -182,6 +192,9 @@ function pushComponentScope() {
|
|
|
182
192
|
function popComponentScope(saved) {
|
|
183
193
|
s().localIdCounter = saved;
|
|
184
194
|
}
|
|
195
|
+
function componentCalledUseId() {
|
|
196
|
+
return s().localIdCounter > 0;
|
|
197
|
+
}
|
|
185
198
|
function snapshotContext() {
|
|
186
199
|
const st = s();
|
|
187
200
|
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
@@ -202,10 +215,10 @@ function makeId() {
|
|
|
202
215
|
const st = s();
|
|
203
216
|
const treeId = getTreeId();
|
|
204
217
|
const n = st.localIdCounter++;
|
|
205
|
-
let id = "
|
|
218
|
+
let id = "\xAB" + st.idPrefix + "R" + treeId;
|
|
206
219
|
if (n > 0)
|
|
207
220
|
id += "H" + n.toString(32);
|
|
208
|
-
return id + "
|
|
221
|
+
return id + "\xBB";
|
|
209
222
|
}
|
|
210
223
|
|
|
211
224
|
// src/slim-react/hooks.ts
|
|
@@ -298,6 +311,47 @@ function createContext(defaultValue) {
|
|
|
298
311
|
return context;
|
|
299
312
|
}
|
|
300
313
|
|
|
314
|
+
// src/slim-react/dispatcher.ts
|
|
315
|
+
var import_react = __toESM(require("react"), 1);
|
|
316
|
+
var _internals = import_react.default.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
317
|
+
var slimDispatcher = {
|
|
318
|
+
useId: makeId,
|
|
319
|
+
readContext: (ctx) => getContextValue(ctx),
|
|
320
|
+
useContext: (ctx) => getContextValue(ctx),
|
|
321
|
+
useState,
|
|
322
|
+
useReducer,
|
|
323
|
+
useEffect,
|
|
324
|
+
useLayoutEffect,
|
|
325
|
+
useInsertionEffect,
|
|
326
|
+
useRef,
|
|
327
|
+
useMemo,
|
|
328
|
+
useCallback,
|
|
329
|
+
useDebugValue,
|
|
330
|
+
useImperativeHandle,
|
|
331
|
+
useSyncExternalStore,
|
|
332
|
+
useTransition,
|
|
333
|
+
useDeferredValue,
|
|
334
|
+
useOptimistic,
|
|
335
|
+
useActionState,
|
|
336
|
+
use,
|
|
337
|
+
// React internals that compiled output may call
|
|
338
|
+
useMemoCache: (size) => new Array(size).fill(void 0),
|
|
339
|
+
useCacheRefresh: () => () => {
|
|
340
|
+
},
|
|
341
|
+
useHostTransitionStatus: () => false
|
|
342
|
+
};
|
|
343
|
+
function installDispatcher() {
|
|
344
|
+
if (!_internals)
|
|
345
|
+
return null;
|
|
346
|
+
const prev = _internals.H;
|
|
347
|
+
_internals.H = slimDispatcher;
|
|
348
|
+
return prev;
|
|
349
|
+
}
|
|
350
|
+
function restoreDispatcher(prev) {
|
|
351
|
+
if (_internals)
|
|
352
|
+
_internals.H = prev;
|
|
353
|
+
}
|
|
354
|
+
|
|
301
355
|
// src/slim-react/render.ts
|
|
302
356
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
303
357
|
"area",
|
|
@@ -701,6 +755,7 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
701
755
|
return;
|
|
702
756
|
}
|
|
703
757
|
let result;
|
|
758
|
+
const prevDispatcher = installDispatcher();
|
|
704
759
|
try {
|
|
705
760
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
706
761
|
const instance = new type(props);
|
|
@@ -714,12 +769,20 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
714
769
|
result = type(props);
|
|
715
770
|
}
|
|
716
771
|
} catch (e) {
|
|
772
|
+
restoreDispatcher(prevDispatcher);
|
|
717
773
|
popComponentScope(savedScope);
|
|
718
774
|
if (isProvider)
|
|
719
775
|
popContextValue(ctx, prevCtxValue);
|
|
720
776
|
throw e;
|
|
721
777
|
}
|
|
778
|
+
restoreDispatcher(prevDispatcher);
|
|
779
|
+
let savedIdTree;
|
|
780
|
+
if (!(result instanceof Promise) && componentCalledUseId()) {
|
|
781
|
+
savedIdTree = pushTreeContext(1, 0);
|
|
782
|
+
}
|
|
722
783
|
const finish = () => {
|
|
784
|
+
if (savedIdTree !== void 0)
|
|
785
|
+
popTreeContext(savedIdTree);
|
|
723
786
|
popComponentScope(savedScope);
|
|
724
787
|
if (isProvider)
|
|
725
788
|
popContextValue(ctx, prevCtxValue);
|
|
@@ -728,22 +791,33 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
728
791
|
const m = captureMap();
|
|
729
792
|
return result.then((resolved) => {
|
|
730
793
|
swapContextMap(m);
|
|
794
|
+
let asyncSavedIdTree;
|
|
795
|
+
if (componentCalledUseId()) {
|
|
796
|
+
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
797
|
+
}
|
|
798
|
+
const asyncFinish = () => {
|
|
799
|
+
if (asyncSavedIdTree !== void 0)
|
|
800
|
+
popTreeContext(asyncSavedIdTree);
|
|
801
|
+
popComponentScope(savedScope);
|
|
802
|
+
if (isProvider)
|
|
803
|
+
popContextValue(ctx, prevCtxValue);
|
|
804
|
+
};
|
|
731
805
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
732
806
|
if (r2 && typeof r2.then === "function") {
|
|
733
807
|
const m2 = captureMap();
|
|
734
808
|
return r2.then(
|
|
735
809
|
() => {
|
|
736
810
|
swapContextMap(m2);
|
|
737
|
-
|
|
811
|
+
asyncFinish();
|
|
738
812
|
},
|
|
739
813
|
(e) => {
|
|
740
814
|
swapContextMap(m2);
|
|
741
|
-
|
|
815
|
+
asyncFinish();
|
|
742
816
|
throw e;
|
|
743
817
|
}
|
|
744
818
|
);
|
|
745
819
|
}
|
|
746
|
-
|
|
820
|
+
asyncFinish();
|
|
747
821
|
}, (e) => {
|
|
748
822
|
swapContextMap(m);
|
|
749
823
|
finish();
|
package/dist/slim-react/index.js
CHANGED
|
@@ -91,6 +91,9 @@ function pushComponentScope() {
|
|
|
91
91
|
function popComponentScope(saved) {
|
|
92
92
|
s().localIdCounter = saved;
|
|
93
93
|
}
|
|
94
|
+
function componentCalledUseId() {
|
|
95
|
+
return s().localIdCounter > 0;
|
|
96
|
+
}
|
|
94
97
|
function snapshotContext() {
|
|
95
98
|
const st = s();
|
|
96
99
|
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
@@ -111,10 +114,10 @@ function makeId() {
|
|
|
111
114
|
const st = s();
|
|
112
115
|
const treeId = getTreeId();
|
|
113
116
|
const n = st.localIdCounter++;
|
|
114
|
-
let id = "
|
|
117
|
+
let id = "\xAB" + st.idPrefix + "R" + treeId;
|
|
115
118
|
if (n > 0)
|
|
116
119
|
id += "H" + n.toString(32);
|
|
117
|
-
return id + "
|
|
120
|
+
return id + "\xBB";
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
// src/slim-react/hooks.ts
|
|
@@ -207,6 +210,47 @@ function createContext(defaultValue) {
|
|
|
207
210
|
return context;
|
|
208
211
|
}
|
|
209
212
|
|
|
213
|
+
// src/slim-react/dispatcher.ts
|
|
214
|
+
import ReactPkg from "react";
|
|
215
|
+
var _internals = ReactPkg.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
216
|
+
var slimDispatcher = {
|
|
217
|
+
useId: makeId,
|
|
218
|
+
readContext: (ctx) => getContextValue(ctx),
|
|
219
|
+
useContext: (ctx) => getContextValue(ctx),
|
|
220
|
+
useState,
|
|
221
|
+
useReducer,
|
|
222
|
+
useEffect,
|
|
223
|
+
useLayoutEffect,
|
|
224
|
+
useInsertionEffect,
|
|
225
|
+
useRef,
|
|
226
|
+
useMemo,
|
|
227
|
+
useCallback,
|
|
228
|
+
useDebugValue,
|
|
229
|
+
useImperativeHandle,
|
|
230
|
+
useSyncExternalStore,
|
|
231
|
+
useTransition,
|
|
232
|
+
useDeferredValue,
|
|
233
|
+
useOptimistic,
|
|
234
|
+
useActionState,
|
|
235
|
+
use,
|
|
236
|
+
// React internals that compiled output may call
|
|
237
|
+
useMemoCache: (size) => new Array(size).fill(void 0),
|
|
238
|
+
useCacheRefresh: () => () => {
|
|
239
|
+
},
|
|
240
|
+
useHostTransitionStatus: () => false
|
|
241
|
+
};
|
|
242
|
+
function installDispatcher() {
|
|
243
|
+
if (!_internals)
|
|
244
|
+
return null;
|
|
245
|
+
const prev = _internals.H;
|
|
246
|
+
_internals.H = slimDispatcher;
|
|
247
|
+
return prev;
|
|
248
|
+
}
|
|
249
|
+
function restoreDispatcher(prev) {
|
|
250
|
+
if (_internals)
|
|
251
|
+
_internals.H = prev;
|
|
252
|
+
}
|
|
253
|
+
|
|
210
254
|
// src/slim-react/render.ts
|
|
211
255
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
212
256
|
"area",
|
|
@@ -610,6 +654,7 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
610
654
|
return;
|
|
611
655
|
}
|
|
612
656
|
let result;
|
|
657
|
+
const prevDispatcher = installDispatcher();
|
|
613
658
|
try {
|
|
614
659
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
615
660
|
const instance = new type(props);
|
|
@@ -623,12 +668,20 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
623
668
|
result = type(props);
|
|
624
669
|
}
|
|
625
670
|
} catch (e) {
|
|
671
|
+
restoreDispatcher(prevDispatcher);
|
|
626
672
|
popComponentScope(savedScope);
|
|
627
673
|
if (isProvider)
|
|
628
674
|
popContextValue(ctx, prevCtxValue);
|
|
629
675
|
throw e;
|
|
630
676
|
}
|
|
677
|
+
restoreDispatcher(prevDispatcher);
|
|
678
|
+
let savedIdTree;
|
|
679
|
+
if (!(result instanceof Promise) && componentCalledUseId()) {
|
|
680
|
+
savedIdTree = pushTreeContext(1, 0);
|
|
681
|
+
}
|
|
631
682
|
const finish = () => {
|
|
683
|
+
if (savedIdTree !== void 0)
|
|
684
|
+
popTreeContext(savedIdTree);
|
|
632
685
|
popComponentScope(savedScope);
|
|
633
686
|
if (isProvider)
|
|
634
687
|
popContextValue(ctx, prevCtxValue);
|
|
@@ -637,22 +690,33 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
637
690
|
const m = captureMap();
|
|
638
691
|
return result.then((resolved) => {
|
|
639
692
|
swapContextMap(m);
|
|
693
|
+
let asyncSavedIdTree;
|
|
694
|
+
if (componentCalledUseId()) {
|
|
695
|
+
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
696
|
+
}
|
|
697
|
+
const asyncFinish = () => {
|
|
698
|
+
if (asyncSavedIdTree !== void 0)
|
|
699
|
+
popTreeContext(asyncSavedIdTree);
|
|
700
|
+
popComponentScope(savedScope);
|
|
701
|
+
if (isProvider)
|
|
702
|
+
popContextValue(ctx, prevCtxValue);
|
|
703
|
+
};
|
|
640
704
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
641
705
|
if (r2 && typeof r2.then === "function") {
|
|
642
706
|
const m2 = captureMap();
|
|
643
707
|
return r2.then(
|
|
644
708
|
() => {
|
|
645
709
|
swapContextMap(m2);
|
|
646
|
-
|
|
710
|
+
asyncFinish();
|
|
647
711
|
},
|
|
648
712
|
(e) => {
|
|
649
713
|
swapContextMap(m2);
|
|
650
|
-
|
|
714
|
+
asyncFinish();
|
|
651
715
|
throw e;
|
|
652
716
|
}
|
|
653
717
|
);
|
|
654
718
|
}
|
|
655
|
-
|
|
719
|
+
asyncFinish();
|
|
656
720
|
}, (e) => {
|
|
657
721
|
swapContextMap(m);
|
|
658
722
|
finish();
|
|
@@ -149,6 +149,9 @@ function pushComponentScope() {
|
|
|
149
149
|
function popComponentScope(saved) {
|
|
150
150
|
s().localIdCounter = saved;
|
|
151
151
|
}
|
|
152
|
+
function componentCalledUseId() {
|
|
153
|
+
return s().localIdCounter > 0;
|
|
154
|
+
}
|
|
152
155
|
function snapshotContext() {
|
|
153
156
|
const st = s();
|
|
154
157
|
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
@@ -158,6 +161,121 @@ function restoreContext(snap) {
|
|
|
158
161
|
st.currentTreeContext = { ...snap.tree };
|
|
159
162
|
st.localIdCounter = snap.localId;
|
|
160
163
|
}
|
|
164
|
+
function getTreeId() {
|
|
165
|
+
const { id, overflow } = s().currentTreeContext;
|
|
166
|
+
if (id === 1)
|
|
167
|
+
return overflow;
|
|
168
|
+
const stripped = (id & ~(1 << 31 - Math.clz32(id))).toString(32);
|
|
169
|
+
return stripped + overflow;
|
|
170
|
+
}
|
|
171
|
+
function makeId() {
|
|
172
|
+
const st = s();
|
|
173
|
+
const treeId = getTreeId();
|
|
174
|
+
const n = st.localIdCounter++;
|
|
175
|
+
let id = "\xAB" + st.idPrefix + "R" + treeId;
|
|
176
|
+
if (n > 0)
|
|
177
|
+
id += "H" + n.toString(32);
|
|
178
|
+
return id + "\xBB";
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/slim-react/hooks.ts
|
|
182
|
+
function useState(initialState) {
|
|
183
|
+
const value = typeof initialState === "function" ? initialState() : initialState;
|
|
184
|
+
return [value, () => {
|
|
185
|
+
}];
|
|
186
|
+
}
|
|
187
|
+
function useReducer(_reducer, initialState) {
|
|
188
|
+
return [initialState, () => {
|
|
189
|
+
}];
|
|
190
|
+
}
|
|
191
|
+
function useEffect(_effect, _deps) {
|
|
192
|
+
}
|
|
193
|
+
function useLayoutEffect(_effect, _deps) {
|
|
194
|
+
}
|
|
195
|
+
function useInsertionEffect(_effect, _deps) {
|
|
196
|
+
}
|
|
197
|
+
function useRef(initialValue) {
|
|
198
|
+
return { current: initialValue };
|
|
199
|
+
}
|
|
200
|
+
function useMemo(factory, _deps) {
|
|
201
|
+
return factory();
|
|
202
|
+
}
|
|
203
|
+
function useCallback(callback, _deps) {
|
|
204
|
+
return callback;
|
|
205
|
+
}
|
|
206
|
+
function useDebugValue(_value, _format) {
|
|
207
|
+
}
|
|
208
|
+
function useImperativeHandle(_ref, _createHandle, _deps) {
|
|
209
|
+
}
|
|
210
|
+
function useSyncExternalStore(_subscribe, getSnapshot, getServerSnapshot) {
|
|
211
|
+
return (getServerSnapshot || getSnapshot)();
|
|
212
|
+
}
|
|
213
|
+
function useTransition() {
|
|
214
|
+
return [false, (cb) => cb()];
|
|
215
|
+
}
|
|
216
|
+
function useDeferredValue(value) {
|
|
217
|
+
return value;
|
|
218
|
+
}
|
|
219
|
+
function useOptimistic(passthrough) {
|
|
220
|
+
return [passthrough, () => {
|
|
221
|
+
}];
|
|
222
|
+
}
|
|
223
|
+
function useActionState(_action, initialState, _permalink) {
|
|
224
|
+
return [initialState, () => {
|
|
225
|
+
}, false];
|
|
226
|
+
}
|
|
227
|
+
function use(usable) {
|
|
228
|
+
if (typeof usable === "object" && usable !== null && ("_currentValue" in usable || "_defaultValue" in usable)) {
|
|
229
|
+
return getContextValue(usable);
|
|
230
|
+
}
|
|
231
|
+
const promise = usable;
|
|
232
|
+
if (promise.status === "fulfilled")
|
|
233
|
+
return promise.value;
|
|
234
|
+
if (promise.status === "rejected")
|
|
235
|
+
throw promise.reason;
|
|
236
|
+
throw promise;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/slim-react/dispatcher.ts
|
|
240
|
+
import ReactPkg from "react";
|
|
241
|
+
var _internals = ReactPkg.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
242
|
+
var slimDispatcher = {
|
|
243
|
+
useId: makeId,
|
|
244
|
+
readContext: (ctx) => getContextValue(ctx),
|
|
245
|
+
useContext: (ctx) => getContextValue(ctx),
|
|
246
|
+
useState,
|
|
247
|
+
useReducer,
|
|
248
|
+
useEffect,
|
|
249
|
+
useLayoutEffect,
|
|
250
|
+
useInsertionEffect,
|
|
251
|
+
useRef,
|
|
252
|
+
useMemo,
|
|
253
|
+
useCallback,
|
|
254
|
+
useDebugValue,
|
|
255
|
+
useImperativeHandle,
|
|
256
|
+
useSyncExternalStore,
|
|
257
|
+
useTransition,
|
|
258
|
+
useDeferredValue,
|
|
259
|
+
useOptimistic,
|
|
260
|
+
useActionState,
|
|
261
|
+
use,
|
|
262
|
+
// React internals that compiled output may call
|
|
263
|
+
useMemoCache: (size) => new Array(size).fill(void 0),
|
|
264
|
+
useCacheRefresh: () => () => {
|
|
265
|
+
},
|
|
266
|
+
useHostTransitionStatus: () => false
|
|
267
|
+
};
|
|
268
|
+
function installDispatcher() {
|
|
269
|
+
if (!_internals)
|
|
270
|
+
return null;
|
|
271
|
+
const prev = _internals.H;
|
|
272
|
+
_internals.H = slimDispatcher;
|
|
273
|
+
return prev;
|
|
274
|
+
}
|
|
275
|
+
function restoreDispatcher(prev) {
|
|
276
|
+
if (_internals)
|
|
277
|
+
_internals.H = prev;
|
|
278
|
+
}
|
|
161
279
|
|
|
162
280
|
// src/slim-react/render.ts
|
|
163
281
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
@@ -562,6 +680,7 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
562
680
|
return;
|
|
563
681
|
}
|
|
564
682
|
let result;
|
|
683
|
+
const prevDispatcher = installDispatcher();
|
|
565
684
|
try {
|
|
566
685
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
567
686
|
const instance = new type(props);
|
|
@@ -575,12 +694,20 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
575
694
|
result = type(props);
|
|
576
695
|
}
|
|
577
696
|
} catch (e) {
|
|
697
|
+
restoreDispatcher(prevDispatcher);
|
|
578
698
|
popComponentScope(savedScope);
|
|
579
699
|
if (isProvider)
|
|
580
700
|
popContextValue(ctx, prevCtxValue);
|
|
581
701
|
throw e;
|
|
582
702
|
}
|
|
703
|
+
restoreDispatcher(prevDispatcher);
|
|
704
|
+
let savedIdTree;
|
|
705
|
+
if (!(result instanceof Promise) && componentCalledUseId()) {
|
|
706
|
+
savedIdTree = pushTreeContext(1, 0);
|
|
707
|
+
}
|
|
583
708
|
const finish = () => {
|
|
709
|
+
if (savedIdTree !== void 0)
|
|
710
|
+
popTreeContext(savedIdTree);
|
|
584
711
|
popComponentScope(savedScope);
|
|
585
712
|
if (isProvider)
|
|
586
713
|
popContextValue(ctx, prevCtxValue);
|
|
@@ -589,22 +716,33 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
589
716
|
const m = captureMap();
|
|
590
717
|
return result.then((resolved) => {
|
|
591
718
|
swapContextMap(m);
|
|
719
|
+
let asyncSavedIdTree;
|
|
720
|
+
if (componentCalledUseId()) {
|
|
721
|
+
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
722
|
+
}
|
|
723
|
+
const asyncFinish = () => {
|
|
724
|
+
if (asyncSavedIdTree !== void 0)
|
|
725
|
+
popTreeContext(asyncSavedIdTree);
|
|
726
|
+
popComponentScope(savedScope);
|
|
727
|
+
if (isProvider)
|
|
728
|
+
popContextValue(ctx, prevCtxValue);
|
|
729
|
+
};
|
|
592
730
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
593
731
|
if (r2 && typeof r2.then === "function") {
|
|
594
732
|
const m2 = captureMap();
|
|
595
733
|
return r2.then(
|
|
596
734
|
() => {
|
|
597
735
|
swapContextMap(m2);
|
|
598
|
-
|
|
736
|
+
asyncFinish();
|
|
599
737
|
},
|
|
600
738
|
(e) => {
|
|
601
739
|
swapContextMap(m2);
|
|
602
|
-
|
|
740
|
+
asyncFinish();
|
|
603
741
|
throw e;
|
|
604
742
|
}
|
|
605
743
|
);
|
|
606
744
|
}
|
|
607
|
-
|
|
745
|
+
asyncFinish();
|
|
608
746
|
}, (e) => {
|
|
609
747
|
swapContextMap(m);
|
|
610
748
|
finish();
|
package/package.json
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React dispatcher shim for slim-react SSR.
|
|
3
|
+
*
|
|
4
|
+
* During a slim-react render, `React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE.H`
|
|
5
|
+
* is null, so any component that calls `React.useId()` (or another hook) via
|
|
6
|
+
* React's own package will hit `resolveDispatcher()` → null → error.
|
|
7
|
+
*
|
|
8
|
+
* We install a minimal dispatcher object for the duration of each component
|
|
9
|
+
* call so that `React.useId()` routes through slim-react's tree-aware
|
|
10
|
+
* `makeId()`. All other hooks already have working SSR stubs in hooks.ts;
|
|
11
|
+
* they are forwarded here so libraries that call them via `React.*` also work.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { makeId, getContextValue } from "./renderContext";
|
|
15
|
+
import {
|
|
16
|
+
useState, useReducer, useEffect, useLayoutEffect, useInsertionEffect,
|
|
17
|
+
useRef, useMemo, useCallback, useDebugValue, useImperativeHandle,
|
|
18
|
+
useSyncExternalStore, useTransition, useDeferredValue,
|
|
19
|
+
useOptimistic, useActionState, use,
|
|
20
|
+
} from "./hooks";
|
|
21
|
+
|
|
22
|
+
import ReactPkg from "react";
|
|
23
|
+
|
|
24
|
+
// React 19 exposes its shared internals under this key.
|
|
25
|
+
const _internals: { H: object | null } | undefined =
|
|
26
|
+
(ReactPkg as any).__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
27
|
+
|
|
28
|
+
// The dispatcher object we install. We keep a stable reference so the same
|
|
29
|
+
// object is reused across every component call.
|
|
30
|
+
const slimDispatcher: Record<string, unknown> = {
|
|
31
|
+
useId: makeId,
|
|
32
|
+
readContext: (ctx: any) => getContextValue(ctx),
|
|
33
|
+
useContext: (ctx: any) => getContextValue(ctx),
|
|
34
|
+
useState,
|
|
35
|
+
useReducer,
|
|
36
|
+
useEffect,
|
|
37
|
+
useLayoutEffect,
|
|
38
|
+
useInsertionEffect,
|
|
39
|
+
useRef,
|
|
40
|
+
useMemo,
|
|
41
|
+
useCallback,
|
|
42
|
+
useDebugValue,
|
|
43
|
+
useImperativeHandle,
|
|
44
|
+
useSyncExternalStore,
|
|
45
|
+
useTransition,
|
|
46
|
+
useDeferredValue,
|
|
47
|
+
useOptimistic,
|
|
48
|
+
useActionState,
|
|
49
|
+
use,
|
|
50
|
+
// React internals that compiled output may call
|
|
51
|
+
useMemoCache: (size: number) => new Array(size).fill(undefined),
|
|
52
|
+
useCacheRefresh: () => () => {},
|
|
53
|
+
useHostTransitionStatus: () => false,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Install the slim dispatcher and return the previous value.
|
|
58
|
+
* Call `restoreDispatcher(prev)` when the component finishes.
|
|
59
|
+
*/
|
|
60
|
+
export function installDispatcher(): object | null {
|
|
61
|
+
if (!_internals) return null;
|
|
62
|
+
const prev = _internals.H;
|
|
63
|
+
_internals.H = slimDispatcher;
|
|
64
|
+
return prev;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function restoreDispatcher(prev: object | null): void {
|
|
68
|
+
if (_internals) _internals.H = prev;
|
|
69
|
+
}
|
package/src/slim-react/render.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
popTreeContext,
|
|
29
29
|
pushComponentScope,
|
|
30
30
|
popComponentScope,
|
|
31
|
+
componentCalledUseId,
|
|
31
32
|
snapshotContext,
|
|
32
33
|
restoreContext,
|
|
33
34
|
pushContextValue,
|
|
@@ -35,7 +36,9 @@ import {
|
|
|
35
36
|
getContextValue,
|
|
36
37
|
swapContextMap,
|
|
37
38
|
captureMap,
|
|
39
|
+
type TreeContext,
|
|
38
40
|
} from "./renderContext";
|
|
41
|
+
import { installDispatcher, restoreDispatcher } from "./dispatcher";
|
|
39
42
|
|
|
40
43
|
// ---------------------------------------------------------------------------
|
|
41
44
|
// HTML helpers
|
|
@@ -630,6 +633,7 @@ function renderComponent(
|
|
|
630
633
|
}
|
|
631
634
|
|
|
632
635
|
let result: SlimNode;
|
|
636
|
+
const prevDispatcher = installDispatcher();
|
|
633
637
|
try {
|
|
634
638
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
635
639
|
const instance = new (type as any)(props);
|
|
@@ -643,12 +647,25 @@ function renderComponent(
|
|
|
643
647
|
result = type(props);
|
|
644
648
|
}
|
|
645
649
|
} catch (e) {
|
|
650
|
+
restoreDispatcher(prevDispatcher);
|
|
646
651
|
popComponentScope(savedScope);
|
|
647
652
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
648
653
|
throw e;
|
|
649
654
|
}
|
|
655
|
+
restoreDispatcher(prevDispatcher);
|
|
656
|
+
|
|
657
|
+
// React 19 finishFunctionComponent: if the component called useId, push a
|
|
658
|
+
// tree-context slot for the component's OUTPUT children — matching React 19's
|
|
659
|
+
// `pushTreeContext(keyPath, 1, 0)` call inside finishFunctionComponent.
|
|
660
|
+
// This ensures that useId IDs produced by child components of a useId-calling
|
|
661
|
+
// component are tree-positioned identically to React's own renderer.
|
|
662
|
+
let savedIdTree: TreeContext | undefined;
|
|
663
|
+
if (!(result instanceof Promise) && componentCalledUseId()) {
|
|
664
|
+
savedIdTree = pushTreeContext(1, 0);
|
|
665
|
+
}
|
|
650
666
|
|
|
651
667
|
const finish = () => {
|
|
668
|
+
if (savedIdTree !== undefined) popTreeContext(savedIdTree);
|
|
652
669
|
popComponentScope(savedScope);
|
|
653
670
|
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
654
671
|
};
|
|
@@ -658,15 +675,25 @@ function renderComponent(
|
|
|
658
675
|
const m = captureMap();
|
|
659
676
|
return result.then((resolved) => {
|
|
660
677
|
swapContextMap(m);
|
|
678
|
+
// Check useId after the async body has finished executing.
|
|
679
|
+
let asyncSavedIdTree: TreeContext | undefined;
|
|
680
|
+
if (componentCalledUseId()) {
|
|
681
|
+
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
682
|
+
}
|
|
683
|
+
const asyncFinish = () => {
|
|
684
|
+
if (asyncSavedIdTree !== undefined) popTreeContext(asyncSavedIdTree);
|
|
685
|
+
popComponentScope(savedScope);
|
|
686
|
+
if (isProvider) popContextValue(ctx, prevCtxValue);
|
|
687
|
+
};
|
|
661
688
|
const r = renderNode(resolved, writer, isSvg);
|
|
662
689
|
if (r && typeof (r as any).then === "function") {
|
|
663
690
|
const m2 = captureMap();
|
|
664
691
|
return (r as Promise<void>).then(
|
|
665
|
-
() => { swapContextMap(m2);
|
|
666
|
-
(e) => { swapContextMap(m2);
|
|
692
|
+
() => { swapContextMap(m2); asyncFinish(); },
|
|
693
|
+
(e) => { swapContextMap(m2); asyncFinish(); throw e; },
|
|
667
694
|
);
|
|
668
695
|
}
|
|
669
|
-
|
|
696
|
+
asyncFinish();
|
|
670
697
|
}, (e) => { swapContextMap(m); finish(); throw e; });
|
|
671
698
|
}
|
|
672
699
|
|
|
@@ -160,6 +160,11 @@ export function popComponentScope(saved: number) {
|
|
|
160
160
|
s().localIdCounter = saved;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/** True if the current component has called useId at least once. */
|
|
164
|
+
export function componentCalledUseId(): boolean {
|
|
165
|
+
return s().localIdCounter > 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
163
168
|
export function snapshotContext(): { tree: TreeContext; localId: number } {
|
|
164
169
|
const st = s();
|
|
165
170
|
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
@@ -187,19 +192,20 @@ function getTreeId(): string {
|
|
|
187
192
|
/**
|
|
188
193
|
* Generate a `useId`-compatible ID for the current call site.
|
|
189
194
|
*
|
|
190
|
-
* Format:
|
|
191
|
-
* with an optional `H<n>` suffix
|
|
192
|
-
*
|
|
195
|
+
* Format: `«<idPrefix>R<treeId>»` (React 19.1+)
|
|
196
|
+
* with an optional `H<n>` suffix for the n-th useId call in the same
|
|
197
|
+
* component (matching React 19's `localIdCounter` behaviour).
|
|
193
198
|
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* the
|
|
199
|
+
* React 19.1 switched from `_R_<id>_` to `«R<id>»` (U+00AB / U+00BB).
|
|
200
|
+
* This matches React 19.1's `mountId` output on the Fizz SSR renderer and
|
|
201
|
+
* the client hydration path, so the IDs produced here will agree with the
|
|
202
|
+
* real React runtime during `hydrateRoot`.
|
|
197
203
|
*/
|
|
198
204
|
export function makeId(): string {
|
|
199
205
|
const st = s();
|
|
200
206
|
const treeId = getTreeId();
|
|
201
207
|
const n = st.localIdCounter++;
|
|
202
|
-
let id = "
|
|
208
|
+
let id = "\u00ab" + st.idPrefix + "R" + treeId;
|
|
203
209
|
if (n > 0) id += "H" + n.toString(32);
|
|
204
|
-
return id + "
|
|
210
|
+
return id + "\u00bb";
|
|
205
211
|
}
|