@reckona/mreact-compat 0.0.183 → 0.0.184
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/README.md +1 -0
- package/dist/devtools.d.ts.map +1 -1
- package/dist/devtools.js +25 -0
- package/dist/devtools.js.map +1 -1
- package/dist/dom-props.d.ts +5 -0
- package/dist/dom-props.d.ts.map +1 -1
- package/dist/dom-props.js +46 -0
- package/dist/dom-props.js.map +1 -1
- package/dist/reactive-prop-cell.d.ts.map +1 -1
- package/dist/reactive-prop-cell.js +3 -0
- package/dist/reactive-prop-cell.js.map +1 -1
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +35 -24
- package/dist/root.js.map +1 -1
- package/dist/server-render.d.ts +5 -0
- package/dist/server-render.d.ts.map +1 -1
- package/dist/server-render.js +59 -16
- package/dist/server-render.js.map +1 -1
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +6 -0
- package/dist/server.js.map +1 -0
- package/package.json +8 -3
- package/src/devtools.ts +32 -0
- package/src/dom-props.ts +59 -0
- package/src/reactive-prop-cell.ts +4 -0
- package/src/root.ts +52 -36
- package/src/server-render.ts +83 -17
- package/src/server.ts +62 -0
package/src/root.ts
CHANGED
|
@@ -32,6 +32,10 @@ import {
|
|
|
32
32
|
enqueueRootRender,
|
|
33
33
|
} from "./fiber-work-loop.js";
|
|
34
34
|
import { commitFiberRoot, detachFiberRefs } from "./fiber-commit.js";
|
|
35
|
+
import {
|
|
36
|
+
withBatchedDelegatedRootReleases,
|
|
37
|
+
withDeferredDelegatedEventPromotions,
|
|
38
|
+
} from "@reckona/mreact-reactive-dom";
|
|
35
39
|
import {
|
|
36
40
|
canRenderHostFiber,
|
|
37
41
|
commitHydratingHostFiberRoot,
|
|
@@ -40,7 +44,6 @@ import {
|
|
|
40
44
|
renderHostFiberRoot,
|
|
41
45
|
} from "./fiber-host.js";
|
|
42
46
|
import type { Fiber, FiberRoot } from "./fiber.js";
|
|
43
|
-
import { renderIntoContainer } from "./reconciler.js";
|
|
44
47
|
|
|
45
48
|
/** Root controller returned by createRoot and hydrateRoot. */
|
|
46
49
|
export interface Root {
|
|
@@ -113,7 +116,7 @@ export function createRoot(
|
|
|
113
116
|
);
|
|
114
117
|
}
|
|
115
118
|
|
|
116
|
-
|
|
119
|
+
throwUnsupportedRootNode();
|
|
117
120
|
});
|
|
118
121
|
}
|
|
119
122
|
}, options);
|
|
@@ -126,17 +129,19 @@ export function createRoot(
|
|
|
126
129
|
return renderHostFiberIntoContainer(container, fiberRoot, runtime, element);
|
|
127
130
|
}
|
|
128
131
|
|
|
129
|
-
|
|
132
|
+
throwUnsupportedRootNode();
|
|
130
133
|
});
|
|
131
134
|
},
|
|
132
135
|
unmount() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
136
|
+
withBatchedDelegatedRootReleases(() => {
|
|
137
|
+
runtime.currentElement = undefined;
|
|
138
|
+
runtime.dispose();
|
|
139
|
+
detachFiberRefs(fiberRoot.current);
|
|
140
|
+
disposeHostFiberResources(fiberRoot.current);
|
|
141
|
+
runtime.instances.clear();
|
|
142
|
+
unmountDevToolsRoot(container);
|
|
143
|
+
clearElementChildren(container);
|
|
144
|
+
});
|
|
140
145
|
},
|
|
141
146
|
};
|
|
142
147
|
}
|
|
@@ -153,7 +158,10 @@ function renderHostFiberIntoContainer(
|
|
|
153
158
|
let committed = false;
|
|
154
159
|
|
|
155
160
|
try {
|
|
156
|
-
const
|
|
161
|
+
const deferred = withDeferredDelegatedEventPromotions(() =>
|
|
162
|
+
renderHostFiberRoot(fiberRoot, element, runtime)
|
|
163
|
+
);
|
|
164
|
+
const finishedWork = deferred.value;
|
|
157
165
|
|
|
158
166
|
if (runtime.renderPhaseUpdate) {
|
|
159
167
|
runtime.renderPhaseUpdate = false;
|
|
@@ -165,9 +173,10 @@ function renderHostFiberIntoContainer(
|
|
|
165
173
|
}
|
|
166
174
|
|
|
167
175
|
fiberRoot.finishedWork = finishedWork;
|
|
168
|
-
commitFiberRoot(fiberRoot);
|
|
176
|
+
withBatchedDelegatedRootReleases(() => commitFiberRoot(fiberRoot));
|
|
169
177
|
collectPortalNodes(fiberRoot.current, runtime, portalSnapshot);
|
|
170
178
|
removeStalePortalNodes(portalSnapshot, runtime);
|
|
179
|
+
deferred.promote?.();
|
|
171
180
|
commitDevToolsRoot(container, fiberRoot);
|
|
172
181
|
runtime.idMode = "client";
|
|
173
182
|
committed = true;
|
|
@@ -203,13 +212,16 @@ function renderHydratingHostFiberIntoContainer(
|
|
|
203
212
|
|
|
204
213
|
try {
|
|
205
214
|
const scope = getHydrationScope(container, options.resumeId);
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
const deferred = withDeferredDelegatedEventPromotions(() =>
|
|
216
|
+
renderHydratingHostFiberRoot(
|
|
217
|
+
fiberRoot,
|
|
218
|
+
element,
|
|
219
|
+
runtime,
|
|
220
|
+
scope,
|
|
221
|
+
options,
|
|
222
|
+
)
|
|
212
223
|
);
|
|
224
|
+
const finishedWork = deferred.value;
|
|
213
225
|
|
|
214
226
|
if (runtime.renderPhaseUpdate) {
|
|
215
227
|
runtime.renderPhaseUpdate = false;
|
|
@@ -220,7 +232,9 @@ function renderHydratingHostFiberIntoContainer(
|
|
|
220
232
|
continue;
|
|
221
233
|
}
|
|
222
234
|
|
|
223
|
-
|
|
235
|
+
withBatchedDelegatedRootReleases(() =>
|
|
236
|
+
commitHydratingHostFiberRoot(fiberRoot, finishedWork, scope, options)
|
|
237
|
+
);
|
|
224
238
|
fiberRoot.current = finishedWork;
|
|
225
239
|
fiberRoot.current.stateNode = fiberRoot;
|
|
226
240
|
fiberRoot.finishedWork = undefined;
|
|
@@ -228,6 +242,7 @@ function renderHydratingHostFiberIntoContainer(
|
|
|
228
242
|
fiberRoot.workInProgressRootRenderLanes = 0;
|
|
229
243
|
collectPortalNodes(fiberRoot.current, runtime, portalSnapshot);
|
|
230
244
|
removeStalePortalNodes(portalSnapshot, runtime);
|
|
245
|
+
deferred.promote?.();
|
|
231
246
|
commitDevToolsRoot(container, fiberRoot);
|
|
232
247
|
runtime.idMode = "client";
|
|
233
248
|
committed = true;
|
|
@@ -302,12 +317,7 @@ export function hydrateRoot(
|
|
|
302
317
|
);
|
|
303
318
|
}
|
|
304
319
|
|
|
305
|
-
|
|
306
|
-
container,
|
|
307
|
-
runtime.currentElement,
|
|
308
|
-
runtime,
|
|
309
|
-
useHydratingRerender ? renderOptions : {},
|
|
310
|
-
);
|
|
320
|
+
throwUnsupportedRootNode();
|
|
311
321
|
});
|
|
312
322
|
}
|
|
313
323
|
}, {
|
|
@@ -325,17 +335,19 @@ export function hydrateRoot(
|
|
|
325
335
|
return renderHostFiberIntoContainer(container, fiberRoot, runtime, nextElement);
|
|
326
336
|
}
|
|
327
337
|
|
|
328
|
-
|
|
338
|
+
throwUnsupportedRootNode();
|
|
329
339
|
});
|
|
330
340
|
},
|
|
331
341
|
unmount() {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
342
|
+
withBatchedDelegatedRootReleases(() => {
|
|
343
|
+
runtime.currentElement = undefined;
|
|
344
|
+
runtime.dispose();
|
|
345
|
+
detachFiberRefs(fiberRoot.current);
|
|
346
|
+
disposeHostFiberResources(fiberRoot.current);
|
|
347
|
+
runtime.instances.clear();
|
|
348
|
+
unmountDevToolsRoot(container);
|
|
349
|
+
clearElementChildren(container);
|
|
350
|
+
});
|
|
339
351
|
},
|
|
340
352
|
};
|
|
341
353
|
|
|
@@ -348,15 +360,19 @@ export function hydrateRoot(
|
|
|
348
360
|
runtime,
|
|
349
361
|
element,
|
|
350
362
|
renderOptions,
|
|
351
|
-
|
|
352
|
-
|
|
363
|
+
);
|
|
364
|
+
}
|
|
353
365
|
|
|
354
|
-
|
|
366
|
+
throwUnsupportedRootNode();
|
|
355
367
|
});
|
|
356
368
|
replayQueuedHydrationEvents(container);
|
|
357
369
|
return root;
|
|
358
370
|
}
|
|
359
371
|
|
|
372
|
+
function throwUnsupportedRootNode(): never {
|
|
373
|
+
throw new Error("Unsupported react-compat root node. Pass a valid React-compatible element, portal, fragment, primitive, array, or nullish value.");
|
|
374
|
+
}
|
|
375
|
+
|
|
360
376
|
function laneForRenderPriority(priority: RenderPriority): Lane {
|
|
361
377
|
if (priority === "transition") {
|
|
362
378
|
return TransitionLane;
|
package/src/server-render.ts
CHANGED
|
@@ -369,39 +369,61 @@ function isEventHandlerName(name: string): boolean {
|
|
|
369
369
|
);
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
+
type AttributeNameClassification =
|
|
373
|
+
| { kind: "skip" }
|
|
374
|
+
| { kind: "style" }
|
|
375
|
+
| {
|
|
376
|
+
kind: "attribute";
|
|
377
|
+
attributeName: string;
|
|
378
|
+
booleanishString: boolean;
|
|
379
|
+
dataAttribute: boolean;
|
|
380
|
+
dangerousHtml: boolean;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
const ATTRIBUTE_CLASSIFICATION_CACHE = new Map<string, AttributeNameClassification>();
|
|
384
|
+
const ATTRIBUTE_CLASSIFICATION_CACHE_LIMIT = 1024;
|
|
385
|
+
let attributeClassificationCacheMissCount = 0;
|
|
386
|
+
|
|
387
|
+
export const __serverRenderAttributeCacheForTesting = {
|
|
388
|
+
clear() {
|
|
389
|
+
ATTRIBUTE_CLASSIFICATION_CACHE.clear();
|
|
390
|
+
attributeClassificationCacheMissCount = 0;
|
|
391
|
+
},
|
|
392
|
+
missCount() {
|
|
393
|
+
return attributeClassificationCacheMissCount;
|
|
394
|
+
},
|
|
395
|
+
size() {
|
|
396
|
+
return ATTRIBUTE_CLASSIFICATION_CACHE.size;
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
|
|
372
400
|
function renderHtmlAttribute(name: string, value: unknown): string {
|
|
373
401
|
if (
|
|
374
402
|
value === null ||
|
|
375
403
|
value === undefined ||
|
|
376
|
-
typeof value === "function"
|
|
377
|
-
name === "children" ||
|
|
378
|
-
name === "key" ||
|
|
379
|
-
name === "ref" ||
|
|
380
|
-
isEventHandlerName(name)
|
|
404
|
+
typeof value === "function"
|
|
381
405
|
) {
|
|
382
406
|
return "";
|
|
383
407
|
}
|
|
384
408
|
|
|
385
|
-
|
|
386
|
-
const style = renderStyleAttribute(value);
|
|
387
|
-
return style === "" ? "" : ` style="${escapeHtml(style)}"`;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const attributeName = toHtmlAttributeName(name);
|
|
409
|
+
const classification = classifyAttributeName(name);
|
|
391
410
|
|
|
392
|
-
if (
|
|
411
|
+
if (classification.kind === "skip") {
|
|
393
412
|
return "";
|
|
394
413
|
}
|
|
395
414
|
|
|
396
|
-
if (
|
|
397
|
-
|
|
415
|
+
if (classification.kind === "style") {
|
|
416
|
+
const style = renderStyleAttribute(value);
|
|
417
|
+
return style === "" ? "" : ` style="${escapeHtml(style)}"`;
|
|
398
418
|
}
|
|
399
419
|
|
|
400
|
-
|
|
420
|
+
const { attributeName } = classification;
|
|
421
|
+
|
|
422
|
+
if (typeof value === "boolean" && classification.booleanishString) {
|
|
401
423
|
return ` ${attributeName}="${value ? "true" : "false"}"`;
|
|
402
424
|
}
|
|
403
425
|
|
|
404
|
-
if (typeof value === "boolean" &&
|
|
426
|
+
if (typeof value === "boolean" && classification.dataAttribute) {
|
|
405
427
|
return ` ${attributeName}="${value ? "true" : "false"}"`;
|
|
406
428
|
}
|
|
407
429
|
|
|
@@ -409,7 +431,7 @@ function renderHtmlAttribute(name: string, value: unknown): string {
|
|
|
409
431
|
return "";
|
|
410
432
|
}
|
|
411
433
|
|
|
412
|
-
if (
|
|
434
|
+
if (classification.dangerousHtml) {
|
|
413
435
|
return isDangerousHtmlOptIn(value)
|
|
414
436
|
? ` ${attributeName}="${escapeHtml(value.__html)}"`
|
|
415
437
|
: "";
|
|
@@ -434,6 +456,50 @@ function renderHtmlAttribute(name: string, value: unknown): string {
|
|
|
434
456
|
|
|
435
457
|
const VALID_ATTRIBUTE_NAME = /^[A-Za-z_][\w.\-:]*$/;
|
|
436
458
|
|
|
459
|
+
function classifyAttributeName(name: string): AttributeNameClassification {
|
|
460
|
+
const cached = ATTRIBUTE_CLASSIFICATION_CACHE.get(name);
|
|
461
|
+
if (cached !== undefined) {
|
|
462
|
+
return cached;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
attributeClassificationCacheMissCount += 1;
|
|
466
|
+
|
|
467
|
+
const classification = createAttributeNameClassification(name);
|
|
468
|
+
if (ATTRIBUTE_CLASSIFICATION_CACHE.size < ATTRIBUTE_CLASSIFICATION_CACHE_LIMIT) {
|
|
469
|
+
ATTRIBUTE_CLASSIFICATION_CACHE.set(name, classification);
|
|
470
|
+
}
|
|
471
|
+
return classification;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function createAttributeNameClassification(name: string): AttributeNameClassification {
|
|
475
|
+
if (
|
|
476
|
+
name === "children" ||
|
|
477
|
+
name === "key" ||
|
|
478
|
+
name === "ref" ||
|
|
479
|
+
isEventHandlerName(name)
|
|
480
|
+
) {
|
|
481
|
+
return { kind: "skip" };
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (name === "style") {
|
|
485
|
+
return { kind: "style" };
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const attributeName = toHtmlAttributeName(name);
|
|
489
|
+
|
|
490
|
+
if (!VALID_ATTRIBUTE_NAME.test(attributeName) || isEventHandlerName(attributeName)) {
|
|
491
|
+
return { kind: "skip" };
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
kind: "attribute",
|
|
496
|
+
attributeName,
|
|
497
|
+
booleanishString: isBooleanishStringAttribute(attributeName),
|
|
498
|
+
dataAttribute: isDataAttribute(attributeName),
|
|
499
|
+
dangerousHtml: isDangerousHtmlAttribute(attributeName),
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
437
503
|
function isBooleanishStringAttribute(attributeName: string): boolean {
|
|
438
504
|
// Callers pass the already-mapped HTML attribute name.
|
|
439
505
|
const lowerCased = attributeName.toLowerCase();
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export {
|
|
2
|
+
Component,
|
|
3
|
+
PureComponent,
|
|
4
|
+
} from "./class-component.js";
|
|
5
|
+
export {
|
|
6
|
+
Fragment,
|
|
7
|
+
Activity,
|
|
8
|
+
Profiler,
|
|
9
|
+
Suspense,
|
|
10
|
+
SuspenseList,
|
|
11
|
+
StrictMode,
|
|
12
|
+
Children,
|
|
13
|
+
cloneElement,
|
|
14
|
+
createElement,
|
|
15
|
+
createErrorBoundary,
|
|
16
|
+
createRef,
|
|
17
|
+
forwardRef,
|
|
18
|
+
isValidElement,
|
|
19
|
+
lazy,
|
|
20
|
+
memo,
|
|
21
|
+
} from "./element.js";
|
|
22
|
+
export type {
|
|
23
|
+
ErrorBoundaryOptions,
|
|
24
|
+
ElementType,
|
|
25
|
+
ReactCompatElement,
|
|
26
|
+
ReactCompatNode,
|
|
27
|
+
ReactCompatRenderableElement,
|
|
28
|
+
} from "./element.js";
|
|
29
|
+
export {
|
|
30
|
+
createContext,
|
|
31
|
+
renderContextConsumerToString,
|
|
32
|
+
renderContextProviderToString,
|
|
33
|
+
useContext,
|
|
34
|
+
} from "./context.js";
|
|
35
|
+
export {
|
|
36
|
+
useCallback,
|
|
37
|
+
useDebugValue,
|
|
38
|
+
useDeferredValue,
|
|
39
|
+
useEffectEvent,
|
|
40
|
+
useEffect,
|
|
41
|
+
useId,
|
|
42
|
+
useImperativeHandle,
|
|
43
|
+
useInsertionEffect,
|
|
44
|
+
useLayoutEffect,
|
|
45
|
+
useMemo,
|
|
46
|
+
useOptimistic,
|
|
47
|
+
useReducer,
|
|
48
|
+
useRef,
|
|
49
|
+
useState,
|
|
50
|
+
useSyncExternalStore,
|
|
51
|
+
use,
|
|
52
|
+
useActionState,
|
|
53
|
+
cache,
|
|
54
|
+
cacheSignal,
|
|
55
|
+
captureOwnerStack,
|
|
56
|
+
startTransition,
|
|
57
|
+
unstable_useCacheRefresh,
|
|
58
|
+
useTransition,
|
|
59
|
+
version,
|
|
60
|
+
} from "./hooks.js";
|
|
61
|
+
export { renderChildToString, renderToString } from "./server-render.js";
|
|
62
|
+
export type { StartTransition, TransitionScope } from "./hooks.js";
|