ilha 0.10.2 → 0.10.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.
@@ -242,6 +242,8 @@ type OnMountContext<TInput, TStateMap extends Record<string, unknown>, TDerivedM
242
242
  input: TInput;
243
243
  host: Element;
244
244
  hydrated: boolean;
245
+ /** AbortSignal that aborts when the island unmounts. */
246
+ signal: AbortSignal;
245
247
  };
246
248
  type HandlerContext<TInput, TStateMap extends Record<string, unknown>, TDerivedMap extends Record<string, unknown> = Record<never, never>, TActionMap extends ActionMap = Record<never, never>> = {
247
249
  state: IslandState<TStateMap>;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as __ilhaJsxSlot, B as mount, C as NativeEventModifier, D as SignalSetter, E as SignalAccessor, F as html, H as raw, I as ilha, L as ilhaComputed, M as context, N as css, O as SignalWriter, P as from, R as ilhaEffect, S as NativeEventHandler, T as RawHtml, U as untrack, V as onUncaughtError, _ as IslandState, a as EffectContext, b as MountResult, c as ExternalSignal, d as HydratableOptions, f as ISLAND_MOUNT_HANDLES, g as IslandDerived, h as IslandActions, i as DerivedValue, j as batch, k as __ilhaJsxEvent, l as HandlerContext, m as Island, n as ActionContext, o as ErrorContext, p as ISLAND_MOUNT_INTERNAL, r as DerivedAccessor, s as ErrorSource, t as ActionAccessor, u as HandlerContextFor, v as KeyedIsland, w as OnMountContext, x as NativeEventContext, y as MountOptions, z as ilhaSignal } from "./index-Bi_I3qEL.js";
1
+ import { A as __ilhaJsxSlot, B as mount, C as NativeEventModifier, D as SignalSetter, E as SignalAccessor, F as html, H as raw, I as ilha, L as ilhaComputed, M as context, N as css, O as SignalWriter, P as from, R as ilhaEffect, S as NativeEventHandler, T as RawHtml, U as untrack, V as onUncaughtError, _ as IslandState, a as EffectContext, b as MountResult, c as ExternalSignal, d as HydratableOptions, f as ISLAND_MOUNT_HANDLES, g as IslandDerived, h as IslandActions, i as DerivedValue, j as batch, k as __ilhaJsxEvent, l as HandlerContext, m as Island, n as ActionContext, o as ErrorContext, p as ISLAND_MOUNT_INTERNAL, r as DerivedAccessor, s as ErrorSource, t as ActionAccessor, u as HandlerContextFor, v as KeyedIsland, w as OnMountContext, x as NativeEventContext, y as MountOptions, z as ilhaSignal } from "./index-BDM797j2.js";
2
2
  export { ActionAccessor, ActionContext, DerivedAccessor, DerivedValue, EffectContext, ErrorContext, ErrorSource, ExternalSignal, HandlerContext, HandlerContextFor, HydratableOptions, ISLAND_MOUNT_HANDLES, ISLAND_MOUNT_INTERNAL, Island, IslandActions, IslandDerived, IslandState, KeyedIsland, MountOptions, MountResult, NativeEventContext, NativeEventHandler, NativeEventModifier, OnMountContext, RawHtml, SignalAccessor, SignalSetter, SignalWriter, __ilhaJsxEvent, __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
@@ -465,6 +465,7 @@ const RAW = Symbol.for("ilha.raw");
465
465
  const SIGNAL_ACCESSOR = Symbol.for("ilha.signalAccessor");
466
466
  const ISLAND = Symbol.for("ilha.island");
467
467
  const ISLAND_CALL = Symbol.for("ilha.islandCall");
468
+ const ASTRO_RENDERER_GLOBAL = Symbol.for("ilha.astroRenderer");
468
469
  /** @internal Internal hook used by a parent's mountSlots to mount a child island and
469
470
  * retain a handle to push updated props into it on subsequent parent
470
471
  * re-renders. Not part of the public surface. */
@@ -523,8 +524,8 @@ function isIslandCall(v) {
523
524
  function emitIslandSlot({ island, props, key }) {
524
525
  const ctx = currentRenderCtx();
525
526
  let id;
526
- if (key !== void 0) id = `k:${key}`;
527
- else id = ctx ? `p:${ctx.positional++}` : "p:0";
527
+ if (key === void 0) id = ctx ? `p:${ctx.positional++}` : "p:0";
528
+ else id = `k:${key}`;
528
529
  if (ctx) ctx.slots.set(id, {
529
530
  island,
530
531
  props
@@ -827,7 +828,8 @@ function ilhaHtml(strings, ...values) {
827
828
  }
828
829
  if (pendingBindSpecs !== "" || pendingEventSpecs !== "") {
829
830
  const { index: gtIdx, quote } = findTagCloseIndex(chunk, pendingQuote);
830
- if (gtIdx !== -1) {
831
+ if (gtIdx === -1) pendingQuote = quote;
832
+ else {
831
833
  const head = chunk.slice(0, gtIdx).replace(/\s*\/\s*$/, "");
832
834
  const bindAttr = pendingBindSpecs ? ` data-ilha-bind="${pendingBindSpecs}"` : "";
833
835
  const eventAttr = pendingEventSpecs ? ` data-ilha-on="${pendingEventSpecs}"` : "";
@@ -835,7 +837,7 @@ function ilhaHtml(strings, ...values) {
835
837
  pendingBindSpecs = "";
836
838
  pendingEventSpecs = "";
837
839
  pendingQuote = null;
838
- } else pendingQuote = quote;
840
+ }
839
841
  }
840
842
  if (i >= values.length) {
841
843
  result += chunk;
@@ -843,13 +845,14 @@ function ilhaHtml(strings, ...values) {
843
845
  }
844
846
  const value = values[i];
845
847
  const eventMatch = chunk.match(EVENT_PREFIX_RE);
846
- if (eventMatch && isEventAttributePosition(result + chunk, result.length + chunk.length - eventMatch[0].length)) {
848
+ const eventMatchStart = eventMatch ? chunk.length - eventMatch[0].length : -1;
849
+ const eventAttributeFragment = eventMatch !== null && chunk.slice(0, eventMatchStart).trim() === "";
850
+ if (eventMatch && (eventAttributeFragment || isEventAttributePosition(result + chunk, result.length + eventMatchStart))) {
847
851
  const eventName = eventMatch[1];
848
852
  const rawModifier = eventMatch[2];
849
853
  const modifier = NATIVE_EVENT_MODIFIERS.has(rawModifier) ? rawModifier : void 0;
850
854
  const openQuote = eventMatch[3] ?? null;
851
- const matchStart = chunk.length - eventMatch[0].length;
852
- const cleanPrefix = chunk.slice(0, matchStart).replace(/\s+$/, "");
855
+ const cleanPrefix = chunk.slice(0, eventMatchStart).replace(/\s+$/, "");
853
856
  result += cleanPrefix;
854
857
  if (ctx && typeof value === "function") {
855
858
  const index = ctx.events.length;
@@ -1153,7 +1156,12 @@ function createDerivedProxy({ entries, state, input, derivedSnapshot }) {
1153
1156
  for (const entry of entries) {
1154
1157
  let initialEnvelope;
1155
1158
  if (derivedSnapshot != null && entry.key in derivedSnapshot) initialEnvelope = { ...derivedSnapshot[entry.key] };
1156
- else if (!(entry.fn.constructor.name === "AsyncFunction" || entry.fn.constructor.name === "AsyncGeneratorFunction")) {
1159
+ else if (entry.fn.constructor.name === "AsyncFunction" || entry.fn.constructor.name === "AsyncGeneratorFunction") initialEnvelope = {
1160
+ loading: true,
1161
+ value: void 0,
1162
+ error: void 0
1163
+ };
1164
+ else {
1157
1165
  const ac = new AbortController();
1158
1166
  const captureSlot = {};
1159
1167
  const stack = queryCaptureStack();
@@ -1170,19 +1178,18 @@ function createDerivedProxy({ entries, state, input, derivedSnapshot }) {
1170
1178
  value: void 0,
1171
1179
  error: void 0
1172
1180
  };
1173
- else if (!(result instanceof Promise)) initialEnvelope = {
1174
- loading: false,
1175
- value: result,
1176
- error: void 0
1177
- };
1178
- else {
1181
+ else if (result instanceof Promise) {
1179
1182
  initialEnvelope = {
1180
1183
  loading: true,
1181
1184
  value: void 0,
1182
1185
  error: void 0
1183
1186
  };
1184
1187
  result.catch(() => {});
1185
- }
1188
+ } else initialEnvelope = {
1189
+ loading: false,
1190
+ value: result,
1191
+ error: void 0
1192
+ };
1186
1193
  } catch (err) {
1187
1194
  globalThis[ILHA_QUERY_PENDING] = void 0;
1188
1195
  initialEnvelope = {
@@ -1194,11 +1201,7 @@ function createDerivedProxy({ entries, state, input, derivedSnapshot }) {
1194
1201
  stack.pop();
1195
1202
  ac.abort();
1196
1203
  }
1197
- } else initialEnvelope = {
1198
- loading: true,
1199
- value: void 0,
1200
- error: void 0
1201
- };
1204
+ }
1202
1205
  const env = signal(initialEnvelope);
1203
1206
  envelopes.set(entry.key, env);
1204
1207
  }
@@ -1478,7 +1481,7 @@ function applyJsxEvents({ host, records, reportError, unmountSignal, onceFired }
1478
1481
  }
1479
1482
  return () => cleanups.forEach((cleanup) => cleanup());
1480
1483
  }
1481
- function applyTemplateBindings(host, binds) {
1484
+ function applyTemplateBindings(host, binds, phase = "all") {
1482
1485
  if (binds.length === 0) return () => {};
1483
1486
  const cleanups = [];
1484
1487
  const elements = [];
@@ -1493,14 +1496,16 @@ function applyTemplateBindings(host, binds) {
1493
1496
  const { event, read, write } = resolveBindOps(el, spec.kind);
1494
1497
  const accessor = record.accessor;
1495
1498
  if (spec.kind === "this") {
1496
- accessor(el);
1497
- cleanups.push(() => accessor(null));
1499
+ if (phase !== "listen") {
1500
+ accessor(el);
1501
+ cleanups.push(() => accessor(null));
1502
+ }
1498
1503
  continue;
1499
1504
  }
1500
- try {
1505
+ if (phase !== "listen") try {
1501
1506
  write(el, accessor());
1502
1507
  } catch (err) {}
1503
- if (event === null) continue;
1508
+ if (phase === "reflect" || event === null) continue;
1504
1509
  const listener = () => {
1505
1510
  const raw = read(el);
1506
1511
  if (spec.kind === "group") {
@@ -1725,7 +1730,7 @@ var IlhaBuilder = class IlhaBuilder {
1725
1730
  }
1726
1731
  render(fn) {
1727
1732
  const { schema, defaultInput, states, deriveds, actions, ons, effects, onMounts, onErrors, transition, css: cssSource, as: slotAs } = this._cfg;
1728
- const stylePrefix = cssSource != null ? buildScopedStyle(cssSource) : "";
1733
+ const stylePrefix = cssSource == null ? "" : buildScopedStyle(cssSource);
1729
1734
  const configuredSlotTag = slotAs ?? "div";
1730
1735
  function resolveInput(props) {
1731
1736
  const merged = {
@@ -1828,6 +1833,7 @@ var IlhaBuilder = class IlhaBuilder {
1828
1833
  if (onMounts.length === 0) return;
1829
1834
  if (currentRenderCtx()) return;
1830
1835
  const host = createSsrOnMountHost();
1836
+ const controller = new AbortController();
1831
1837
  const ssrCleanups = [];
1832
1838
  for (const entry of onMounts) {
1833
1839
  const prevSub = setActiveSub(void 0);
@@ -1839,7 +1845,8 @@ var IlhaBuilder = class IlhaBuilder {
1839
1845
  action,
1840
1846
  input,
1841
1847
  host,
1842
- hydrated: false
1848
+ hydrated: false,
1849
+ signal: controller.signal
1843
1850
  });
1844
1851
  } catch (err) {
1845
1852
  const error = err instanceof Error ? err : new Error(String(err));
@@ -1863,6 +1870,7 @@ var IlhaBuilder = class IlhaBuilder {
1863
1870
  }
1864
1871
  if (typeof userCleanup === "function") ssrCleanups.push(userCleanup);
1865
1872
  }
1873
+ controller.abort();
1866
1874
  for (const teardown of ssrCleanups.reverse()) try {
1867
1875
  teardown();
1868
1876
  } catch (err) {
@@ -2350,7 +2358,8 @@ var IlhaBuilder = class IlhaBuilder {
2350
2358
  action,
2351
2359
  input,
2352
2360
  host,
2353
- hydrated
2361
+ hydrated,
2362
+ signal: unmountController.signal
2354
2363
  });
2355
2364
  } catch (err) {
2356
2365
  reportError(err, "mount");
@@ -2382,7 +2391,8 @@ var IlhaBuilder = class IlhaBuilder {
2382
2391
  liveHost: preserveSSRDom ? host : void 0
2383
2392
  });
2384
2393
  if (!preserveSSRDom) host.innerHTML = stylePrefix + initial.html;
2385
- let stopBindings = applyTemplateBindings(host, initial.binds);
2394
+ const stopInitialBindingReflection = applyTemplateBindings(host, initial.binds, "reflect");
2395
+ let stopBindings = stopInitialBindingReflection;
2386
2396
  cleanups.push(() => stopBindings());
2387
2397
  let stopJsxEvents = applyJsxEvents({
2388
2398
  host,
@@ -2396,6 +2406,11 @@ var IlhaBuilder = class IlhaBuilder {
2396
2406
  cleanups.push(() => mountedSlots.forEach((entry) => entry.unmount()));
2397
2407
  attachListeners();
2398
2408
  if (!hydrated && onMounts.length > 0) invokeOnMounts();
2409
+ const stopInitialBindingListeners = applyTemplateBindings(host, initial.binds, "listen");
2410
+ stopBindings = () => {
2411
+ stopInitialBindingListeners();
2412
+ stopInitialBindingReflection();
2413
+ };
2399
2414
  for (const entry of effects) {
2400
2415
  let userCleanup;
2401
2416
  let runController = null;
@@ -2631,6 +2646,8 @@ var IlhaBuilder = class IlhaBuilder {
2631
2646
  return keyed;
2632
2647
  };
2633
2648
  island[ISLAND] = true;
2649
+ const astroRendererName = globalThis[ASTRO_RENDERER_GLOBAL];
2650
+ if (typeof astroRendererName === "string") island[Symbol.for("astro:renderer")] = astroRendererName;
2634
2651
  island.define = (tagName, options) => {
2635
2652
  if (typeof customElements === "undefined" || typeof HTMLElement === "undefined") {
2636
2653
  `${tagName}`;
@@ -1,2 +1,2 @@
1
- import { a as JSX, r as jsxDEV, t as Fragment } from "./jsx-runtime-DJ2B4fvA.js";
1
+ import { a as JSX, r as jsxDEV, t as Fragment } from "./jsx-runtime-C6R6IiOD.js";
2
2
  export { Fragment, type JSX, jsxDEV };
@@ -1,4 +1,4 @@
1
- import { C as NativeEventModifier, E as SignalAccessor, O as SignalWriter, S as NativeEventHandler, T as RawHtml } from "./index-Bi_I3qEL.js";
1
+ import { C as NativeEventModifier, E as SignalAccessor, O as SignalWriter, S as NativeEventHandler, T as RawHtml } from "./index-BDM797j2.js";
2
2
  //#region src/jsx-types.d.ts
3
3
  declare namespace JSX {
4
4
  export type Child = unknown;
@@ -1,2 +1,2 @@
1
- import { a as JSX, i as jsxs, n as jsx, r as jsxDEV, t as Fragment } from "./jsx-runtime-DJ2B4fvA.js";
1
+ import { a as JSX, i as jsxs, n as jsx, r as jsxDEV, t as Fragment } from "./jsx-runtime-C6R6IiOD.js";
2
2
  export { Fragment, type JSX, jsx, jsxDEV, jsxs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilha",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "A tiny, framework-free island architecture library",
5
5
  "keywords": [
6
6
  "framework-free",
@@ -53,6 +53,7 @@
53
53
  },
54
54
  "scripts": {
55
55
  "build": "tsc && tsdown",
56
+ "cleanup": "rimraf dist node_modules",
56
57
  "test": "bun test"
57
58
  },
58
59
  "dependencies": {