hadars 0.1.18 → 0.1.19
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/{chunk-TGSIYGY2.js → chunk-OS3V4CPN.js} +2 -0
- package/dist/cli.js +140 -19
- package/dist/slim-react/index.cjs +146 -19
- package/dist/slim-react/index.js +147 -20
- package/dist/slim-react/jsx-runtime.cjs +1 -0
- package/dist/slim-react/jsx-runtime.js +1 -1
- package/dist/ssr-render-worker.js +140 -19
- package/package.json +2 -2
- package/src/slim-react/render.ts +204 -27
- package/src/slim-react/types.ts +9 -3
package/dist/slim-react/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FRAGMENT_TYPE,
|
|
3
3
|
Fragment,
|
|
4
|
+
REACT19_ELEMENT,
|
|
4
5
|
SLIM_ELEMENT,
|
|
5
6
|
SUSPENSE_TYPE,
|
|
6
7
|
createElement,
|
|
7
8
|
jsx
|
|
8
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-OS3V4CPN.js";
|
|
9
10
|
|
|
10
11
|
// src/slim-react/renderContext.ts
|
|
11
12
|
var GLOBAL_KEY = "__slimReactRenderState";
|
|
@@ -187,7 +188,7 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
187
188
|
"wbr"
|
|
188
189
|
]);
|
|
189
190
|
function escapeHtml(str) {
|
|
190
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
191
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
191
192
|
}
|
|
192
193
|
function escapeAttr(str) {
|
|
193
194
|
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -332,7 +333,7 @@ var SVG_ATTR_MAP = {
|
|
|
332
333
|
function renderAttributes(props, isSvg) {
|
|
333
334
|
let attrs = "";
|
|
334
335
|
for (const [key, value] of Object.entries(props)) {
|
|
335
|
-
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML")
|
|
336
|
+
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || key === "suppressHydrationWarning" || key === "suppressContentEditableWarning")
|
|
336
337
|
continue;
|
|
337
338
|
if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase())
|
|
338
339
|
continue;
|
|
@@ -340,12 +341,16 @@ function renderAttributes(props, isSvg) {
|
|
|
340
341
|
if (isSvg && key in SVG_ATTR_MAP) {
|
|
341
342
|
attrName = SVG_ATTR_MAP[key];
|
|
342
343
|
} else {
|
|
343
|
-
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key;
|
|
344
|
+
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key === "defaultValue" ? "value" : key === "defaultChecked" ? "checked" : key;
|
|
344
345
|
}
|
|
345
|
-
if (value === false || value == null)
|
|
346
|
+
if (value === false || value == null) {
|
|
347
|
+
if (value === false && (attrName.startsWith("aria-") || attrName.startsWith("data-"))) {
|
|
348
|
+
attrs += ` ${attrName}="false"`;
|
|
349
|
+
}
|
|
346
350
|
continue;
|
|
351
|
+
}
|
|
347
352
|
if (value === true) {
|
|
348
|
-
attrs += ` ${attrName}`;
|
|
353
|
+
attrs += ` ${attrName}=""`;
|
|
349
354
|
continue;
|
|
350
355
|
}
|
|
351
356
|
if (key === "style" && typeof value === "object") {
|
|
@@ -358,23 +363,30 @@ function renderAttributes(props, isSvg) {
|
|
|
358
363
|
}
|
|
359
364
|
var BufferWriter = class {
|
|
360
365
|
chunks = [];
|
|
366
|
+
lastWasText = false;
|
|
361
367
|
write(chunk) {
|
|
362
368
|
this.chunks.push(chunk);
|
|
369
|
+
this.lastWasText = false;
|
|
370
|
+
}
|
|
371
|
+
text(s2) {
|
|
372
|
+
this.chunks.push(s2);
|
|
373
|
+
this.lastWasText = true;
|
|
363
374
|
}
|
|
364
375
|
flush(target) {
|
|
365
376
|
for (const c of this.chunks)
|
|
366
377
|
target.write(c);
|
|
378
|
+
target.lastWasText = this.lastWasText;
|
|
367
379
|
}
|
|
368
380
|
};
|
|
369
381
|
function renderNode(node, writer, isSvg = false) {
|
|
370
382
|
if (node == null || typeof node === "boolean")
|
|
371
383
|
return;
|
|
372
384
|
if (typeof node === "string") {
|
|
373
|
-
writer.
|
|
385
|
+
writer.text(escapeHtml(node));
|
|
374
386
|
return;
|
|
375
387
|
}
|
|
376
388
|
if (typeof node === "number") {
|
|
377
|
-
writer.
|
|
389
|
+
writer.text(String(node));
|
|
378
390
|
return;
|
|
379
391
|
}
|
|
380
392
|
if (Array.isArray(node)) {
|
|
@@ -387,7 +399,10 @@ function renderNode(node, writer, isSvg = false) {
|
|
|
387
399
|
isSvg
|
|
388
400
|
);
|
|
389
401
|
}
|
|
390
|
-
if (typeof node === "object" && node !== null && "$$typeof" in node
|
|
402
|
+
if (typeof node === "object" && node !== null && "$$typeof" in node) {
|
|
403
|
+
const elType = node["$$typeof"];
|
|
404
|
+
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
405
|
+
return;
|
|
391
406
|
const element = node;
|
|
392
407
|
const { type, props } = element;
|
|
393
408
|
if (type === FRAGMENT_TYPE) {
|
|
@@ -399,16 +414,79 @@ function renderNode(node, writer, isSvg = false) {
|
|
|
399
414
|
if (typeof type === "function") {
|
|
400
415
|
return renderComponent(type, props, writer, isSvg);
|
|
401
416
|
}
|
|
417
|
+
if (typeof type === "object" && type !== null) {
|
|
418
|
+
return renderComponent(type, props, writer, isSvg);
|
|
419
|
+
}
|
|
402
420
|
if (typeof type === "string") {
|
|
403
421
|
return renderHostElement(type, props, writer, isSvg);
|
|
404
422
|
}
|
|
405
423
|
}
|
|
406
424
|
}
|
|
425
|
+
function markSelectedOptionsMulti(children, selectedValues) {
|
|
426
|
+
if (children == null || typeof children === "boolean")
|
|
427
|
+
return children;
|
|
428
|
+
if (typeof children === "string" || typeof children === "number")
|
|
429
|
+
return children;
|
|
430
|
+
if (Array.isArray(children)) {
|
|
431
|
+
return children.map((c) => markSelectedOptionsMulti(c, selectedValues));
|
|
432
|
+
}
|
|
433
|
+
if (typeof children === "object" && "$$typeof" in children) {
|
|
434
|
+
const elType = children["$$typeof"];
|
|
435
|
+
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
436
|
+
return children;
|
|
437
|
+
const el = children;
|
|
438
|
+
if (el.type === "option") {
|
|
439
|
+
const optValue = el.props.value !== void 0 ? el.props.value : el.props.children;
|
|
440
|
+
const isSelected = selectedValues.has(String(optValue));
|
|
441
|
+
return { ...el, props: { ...el.props, selected: isSelected || void 0 } };
|
|
442
|
+
}
|
|
443
|
+
if (el.type === "optgroup" || el.type === FRAGMENT_TYPE) {
|
|
444
|
+
const newChildren = markSelectedOptionsMulti(el.props.children, selectedValues);
|
|
445
|
+
return { ...el, props: { ...el.props, children: newChildren } };
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return children;
|
|
449
|
+
}
|
|
407
450
|
function renderHostElement(tag, props, writer, isSvg) {
|
|
408
451
|
const enteringSvg = tag === "svg";
|
|
409
452
|
const childSvg = isSvg || enteringSvg;
|
|
410
|
-
|
|
411
|
-
|
|
453
|
+
if (tag === "textarea") {
|
|
454
|
+
const textContent = props.value ?? props.defaultValue ?? props.children ?? "";
|
|
455
|
+
const filteredProps = {};
|
|
456
|
+
for (const k of Object.keys(props)) {
|
|
457
|
+
if (k !== "value" && k !== "defaultValue" && k !== "children")
|
|
458
|
+
filteredProps[k] = props[k];
|
|
459
|
+
}
|
|
460
|
+
writer.write(`<textarea${renderAttributes(filteredProps, false)}>`);
|
|
461
|
+
writer.text(escapeHtml(String(textContent)));
|
|
462
|
+
writer.write("</textarea>");
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
if (tag === "select") {
|
|
466
|
+
const selectedValue = props.value ?? props.defaultValue;
|
|
467
|
+
const filteredProps = {};
|
|
468
|
+
for (const k of Object.keys(props)) {
|
|
469
|
+
if (k !== "value" && k !== "defaultValue")
|
|
470
|
+
filteredProps[k] = props[k];
|
|
471
|
+
}
|
|
472
|
+
writer.write(`<select${renderAttributes(filteredProps, false)}>`);
|
|
473
|
+
const selectedSet = selectedValue == null ? null : Array.isArray(selectedValue) ? new Set(selectedValue.map(String)) : /* @__PURE__ */ new Set([String(selectedValue)]);
|
|
474
|
+
const patchedChildren = selectedSet != null ? markSelectedOptionsMulti(props.children, selectedSet) : props.children;
|
|
475
|
+
const inner2 = renderChildren(patchedChildren, writer, false);
|
|
476
|
+
if (inner2 && typeof inner2.then === "function") {
|
|
477
|
+
return inner2.then(() => {
|
|
478
|
+
writer.write("</select>");
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
writer.write("</select>");
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
writer.write(`<${tag}${renderAttributes(props, childSvg)}`);
|
|
485
|
+
if (VOID_ELEMENTS.has(tag)) {
|
|
486
|
+
writer.write("/>");
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
writer.write(">");
|
|
412
490
|
const childContext = tag === "foreignObject" ? false : childSvg;
|
|
413
491
|
let inner = void 0;
|
|
414
492
|
if (props.dangerouslySetInnerHTML) {
|
|
@@ -418,17 +496,17 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
418
496
|
}
|
|
419
497
|
if (inner && typeof inner.then === "function") {
|
|
420
498
|
return inner.then(() => {
|
|
421
|
-
|
|
422
|
-
writer.write(`</${tag}>`);
|
|
499
|
+
writer.write(`</${tag}>`);
|
|
423
500
|
});
|
|
424
501
|
}
|
|
425
|
-
|
|
426
|
-
writer.write(`</${tag}>`);
|
|
502
|
+
writer.write(`</${tag}>`);
|
|
427
503
|
}
|
|
428
504
|
var REACT_MEMO = Symbol.for("react.memo");
|
|
429
505
|
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
430
506
|
var REACT_PROVIDER = Symbol.for("react.provider");
|
|
431
507
|
var REACT_CONTEXT = Symbol.for("react.context");
|
|
508
|
+
var REACT_CONSUMER = Symbol.for("react.consumer");
|
|
509
|
+
var REACT_LAZY = Symbol.for("react.lazy");
|
|
432
510
|
function renderComponent(type, props, writer, isSvg) {
|
|
433
511
|
const typeOf = type?.$$typeof;
|
|
434
512
|
if (typeOf === REACT_MEMO) {
|
|
@@ -441,6 +519,24 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
441
519
|
if (typeOf === REACT_FORWARD_REF) {
|
|
442
520
|
return renderComponent(type.render, props, writer, isSvg);
|
|
443
521
|
}
|
|
522
|
+
if (typeOf === REACT_LAZY) {
|
|
523
|
+
const resolved = type._init(type._payload);
|
|
524
|
+
const LazyComp = resolved?.default ?? resolved;
|
|
525
|
+
return renderComponent(LazyComp, props, writer, isSvg);
|
|
526
|
+
}
|
|
527
|
+
if (typeOf === REACT_CONSUMER) {
|
|
528
|
+
const ctx2 = type._context;
|
|
529
|
+
const value = ctx2?._currentValue;
|
|
530
|
+
const result2 = typeof props.children === "function" ? props.children(value) : null;
|
|
531
|
+
const savedScope2 = pushComponentScope();
|
|
532
|
+
const finish2 = () => popComponentScope(savedScope2);
|
|
533
|
+
const r2 = renderNode(result2, writer, isSvg);
|
|
534
|
+
if (r2 && typeof r2.then === "function") {
|
|
535
|
+
return r2.then(finish2);
|
|
536
|
+
}
|
|
537
|
+
finish2();
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
444
540
|
const isProvider = "_context" in type || typeOf === REACT_PROVIDER || typeOf === REACT_CONTEXT && "value" in props;
|
|
445
541
|
let prevCtxValue;
|
|
446
542
|
let ctx;
|
|
@@ -450,10 +546,27 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
450
546
|
ctx._currentValue = props.value;
|
|
451
547
|
}
|
|
452
548
|
const savedScope = pushComponentScope();
|
|
549
|
+
if (isProvider && typeof type !== "function") {
|
|
550
|
+
const finish2 = () => {
|
|
551
|
+
popComponentScope(savedScope);
|
|
552
|
+
ctx._currentValue = prevCtxValue;
|
|
553
|
+
};
|
|
554
|
+
const r2 = renderChildren(props.children, writer, isSvg);
|
|
555
|
+
if (r2 && typeof r2.then === "function") {
|
|
556
|
+
return r2.then(finish2);
|
|
557
|
+
}
|
|
558
|
+
finish2();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
453
561
|
let result;
|
|
454
562
|
try {
|
|
455
563
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
456
564
|
const instance = new type(props);
|
|
565
|
+
if (typeof type.getDerivedStateFromProps === "function") {
|
|
566
|
+
const derived = type.getDerivedStateFromProps(props, instance.state ?? {});
|
|
567
|
+
if (derived != null)
|
|
568
|
+
instance.state = { ...instance.state ?? {}, ...derived };
|
|
569
|
+
}
|
|
457
570
|
result = instance.render();
|
|
458
571
|
} else {
|
|
459
572
|
result = type(props);
|
|
@@ -490,7 +603,7 @@ function isTextLike(node) {
|
|
|
490
603
|
function renderChildArray(children, writer, isSvg) {
|
|
491
604
|
const totalChildren = children.length;
|
|
492
605
|
for (let i = 0; i < totalChildren; i++) {
|
|
493
|
-
if (
|
|
606
|
+
if (isTextLike(children[i]) && writer.lastWasText) {
|
|
494
607
|
writer.write("<!-- -->");
|
|
495
608
|
}
|
|
496
609
|
const savedTree = pushTreeContext(totalChildren, i);
|
|
@@ -507,7 +620,7 @@ function renderChildArray(children, writer, isSvg) {
|
|
|
507
620
|
function renderChildArrayFrom(children, startIndex, writer, isSvg) {
|
|
508
621
|
const totalChildren = children.length;
|
|
509
622
|
for (let i = startIndex; i < totalChildren; i++) {
|
|
510
|
-
if (
|
|
623
|
+
if (isTextLike(children[i]) && writer.lastWasText) {
|
|
511
624
|
writer.write("<!-- -->");
|
|
512
625
|
}
|
|
513
626
|
const savedTree = pushTreeContext(totalChildren, i);
|
|
@@ -570,8 +683,14 @@ function renderToStream(element) {
|
|
|
570
683
|
async start(controller) {
|
|
571
684
|
resetRenderState();
|
|
572
685
|
const writer = {
|
|
686
|
+
lastWasText: false,
|
|
573
687
|
write(chunk) {
|
|
574
688
|
controller.enqueue(encoder.encode(chunk));
|
|
689
|
+
this.lastWasText = false;
|
|
690
|
+
},
|
|
691
|
+
text(s2) {
|
|
692
|
+
controller.enqueue(encoder.encode(s2));
|
|
693
|
+
this.lastWasText = true;
|
|
575
694
|
}
|
|
576
695
|
};
|
|
577
696
|
try {
|
|
@@ -589,9 +708,17 @@ async function renderToString(element) {
|
|
|
589
708
|
for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
|
|
590
709
|
resetRenderState();
|
|
591
710
|
const chunks = [];
|
|
592
|
-
const writer = {
|
|
593
|
-
|
|
594
|
-
|
|
711
|
+
const writer = {
|
|
712
|
+
lastWasText: false,
|
|
713
|
+
write(c) {
|
|
714
|
+
chunks.push(c);
|
|
715
|
+
this.lastWasText = false;
|
|
716
|
+
},
|
|
717
|
+
text(s2) {
|
|
718
|
+
chunks.push(s2);
|
|
719
|
+
this.lastWasText = true;
|
|
720
|
+
}
|
|
721
|
+
};
|
|
595
722
|
try {
|
|
596
723
|
const r = renderNode(element, writer);
|
|
597
724
|
if (r && typeof r.then === "function")
|
|
@@ -29,6 +29,7 @@ module.exports = __toCommonJS(jsx_runtime_exports);
|
|
|
29
29
|
|
|
30
30
|
// src/slim-react/types.ts
|
|
31
31
|
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
32
|
+
var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
32
33
|
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
33
34
|
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
34
35
|
|
|
@@ -43,6 +43,7 @@ function processSegmentCache(html) {
|
|
|
43
43
|
|
|
44
44
|
// src/slim-react/types.ts
|
|
45
45
|
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
46
|
+
var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
46
47
|
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
47
48
|
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
48
49
|
|
|
@@ -140,7 +141,7 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
140
141
|
"wbr"
|
|
141
142
|
]);
|
|
142
143
|
function escapeHtml(str) {
|
|
143
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
144
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
144
145
|
}
|
|
145
146
|
function escapeAttr(str) {
|
|
146
147
|
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -285,7 +286,7 @@ var SVG_ATTR_MAP = {
|
|
|
285
286
|
function renderAttributes(props, isSvg) {
|
|
286
287
|
let attrs = "";
|
|
287
288
|
for (const [key, value] of Object.entries(props)) {
|
|
288
|
-
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML")
|
|
289
|
+
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || key === "suppressHydrationWarning" || key === "suppressContentEditableWarning")
|
|
289
290
|
continue;
|
|
290
291
|
if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase())
|
|
291
292
|
continue;
|
|
@@ -293,12 +294,16 @@ function renderAttributes(props, isSvg) {
|
|
|
293
294
|
if (isSvg && key in SVG_ATTR_MAP) {
|
|
294
295
|
attrName = SVG_ATTR_MAP[key];
|
|
295
296
|
} else {
|
|
296
|
-
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key;
|
|
297
|
+
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key === "defaultValue" ? "value" : key === "defaultChecked" ? "checked" : key;
|
|
297
298
|
}
|
|
298
|
-
if (value === false || value == null)
|
|
299
|
+
if (value === false || value == null) {
|
|
300
|
+
if (value === false && (attrName.startsWith("aria-") || attrName.startsWith("data-"))) {
|
|
301
|
+
attrs += ` ${attrName}="false"`;
|
|
302
|
+
}
|
|
299
303
|
continue;
|
|
304
|
+
}
|
|
300
305
|
if (value === true) {
|
|
301
|
-
attrs += ` ${attrName}`;
|
|
306
|
+
attrs += ` ${attrName}=""`;
|
|
302
307
|
continue;
|
|
303
308
|
}
|
|
304
309
|
if (key === "style" && typeof value === "object") {
|
|
@@ -311,23 +316,30 @@ function renderAttributes(props, isSvg) {
|
|
|
311
316
|
}
|
|
312
317
|
var BufferWriter = class {
|
|
313
318
|
chunks = [];
|
|
319
|
+
lastWasText = false;
|
|
314
320
|
write(chunk) {
|
|
315
321
|
this.chunks.push(chunk);
|
|
322
|
+
this.lastWasText = false;
|
|
323
|
+
}
|
|
324
|
+
text(s2) {
|
|
325
|
+
this.chunks.push(s2);
|
|
326
|
+
this.lastWasText = true;
|
|
316
327
|
}
|
|
317
328
|
flush(target) {
|
|
318
329
|
for (const c of this.chunks)
|
|
319
330
|
target.write(c);
|
|
331
|
+
target.lastWasText = this.lastWasText;
|
|
320
332
|
}
|
|
321
333
|
};
|
|
322
334
|
function renderNode(node, writer, isSvg = false) {
|
|
323
335
|
if (node == null || typeof node === "boolean")
|
|
324
336
|
return;
|
|
325
337
|
if (typeof node === "string") {
|
|
326
|
-
writer.
|
|
338
|
+
writer.text(escapeHtml(node));
|
|
327
339
|
return;
|
|
328
340
|
}
|
|
329
341
|
if (typeof node === "number") {
|
|
330
|
-
writer.
|
|
342
|
+
writer.text(String(node));
|
|
331
343
|
return;
|
|
332
344
|
}
|
|
333
345
|
if (Array.isArray(node)) {
|
|
@@ -340,7 +352,10 @@ function renderNode(node, writer, isSvg = false) {
|
|
|
340
352
|
isSvg
|
|
341
353
|
);
|
|
342
354
|
}
|
|
343
|
-
if (typeof node === "object" && node !== null && "$$typeof" in node
|
|
355
|
+
if (typeof node === "object" && node !== null && "$$typeof" in node) {
|
|
356
|
+
const elType = node["$$typeof"];
|
|
357
|
+
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
358
|
+
return;
|
|
344
359
|
const element = node;
|
|
345
360
|
const { type, props } = element;
|
|
346
361
|
if (type === FRAGMENT_TYPE) {
|
|
@@ -352,16 +367,79 @@ function renderNode(node, writer, isSvg = false) {
|
|
|
352
367
|
if (typeof type === "function") {
|
|
353
368
|
return renderComponent(type, props, writer, isSvg);
|
|
354
369
|
}
|
|
370
|
+
if (typeof type === "object" && type !== null) {
|
|
371
|
+
return renderComponent(type, props, writer, isSvg);
|
|
372
|
+
}
|
|
355
373
|
if (typeof type === "string") {
|
|
356
374
|
return renderHostElement(type, props, writer, isSvg);
|
|
357
375
|
}
|
|
358
376
|
}
|
|
359
377
|
}
|
|
378
|
+
function markSelectedOptionsMulti(children, selectedValues) {
|
|
379
|
+
if (children == null || typeof children === "boolean")
|
|
380
|
+
return children;
|
|
381
|
+
if (typeof children === "string" || typeof children === "number")
|
|
382
|
+
return children;
|
|
383
|
+
if (Array.isArray(children)) {
|
|
384
|
+
return children.map((c) => markSelectedOptionsMulti(c, selectedValues));
|
|
385
|
+
}
|
|
386
|
+
if (typeof children === "object" && "$$typeof" in children) {
|
|
387
|
+
const elType = children["$$typeof"];
|
|
388
|
+
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
389
|
+
return children;
|
|
390
|
+
const el = children;
|
|
391
|
+
if (el.type === "option") {
|
|
392
|
+
const optValue = el.props.value !== void 0 ? el.props.value : el.props.children;
|
|
393
|
+
const isSelected = selectedValues.has(String(optValue));
|
|
394
|
+
return { ...el, props: { ...el.props, selected: isSelected || void 0 } };
|
|
395
|
+
}
|
|
396
|
+
if (el.type === "optgroup" || el.type === FRAGMENT_TYPE) {
|
|
397
|
+
const newChildren = markSelectedOptionsMulti(el.props.children, selectedValues);
|
|
398
|
+
return { ...el, props: { ...el.props, children: newChildren } };
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return children;
|
|
402
|
+
}
|
|
360
403
|
function renderHostElement(tag, props, writer, isSvg) {
|
|
361
404
|
const enteringSvg = tag === "svg";
|
|
362
405
|
const childSvg = isSvg || enteringSvg;
|
|
363
|
-
|
|
364
|
-
|
|
406
|
+
if (tag === "textarea") {
|
|
407
|
+
const textContent = props.value ?? props.defaultValue ?? props.children ?? "";
|
|
408
|
+
const filteredProps = {};
|
|
409
|
+
for (const k of Object.keys(props)) {
|
|
410
|
+
if (k !== "value" && k !== "defaultValue" && k !== "children")
|
|
411
|
+
filteredProps[k] = props[k];
|
|
412
|
+
}
|
|
413
|
+
writer.write(`<textarea${renderAttributes(filteredProps, false)}>`);
|
|
414
|
+
writer.text(escapeHtml(String(textContent)));
|
|
415
|
+
writer.write("</textarea>");
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (tag === "select") {
|
|
419
|
+
const selectedValue = props.value ?? props.defaultValue;
|
|
420
|
+
const filteredProps = {};
|
|
421
|
+
for (const k of Object.keys(props)) {
|
|
422
|
+
if (k !== "value" && k !== "defaultValue")
|
|
423
|
+
filteredProps[k] = props[k];
|
|
424
|
+
}
|
|
425
|
+
writer.write(`<select${renderAttributes(filteredProps, false)}>`);
|
|
426
|
+
const selectedSet = selectedValue == null ? null : Array.isArray(selectedValue) ? new Set(selectedValue.map(String)) : /* @__PURE__ */ new Set([String(selectedValue)]);
|
|
427
|
+
const patchedChildren = selectedSet != null ? markSelectedOptionsMulti(props.children, selectedSet) : props.children;
|
|
428
|
+
const inner2 = renderChildren(patchedChildren, writer, false);
|
|
429
|
+
if (inner2 && typeof inner2.then === "function") {
|
|
430
|
+
return inner2.then(() => {
|
|
431
|
+
writer.write("</select>");
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
writer.write("</select>");
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
writer.write(`<${tag}${renderAttributes(props, childSvg)}`);
|
|
438
|
+
if (VOID_ELEMENTS.has(tag)) {
|
|
439
|
+
writer.write("/>");
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
writer.write(">");
|
|
365
443
|
const childContext = tag === "foreignObject" ? false : childSvg;
|
|
366
444
|
let inner = void 0;
|
|
367
445
|
if (props.dangerouslySetInnerHTML) {
|
|
@@ -371,17 +449,17 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
371
449
|
}
|
|
372
450
|
if (inner && typeof inner.then === "function") {
|
|
373
451
|
return inner.then(() => {
|
|
374
|
-
|
|
375
|
-
writer.write(`</${tag}>`);
|
|
452
|
+
writer.write(`</${tag}>`);
|
|
376
453
|
});
|
|
377
454
|
}
|
|
378
|
-
|
|
379
|
-
writer.write(`</${tag}>`);
|
|
455
|
+
writer.write(`</${tag}>`);
|
|
380
456
|
}
|
|
381
457
|
var REACT_MEMO = Symbol.for("react.memo");
|
|
382
458
|
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
383
459
|
var REACT_PROVIDER = Symbol.for("react.provider");
|
|
384
460
|
var REACT_CONTEXT = Symbol.for("react.context");
|
|
461
|
+
var REACT_CONSUMER = Symbol.for("react.consumer");
|
|
462
|
+
var REACT_LAZY = Symbol.for("react.lazy");
|
|
385
463
|
function renderComponent(type, props, writer, isSvg) {
|
|
386
464
|
const typeOf = type?.$$typeof;
|
|
387
465
|
if (typeOf === REACT_MEMO) {
|
|
@@ -394,6 +472,24 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
394
472
|
if (typeOf === REACT_FORWARD_REF) {
|
|
395
473
|
return renderComponent(type.render, props, writer, isSvg);
|
|
396
474
|
}
|
|
475
|
+
if (typeOf === REACT_LAZY) {
|
|
476
|
+
const resolved = type._init(type._payload);
|
|
477
|
+
const LazyComp = resolved?.default ?? resolved;
|
|
478
|
+
return renderComponent(LazyComp, props, writer, isSvg);
|
|
479
|
+
}
|
|
480
|
+
if (typeOf === REACT_CONSUMER) {
|
|
481
|
+
const ctx2 = type._context;
|
|
482
|
+
const value = ctx2?._currentValue;
|
|
483
|
+
const result2 = typeof props.children === "function" ? props.children(value) : null;
|
|
484
|
+
const savedScope2 = pushComponentScope();
|
|
485
|
+
const finish2 = () => popComponentScope(savedScope2);
|
|
486
|
+
const r2 = renderNode(result2, writer, isSvg);
|
|
487
|
+
if (r2 && typeof r2.then === "function") {
|
|
488
|
+
return r2.then(finish2);
|
|
489
|
+
}
|
|
490
|
+
finish2();
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
397
493
|
const isProvider = "_context" in type || typeOf === REACT_PROVIDER || typeOf === REACT_CONTEXT && "value" in props;
|
|
398
494
|
let prevCtxValue;
|
|
399
495
|
let ctx;
|
|
@@ -403,10 +499,27 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
403
499
|
ctx._currentValue = props.value;
|
|
404
500
|
}
|
|
405
501
|
const savedScope = pushComponentScope();
|
|
502
|
+
if (isProvider && typeof type !== "function") {
|
|
503
|
+
const finish2 = () => {
|
|
504
|
+
popComponentScope(savedScope);
|
|
505
|
+
ctx._currentValue = prevCtxValue;
|
|
506
|
+
};
|
|
507
|
+
const r2 = renderChildren(props.children, writer, isSvg);
|
|
508
|
+
if (r2 && typeof r2.then === "function") {
|
|
509
|
+
return r2.then(finish2);
|
|
510
|
+
}
|
|
511
|
+
finish2();
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
406
514
|
let result;
|
|
407
515
|
try {
|
|
408
516
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
409
517
|
const instance = new type(props);
|
|
518
|
+
if (typeof type.getDerivedStateFromProps === "function") {
|
|
519
|
+
const derived = type.getDerivedStateFromProps(props, instance.state ?? {});
|
|
520
|
+
if (derived != null)
|
|
521
|
+
instance.state = { ...instance.state ?? {}, ...derived };
|
|
522
|
+
}
|
|
410
523
|
result = instance.render();
|
|
411
524
|
} else {
|
|
412
525
|
result = type(props);
|
|
@@ -443,7 +556,7 @@ function isTextLike(node) {
|
|
|
443
556
|
function renderChildArray(children, writer, isSvg) {
|
|
444
557
|
const totalChildren = children.length;
|
|
445
558
|
for (let i = 0; i < totalChildren; i++) {
|
|
446
|
-
if (
|
|
559
|
+
if (isTextLike(children[i]) && writer.lastWasText) {
|
|
447
560
|
writer.write("<!-- -->");
|
|
448
561
|
}
|
|
449
562
|
const savedTree = pushTreeContext(totalChildren, i);
|
|
@@ -460,7 +573,7 @@ function renderChildArray(children, writer, isSvg) {
|
|
|
460
573
|
function renderChildArrayFrom(children, startIndex, writer, isSvg) {
|
|
461
574
|
const totalChildren = children.length;
|
|
462
575
|
for (let i = startIndex; i < totalChildren; i++) {
|
|
463
|
-
if (
|
|
576
|
+
if (isTextLike(children[i]) && writer.lastWasText) {
|
|
464
577
|
writer.write("<!-- -->");
|
|
465
578
|
}
|
|
466
579
|
const savedTree = pushTreeContext(totalChildren, i);
|
|
@@ -521,9 +634,17 @@ async function renderToString(element) {
|
|
|
521
634
|
for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
|
|
522
635
|
resetRenderState();
|
|
523
636
|
const chunks = [];
|
|
524
|
-
const writer = {
|
|
525
|
-
|
|
526
|
-
|
|
637
|
+
const writer = {
|
|
638
|
+
lastWasText: false,
|
|
639
|
+
write(c) {
|
|
640
|
+
chunks.push(c);
|
|
641
|
+
this.lastWasText = false;
|
|
642
|
+
},
|
|
643
|
+
text(s2) {
|
|
644
|
+
chunks.push(s2);
|
|
645
|
+
this.lastWasText = true;
|
|
646
|
+
}
|
|
647
|
+
};
|
|
527
648
|
try {
|
|
528
649
|
const r = renderNode(element, writer);
|
|
529
650
|
if (r && typeof r.then === "function")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hadars",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "Minimal SSR framework for React — rspack, HMR, TypeScript, Bun/Node/Deno",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build:lib": "tsup src/index.tsx src/slim-react/index.ts src/slim-react/jsx-runtime.ts --format esm,cjs --dts --out-dir dist --clean --external '@rspack/*' --external '@rspack/binding'",
|
|
33
33
|
"build:cli": "node build-scripts/build-cli.mjs",
|
|
34
34
|
"build:all": "npm run build:lib && npm run build:cli",
|
|
35
|
-
"test": "bun test test/ssr.test.ts",
|
|
35
|
+
"test": "bun test test/render-compare.test.tsx && bun test test/ssr.test.ts",
|
|
36
36
|
"prepare": "npm run build:all",
|
|
37
37
|
"prepublishOnly": "npm run build:all"
|
|
38
38
|
},
|