ilha 0.9.5 → 0.10.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.
- package/README.md +102 -41
- package/dist/{index-Dx_q_SGo.d.ts → index-Bi_I3qEL.d.ts} +106 -46
- package/dist/index.d.ts +2 -2
- package/dist/index.js +494 -65
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-runtime-DJ2B4fvA.d.ts +633 -0
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +94 -16
- package/package.json +1 -1
- package/dist/jsx-runtime-DysRyz9R.d.ts +0 -37
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ function exceedsMaxDepth(value, depth) {
|
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
13
|
for (const key in value) {
|
|
14
|
-
if (!Object.
|
|
14
|
+
if (!Object.hasOwn(value, key)) continue;
|
|
15
15
|
if (exceedsMaxDepth(value[key], depth + 1)) return true;
|
|
16
16
|
}
|
|
17
17
|
return false;
|
|
@@ -60,7 +60,7 @@ function shallowEqualInput(a, b) {
|
|
|
60
60
|
const bk = Object.keys(b);
|
|
61
61
|
if (ak.length !== bk.length) return false;
|
|
62
62
|
for (const k of ak) {
|
|
63
|
-
if (!Object.
|
|
63
|
+
if (!Object.hasOwn(b, k)) return false;
|
|
64
64
|
if (!Object.is(a[k], b[k])) return false;
|
|
65
65
|
}
|
|
66
66
|
return true;
|
|
@@ -103,10 +103,10 @@ function getIslandSlotTag(island) {
|
|
|
103
103
|
if (typeof tag === "string" && tag.length > 0) return tag;
|
|
104
104
|
return "div";
|
|
105
105
|
}
|
|
106
|
-
function wrapIslandSlotHtml(tag, id, propsAttr, inner) {
|
|
106
|
+
function wrapIslandSlotHtml({ tag, id, propsAttr, inner }) {
|
|
107
107
|
return `<${tag} ${SLOT_ATTR}="${escapeHtml(id)}"${propsAttr}>${inner}</${tag}>`;
|
|
108
108
|
}
|
|
109
|
-
function isStableInlineSlotMount(initialHtml, renderedHtml, slotIds) {
|
|
109
|
+
function isStableInlineSlotMount({ initialHtml, renderedHtml, slotIds }) {
|
|
110
110
|
if (typeof document === "undefined") return false;
|
|
111
111
|
const initialRoot = parseHtmlFragment(initialHtml);
|
|
112
112
|
const renderedRoot = parseHtmlFragment(renderedHtml);
|
|
@@ -485,7 +485,8 @@ const PROPS_ATTR = "data-ilha-props";
|
|
|
485
485
|
const STATE_ATTR = "data-ilha-state";
|
|
486
486
|
const CSS_ATTR = "data-ilha-css";
|
|
487
487
|
function buildScopedStyle(css) {
|
|
488
|
-
|
|
488
|
+
const safeCss = css.replace(/<\/style/gi, "<\\/style");
|
|
489
|
+
return `<style ${CSS_ATTR}>@scope (:scope) to ([data-ilha]){${safeCss}}</style>`;
|
|
489
490
|
}
|
|
490
491
|
const RENDER_CTX_STACK = Symbol.for("ilha.renderCtxStack");
|
|
491
492
|
function renderCtxStack() {
|
|
@@ -498,7 +499,8 @@ function pushRenderCtx(liveHost, asyncChildren) {
|
|
|
498
499
|
positional: 0,
|
|
499
500
|
liveHost,
|
|
500
501
|
pending: asyncChildren ? /* @__PURE__ */ new Map() : void 0,
|
|
501
|
-
binds: []
|
|
502
|
+
binds: [],
|
|
503
|
+
events: []
|
|
502
504
|
};
|
|
503
505
|
renderCtxStack().push(ctx);
|
|
504
506
|
return ctx;
|
|
@@ -518,7 +520,7 @@ function isIslandCall(v) {
|
|
|
518
520
|
if (ISLAND_CALL in v) return true;
|
|
519
521
|
return typeof v === "object" && "island" in v && isIsland(v.island);
|
|
520
522
|
}
|
|
521
|
-
function emitIslandSlot(island, props, key) {
|
|
523
|
+
function emitIslandSlot({ island, props, key }) {
|
|
522
524
|
const ctx = currentRenderCtx();
|
|
523
525
|
let id;
|
|
524
526
|
if (key !== void 0) id = `k:${key}`;
|
|
@@ -530,22 +532,42 @@ function emitIslandSlot(island, props, key) {
|
|
|
530
532
|
const slotTag = getIslandSlotTag(island);
|
|
531
533
|
const attrProps = slotPropsForAttr(props);
|
|
532
534
|
const propsAttr = attrProps ? ` ${PROPS_ATTR}='${escapeHtml(JSON.stringify(attrProps))}'` : "";
|
|
533
|
-
if (ctx?.liveHost) return wrapIslandSlotHtml(
|
|
535
|
+
if (ctx?.liveHost) return wrapIslandSlotHtml({
|
|
536
|
+
tag: slotTag,
|
|
537
|
+
id,
|
|
538
|
+
propsAttr,
|
|
539
|
+
inner: ""
|
|
540
|
+
});
|
|
534
541
|
if (ctx?.pending) {
|
|
535
542
|
popRenderCtx();
|
|
536
543
|
try {
|
|
537
544
|
const result = island(props);
|
|
538
545
|
if (result instanceof Promise) {
|
|
539
546
|
ctx.pending.set(id, result.then(String));
|
|
540
|
-
return wrapIslandSlotHtml(
|
|
547
|
+
return wrapIslandSlotHtml({
|
|
548
|
+
tag: slotTag,
|
|
549
|
+
id,
|
|
550
|
+
propsAttr,
|
|
551
|
+
inner: asyncSlotMarker(id)
|
|
552
|
+
});
|
|
541
553
|
}
|
|
542
|
-
return wrapIslandSlotHtml(
|
|
554
|
+
return wrapIslandSlotHtml({
|
|
555
|
+
tag: slotTag,
|
|
556
|
+
id,
|
|
557
|
+
propsAttr,
|
|
558
|
+
inner: String(result)
|
|
559
|
+
});
|
|
543
560
|
} finally {
|
|
544
561
|
renderCtxStack().push(ctx);
|
|
545
562
|
}
|
|
546
563
|
}
|
|
547
564
|
const inner = island.toString(props);
|
|
548
|
-
return wrapIslandSlotHtml(
|
|
565
|
+
return wrapIslandSlotHtml({
|
|
566
|
+
tag: slotTag,
|
|
567
|
+
id,
|
|
568
|
+
propsAttr,
|
|
569
|
+
inner
|
|
570
|
+
});
|
|
549
571
|
}
|
|
550
572
|
function asyncSlotMarker(id) {
|
|
551
573
|
return `<!--ilha-async:${escapeHtml(id)}-->`;
|
|
@@ -557,6 +579,15 @@ async function resolveAsyncChildren(html, pending) {
|
|
|
557
579
|
}
|
|
558
580
|
return html;
|
|
559
581
|
}
|
|
582
|
+
function resolveSignalSetter(read, value) {
|
|
583
|
+
if (typeof value !== "function") return value;
|
|
584
|
+
const prevSub = setActiveSub(void 0);
|
|
585
|
+
try {
|
|
586
|
+
return value(read());
|
|
587
|
+
} finally {
|
|
588
|
+
setActiveSub(prevSub);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
560
591
|
function markSignalAccessor(fn) {
|
|
561
592
|
fn[SIGNAL_ACCESSOR] = true;
|
|
562
593
|
const accessor = fn;
|
|
@@ -574,14 +605,19 @@ function getAtPath(obj, path) {
|
|
|
574
605
|
}
|
|
575
606
|
return cur;
|
|
576
607
|
}
|
|
577
|
-
function setAtPath(
|
|
608
|
+
function setAtPath({ object, path, value }) {
|
|
609
|
+
const obj = object;
|
|
578
610
|
if (path.length === 0) return value;
|
|
579
611
|
const [head, ...rest] = path;
|
|
580
612
|
if (Array.isArray(obj)) {
|
|
581
613
|
const idx = head;
|
|
582
614
|
if (idx < 0 || idx >= obj.length) return obj;
|
|
583
615
|
const next = obj[idx];
|
|
584
|
-
const updated = rest.length === 0 ? value : setAtPath(
|
|
616
|
+
const updated = rest.length === 0 ? value : setAtPath({
|
|
617
|
+
object: next,
|
|
618
|
+
path: rest,
|
|
619
|
+
value
|
|
620
|
+
});
|
|
585
621
|
if (Object.is(next, updated)) return obj;
|
|
586
622
|
const copy = obj.slice();
|
|
587
623
|
copy[idx] = updated;
|
|
@@ -591,7 +627,11 @@ function setAtPath(obj, path, value) {
|
|
|
591
627
|
const record = obj;
|
|
592
628
|
const key = String(head);
|
|
593
629
|
const next = record[key];
|
|
594
|
-
const updated = rest.length === 0 ? value : setAtPath(
|
|
630
|
+
const updated = rest.length === 0 ? value : setAtPath({
|
|
631
|
+
object: next,
|
|
632
|
+
path: rest,
|
|
633
|
+
value
|
|
634
|
+
});
|
|
595
635
|
if (rest.length === 0) {
|
|
596
636
|
if (Object.is(next, value)) return obj;
|
|
597
637
|
} else if (Object.is(next, updated)) return obj;
|
|
@@ -600,7 +640,11 @@ function setAtPath(obj, path, value) {
|
|
|
600
640
|
[key]: updated
|
|
601
641
|
};
|
|
602
642
|
}
|
|
603
|
-
return rest.length === 0 ? value : setAtPath(
|
|
643
|
+
return rest.length === 0 ? value : setAtPath({
|
|
644
|
+
object: void 0,
|
|
645
|
+
path: rest,
|
|
646
|
+
value
|
|
647
|
+
});
|
|
604
648
|
}
|
|
605
649
|
function toPathSegment(prop) {
|
|
606
650
|
if (typeof prop === "symbol") return null;
|
|
@@ -629,8 +673,15 @@ function createSelectAccessor(root, selector) {
|
|
|
629
673
|
if (!Object.is(selected, resolved)) throw new Error("select(): selector must only traverse nested properties or array indexes — derived or transformed values are not supported.");
|
|
630
674
|
return markSignalAccessor((...args) => {
|
|
631
675
|
if (args.length === 0) return path.length === 0 ? selector(root()) : getAtPath(root(), path);
|
|
632
|
-
const
|
|
633
|
-
|
|
676
|
+
const previousRoot = root();
|
|
677
|
+
const previousSelected = path.length === 0 ? selector(previousRoot) : getAtPath(previousRoot, path);
|
|
678
|
+
const value = resolveSignalSetter(() => previousSelected, args[0]);
|
|
679
|
+
const next = path.length === 0 ? value : setAtPath({
|
|
680
|
+
object: previousRoot,
|
|
681
|
+
path,
|
|
682
|
+
value
|
|
683
|
+
});
|
|
684
|
+
if (!Object.is(previousRoot, next)) root((() => next));
|
|
634
685
|
});
|
|
635
686
|
}
|
|
636
687
|
function ilhaRaw(value) {
|
|
@@ -654,9 +705,17 @@ function interpolateValue(v) {
|
|
|
654
705
|
if (isRawHtml(v)) return v.value;
|
|
655
706
|
if (isIslandCall(v)) {
|
|
656
707
|
const call = typeof v === "function" ? v() : v;
|
|
657
|
-
return emitIslandSlot(
|
|
708
|
+
return emitIslandSlot({
|
|
709
|
+
island: call.island,
|
|
710
|
+
props: call.props,
|
|
711
|
+
key: call.key
|
|
712
|
+
});
|
|
658
713
|
}
|
|
659
|
-
if (isIsland(v)) return emitIslandSlot(
|
|
714
|
+
if (isIsland(v)) return emitIslandSlot({
|
|
715
|
+
island: v,
|
|
716
|
+
props: void 0,
|
|
717
|
+
key: void 0
|
|
718
|
+
});
|
|
660
719
|
if (isSignalAccessor(v)) return escapeHtml(v());
|
|
661
720
|
if (typeof v === "function") return escapeHtml(v());
|
|
662
721
|
return escapeHtml(v);
|
|
@@ -672,6 +731,30 @@ const BIND_VALID_KINDS = /* @__PURE__ */ new Set([
|
|
|
672
731
|
"this"
|
|
673
732
|
]);
|
|
674
733
|
const BIND_PREFIX_RE = /\bbind:([a-zA-Z]+)\s*=\s*("|')?$/;
|
|
734
|
+
const EVENT_PREFIX_RE = /(?:^|\s)on([a-z][a-z0-9-]*)(?::([a-z][a-z0-9-]*))?\s*=\s*("|')?$/;
|
|
735
|
+
const NATIVE_EVENT_MODIFIERS = /* @__PURE__ */ new Set([
|
|
736
|
+
"abortable",
|
|
737
|
+
"once",
|
|
738
|
+
"capture",
|
|
739
|
+
"passive"
|
|
740
|
+
]);
|
|
741
|
+
function isEventAttributePosition(source, index) {
|
|
742
|
+
let open = -1;
|
|
743
|
+
let quote = null;
|
|
744
|
+
for (let i = 0; i < index; i++) {
|
|
745
|
+
const char = source[i];
|
|
746
|
+
if (open === -1) {
|
|
747
|
+
if (char === "<") open = i;
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
if (quote) {
|
|
751
|
+
if (char === quote) quote = null;
|
|
752
|
+
} else if (char === "\"" || char === "'") quote = char;
|
|
753
|
+
else if (char === ">") open = -1;
|
|
754
|
+
}
|
|
755
|
+
if (open === -1 || quote !== null) return false;
|
|
756
|
+
return !/^\s*[!/?]/.test(source.slice(open + 1, index));
|
|
757
|
+
}
|
|
675
758
|
function findTagCloseIndex(chunk, initialQuote) {
|
|
676
759
|
let quote = initialQuote;
|
|
677
760
|
for (let i = 0; i < chunk.length; i++) {
|
|
@@ -706,7 +789,7 @@ function extractElementStaticValue(prefix) {
|
|
|
706
789
|
if (!m) return null;
|
|
707
790
|
return m[2] ?? m[3] ?? m[4] ?? null;
|
|
708
791
|
}
|
|
709
|
-
function emitBindSSR(kind, index, accessor, prefixForStaticPeek) {
|
|
792
|
+
function emitBindSSR({ kind, index, accessor, prefixForStaticPeek }) {
|
|
710
793
|
const spec = `${kind}:${index}`;
|
|
711
794
|
let v;
|
|
712
795
|
try {
|
|
@@ -733,6 +816,7 @@ function ilhaHtml(strings, ...values) {
|
|
|
733
816
|
let result = "";
|
|
734
817
|
let stripLeadingQuote = null;
|
|
735
818
|
let pendingBindSpecs = "";
|
|
819
|
+
let pendingEventSpecs = "";
|
|
736
820
|
let pendingQuote = null;
|
|
737
821
|
const ctx = currentRenderCtx();
|
|
738
822
|
for (let i = 0; i < strings.length; i++) {
|
|
@@ -741,11 +825,15 @@ function ilhaHtml(strings, ...values) {
|
|
|
741
825
|
if (chunk.startsWith(stripLeadingQuote)) chunk = chunk.slice(1);
|
|
742
826
|
stripLeadingQuote = null;
|
|
743
827
|
}
|
|
744
|
-
if (pendingBindSpecs !== "") {
|
|
828
|
+
if (pendingBindSpecs !== "" || pendingEventSpecs !== "") {
|
|
745
829
|
const { index: gtIdx, quote } = findTagCloseIndex(chunk, pendingQuote);
|
|
746
830
|
if (gtIdx !== -1) {
|
|
747
|
-
|
|
831
|
+
const head = chunk.slice(0, gtIdx).replace(/\s*\/\s*$/, "");
|
|
832
|
+
const bindAttr = pendingBindSpecs ? ` data-ilha-bind="${pendingBindSpecs}"` : "";
|
|
833
|
+
const eventAttr = pendingEventSpecs ? ` data-ilha-on="${pendingEventSpecs}"` : "";
|
|
834
|
+
chunk = head + bindAttr + eventAttr + ">" + chunk.slice(gtIdx + 1);
|
|
748
835
|
pendingBindSpecs = "";
|
|
836
|
+
pendingEventSpecs = "";
|
|
749
837
|
pendingQuote = null;
|
|
750
838
|
} else pendingQuote = quote;
|
|
751
839
|
}
|
|
@@ -754,6 +842,29 @@ function ilhaHtml(strings, ...values) {
|
|
|
754
842
|
continue;
|
|
755
843
|
}
|
|
756
844
|
const value = values[i];
|
|
845
|
+
const eventMatch = chunk.match(EVENT_PREFIX_RE);
|
|
846
|
+
if (eventMatch && isEventAttributePosition(result + chunk, result.length + chunk.length - eventMatch[0].length)) {
|
|
847
|
+
const eventName = eventMatch[1];
|
|
848
|
+
const rawModifier = eventMatch[2];
|
|
849
|
+
const modifier = NATIVE_EVENT_MODIFIERS.has(rawModifier) ? rawModifier : void 0;
|
|
850
|
+
const openQuote = eventMatch[3] ?? null;
|
|
851
|
+
const matchStart = chunk.length - eventMatch[0].length;
|
|
852
|
+
const cleanPrefix = chunk.slice(0, matchStart).replace(/\s+$/, "");
|
|
853
|
+
result += cleanPrefix;
|
|
854
|
+
if (ctx && typeof value === "function") {
|
|
855
|
+
const index = ctx.events.length;
|
|
856
|
+
if (rawModifier && !modifier) {} else {
|
|
857
|
+
ctx.events.push({
|
|
858
|
+
type: eventName,
|
|
859
|
+
handler: value,
|
|
860
|
+
modifier
|
|
861
|
+
});
|
|
862
|
+
pendingEventSpecs += (pendingEventSpecs ? "," : "") + `${eventName}:${index}`;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
if (openQuote) stripLeadingQuote = openQuote;
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
757
868
|
const m = chunk.match(BIND_PREFIX_RE);
|
|
758
869
|
if (m && isSignalAccessor(value)) {
|
|
759
870
|
const name = m[1];
|
|
@@ -776,7 +887,12 @@ function ilhaHtml(strings, ...values) {
|
|
|
776
887
|
kind: name,
|
|
777
888
|
accessor: value
|
|
778
889
|
});
|
|
779
|
-
const [valueAttrs, spec] = emitBindSSR(
|
|
890
|
+
const [valueAttrs, spec] = emitBindSSR({
|
|
891
|
+
kind: name,
|
|
892
|
+
index,
|
|
893
|
+
accessor: value,
|
|
894
|
+
prefixForStaticPeek: cleanPrefix
|
|
895
|
+
});
|
|
780
896
|
result += cleanPrefix + valueAttrs;
|
|
781
897
|
pendingBindSpecs += (pendingBindSpecs ? "," : "") + spec;
|
|
782
898
|
if (openQuote) stripLeadingQuote = openQuote;
|
|
@@ -785,6 +901,7 @@ function ilhaHtml(strings, ...values) {
|
|
|
785
901
|
result += chunk + interpolateValue(value);
|
|
786
902
|
}
|
|
787
903
|
if (pendingBindSpecs !== "") result += ` data-ilha-bind="${pendingBindSpecs}"`;
|
|
904
|
+
if (pendingEventSpecs !== "") result += ` data-ilha-on="${pendingEventSpecs}"`;
|
|
788
905
|
return {
|
|
789
906
|
[RAW]: true,
|
|
790
907
|
value: dedentString(result)
|
|
@@ -803,7 +920,7 @@ function ilhaContextFn(key, initial) {
|
|
|
803
920
|
const s = signal(initial);
|
|
804
921
|
const accessor = (...args) => {
|
|
805
922
|
if (args.length === 0) return s();
|
|
806
|
-
s(args[0]);
|
|
923
|
+
s(resolveSignalSetter(() => s(), args[0]));
|
|
807
924
|
};
|
|
808
925
|
contextRegistry.set(key, accessor);
|
|
809
926
|
return accessor;
|
|
@@ -833,7 +950,7 @@ function ilhaSignal(initial) {
|
|
|
833
950
|
const s = signal(initial);
|
|
834
951
|
return markSignalAccessor((...args) => {
|
|
835
952
|
if (args.length === 0) return s();
|
|
836
|
-
s(args[0]);
|
|
953
|
+
s(resolveSignalSetter(() => s(), args[0]));
|
|
837
954
|
});
|
|
838
955
|
}
|
|
839
956
|
/**
|
|
@@ -960,7 +1077,7 @@ function buildDerivedAccessors(envelopes) {
|
|
|
960
1077
|
return accessors.get(key) ?? defaultDerivedAccessor();
|
|
961
1078
|
} });
|
|
962
1079
|
}
|
|
963
|
-
function createDerivedProxy(entries, state, input, derivedSnapshot) {
|
|
1080
|
+
function createDerivedProxy({ entries, state, input, derivedSnapshot }) {
|
|
964
1081
|
const envelopes = /* @__PURE__ */ new Map();
|
|
965
1082
|
for (const entry of entries) {
|
|
966
1083
|
let initialEnvelope;
|
|
@@ -1067,9 +1184,10 @@ function createDerivedProxy(entries, state, input, derivedSnapshot) {
|
|
|
1067
1184
|
return;
|
|
1068
1185
|
}
|
|
1069
1186
|
const prevSub = setActiveSub(void 0);
|
|
1187
|
+
const prevVal = env();
|
|
1070
1188
|
env({
|
|
1071
1189
|
loading: true,
|
|
1072
|
-
value:
|
|
1190
|
+
value: prevVal.value,
|
|
1073
1191
|
error: void 0
|
|
1074
1192
|
});
|
|
1075
1193
|
setActiveSub(prevSub);
|
|
@@ -1102,6 +1220,7 @@ function createDerivedProxy(entries, state, input, derivedSnapshot) {
|
|
|
1102
1220
|
};
|
|
1103
1221
|
}
|
|
1104
1222
|
const BIND_SENTINEL_ATTR = "data-ilha-bind";
|
|
1223
|
+
const EVENT_SENTINEL_ATTR = "data-ilha-on";
|
|
1105
1224
|
function parseBindSentinel(value) {
|
|
1106
1225
|
const out = [];
|
|
1107
1226
|
for (const part of value.split(",")) {
|
|
@@ -1181,12 +1300,86 @@ function resolveBindOps(el, kind) {
|
|
|
1181
1300
|
}
|
|
1182
1301
|
}
|
|
1183
1302
|
}
|
|
1303
|
+
function templateElementBelongsToHost(host, candidate) {
|
|
1304
|
+
if (candidate === host) return true;
|
|
1305
|
+
let current = candidate;
|
|
1306
|
+
while (current && current !== host) {
|
|
1307
|
+
if (current.hasAttribute(SLOT_ATTR) || current.hasAttribute("data-ilha")) return false;
|
|
1308
|
+
current = current.parentElement;
|
|
1309
|
+
}
|
|
1310
|
+
return current === host;
|
|
1311
|
+
}
|
|
1312
|
+
function applyJsxEvents({ host, records, reportError, unmountSignal, onceFired }) {
|
|
1313
|
+
if (records.length === 0) return () => {};
|
|
1314
|
+
const cleanups = [];
|
|
1315
|
+
const elements = [];
|
|
1316
|
+
if (host.hasAttribute(EVENT_SENTINEL_ATTR)) elements.push(host);
|
|
1317
|
+
elements.push(...Array.from(host.querySelectorAll(`[${EVENT_SENTINEL_ATTR}]`)).filter((element) => templateElementBelongsToHost(host, element)));
|
|
1318
|
+
for (const el of elements) {
|
|
1319
|
+
const sentinel = el.getAttribute(EVENT_SENTINEL_ATTR) ?? "";
|
|
1320
|
+
for (const part of sentinel.split(",")) {
|
|
1321
|
+
const separator = part.lastIndexOf(":");
|
|
1322
|
+
if (separator < 1) continue;
|
|
1323
|
+
const type = part.slice(0, separator);
|
|
1324
|
+
const index = Number(part.slice(separator + 1));
|
|
1325
|
+
if (!Number.isInteger(index) || index < 0) continue;
|
|
1326
|
+
const record = records[index];
|
|
1327
|
+
if (!record || record.type !== type) continue;
|
|
1328
|
+
if (record.modifier === "once" && onceFired.get(el)?.has(type)) continue;
|
|
1329
|
+
const listenerController = new AbortController();
|
|
1330
|
+
let invocationController;
|
|
1331
|
+
const options = {
|
|
1332
|
+
once: record.modifier === "once",
|
|
1333
|
+
capture: record.modifier === "capture",
|
|
1334
|
+
passive: record.modifier === "passive"
|
|
1335
|
+
};
|
|
1336
|
+
const reportHandlerError = (error) => {
|
|
1337
|
+
if (error?.name !== "AbortError") reportError(error);
|
|
1338
|
+
};
|
|
1339
|
+
const listener = (event) => {
|
|
1340
|
+
if (record.modifier === "once") {
|
|
1341
|
+
let fired = onceFired.get(el);
|
|
1342
|
+
if (!fired) onceFired.set(el, fired = /* @__PURE__ */ new Set());
|
|
1343
|
+
fired.add(type);
|
|
1344
|
+
}
|
|
1345
|
+
if (record.modifier === "abortable") {
|
|
1346
|
+
invocationController?.abort();
|
|
1347
|
+
invocationController = new AbortController();
|
|
1348
|
+
}
|
|
1349
|
+
const signal = invocationController ? anySignal([listenerController.signal, invocationController.signal]) : listenerController.signal;
|
|
1350
|
+
let result;
|
|
1351
|
+
startBatch();
|
|
1352
|
+
try {
|
|
1353
|
+
result = record.handler(event, { signal });
|
|
1354
|
+
} catch (error) {
|
|
1355
|
+
reportHandlerError(error);
|
|
1356
|
+
return;
|
|
1357
|
+
} finally {
|
|
1358
|
+
endBatch();
|
|
1359
|
+
}
|
|
1360
|
+
if (result != null && typeof result.then === "function") Promise.resolve(result).catch(reportHandlerError);
|
|
1361
|
+
};
|
|
1362
|
+
const stop = () => {
|
|
1363
|
+
listenerController.abort();
|
|
1364
|
+
invocationController?.abort();
|
|
1365
|
+
el.removeEventListener(type, listener, options);
|
|
1366
|
+
};
|
|
1367
|
+
el.addEventListener(type, listener, options);
|
|
1368
|
+
unmountSignal.addEventListener("abort", stop, { once: true });
|
|
1369
|
+
cleanups.push(() => {
|
|
1370
|
+
unmountSignal.removeEventListener("abort", stop);
|
|
1371
|
+
stop();
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
return () => cleanups.forEach((cleanup) => cleanup());
|
|
1376
|
+
}
|
|
1184
1377
|
function applyTemplateBindings(host, binds) {
|
|
1185
1378
|
if (binds.length === 0) return () => {};
|
|
1186
1379
|
const cleanups = [];
|
|
1187
1380
|
const elements = [];
|
|
1188
1381
|
if (host.hasAttribute(BIND_SENTINEL_ATTR)) elements.push(host);
|
|
1189
|
-
for (const el of host.querySelectorAll(`[${BIND_SENTINEL_ATTR}]`)) elements.push(el);
|
|
1382
|
+
for (const el of host.querySelectorAll(`[${BIND_SENTINEL_ATTR}]`)) if (templateElementBelongsToHost(host, el)) elements.push(el);
|
|
1190
1383
|
for (const el of elements) {
|
|
1191
1384
|
const specs = parseBindSentinel(el.getAttribute(BIND_SENTINEL_ATTR));
|
|
1192
1385
|
for (const spec of specs) {
|
|
@@ -1328,6 +1521,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1328
1521
|
defaultInput,
|
|
1329
1522
|
states: [],
|
|
1330
1523
|
deriveds: [],
|
|
1524
|
+
actions: [],
|
|
1331
1525
|
ons: [],
|
|
1332
1526
|
effects: [],
|
|
1333
1527
|
onMounts: [],
|
|
@@ -1363,6 +1557,15 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1363
1557
|
}]
|
|
1364
1558
|
});
|
|
1365
1559
|
}
|
|
1560
|
+
action(key, fn) {
|
|
1561
|
+
return new IlhaBuilder({
|
|
1562
|
+
...this._cfg,
|
|
1563
|
+
actions: [...this._cfg.actions, {
|
|
1564
|
+
key,
|
|
1565
|
+
fn
|
|
1566
|
+
}]
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1366
1569
|
on(selectorOrCombined, handler) {
|
|
1367
1570
|
const parsed = parseOnArgs(selectorOrCombined);
|
|
1368
1571
|
return new IlhaBuilder({
|
|
@@ -1417,7 +1620,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1417
1620
|
});
|
|
1418
1621
|
}
|
|
1419
1622
|
render(fn) {
|
|
1420
|
-
const { schema, defaultInput, states, deriveds, ons, effects, onMounts, onErrors, transition, css: cssSource, as: slotAs } = this._cfg;
|
|
1623
|
+
const { schema, defaultInput, states, deriveds, actions, ons, effects, onMounts, onErrors, transition, css: cssSource, as: slotAs } = this._cfg;
|
|
1421
1624
|
const stylePrefix = cssSource != null ? buildScopedStyle(cssSource) : "";
|
|
1422
1625
|
const configuredSlotTag = slotAs ?? "div";
|
|
1423
1626
|
function resolveInput(props) {
|
|
@@ -1428,26 +1631,29 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1428
1631
|
if (!schema) return merged;
|
|
1429
1632
|
return validateSchema(schema, merged);
|
|
1430
1633
|
}
|
|
1431
|
-
function renderWithCtx(
|
|
1634
|
+
function renderWithCtx({ render, liveHost, asyncChildren }) {
|
|
1432
1635
|
const ctx = pushRenderCtx(liveHost, asyncChildren);
|
|
1433
1636
|
try {
|
|
1434
|
-
const html = unwrapHtml(
|
|
1637
|
+
const html = unwrapHtml(render());
|
|
1435
1638
|
const slots = ctx.slots;
|
|
1436
1639
|
const binds = ctx.binds;
|
|
1640
|
+
const events = ctx.events;
|
|
1437
1641
|
if (ctx.pending && ctx.pending.size > 0) {
|
|
1438
1642
|
const pending = ctx.pending;
|
|
1439
1643
|
return (async () => {
|
|
1440
1644
|
return {
|
|
1441
1645
|
html: await resolveAsyncChildren(html, pending),
|
|
1442
1646
|
slots,
|
|
1443
|
-
binds
|
|
1647
|
+
binds,
|
|
1648
|
+
events
|
|
1444
1649
|
};
|
|
1445
1650
|
})();
|
|
1446
1651
|
}
|
|
1447
1652
|
return {
|
|
1448
1653
|
html,
|
|
1449
1654
|
slots,
|
|
1450
|
-
binds
|
|
1655
|
+
binds,
|
|
1656
|
+
events
|
|
1451
1657
|
};
|
|
1452
1658
|
} finally {
|
|
1453
1659
|
popRenderCtx();
|
|
@@ -1470,12 +1676,34 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1470
1676
|
const s = signal(snapshot && entry.key in snapshot ? snapshot[entry.key] : typeof entry.init === "function" ? entry.init(input) : entry.init);
|
|
1471
1677
|
const accessor = markSignalAccessor((...args) => {
|
|
1472
1678
|
if (args.length === 0) return s();
|
|
1473
|
-
s(args[0]);
|
|
1679
|
+
s(resolveSignalSetter(() => s(), args[0]));
|
|
1474
1680
|
});
|
|
1475
1681
|
state[entry.key] = accessor;
|
|
1476
1682
|
}
|
|
1477
1683
|
return state;
|
|
1478
1684
|
}
|
|
1685
|
+
function buildSsrActions() {
|
|
1686
|
+
const out = {};
|
|
1687
|
+
for (const entry of actions) {
|
|
1688
|
+
const invoke = () => {};
|
|
1689
|
+
Object.defineProperties(invoke, {
|
|
1690
|
+
pending: {
|
|
1691
|
+
get: () => false,
|
|
1692
|
+
enumerable: true
|
|
1693
|
+
},
|
|
1694
|
+
data: {
|
|
1695
|
+
get: () => void 0,
|
|
1696
|
+
enumerable: true
|
|
1697
|
+
},
|
|
1698
|
+
error: {
|
|
1699
|
+
get: () => void 0,
|
|
1700
|
+
enumerable: true
|
|
1701
|
+
}
|
|
1702
|
+
});
|
|
1703
|
+
out[entry.key] = invoke;
|
|
1704
|
+
}
|
|
1705
|
+
return out;
|
|
1706
|
+
}
|
|
1479
1707
|
/** Detached host for SSR setup hooks; must not be `{}` (Areia/components call host.matches). */
|
|
1480
1708
|
function createSsrOnMountHost() {
|
|
1481
1709
|
if (typeof document !== "undefined") return document.createElement("div");
|
|
@@ -1491,18 +1719,19 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1491
1719
|
return stub;
|
|
1492
1720
|
}
|
|
1493
1721
|
/** Run .onMount() before top-level SSR only (seed module/external state from `input`). */
|
|
1494
|
-
function runOnMountForRender(input, state, derived) {
|
|
1722
|
+
function runOnMountForRender({ input, state, derived, action }) {
|
|
1495
1723
|
if (onMounts.length === 0) return;
|
|
1496
1724
|
if (currentRenderCtx()) return;
|
|
1497
1725
|
const host = createSsrOnMountHost();
|
|
1498
1726
|
const ssrCleanups = [];
|
|
1499
1727
|
for (const entry of onMounts) {
|
|
1500
1728
|
const prevSub = setActiveSub(void 0);
|
|
1501
|
-
let userCleanup
|
|
1729
|
+
let userCleanup;
|
|
1502
1730
|
try {
|
|
1503
1731
|
userCleanup = entry.fn({
|
|
1504
1732
|
state,
|
|
1505
1733
|
derived,
|
|
1734
|
+
action,
|
|
1506
1735
|
input,
|
|
1507
1736
|
host,
|
|
1508
1737
|
hydrated: false
|
|
@@ -1517,6 +1746,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1517
1746
|
source: "mount",
|
|
1518
1747
|
state,
|
|
1519
1748
|
derived,
|
|
1749
|
+
action,
|
|
1520
1750
|
input,
|
|
1521
1751
|
host
|
|
1522
1752
|
});
|
|
@@ -1540,6 +1770,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1540
1770
|
function renderToString(props, sync = false) {
|
|
1541
1771
|
const input = resolveInput(props);
|
|
1542
1772
|
const state = buildSignalState(input);
|
|
1773
|
+
const action = buildSsrActions();
|
|
1543
1774
|
const results = deriveds.map((entry) => {
|
|
1544
1775
|
const prevSub = setActiveSub(void 0);
|
|
1545
1776
|
try {
|
|
@@ -1573,14 +1804,20 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1573
1804
|
error: void 0
|
|
1574
1805
|
};
|
|
1575
1806
|
const derived = buildDerivedAccessors(envelopes);
|
|
1576
|
-
if (!currentRenderCtx()) runOnMountForRender(
|
|
1807
|
+
if (!currentRenderCtx()) runOnMountForRender({
|
|
1808
|
+
input,
|
|
1809
|
+
state,
|
|
1810
|
+
derived,
|
|
1811
|
+
action
|
|
1812
|
+
});
|
|
1577
1813
|
const prevSub = setActiveSub(void 0);
|
|
1578
1814
|
try {
|
|
1579
|
-
const { html } = renderWithCtx(() => fn({
|
|
1815
|
+
const { html } = renderWithCtx({ render: () => fn({
|
|
1580
1816
|
state,
|
|
1581
1817
|
derived,
|
|
1818
|
+
action,
|
|
1582
1819
|
input
|
|
1583
|
-
}));
|
|
1820
|
+
}) });
|
|
1584
1821
|
return stylePrefix + html;
|
|
1585
1822
|
} finally {
|
|
1586
1823
|
setActiveSub(prevSub);
|
|
@@ -1610,14 +1847,23 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1610
1847
|
const envelopes = {};
|
|
1611
1848
|
for (const r of resolved) envelopes[r.key] = r.envelope;
|
|
1612
1849
|
const derived = buildDerivedAccessors(envelopes);
|
|
1613
|
-
if (!currentRenderCtx()) runOnMountForRender(
|
|
1850
|
+
if (!currentRenderCtx()) runOnMountForRender({
|
|
1851
|
+
input,
|
|
1852
|
+
state,
|
|
1853
|
+
derived,
|
|
1854
|
+
action
|
|
1855
|
+
});
|
|
1614
1856
|
const prevSub = setActiveSub(void 0);
|
|
1615
1857
|
try {
|
|
1616
|
-
const { html } = await renderWithCtx(
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1858
|
+
const { html } = await renderWithCtx({
|
|
1859
|
+
render: () => fn({
|
|
1860
|
+
state,
|
|
1861
|
+
derived,
|
|
1862
|
+
action,
|
|
1863
|
+
input
|
|
1864
|
+
}),
|
|
1865
|
+
asyncChildren: true
|
|
1866
|
+
});
|
|
1621
1867
|
return stylePrefix + html;
|
|
1622
1868
|
} finally {
|
|
1623
1869
|
setActiveSub(prevSub);
|
|
@@ -1684,8 +1930,14 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1684
1930
|
const cleanups = [];
|
|
1685
1931
|
const unmountController = new AbortController();
|
|
1686
1932
|
cleanups.push(() => unmountController.abort());
|
|
1687
|
-
const { proxy: derived, setup: setupDerived } = createDerivedProxy(
|
|
1933
|
+
const { proxy: derived, setup: setupDerived } = createDerivedProxy({
|
|
1934
|
+
entries: deriveds,
|
|
1935
|
+
state,
|
|
1936
|
+
input,
|
|
1937
|
+
derivedSnapshot
|
|
1938
|
+
});
|
|
1688
1939
|
let stopDerived = () => {};
|
|
1940
|
+
let action = {};
|
|
1689
1941
|
function reportError(err, source) {
|
|
1690
1942
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1691
1943
|
if (onErrors.length === 0) {
|
|
@@ -1698,6 +1950,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1698
1950
|
source,
|
|
1699
1951
|
state,
|
|
1700
1952
|
derived,
|
|
1953
|
+
action,
|
|
1701
1954
|
input,
|
|
1702
1955
|
host
|
|
1703
1956
|
});
|
|
@@ -1705,6 +1958,107 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1705
1958
|
console.error(handlerErr);
|
|
1706
1959
|
}
|
|
1707
1960
|
}
|
|
1961
|
+
const actionEntries = actions;
|
|
1962
|
+
const actionObject = {};
|
|
1963
|
+
let disposed = false;
|
|
1964
|
+
cleanups.push(() => {
|
|
1965
|
+
disposed = true;
|
|
1966
|
+
});
|
|
1967
|
+
for (const entry of actionEntries) {
|
|
1968
|
+
const envelope = signal({
|
|
1969
|
+
pending: 0,
|
|
1970
|
+
data: void 0,
|
|
1971
|
+
error: void 0
|
|
1972
|
+
});
|
|
1973
|
+
const readEnvelope = () => untrack(() => envelope());
|
|
1974
|
+
let latestRun = 0;
|
|
1975
|
+
const invoke = (props) => {
|
|
1976
|
+
if (currentRenderCtx()) return;
|
|
1977
|
+
if (disposed) return;
|
|
1978
|
+
const run = ++latestRun;
|
|
1979
|
+
const runSignal = unmountController.signal;
|
|
1980
|
+
const ctx = {
|
|
1981
|
+
state,
|
|
1982
|
+
derived,
|
|
1983
|
+
input,
|
|
1984
|
+
host,
|
|
1985
|
+
signal: runSignal
|
|
1986
|
+
};
|
|
1987
|
+
let result;
|
|
1988
|
+
let isAsync = false;
|
|
1989
|
+
startBatch();
|
|
1990
|
+
try {
|
|
1991
|
+
result = entry.fn(props, ctx);
|
|
1992
|
+
isAsync = result != null && typeof result.then === "function";
|
|
1993
|
+
const current = readEnvelope();
|
|
1994
|
+
envelope(isAsync ? {
|
|
1995
|
+
pending: current.pending + 1,
|
|
1996
|
+
data: current.data,
|
|
1997
|
+
error: void 0
|
|
1998
|
+
} : {
|
|
1999
|
+
pending: current.pending,
|
|
2000
|
+
data: result,
|
|
2001
|
+
error: void 0
|
|
2002
|
+
});
|
|
2003
|
+
} catch (error) {
|
|
2004
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
2005
|
+
envelope({
|
|
2006
|
+
pending: readEnvelope().pending,
|
|
2007
|
+
data: void 0,
|
|
2008
|
+
error: normalized
|
|
2009
|
+
});
|
|
2010
|
+
reportError(normalized, "action");
|
|
2011
|
+
return;
|
|
2012
|
+
} finally {
|
|
2013
|
+
endBatch();
|
|
2014
|
+
}
|
|
2015
|
+
if (!isAsync) return;
|
|
2016
|
+
Promise.resolve(result).then((data) => {
|
|
2017
|
+
if (disposed || runSignal.aborted || run !== latestRun) return;
|
|
2018
|
+
const value = readEnvelope();
|
|
2019
|
+
envelope({
|
|
2020
|
+
pending: value.pending,
|
|
2021
|
+
data,
|
|
2022
|
+
error: void 0
|
|
2023
|
+
});
|
|
2024
|
+
}).catch((error) => {
|
|
2025
|
+
if (disposed || runSignal.aborted || error?.name === "AbortError") return;
|
|
2026
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
2027
|
+
if (run === latestRun) {
|
|
2028
|
+
const value = readEnvelope();
|
|
2029
|
+
envelope({
|
|
2030
|
+
pending: value.pending,
|
|
2031
|
+
data: void 0,
|
|
2032
|
+
error: normalized
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
reportError(normalized, "action");
|
|
2036
|
+
}).finally(() => {
|
|
2037
|
+
if (disposed) return;
|
|
2038
|
+
const value = readEnvelope();
|
|
2039
|
+
envelope({
|
|
2040
|
+
...value,
|
|
2041
|
+
pending: Math.max(0, value.pending - 1)
|
|
2042
|
+
});
|
|
2043
|
+
});
|
|
2044
|
+
};
|
|
2045
|
+
Object.defineProperties(invoke, {
|
|
2046
|
+
pending: {
|
|
2047
|
+
get: () => envelope().pending > 0,
|
|
2048
|
+
enumerable: true
|
|
2049
|
+
},
|
|
2050
|
+
data: {
|
|
2051
|
+
get: () => envelope().data,
|
|
2052
|
+
enumerable: true
|
|
2053
|
+
},
|
|
2054
|
+
error: {
|
|
2055
|
+
get: () => envelope().error,
|
|
2056
|
+
enumerable: true
|
|
2057
|
+
}
|
|
2058
|
+
});
|
|
2059
|
+
actionObject[entry.key] = invoke;
|
|
2060
|
+
}
|
|
2061
|
+
action = actionObject;
|
|
1708
2062
|
if (transition?.enter) try {
|
|
1709
2063
|
const result = transition.enter(host);
|
|
1710
2064
|
if (result instanceof Promise) result.catch((err) => reportError(err, "transition"));
|
|
@@ -1809,7 +2163,13 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1809
2163
|
function attachListeners() {
|
|
1810
2164
|
for (const entry of ons) {
|
|
1811
2165
|
if (entry.options.once && firedOnce.has(entry)) continue;
|
|
1812
|
-
|
|
2166
|
+
let targets;
|
|
2167
|
+
try {
|
|
2168
|
+
targets = entry.selector === "" ? [host] : Array.from(host.querySelectorAll(entry.selector)).filter((element) => templateElementBelongsToHost(host, element));
|
|
2169
|
+
} catch {
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2172
|
+
targets.forEach((listenerTarget) => {
|
|
1813
2173
|
const listener = (event) => {
|
|
1814
2174
|
if (entry.options.once) {
|
|
1815
2175
|
firedOnce.add(entry);
|
|
@@ -1837,6 +2197,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1837
2197
|
result = entry.handler({
|
|
1838
2198
|
state,
|
|
1839
2199
|
derived,
|
|
2200
|
+
action,
|
|
1840
2201
|
input,
|
|
1841
2202
|
host,
|
|
1842
2203
|
target: handlerTarget,
|
|
@@ -1876,11 +2237,12 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1876
2237
|
function invokeOnMounts() {
|
|
1877
2238
|
for (const entry of onMounts) {
|
|
1878
2239
|
const prevSub = setActiveSub(void 0);
|
|
1879
|
-
let userCleanup
|
|
2240
|
+
let userCleanup;
|
|
1880
2241
|
try {
|
|
1881
2242
|
userCleanup = entry.fn({
|
|
1882
2243
|
state,
|
|
1883
2244
|
derived,
|
|
2245
|
+
action,
|
|
1884
2246
|
input,
|
|
1885
2247
|
host,
|
|
1886
2248
|
hydrated
|
|
@@ -1904,14 +2266,27 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1904
2266
|
}
|
|
1905
2267
|
const preserveSSRDom = hydrated && host.childNodes.length > 0;
|
|
1906
2268
|
if (hydrated && onMounts.length > 0 && !shouldSkipOnMount) invokeOnMounts();
|
|
1907
|
-
const
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
2269
|
+
const nativeOnceFired = /* @__PURE__ */ new WeakMap();
|
|
2270
|
+
const initial = renderWithCtx({
|
|
2271
|
+
render: () => fn({
|
|
2272
|
+
state,
|
|
2273
|
+
derived,
|
|
2274
|
+
action,
|
|
2275
|
+
input
|
|
2276
|
+
}),
|
|
2277
|
+
liveHost: preserveSSRDom ? host : void 0
|
|
2278
|
+
});
|
|
1912
2279
|
if (!preserveSSRDom) host.innerHTML = stylePrefix + initial.html;
|
|
1913
2280
|
let stopBindings = applyTemplateBindings(host, initial.binds);
|
|
1914
2281
|
cleanups.push(() => stopBindings());
|
|
2282
|
+
let stopJsxEvents = applyJsxEvents({
|
|
2283
|
+
host,
|
|
2284
|
+
records: initial.events,
|
|
2285
|
+
reportError: (error) => reportError(error, "on"),
|
|
2286
|
+
unmountSignal: unmountController.signal,
|
|
2287
|
+
onceFired: nativeOnceFired
|
|
2288
|
+
});
|
|
2289
|
+
cleanups.push(() => stopJsxEvents());
|
|
1915
2290
|
mountSlots(initial.slots);
|
|
1916
2291
|
cleanups.push(() => mountedSlots.forEach((entry) => entry.unmount()));
|
|
1917
2292
|
attachListeners();
|
|
@@ -1936,6 +2311,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1936
2311
|
userCleanup = entry.fn({
|
|
1937
2312
|
state,
|
|
1938
2313
|
derived,
|
|
2314
|
+
action,
|
|
1939
2315
|
input,
|
|
1940
2316
|
host,
|
|
1941
2317
|
signal: runSignal
|
|
@@ -1964,11 +2340,23 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1964
2340
|
let renderEpoch = 0;
|
|
1965
2341
|
const stopRender = effect(() => {
|
|
1966
2342
|
const epoch = ++renderEpoch;
|
|
1967
|
-
const { html: rendered, slots: newSlotMap, binds: newBinds } = renderWithCtx(
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2343
|
+
const { html: rendered, slots: newSlotMap, binds: newBinds, events: newEvents } = renderWithCtx({
|
|
2344
|
+
render: () => fn({
|
|
2345
|
+
state,
|
|
2346
|
+
derived,
|
|
2347
|
+
action,
|
|
2348
|
+
input
|
|
2349
|
+
}),
|
|
2350
|
+
liveHost: host
|
|
2351
|
+
});
|
|
2352
|
+
stopJsxEvents();
|
|
2353
|
+
stopJsxEvents = applyJsxEvents({
|
|
2354
|
+
host,
|
|
2355
|
+
records: newEvents,
|
|
2356
|
+
reportError: (error) => reportError(error, "on"),
|
|
2357
|
+
unmountSignal: unmountController.signal,
|
|
2358
|
+
onceFired: nativeOnceFired
|
|
2359
|
+
});
|
|
1972
2360
|
const html = stylePrefix + rendered;
|
|
1973
2361
|
if (!initialized) {
|
|
1974
2362
|
initialized = true;
|
|
@@ -1983,7 +2371,11 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1983
2371
|
lastRendered = rendered;
|
|
1984
2372
|
return;
|
|
1985
2373
|
}
|
|
1986
|
-
if (mountedSlots.size > 0 && mountedSlots.size === newSlotMap.size && [...newSlotMap.keys()].every((id) => mountedSlots.has(id)) && isStableInlineSlotMount(
|
|
2374
|
+
if (mountedSlots.size > 0 && mountedSlots.size === newSlotMap.size && [...newSlotMap.keys()].every((id) => mountedSlots.has(id)) && isStableInlineSlotMount({
|
|
2375
|
+
initialHtml: initialRenderedHtml,
|
|
2376
|
+
renderedHtml: rendered,
|
|
2377
|
+
slotIds: newSlotMap.keys()
|
|
2378
|
+
})) {
|
|
1987
2379
|
pushUpdatedProps(newSlotMap);
|
|
1988
2380
|
return;
|
|
1989
2381
|
}
|
|
@@ -1994,6 +2386,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
1994
2386
|
}
|
|
1995
2387
|
detachListeners();
|
|
1996
2388
|
stopBindings();
|
|
2389
|
+
stopJsxEvents();
|
|
1997
2390
|
const prevMountedCount = mountedSlots.size;
|
|
1998
2391
|
const leavingPromises = [];
|
|
1999
2392
|
for (const [id, entry] of mountedSlots) if (!newSlotMap.has(id)) {
|
|
@@ -2039,6 +2432,13 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
2039
2432
|
}
|
|
2040
2433
|
attachListeners();
|
|
2041
2434
|
stopBindings = applyTemplateBindings(host, newBinds);
|
|
2435
|
+
stopJsxEvents = applyJsxEvents({
|
|
2436
|
+
host,
|
|
2437
|
+
records: newEvents,
|
|
2438
|
+
reportError: (error) => reportError(error, "on"),
|
|
2439
|
+
unmountSignal: unmountController.signal,
|
|
2440
|
+
onceFired: nativeOnceFired
|
|
2441
|
+
});
|
|
2042
2442
|
mountSlots(newSlotMap);
|
|
2043
2443
|
};
|
|
2044
2444
|
if (leavingPromises.length > 0) Promise.allSettled(leavingPromises).then((results) => {
|
|
@@ -2051,6 +2451,8 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
2051
2451
|
const unmount = () => {
|
|
2052
2452
|
if (tornDown) return;
|
|
2053
2453
|
tornDown = true;
|
|
2454
|
+
disposed = true;
|
|
2455
|
+
unmountController.abort();
|
|
2054
2456
|
ISLAND_MOUNT_HANDLES.delete(host);
|
|
2055
2457
|
stopRender();
|
|
2056
2458
|
detachListeners();
|
|
@@ -2098,7 +2500,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
2098
2500
|
* The declared return type omits {@link IslandCall} because TypeScript
|
|
2099
2501
|
* cannot narrow based on runtime stack state.
|
|
2100
2502
|
*/
|
|
2101
|
-
const island =
|
|
2503
|
+
const island = ((props) => {
|
|
2102
2504
|
if (currentRenderCtx()) return {
|
|
2103
2505
|
[ISLAND_CALL]: true,
|
|
2104
2506
|
island,
|
|
@@ -2106,7 +2508,7 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
2106
2508
|
key: void 0
|
|
2107
2509
|
};
|
|
2108
2510
|
return renderToString(props);
|
|
2109
|
-
};
|
|
2511
|
+
});
|
|
2110
2512
|
island.toString = (props) => renderToString(props, true);
|
|
2111
2513
|
island.mount = (host, props) => mountIsland(host, props);
|
|
2112
2514
|
island[ISLAND_MOUNT_INTERNAL] = (host, props) => mountIslandInternal(host, props);
|
|
@@ -2329,6 +2731,7 @@ const rootBuilder = new IlhaBuilder({
|
|
|
2329
2731
|
defaultInput: null,
|
|
2330
2732
|
states: [],
|
|
2331
2733
|
deriveds: [],
|
|
2734
|
+
actions: [],
|
|
2332
2735
|
ons: [],
|
|
2333
2736
|
effects: [],
|
|
2334
2737
|
onMounts: [],
|
|
@@ -2337,7 +2740,17 @@ const rootBuilder = new IlhaBuilder({
|
|
|
2337
2740
|
css: null,
|
|
2338
2741
|
as: null
|
|
2339
2742
|
});
|
|
2340
|
-
const
|
|
2743
|
+
const callableRoot = ((fn) => rootBuilder.input().render(fn));
|
|
2744
|
+
Object.defineProperty(callableRoot, "_cfg", {
|
|
2745
|
+
value: rootBuilder._cfg,
|
|
2746
|
+
enumerable: false
|
|
2747
|
+
});
|
|
2748
|
+
for (const key of Object.getOwnPropertyNames(IlhaBuilder.prototype)) {
|
|
2749
|
+
if (key === "constructor") continue;
|
|
2750
|
+
const descriptor = Object.getOwnPropertyDescriptor(IlhaBuilder.prototype, key);
|
|
2751
|
+
if (descriptor) Object.defineProperty(callableRoot, key, descriptor);
|
|
2752
|
+
}
|
|
2753
|
+
const ilha = Object.assign(callableRoot, {
|
|
2341
2754
|
html: ilhaHtml,
|
|
2342
2755
|
raw: ilhaRaw,
|
|
2343
2756
|
mount: mountAll,
|
|
@@ -2349,9 +2762,25 @@ const ilha = Object.assign(rootBuilder, {
|
|
|
2349
2762
|
untrack,
|
|
2350
2763
|
onUncaughtError
|
|
2351
2764
|
});
|
|
2765
|
+
/** @internal Used by the separate JSX runtime to register a native event handler. */
|
|
2766
|
+
function __ilhaJsxEvent({ type, handler, modifier }) {
|
|
2767
|
+
const ctx = currentRenderCtx();
|
|
2768
|
+
if (!ctx) return void 0;
|
|
2769
|
+
const index = ctx.events.length;
|
|
2770
|
+
ctx.events.push({
|
|
2771
|
+
type,
|
|
2772
|
+
handler,
|
|
2773
|
+
modifier
|
|
2774
|
+
});
|
|
2775
|
+
return index;
|
|
2776
|
+
}
|
|
2352
2777
|
/** @internal Used by the separate JSX runtime entry to preserve island slot composition. */
|
|
2353
|
-
function __ilhaJsxSlot(island, props, key) {
|
|
2354
|
-
return ilhaRaw(emitIslandSlot(
|
|
2778
|
+
function __ilhaJsxSlot({ island, props, key }) {
|
|
2779
|
+
return ilhaRaw(emitIslandSlot({
|
|
2780
|
+
island,
|
|
2781
|
+
props,
|
|
2782
|
+
key
|
|
2783
|
+
}));
|
|
2355
2784
|
}
|
|
2356
2785
|
const html = ilhaHtml;
|
|
2357
2786
|
const raw = ilhaRaw;
|
|
@@ -2361,4 +2790,4 @@ const from = ilhaFrom;
|
|
|
2361
2790
|
const context = ilhaContext;
|
|
2362
2791
|
|
|
2363
2792
|
//#endregion
|
|
2364
|
-
export { ISLAND_MOUNT_HANDLES, ISLAND_MOUNT_INTERNAL, __ilhaJsxSlot, batch, ilhaComputed as computed, context, css, ilha as default, ilhaEffect as effect, from, html, ilhaSignal, ilhaSignal as signal, mount, onUncaughtError, raw, untrack };
|
|
2793
|
+
export { ISLAND_MOUNT_HANDLES, ISLAND_MOUNT_INTERNAL, __ilhaJsxEvent, __ilhaJsxSlot, batch, ilhaComputed as computed, context, css, ilha as default, ilhaEffect as effect, from, html, ilhaSignal, ilhaSignal as signal, mount, onUncaughtError, raw, untrack };
|