ilha 0.9.1 → 0.9.3

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.
@@ -38,6 +38,14 @@ declare const ISLAND_CALL: unique symbol;
38
38
  * retain a handle to push updated props into it on subsequent parent
39
39
  * re-renders. Not part of the public surface. */
40
40
  declare const ISLAND_MOUNT_INTERNAL: unique symbol;
41
+ /** @internal Live mount handles keyed by host element. Lets @ilha/router adopt
42
+ * islands hydrated by `ilha.mount()` (whose handles it never saw) and push new
43
+ * loader props into them in place instead of remounting. Entries are removed
44
+ * on unmount. Not part of the public surface. */
45
+ declare const ISLAND_MOUNT_HANDLES: WeakMap<Element, {
46
+ unmount: () => void | Promise<void>;
47
+ updateProps: (props?: Record<string, unknown>) => void;
48
+ }>;
41
49
  interface RawHtml {
42
50
  [RAW]: true;
43
51
  value: string;
@@ -350,4 +358,4 @@ declare const context: typeof ilhaContextFn & {
350
358
  clear(): void;
351
359
  };
352
360
  //#endregion
353
- export { mount as A, css as C, ilhaComputed as D, ilha as E, raw as M, untrack as N, ilhaEffect as O, context as S, html as T, OnMountContext as _, ErrorSource as a, __ilhaJsxSlot as b, HandlerContextFor as c, Island as d, IslandDerived as f, MountResult as g, MountOptions as h, ErrorContext as i, onUncaughtError as j, ilhaSignal as k, HydratableOptions as l, KeyedIsland as m, DerivedValue as n, ExternalSignal as o, IslandState as p, EffectContext as r, HandlerContext as s, DerivedAccessor as t, ISLAND_MOUNT_INTERNAL as u, RawHtml as v, from as w, batch as x, SignalAccessor as y };
361
+ export { ilhaSignal as A, context as C, ilha as D, html as E, onUncaughtError as M, raw as N, ilhaComputed as O, untrack as P, batch as S, from as T, MountResult as _, ErrorSource as a, SignalAccessor as b, HandlerContextFor as c, ISLAND_MOUNT_INTERNAL as d, Island as f, MountOptions as g, KeyedIsland as h, ErrorContext as i, mount as j, ilhaEffect as k, HydratableOptions as l, IslandState as m, DerivedValue as n, ExternalSignal as o, IslandDerived as p, EffectContext as r, HandlerContext as s, DerivedAccessor as t, ISLAND_MOUNT_HANDLES as u, OnMountContext as v, css as w, __ilhaJsxSlot as x, RawHtml as y };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as mount, C as css, D as ilhaComputed, E as ilha, M as raw, N as untrack, O as ilhaEffect, S as context, T as html, _ as OnMountContext, a as ErrorSource, b as __ilhaJsxSlot, c as HandlerContextFor, d as Island, f as IslandDerived, g as MountResult, h as MountOptions, i as ErrorContext, j as onUncaughtError, k as ilhaSignal, l as HydratableOptions, m as KeyedIsland, n as DerivedValue, o as ExternalSignal, p as IslandState, r as EffectContext, s as HandlerContext, t as DerivedAccessor, u as ISLAND_MOUNT_INTERNAL, v as RawHtml, w as from, x as batch, y as SignalAccessor } from "./index-C0SWn9oq.js";
2
- export { DerivedAccessor, DerivedValue, EffectContext, ErrorContext, ErrorSource, ExternalSignal, HandlerContext, HandlerContextFor, HydratableOptions, ISLAND_MOUNT_INTERNAL, Island, IslandDerived, IslandState, KeyedIsland, MountOptions, MountResult, OnMountContext, RawHtml, SignalAccessor, __ilhaJsxSlot, batch, ilhaComputed as computed, context, css, ilha as default, ilhaEffect as effect, from, html, ilhaSignal, ilhaSignal as signal, mount, onUncaughtError, raw, untrack };
1
+ import { A as ilhaSignal, C as context, D as ilha, E as html, M as onUncaughtError, N as raw, O as ilhaComputed, P as untrack, S as batch, T as from, _ as MountResult, a as ErrorSource, b as SignalAccessor, c as HandlerContextFor, d as ISLAND_MOUNT_INTERNAL, f as Island, g as MountOptions, h as KeyedIsland, i as ErrorContext, j as mount, k as ilhaEffect, l as HydratableOptions, m as IslandState, n as DerivedValue, o as ExternalSignal, p as IslandDerived, r as EffectContext, s as HandlerContext, t as DerivedAccessor, u as ISLAND_MOUNT_HANDLES, v as OnMountContext, w as css, x as __ilhaJsxSlot, y as RawHtml } from "./index-Dx_q_SGo.js";
2
+ export { DerivedAccessor, DerivedValue, EffectContext, ErrorContext, ErrorSource, ExternalSignal, HandlerContext, HandlerContextFor, HydratableOptions, ISLAND_MOUNT_HANDLES, ISLAND_MOUNT_INTERNAL, Island, IslandDerived, IslandState, KeyedIsland, MountOptions, MountResult, OnMountContext, RawHtml, SignalAccessor, __ilhaJsxSlot, batch, ilhaComputed as computed, context, css, ilha as default, ilhaEffect as effect, from, html, ilhaSignal, ilhaSignal as signal, mount, onUncaughtError, raw, untrack };
package/dist/index.js CHANGED
@@ -169,21 +169,23 @@ function morphChildren(fromParent, toParent) {
169
169
  for (let i = 0; i < toNodes.length; i++) {
170
170
  const toNode = toNodes[i];
171
171
  let fromNode = fromParent.childNodes[i];
172
- if (fromKeyed !== null && toNode.nodeType === 1) {
173
- const key = toNode.getAttribute("data-key");
174
- if (key !== null) {
175
- const match = fromKeyed.get(key);
172
+ if (fromKeyed !== null) {
173
+ const toKey = toNode.nodeType === 1 ? toNode.getAttribute("data-key") : null;
174
+ if (toKey !== null) {
175
+ const match = fromKeyed.get(toKey);
176
176
  if (match) {
177
+ fromKeyed.delete(toKey);
177
178
  if (match !== fromNode) {
178
179
  fromParent.insertBefore(match, fromNode ?? null);
179
180
  fromNode = match;
180
181
  }
181
- } else if (fromNode instanceof Element) {
182
- const fromKey = fromNode.getAttribute("data-key");
183
- if (fromKey !== null && toKeys.has(fromKey)) {
184
- fromParent.insertBefore(toNode.cloneNode(true), fromNode);
185
- continue;
186
- }
182
+ }
183
+ }
184
+ if (fromNode instanceof Element) {
185
+ const fromKey = fromNode.getAttribute("data-key");
186
+ if (fromKey !== null && fromKey !== toKey && toKeys.has(fromKey)) {
187
+ fromParent.insertBefore(toNode.cloneNode(true), fromNode);
188
+ continue;
187
189
  }
188
190
  }
189
191
  }
@@ -210,6 +212,16 @@ function morphChildren(fromParent, toParent) {
210
212
  fromParent.replaceChild(toEl.cloneNode(true), fromEl);
211
213
  continue;
212
214
  }
215
+ if (fromEl.localName === "input") {
216
+ const hadChecked = fromEl.hasAttribute("checked");
217
+ const hadValue = fromEl.getAttribute("value");
218
+ syncAttributes(fromEl, toEl);
219
+ const hasChecked = toEl.hasAttribute("checked");
220
+ if (hasChecked !== hadChecked) fromEl.checked = hasChecked;
221
+ const newValue = toEl.getAttribute("value");
222
+ if (newValue !== hadValue) fromEl.value = newValue ?? "";
223
+ continue;
224
+ }
213
225
  syncAttributes(fromEl, toEl);
214
226
  if (fromEl.localName === "textarea") {
215
227
  const newText = toEl.textContent ?? "";
@@ -265,6 +277,11 @@ const ISLAND_CALL = Symbol.for("ilha.islandCall");
265
277
  * re-renders. Not part of the public surface. */
266
278
  const ISLAND_MOUNT_INTERNAL = Symbol.for("ilha.islandMountInternal");
267
279
  const ISLAND_SLOT_TAG = Symbol.for("ilha.islandSlotTag");
280
+ /** @internal Live mount handles keyed by host element. Lets @ilha/router adopt
281
+ * islands hydrated by `ilha.mount()` (whose handles it never saw) and push new
282
+ * loader props into them in place instead of remounting. Entries are removed
283
+ * on unmount. Not part of the public surface. */
284
+ const ISLAND_MOUNT_HANDLES = /* @__PURE__ */ new WeakMap();
268
285
  const SLOT_ATTR = "data-ilha-slot";
269
286
  const PROPS_ATTR = "data-ilha-props";
270
287
  const STATE_ATTR = "data-ilha-state";
@@ -1811,6 +1828,7 @@ var IlhaBuilder = class IlhaBuilder {
1811
1828
  const unmount = () => {
1812
1829
  if (tornDown) return;
1813
1830
  tornDown = true;
1831
+ ISLAND_MOUNT_HANDLES.delete(host);
1814
1832
  stopRender();
1815
1833
  detachListeners();
1816
1834
  const pending = [];
@@ -1839,10 +1857,12 @@ var IlhaBuilder = class IlhaBuilder {
1839
1857
  if (shallowEqualInput(inputSignal(), next)) return;
1840
1858
  inputSignal(next);
1841
1859
  };
1842
- return {
1860
+ const handle = {
1843
1861
  unmount,
1844
1862
  updateProps
1845
1863
  };
1864
+ ISLAND_MOUNT_HANDLES.set(host, handle);
1865
+ return handle;
1846
1866
  }
1847
1867
  /**
1848
1868
  * Dual-mode island invocation:
@@ -2118,4 +2138,4 @@ const from = ilhaFrom;
2118
2138
  const context = ilhaContext;
2119
2139
 
2120
2140
  //#endregion
2121
- export { 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 };
2141
+ 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 };
@@ -1,2 +1,2 @@
1
- import { a as JSX, r as jsxDEV, t as Fragment } from "./jsx-runtime-DBCAZ9YL.js";
1
+ import { a as JSX, r as jsxDEV, t as Fragment } from "./jsx-runtime-DysRyz9R.js";
2
2
  export { Fragment, type JSX, jsxDEV };
@@ -1,4 +1,4 @@
1
- import { v as RawHtml } from "./index-C0SWn9oq.js";
1
+ import { y as RawHtml } from "./index-Dx_q_SGo.js";
2
2
 
3
3
  //#region src/jsx-types.d.ts
4
4
  declare namespace JSX {
@@ -1,2 +1,2 @@
1
- import { a as JSX, i as jsxs, n as jsx, r as jsxDEV, t as Fragment } from "./jsx-runtime-DBCAZ9YL.js";
1
+ import { a as JSX, i as jsxs, n as jsx, r as jsxDEV, t as Fragment } from "./jsx-runtime-DysRyz9R.js";
2
2
  export { Fragment, type JSX, jsx, jsxDEV, jsxs };
@@ -111,10 +111,23 @@ function pushJsxAttr(chunks, values, name, value) {
111
111
  values.push(value);
112
112
  chunks.push("\"");
113
113
  }
114
- function renderJsxElement(type, props, children) {
114
+ function escapeAttrValue(value) {
115
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
116
+ }
117
+ function injectDataKey(out, key) {
118
+ const m = /^\s*<([a-zA-Z][a-zA-Z0-9:._-]*)/.exec(out.value);
119
+ if (!m) return out;
120
+ const openEnd = out.value.indexOf(">", m.index);
121
+ const openTag = out.value.slice(m.index, openEnd === -1 ? void 0 : openEnd);
122
+ if (/\sdata-key\s*=/.test(openTag)) return out;
123
+ const insertAt = m.index + m[0].length;
124
+ return raw(`${out.value.slice(0, insertAt)} data-key="${escapeAttrValue(key)}"${out.value.slice(insertAt)}`);
125
+ }
126
+ function renderJsxElement(type, props, children, slotKey) {
115
127
  const chunks = [`<${type}`];
116
128
  const values = [];
117
129
  if (props) for (const [name, value] of Object.entries(props)) pushJsxAttr(chunks, values, name, value);
130
+ if (slotKey !== void 0 && props?.["data-key"] == null) pushJsxAttr(chunks, values, "data-key", slotKey);
118
131
  chunks[chunks.length - 1] += ">";
119
132
  if (!VOID_ELEMENTS.has(type)) {
120
133
  for (const child of children) {
@@ -129,8 +142,8 @@ function jsx(type, props, maybeKey, ...restChildren) {
129
142
  const hasKeyArg = typeof maybeKey === "string" || typeof maybeKey === "number";
130
143
  const keyFromArg = hasKeyArg ? maybeKey : void 0;
131
144
  const normalizedChildren = normalizeJsxChildren(props, hasKeyArg || maybeKey === void 0 ? restChildren : [maybeKey, ...restChildren]);
145
+ const slotKey = extractJsxSlotKey(props, typeof keyFromArg === "string" || typeof keyFromArg === "number" ? keyFromArg : void 0);
132
146
  if (typeof type === "function") {
133
- const slotKey = extractJsxSlotKey(props, typeof keyFromArg === "string" || typeof keyFromArg === "number" ? keyFromArg : void 0);
134
147
  const componentProps = {
135
148
  ...props,
136
149
  ...normalizedChildren.length > 0 ? { children: normalizedChildren } : {}
@@ -141,13 +154,13 @@ function jsx(type, props, maybeKey, ...restChildren) {
141
154
  if (slotKey !== void 0) out.key = slotKey;
142
155
  return html`${out}`;
143
156
  }
144
- if (isRawHtml(out)) return out;
157
+ if (isRawHtml(out)) return slotKey !== void 0 ? injectDataKey(out, slotKey) : out;
145
158
  if (typeof out === "string" && isIsland(type)) return __ilhaJsxSlot(type, componentProps, slotKey);
146
159
  if (typeof out === "string") return html`${out}`;
147
160
  if (typeof out === "object" && out !== null && Object.getPrototypeOf(out) === Object.prototype && out[RENDER_PART] === true && typeof out.toString === "function") return raw(String(out));
148
161
  return html`${out}`;
149
162
  }
150
- return renderJsxElement(type, props, normalizedChildren);
163
+ return renderJsxElement(type, props, normalizedChildren, slotKey);
151
164
  }
152
165
  const jsxs = jsx;
153
166
  function Fragment(props, ...children) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilha",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "A tiny, framework-free island architecture library",
5
5
  "keywords": [
6
6
  "framework-free",