ilha 0.4.1 → 0.4.2
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/index.js +72 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,6 +4,18 @@ const __DEV__ = typeof process !== "undefined" ? process.env?.["NODE_ENV"] !== "
|
|
|
4
4
|
function warn(msg) {
|
|
5
5
|
if (__DEV__) console.warn(`[ilha] ${msg}`);
|
|
6
6
|
}
|
|
7
|
+
function shallowEqualInput(a, b) {
|
|
8
|
+
if (Object.is(a, b)) return true;
|
|
9
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
|
|
10
|
+
const ak = Object.keys(a);
|
|
11
|
+
const bk = Object.keys(b);
|
|
12
|
+
if (ak.length !== bk.length) return false;
|
|
13
|
+
for (const k of ak) {
|
|
14
|
+
if (!Object.prototype.hasOwnProperty.call(b, k)) return false;
|
|
15
|
+
if (!Object.is(a[k], b[k])) return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
7
19
|
function syncAttributes(from, to) {
|
|
8
20
|
for (const { name, value } of to.attributes) if (from.getAttribute(name) !== value) from.setAttribute(name, value);
|
|
9
21
|
for (const { name } of Array.from(from.attributes)) if (!to.hasAttribute(name)) from.removeAttribute(name);
|
|
@@ -80,6 +92,7 @@ const RAW = Symbol("ilha.raw");
|
|
|
80
92
|
const SIGNAL_ACCESSOR = Symbol("ilha.signalAccessor");
|
|
81
93
|
const ISLAND = Symbol("ilha.island");
|
|
82
94
|
const ISLAND_CALL = Symbol("ilha.islandCall");
|
|
95
|
+
const ISLAND_MOUNT_INTERNAL = Symbol("ilha.islandMountInternal");
|
|
83
96
|
const SLOT_ATTR = "data-ilha-slot";
|
|
84
97
|
const PROPS_ATTR = "data-ilha-props";
|
|
85
98
|
const STATE_ATTR = "data-ilha-state";
|
|
@@ -685,11 +698,18 @@ var IlhaBuilder = class IlhaBuilder {
|
|
|
685
698
|
});
|
|
686
699
|
}
|
|
687
700
|
function mountIsland(host, props) {
|
|
701
|
+
return mountIslandInternal(host, props).unmount;
|
|
702
|
+
}
|
|
703
|
+
function mountIslandInternal(host, props) {
|
|
704
|
+
const noop = {
|
|
705
|
+
unmount: () => {},
|
|
706
|
+
updateProps: () => {}
|
|
707
|
+
};
|
|
688
708
|
if (__DEV__ && _mountedHosts) {
|
|
689
709
|
if (_mountedHosts.has(host)) {
|
|
690
710
|
warn(`mount(): this element is already mounted. Call the previous unmount() first to avoid memory leaks and duplicate event listeners.
|
|
691
711
|
Element: ${host.outerHTML.slice(0, 120)}`);
|
|
692
|
-
return
|
|
712
|
+
return noop;
|
|
693
713
|
}
|
|
694
714
|
_mountedHosts.add(host);
|
|
695
715
|
}
|
|
@@ -701,7 +721,31 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
701
721
|
warn("Failed to parse data-ilha-props — invalid JSON, falling back to empty props.");
|
|
702
722
|
}
|
|
703
723
|
}
|
|
704
|
-
const
|
|
724
|
+
const inputSignal = signal(resolveInput(props));
|
|
725
|
+
const input = new Proxy({}, {
|
|
726
|
+
get(_t, key) {
|
|
727
|
+
return inputSignal()[key];
|
|
728
|
+
},
|
|
729
|
+
has(_t, key) {
|
|
730
|
+
return key in inputSignal();
|
|
731
|
+
},
|
|
732
|
+
ownKeys() {
|
|
733
|
+
const prevSub = setActiveSub(void 0);
|
|
734
|
+
try {
|
|
735
|
+
return Reflect.ownKeys(inputSignal());
|
|
736
|
+
} finally {
|
|
737
|
+
setActiveSub(prevSub);
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
getOwnPropertyDescriptor(_t, key) {
|
|
741
|
+
const prevSub = setActiveSub(void 0);
|
|
742
|
+
try {
|
|
743
|
+
return Reflect.getOwnPropertyDescriptor(inputSignal(), key);
|
|
744
|
+
} finally {
|
|
745
|
+
setActiveSub(prevSub);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
});
|
|
705
749
|
let snapshotRaw;
|
|
706
750
|
const rawState = host.getAttribute(STATE_ATTR);
|
|
707
751
|
if (rawState) try {
|
|
@@ -771,7 +815,11 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
771
815
|
mountedSlots.delete(id);
|
|
772
816
|
}
|
|
773
817
|
for (const [id, { island: childIsland, props }] of slotMap) {
|
|
774
|
-
|
|
818
|
+
const existing = mountedSlots.get(id);
|
|
819
|
+
if (existing) {
|
|
820
|
+
existing.updateProps(props);
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
775
823
|
const slotEl = findSlot(id);
|
|
776
824
|
if (!slotEl) continue;
|
|
777
825
|
let slotProps = props;
|
|
@@ -784,15 +832,19 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
784
832
|
}
|
|
785
833
|
}
|
|
786
834
|
const prevSub = setActiveSub(void 0);
|
|
787
|
-
let
|
|
835
|
+
let handle;
|
|
788
836
|
try {
|
|
789
|
-
|
|
837
|
+
const internal = childIsland[ISLAND_MOUNT_INTERNAL];
|
|
838
|
+
handle = internal ? internal(slotEl, slotProps) : {
|
|
839
|
+
unmount: childIsland.mount(slotEl, slotProps),
|
|
840
|
+
updateProps: () => {}
|
|
841
|
+
};
|
|
790
842
|
} finally {
|
|
791
843
|
setActiveSub(prevSub);
|
|
792
844
|
}
|
|
793
845
|
mountedSlots.set(id, {
|
|
794
846
|
el: slotEl,
|
|
795
|
-
|
|
847
|
+
...handle
|
|
796
848
|
});
|
|
797
849
|
}
|
|
798
850
|
}
|
|
@@ -896,6 +948,7 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
896
948
|
if (userCleanup) cleanups.push(userCleanup);
|
|
897
949
|
}
|
|
898
950
|
let initialized = false;
|
|
951
|
+
const initialRenderedHtml = initial.html;
|
|
899
952
|
const stopRender = effect(() => {
|
|
900
953
|
const { html: rendered, slots: newSlotMap } = renderWithCtx(() => fn({
|
|
901
954
|
state,
|
|
@@ -905,7 +958,7 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
905
958
|
const html = stylePrefix + rendered;
|
|
906
959
|
if (!initialized) {
|
|
907
960
|
initialized = true;
|
|
908
|
-
return;
|
|
961
|
+
if (rendered === initialRenderedHtml) return;
|
|
909
962
|
}
|
|
910
963
|
detachListeners();
|
|
911
964
|
stopBindings();
|
|
@@ -976,7 +1029,7 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
976
1029
|
});
|
|
977
1030
|
}
|
|
978
1031
|
let tornDown = false;
|
|
979
|
-
|
|
1032
|
+
const unmount = () => {
|
|
980
1033
|
if (tornDown) return;
|
|
981
1034
|
tornDown = true;
|
|
982
1035
|
if (__DEV__ && _mountedHosts) _mountedHosts.delete(host);
|
|
@@ -989,6 +1042,16 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
989
1042
|
}
|
|
990
1043
|
cleanups.forEach((c) => c());
|
|
991
1044
|
};
|
|
1045
|
+
const updateProps = (nextProps) => {
|
|
1046
|
+
if (tornDown) return;
|
|
1047
|
+
const next = resolveInput(nextProps);
|
|
1048
|
+
if (shallowEqualInput(inputSignal(), next)) return;
|
|
1049
|
+
inputSignal(next);
|
|
1050
|
+
};
|
|
1051
|
+
return {
|
|
1052
|
+
unmount,
|
|
1053
|
+
updateProps
|
|
1054
|
+
};
|
|
992
1055
|
}
|
|
993
1056
|
/**
|
|
994
1057
|
* Dual-mode island invocation:
|
|
@@ -1012,6 +1075,7 @@ Element: ${host.outerHTML.slice(0, 120)}`);
|
|
|
1012
1075
|
};
|
|
1013
1076
|
island.toString = (props) => renderToString(props, true);
|
|
1014
1077
|
island.mount = (host, props) => mountIsland(host, props);
|
|
1078
|
+
island[ISLAND_MOUNT_INTERNAL] = (host, props) => mountIslandInternal(host, props);
|
|
1015
1079
|
island.key = (key) => {
|
|
1016
1080
|
if (typeof key !== "string" || key.trim().length === 0) throw new Error("island.key() requires a non-empty string.");
|
|
1017
1081
|
if (key.includes(":")) throw new Error(`island.key() key cannot contain the slot separator ":" (got "${key}").`);
|