@moku-labs/web 1.17.0 → 2.0.1

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.cjs CHANGED
@@ -9147,15 +9147,15 @@ const cliPlugin = createPlugin$1("cli", {
9147
9147
  function createApi(ctx) {
9148
9148
  return {
9149
9149
  /**
9150
- * Register a component definition (last-registered-wins); warns on collision.
9150
+ * Register a island definition (last-registered-wins); warns on collision.
9151
9151
  *
9152
- * @param component - The component definition created via `createComponent`.
9152
+ * @param island - The island definition created via `createIsland`.
9153
9153
  * @example
9154
9154
  * app.spa.register(counter);
9155
9155
  */
9156
- register(component) {
9157
- if (ctx.state.registeredComponents.has(component.name)) ctx.log.warn("spa:component-collision", { name: component.name });
9158
- ctx.state.kernel?.register(component);
9156
+ register(island) {
9157
+ if (ctx.state.registeredIslands.has(island.name)) ctx.log.warn("spa:island-collision", { name: island.name });
9158
+ ctx.state.kernel?.register(island);
9159
9159
  },
9160
9160
  /**
9161
9161
  * Programmatically navigate to a path (client runtime; no-op without a DOM).
@@ -9181,13 +9181,13 @@ function createApi(ctx) {
9181
9181
  * Resolve a registered island's api by name (the cross-island seam). Returns
9182
9182
  * `undefined` when no provider with that name is currently registered.
9183
9183
  *
9184
- * @param name - The provider island's component name.
9184
+ * @param name - The provider island's island name.
9185
9185
  * @returns The provider's api, or `undefined`.
9186
9186
  * @example
9187
- * app.spa.component("lightbox");
9187
+ * app.spa.island("lightbox");
9188
9188
  */
9189
- component(name) {
9190
- return ctx.state.componentApis.get(name);
9189
+ island(name) {
9190
+ return ctx.state.islandApis.get(name);
9191
9191
  }
9192
9192
  };
9193
9193
  }
@@ -9206,15 +9206,89 @@ function spaEvents(register) {
9206
9206
  return {
9207
9207
  "spa:navigate": register("A navigation has been intercepted and is starting."),
9208
9208
  "spa:navigated": register("The swap completed and the new URL is active."),
9209
- "spa:component-mount": register("A component instance attached to an element."),
9210
- "spa:component-unmount": register("A component instance detached from an element.")
9209
+ "spa:island-mount": register("A island instance attached to an element."),
9210
+ "spa:island-unmount": register("A island instance detached from an element.")
9211
9211
  };
9212
9212
  }
9213
9213
  //#endregion
9214
+ //#region src/plugins/spa/head.ts
9215
+ /** Single-element head selectors synced by replace/append/remove on navigation. */
9216
+ const META_SELECTORS = [
9217
+ "meta[name=\"description\"]",
9218
+ "meta[property=\"og:title\"]",
9219
+ "meta[property=\"og:description\"]",
9220
+ "meta[property=\"og:url\"]",
9221
+ "meta[property=\"og:image\"]",
9222
+ "meta[property=\"og:type\"]",
9223
+ "meta[property=\"og:locale\"]",
9224
+ "meta[name=\"twitter:card\"]",
9225
+ "meta[name=\"twitter:title\"]",
9226
+ "meta[name=\"twitter:description\"]",
9227
+ "meta[name=\"twitter:image\"]",
9228
+ "meta[name=\"twitter:site\"]",
9229
+ "link[rel=\"canonical\"]"
9230
+ ];
9231
+ /** Head element groups fully replaced (remove-all-then-clone) on navigation. */
9232
+ const REPLACE_ALL_SELECTORS = [
9233
+ "script[type=\"application/ld+json\"]",
9234
+ "link[rel=\"alternate\"][hreflang]",
9235
+ "meta[property^=\"article:\"]"
9236
+ ];
9237
+ /**
9238
+ * Sync a single head element by selector between the fetched and live document:
9239
+ * replace when both exist, append when only the new doc has it, remove when only
9240
+ * the live doc has it.
9241
+ *
9242
+ * @param selector - CSS selector for the head element to sync.
9243
+ * @param doc - The fetched document (DOMParser-parsed).
9244
+ * @example
9245
+ * syncElement('link[rel="canonical"]', doc);
9246
+ */
9247
+ function syncElement(selector, doc) {
9248
+ const newElement = doc.querySelector(selector);
9249
+ const oldElement = document.querySelector(selector);
9250
+ if (newElement && oldElement) oldElement.replaceWith(newElement.cloneNode(true));
9251
+ else if (newElement) document.head.append(newElement.cloneNode(true));
9252
+ else if (oldElement) oldElement.remove();
9253
+ }
9254
+ /**
9255
+ * Remove all live matches for a selector and re-clone the fetched document's
9256
+ * matches into the live `<head>`.
9257
+ *
9258
+ * @param selector - CSS selector for the element group to replace wholesale.
9259
+ * @param doc - The fetched document (DOMParser-parsed).
9260
+ * @example
9261
+ * replaceAllBySelector('script[type="application/ld+json"]', doc);
9262
+ */
9263
+ function replaceAllBySelector(selector, doc) {
9264
+ for (const element of document.querySelectorAll(selector)) element.remove();
9265
+ for (const element of doc.querySelectorAll(selector)) document.head.append(element.cloneNode(true));
9266
+ }
9267
+ /**
9268
+ * Syncs the live document `<head>` after a navigation from the fetched document
9269
+ * (whose head was composed by the `head` plugin). Recomputes
9270
+ * title/meta/canonical/JSON-LD/hreflang/`<html lang>` once and applies them.
9271
+ * The `head` API is accepted to bind the structural dependency (spec/09 deps).
9272
+ *
9273
+ * @param _head - The head plugin API (dependency binding; composition reused via the fetched doc).
9274
+ * @param doc - The fetched document parsed from the navigated page's HTML.
9275
+ * @example
9276
+ * syncHead(headApi, parsedDoc);
9277
+ */
9278
+ function syncHead(_head, doc) {
9279
+ if (typeof document === "undefined") return;
9280
+ const newTitle = doc.querySelector("title")?.textContent;
9281
+ if (newTitle) document.title = newTitle;
9282
+ const newLang = doc.documentElement.lang;
9283
+ if (newLang) document.documentElement.lang = newLang;
9284
+ for (const selector of META_SELECTORS) syncElement(selector, doc);
9285
+ for (const selector of REPLACE_ALL_SELECTORS) replaceAllBySelector(selector, doc);
9286
+ }
9287
+ //#endregion
9214
9288
  //#region src/plugins/spa/types.ts
9215
- var types_exports$7 = /* @__PURE__ */ require_convention.__exportAll({ COMPONENT_HOOK_NAMES: () => COMPONENT_HOOK_NAMES });
9289
+ var types_exports$7 = /* @__PURE__ */ require_convention.__exportAll({ ISLAND_HOOK_NAMES: () => ISLAND_HOOK_NAMES });
9216
9290
  /** Allowed hook names — single source of truth for fail-fast validation. */
9217
- const COMPONENT_HOOK_NAMES = [
9291
+ const ISLAND_HOOK_NAMES = [
9218
9292
  "onCreate",
9219
9293
  "onMount",
9220
9294
  "onNavStart",
@@ -9223,10 +9297,10 @@ const COMPONENT_HOOK_NAMES = [
9223
9297
  "onDestroy"
9224
9298
  ];
9225
9299
  //#endregion
9226
- //#region src/plugins/spa/components.ts
9300
+ //#region src/plugins/spa/islands.ts
9227
9301
  /**
9228
- * @file spa plugin — component lifecycle, mounting, the plugin-mirror authoring
9229
- * surface (`createComponent` with a typed `{ state, render, events, api }` spec),
9302
+ * @file spa plugin — island lifecycle, mounting, the plugin-mirror authoring
9303
+ * surface (`createIsland` with a typed `{ state, render, events, api }` spec),
9230
9304
  * the per-instance state + microtask-batched render scheduler, declarative
9231
9305
  * delegated events, and the cross-island api registry.
9232
9306
  * @see README.md
@@ -9234,8 +9308,8 @@ const COMPONENT_HOOK_NAMES = [
9234
9308
  /** Error prefix for spa fail-fast failures (spec/11 Part-3). */
9235
9309
  const ERROR_PREFIX$2 = "[web]";
9236
9310
  /** The set of legal hook names, frozen for O(1) membership checks. */
9237
- const HOOK_NAME_SET = new Set(COMPONENT_HOOK_NAMES);
9238
- /** The spec-only keys that select the plugin-mirror form of {@link createComponent}. */
9311
+ const HOOK_NAME_SET = new Set(ISLAND_HOOK_NAMES);
9312
+ /** The spec-only keys that select the plugin-mirror form of {@link createIsland}. */
9239
9313
  const SPEC_KEYS = new Set([
9240
9314
  "state",
9241
9315
  "render",
@@ -9274,7 +9348,7 @@ let renderChunk;
9274
9348
  let commitVNodeFunction;
9275
9349
  /**
9276
9350
  * Load the lazy `./render` chunk (once) and cache its `commitVNode` for synchronous
9277
- * use by later renders. Awaited by a component's `mountPromise` so the test harness's
9351
+ * use by later renders. Awaited by a island's `mountPromise` so the test harness's
9278
9352
  * `settle()` can deterministically flush a VNode render.
9279
9353
  *
9280
9354
  * @returns A promise that resolves once `commitVNode` is available.
@@ -9282,7 +9356,7 @@ let commitVNodeFunction;
9282
9356
  * await loadRenderChunk();
9283
9357
  */
9284
9358
  async function loadRenderChunk() {
9285
- renderChunk ??= Promise.resolve().then(() => require("./render-KdufA3_b.cjs"));
9359
+ renderChunk ??= Promise.resolve().then(() => require("./render-DHUcHCYs.cjs"));
9286
9360
  commitVNodeFunction = (await renderChunk).commitVNode;
9287
9361
  }
9288
9362
  /**
@@ -9291,7 +9365,7 @@ async function loadRenderChunk() {
9291
9365
  * a Preact `VNode` → committed through the lazy gate (loading it on demand if needed).
9292
9366
  *
9293
9367
  * @param host - The island host element to render into.
9294
- * @param result - The value returned by the component's `render`.
9368
+ * @param result - The value returned by the island's `render`.
9295
9369
  * @example
9296
9370
  * commitResult(host, h(View, { items }));
9297
9371
  */
@@ -9313,7 +9387,7 @@ function commitResult(host, result) {
9313
9387
  loadRenderChunk().then(() => commitVNodeFunction?.(vnode, host)).catch(() => {});
9314
9388
  }
9315
9389
  /**
9316
- * Run a component's `render(state, ctx)` and commit the result now. Guards against
9390
+ * Run a island's `render(state, ctx)` and commit the result now. Guards against
9317
9391
  * synchronous re-entrancy (a render that calls `ctx.flush`) with a depth cap.
9318
9392
  *
9319
9393
  * @param instance - The instance to render.
@@ -9324,7 +9398,7 @@ function commitResult(host, result) {
9324
9398
  function runRender(instance) {
9325
9399
  const render = instance.def.spec?.render;
9326
9400
  if (!render) return;
9327
- if (instance.renderDepth > MAX_RENDER_DEPTH) throw new Error(`${ERROR_PREFIX$2} component "${instance.def.name}" render re-entered ${MAX_RENDER_DEPTH}+ times\n → a render must not synchronously trigger its own render (avoid ctx.flush() inside render)`);
9401
+ if (instance.renderDepth > MAX_RENDER_DEPTH) throw new Error(`${ERROR_PREFIX$2} island "${instance.def.name}" render re-entered ${MAX_RENDER_DEPTH}+ times\n → a render must not synchronously trigger its own render (avoid ctx.flush() inside render)`);
9328
9402
  instance.renderDepth += 1;
9329
9403
  try {
9330
9404
  commitResult(instance.el, render(instance.state ?? {}, instance.ctx));
@@ -9350,12 +9424,12 @@ function scheduleRender(instance) {
9350
9424
  });
9351
9425
  }
9352
9426
  /**
9353
- * Build the single per-instance {@link ComponentContext} reused by every hook, event
9427
+ * Build the single per-instance {@link IslandContext} reused by every hook, event
9354
9428
  * handler, and render. Route fields (`params`/`meta`/`locale`/`url`) and `data` read
9355
9429
  * through the instance so a navigation update is reflected without rebuilding the ctx;
9356
- * `state`/`set`/`flush`/`cleanup`/`component` are bound to the instance + plugin state.
9430
+ * `state`/`set`/`flush`/`cleanup`/`island` are bound to the instance + plugin state.
9357
9431
  *
9358
- * @param state - The plugin state (for the cross-island `component` resolver).
9432
+ * @param state - The plugin state (for the cross-island `island` resolver).
9359
9433
  * @param instance - The instance the context is bound to.
9360
9434
  * @returns The instance-bound context.
9361
9435
  * @example
@@ -9459,13 +9533,13 @@ function buildContext(state, instance) {
9459
9533
  /**
9460
9534
  * Resolve another island's registered api by name (`undefined` when absent).
9461
9535
  *
9462
- * @param name - The provider island's component name.
9536
+ * @param name - The provider island's island name.
9463
9537
  * @returns The provider's api, or `undefined`.
9464
9538
  * @example
9465
- * ctx.component("lightbox");
9539
+ * ctx.island("lightbox");
9466
9540
  */
9467
- component(name) {
9468
- return state.componentApis.get(name);
9541
+ island(name) {
9542
+ return state.islandApis.get(name);
9469
9543
  }
9470
9544
  };
9471
9545
  }
@@ -9489,7 +9563,7 @@ function matchTarget(host, event, selector) {
9489
9563
  return matched && host.contains(matched) ? matched : void 0;
9490
9564
  }
9491
9565
  /**
9492
- * Attach a component's declarative `events` map: one real listener per event TYPE on
9566
+ * Attach a island's declarative `events` map: one real listener per event TYPE on
9493
9567
  * the host (dispatch walks `closest(selector)` for each registered selector), each
9494
9568
  * removed via the instance's cleanup registry on destroy.
9495
9569
  *
@@ -9506,7 +9580,7 @@ function attachEvents(instance, events) {
9506
9580
  const space = key.indexOf(" ");
9507
9581
  const type = (space === -1 ? key : key.slice(0, space)).trim();
9508
9582
  const selector = space === -1 ? "" : key.slice(space + 1).trim();
9509
- if (type === "") throw new Error(`${ERROR_PREFIX$2} component "${instance.def.name}" event key must start with an event type: "${key}"\n → use "<type>" or "<type> <selector>" (e.g. "click [data-action]")`);
9583
+ if (type === "") throw new Error(`${ERROR_PREFIX$2} island "${instance.def.name}" event key must start with an event type: "${key}"\n → use "<type>" or "<type> <selector>" (e.g. "click [data-action]")`);
9510
9584
  const list = byType.get(type) ?? [];
9511
9585
  list.push({
9512
9586
  selector,
@@ -9529,62 +9603,62 @@ function attachEvents(instance, events) {
9529
9603
  * Validate a single hook entry: its key must be a known hook name and its value
9530
9604
  * must be a function. Throws fail-fast on the first violation.
9531
9605
  *
9532
- * @param componentName - The owning component name (for error messages).
9606
+ * @param islandName - The owning island name (for error messages).
9533
9607
  * @param source - The raw authoring object being validated.
9534
9608
  * @param key - The hook key to validate.
9535
- * @throws {Error} If `key` is not in `COMPONENT_HOOK_NAMES`.
9609
+ * @throws {Error} If `key` is not in `ISLAND_HOOK_NAMES`.
9536
9610
  * @throws {TypeError} If the hook value is not a function.
9537
9611
  * @example
9538
9612
  * validateHookEntry("counter", source, "onMount");
9539
9613
  */
9540
- function validateHookEntry(componentName, source, key) {
9541
- if (!HOOK_NAME_SET.has(key)) throw new Error(`${ERROR_PREFIX$2} unknown component hook "${key}" on "${componentName}"\n → valid hooks: ${COMPONENT_HOOK_NAMES.join(", ")}\n → spec keys: state, render, events, api`);
9542
- if (typeof source[key] !== "function") throw new TypeError(`${ERROR_PREFIX$2} component hook "${key}" on "${componentName}" must be a function\n → provide a function or omit the hook`);
9614
+ function validateHookEntry(islandName, source, key) {
9615
+ if (!HOOK_NAME_SET.has(key)) throw new Error(`${ERROR_PREFIX$2} unknown island hook "${key}" on "${islandName}"\n → valid hooks: ${ISLAND_HOOK_NAMES.join(", ")}\n → spec keys: state, render, events, api`);
9616
+ if (typeof source[key] !== "function") throw new TypeError(`${ERROR_PREFIX$2} island hook "${key}" on "${islandName}" must be a function\n → provide a function or omit the hook`);
9543
9617
  }
9544
9618
  /**
9545
9619
  * Validate the spec extras (`state`/`render`/`api` must be functions; `events` must be
9546
9620
  * a plain object of functions). Throws fail-fast on the first violation.
9547
9621
  *
9548
- * @param componentName - The owning component name (for error messages).
9622
+ * @param islandName - The owning island name (for error messages).
9549
9623
  * @param extras - The partitioned spec extras to validate.
9550
9624
  * @throws {TypeError} If a present extra has the wrong shape.
9551
9625
  * @example
9552
9626
  * validateSpecExtras("board", { state: () => ({}) });
9553
9627
  */
9554
- function validateSpecExtras(componentName, extras) {
9628
+ function validateSpecExtras(islandName, extras) {
9555
9629
  for (const key of [
9556
9630
  "state",
9557
9631
  "render",
9558
9632
  "api"
9559
- ]) if (extras[key] !== void 0 && typeof extras[key] !== "function") throw new TypeError(`${ERROR_PREFIX$2} component "${key}" on "${componentName}" must be a function\n → provide a function or omit it`);
9633
+ ]) if (extras[key] !== void 0 && typeof extras[key] !== "function") throw new TypeError(`${ERROR_PREFIX$2} island "${key}" on "${islandName}" must be a function\n → provide a function or omit it`);
9560
9634
  if (extras.events !== void 0) {
9561
9635
  const events = extras.events;
9562
- if (!(typeof events === "object")) throw new TypeError(`${ERROR_PREFIX$2} component "events" on "${componentName}" must be an object of handlers`);
9563
- for (const [key, handler] of Object.entries(events)) if (typeof handler !== "function") throw new TypeError(`${ERROR_PREFIX$2} component event "${key}" on "${componentName}" must be a function`);
9636
+ if (!(typeof events === "object")) throw new TypeError(`${ERROR_PREFIX$2} island "events" on "${islandName}" must be an object of handlers`);
9637
+ for (const [key, handler] of Object.entries(events)) if (typeof handler !== "function") throw new TypeError(`${ERROR_PREFIX$2} island event "${key}" on "${islandName}" must be a function`);
9564
9638
  }
9565
9639
  }
9566
9640
  /**
9567
- * Create a validated component definition. Accepts either the legacy hooks-only form
9568
- * (`createComponent("counter", { onMount() {} })`) or the plugin-mirror spec form
9569
- * (`createComponent("board", { state, render, events, api, ...hooks })`). Spec-only
9641
+ * Create a validated island definition. Accepts either the legacy hooks-only form
9642
+ * (`createIsland("counter", { onMount() {} })`) or the plugin-mirror spec form
9643
+ * (`createIsland("board", { state, render, events, api, ...hooks })`). Spec-only
9570
9644
  * keys (`state`/`render`/`events`/`api`) are partitioned out before hook-name
9571
9645
  * validation, so a real typo (e.g. `onMout`) still throws immediately while the spec
9572
9646
  * keys are accepted.
9573
9647
  *
9574
- * @param name - Unique component name.
9648
+ * @param name - Unique island name.
9575
9649
  * @param spec - Lifecycle hooks, or the `{ state, render, events, api, ...hooks }` spec.
9576
- * @returns A `ComponentDef` ready to `register`.
9650
+ * @returns A `IslandDef` ready to `register`.
9577
9651
  * @throws {Error} If `name` is empty, a hook key is unknown, or an extra/hook value has the wrong shape.
9578
9652
  * @example
9579
- * const counter = createComponent("counter", { onMount({ el }) { el.textContent = "0"; } });
9653
+ * const counter = createIsland("counter", { onMount({ el }) { el.textContent = "0"; } });
9580
9654
  * @example
9581
- * const list = createComponent<{ items: string[] }>("list", {
9655
+ * const list = createIsland<{ items: string[] }>("list", {
9582
9656
  * state: () => ({ items: [] }),
9583
9657
  * render: (s) => h(List, { items: s.items })
9584
9658
  * });
9585
9659
  */
9586
- function createComponent(name, spec) {
9587
- if (name.trim() === "") throw new Error(`${ERROR_PREFIX$2} component name must be a non-empty string\n → pass a unique name to createComponent("name", hooks)`);
9660
+ function createIsland(name, spec) {
9661
+ if (name.trim() === "") throw new Error(`${ERROR_PREFIX$2} island name must be a non-empty string\n → pass a unique name to createIsland("name", hooks)`);
9588
9662
  const source = spec;
9589
9663
  const hooks = {};
9590
9664
  const extras = {};
@@ -9661,30 +9735,30 @@ function disposeInstance(state, instance) {
9661
9735
  } catch {}
9662
9736
  instance.cleanups.length = 0;
9663
9737
  instance.renderScheduled = false;
9664
- if (instance.api !== void 0 && state.componentApis.get(instance.def.name) === instance.api) state.componentApis.delete(instance.def.name);
9738
+ if (instance.api !== void 0 && state.islandApis.get(instance.def.name) === instance.api) state.islandApis.delete(instance.def.name);
9665
9739
  }
9666
9740
  /**
9667
- * Mounts a single `data-component` element: classifies persistent vs page-specific,
9741
+ * Mounts a single `data-island` element: classifies persistent vs page-specific,
9668
9742
  * builds the instance + its bound context, initializes per-instance `state`, registers
9669
9743
  * its `api`, attaches declarative `events`, fires `onCreate` then `onMount` (capturing
9670
9744
  * an async `onMount` + render-chunk load as `mountPromise`), schedules the initial
9671
- * render, records it, and emits `spa:component-mount`. No-ops if the element is already
9672
- * mounted, has no component name, or names an unregistered component.
9745
+ * render, records it, and emits `spa:island-mount`. No-ops if the element is already
9746
+ * mounted, has no island name, or names an unregistered island.
9673
9747
  *
9674
- * @param state - The plugin state (registeredComponents + instances + componentApis).
9675
- * @param emit - The event emitter for spa:component-mount.
9748
+ * @param state - The plugin state (registeredIslands + instances + islandApis).
9749
+ * @param emit - The event emitter for spa:island-mount.
9676
9750
  * @param swapArea - The swap-region element, or null when none was found.
9677
9751
  * @param data - The current page data payload.
9678
- * @param element - The candidate element carrying a `data-component` attribute.
9752
+ * @param element - The candidate element carrying a `data-island` attribute.
9679
9753
  * @param route - The matched-route slice for the current URL (params/meta/locale/url).
9680
9754
  * @example
9681
9755
  * mountElement(state, emit, swapArea, data, element, route);
9682
9756
  */
9683
9757
  function mountElement(state, emit, swapArea, data, element, route = EMPTY_ROUTE) {
9684
9758
  if (state.instances.has(element)) return;
9685
- const name = element.dataset.component;
9759
+ const name = element.dataset.island;
9686
9760
  if (!name) return;
9687
- const definition = state.registeredComponents.get(name);
9761
+ const definition = state.registeredIslands.get(name);
9688
9762
  if (!definition) return;
9689
9763
  const instance = {
9690
9764
  def: definition,
@@ -9710,7 +9784,7 @@ function mountElement(state, emit, swapArea, data, element, route = EMPTY_ROUTE)
9710
9784
  if (spec?.state) instance.state = spec.state(instance.ctx);
9711
9785
  if (spec?.api) {
9712
9786
  instance.api = spec.api(instance.ctx);
9713
- state.componentApis.set(definition.name, instance.api);
9787
+ state.islandApis.set(definition.name, instance.api);
9714
9788
  }
9715
9789
  if (spec?.events) attachEvents(instance, spec.events);
9716
9790
  runHook(instance, "onCreate");
@@ -9721,20 +9795,20 @@ function mountElement(state, emit, swapArea, data, element, route = EMPTY_ROUTE)
9721
9795
  if (onMountResult && typeof onMountResult.then === "function") pending.push(onMountResult);
9722
9796
  instance.mountPromise = pending.length > 0 ? Promise.all(pending).then(() => {}) : void 0;
9723
9797
  state.instances.set(element, instance);
9724
- emit("spa:component-mount", {
9798
+ emit("spa:island-mount", {
9725
9799
  name: definition.name,
9726
9800
  el: element
9727
9801
  });
9728
9802
  }
9729
9803
  /**
9730
- * Scans the swap region, mounts components for matching `data-component` elements,
9804
+ * Scans the swap region, mounts islands for matching `data-island` elements,
9731
9805
  * classifies persistent (outside swap area) vs page-specific (inside), runs
9732
- * `onCreate`/`onMount` + initial render, and emits `spa:component-mount` per instance.
9806
+ * `onCreate`/`onMount` + initial render, and emits `spa:island-mount` per instance.
9733
9807
  * Already-mounted elements are skipped.
9734
9808
  *
9735
- * @param state - The plugin state (registeredComponents + instances + componentApis).
9736
- * @param emit - The event emitter for spa:component-mount.
9737
- * @param swapSelector - CSS selector bounding page-specific components.
9809
+ * @param state - The plugin state (registeredIslands + instances + islandApis).
9810
+ * @param emit - The event emitter for spa:island-mount.
9811
+ * @param swapSelector - CSS selector bounding page-specific islands.
9738
9812
  * @param route - The matched-route slice for the current URL (params/meta/locale/url).
9739
9813
  * @example
9740
9814
  * scanAndMount(state, emit, "main > section", route);
@@ -9743,16 +9817,16 @@ function scanAndMount(state, emit, swapSelector, route = EMPTY_ROUTE) {
9743
9817
  if (typeof document === "undefined") return;
9744
9818
  const swapArea = document.querySelector(swapSelector);
9745
9819
  const data = extractPageData(document);
9746
- for (const element of document.querySelectorAll("[data-component]")) mountElement(state, emit, swapArea, data, element, route);
9820
+ for (const element of document.querySelectorAll("[data-island]")) mountElement(state, emit, swapArea, data, element, route);
9747
9821
  }
9748
9822
  /**
9749
9823
  * Unmounts page-specific instances inside the swap region (runs `onUnMount` then
9750
9824
  * `onDestroy`, then their cleanup disposers + api unregister), removes them from state,
9751
- * and emits `spa:component-unmount`. Persistent instances (outside the swap area) are
9825
+ * and emits `spa:island-unmount`. Persistent instances (outside the swap area) are
9752
9826
  * left in place.
9753
9827
  *
9754
9828
  * @param state - The plugin state holding live instances.
9755
- * @param emit - The event emitter for spa:component-unmount.
9829
+ * @param emit - The event emitter for spa:island-unmount.
9756
9830
  * @example
9757
9831
  * unmountPageSpecific(state, emit);
9758
9832
  */
@@ -9765,7 +9839,7 @@ function unmountPageSpecific(state, emit) {
9765
9839
  runHook(instance, "onDestroy");
9766
9840
  disposeInstance(state, instance);
9767
9841
  state.instances.delete(element);
9768
- emit("spa:component-unmount", {
9842
+ emit("spa:island-unmount", {
9769
9843
  name: instance.def.name,
9770
9844
  el: element
9771
9845
  });
@@ -9774,11 +9848,11 @@ function unmountPageSpecific(state, emit) {
9774
9848
  /**
9775
9849
  * Disposes ALL live instances (persistent and page-specific) on teardown: runs
9776
9850
  * `onUnMount` then `onDestroy`, then their cleanup disposers + api unregister, emits
9777
- * `spa:component-unmount`, and clears the instance + api maps. Used by the kernel's
9851
+ * `spa:island-unmount`, and clears the instance + api maps. Used by the kernel's
9778
9852
  * `dispose` on plugin stop.
9779
9853
  *
9780
9854
  * @param state - The plugin state holding live instances.
9781
- * @param emit - The event emitter for spa:component-unmount.
9855
+ * @param emit - The event emitter for spa:island-unmount.
9782
9856
  * @example
9783
9857
  * unmountAll(state, emit);
9784
9858
  */
@@ -9789,13 +9863,13 @@ function unmountAll(state, emit) {
9789
9863
  runHook(instance, "onUnMount");
9790
9864
  runHook(instance, "onDestroy");
9791
9865
  disposeInstance(state, instance);
9792
- emit("spa:component-unmount", {
9866
+ emit("spa:island-unmount", {
9793
9867
  name: instance.def.name,
9794
9868
  el: element
9795
9869
  });
9796
9870
  }
9797
9871
  state.instances.clear();
9798
- state.componentApis.clear();
9872
+ state.islandApis.clear();
9799
9873
  }
9800
9874
  /**
9801
9875
  * Fires `onNavStart` on every currently-mounted instance (persistent instances
@@ -9832,80 +9906,6 @@ function notifyNavEnd(state, route = EMPTY_ROUTE) {
9832
9906
  }
9833
9907
  }
9834
9908
  //#endregion
9835
- //#region src/plugins/spa/head.ts
9836
- /** Single-element head selectors synced by replace/append/remove on navigation. */
9837
- const META_SELECTORS = [
9838
- "meta[name=\"description\"]",
9839
- "meta[property=\"og:title\"]",
9840
- "meta[property=\"og:description\"]",
9841
- "meta[property=\"og:url\"]",
9842
- "meta[property=\"og:image\"]",
9843
- "meta[property=\"og:type\"]",
9844
- "meta[property=\"og:locale\"]",
9845
- "meta[name=\"twitter:card\"]",
9846
- "meta[name=\"twitter:title\"]",
9847
- "meta[name=\"twitter:description\"]",
9848
- "meta[name=\"twitter:image\"]",
9849
- "meta[name=\"twitter:site\"]",
9850
- "link[rel=\"canonical\"]"
9851
- ];
9852
- /** Head element groups fully replaced (remove-all-then-clone) on navigation. */
9853
- const REPLACE_ALL_SELECTORS = [
9854
- "script[type=\"application/ld+json\"]",
9855
- "link[rel=\"alternate\"][hreflang]",
9856
- "meta[property^=\"article:\"]"
9857
- ];
9858
- /**
9859
- * Sync a single head element by selector between the fetched and live document:
9860
- * replace when both exist, append when only the new doc has it, remove when only
9861
- * the live doc has it.
9862
- *
9863
- * @param selector - CSS selector for the head element to sync.
9864
- * @param doc - The fetched document (DOMParser-parsed).
9865
- * @example
9866
- * syncElement('link[rel="canonical"]', doc);
9867
- */
9868
- function syncElement(selector, doc) {
9869
- const newElement = doc.querySelector(selector);
9870
- const oldElement = document.querySelector(selector);
9871
- if (newElement && oldElement) oldElement.replaceWith(newElement.cloneNode(true));
9872
- else if (newElement) document.head.append(newElement.cloneNode(true));
9873
- else if (oldElement) oldElement.remove();
9874
- }
9875
- /**
9876
- * Remove all live matches for a selector and re-clone the fetched document's
9877
- * matches into the live `<head>`.
9878
- *
9879
- * @param selector - CSS selector for the element group to replace wholesale.
9880
- * @param doc - The fetched document (DOMParser-parsed).
9881
- * @example
9882
- * replaceAllBySelector('script[type="application/ld+json"]', doc);
9883
- */
9884
- function replaceAllBySelector(selector, doc) {
9885
- for (const element of document.querySelectorAll(selector)) element.remove();
9886
- for (const element of doc.querySelectorAll(selector)) document.head.append(element.cloneNode(true));
9887
- }
9888
- /**
9889
- * Syncs the live document `<head>` after a navigation from the fetched document
9890
- * (whose head was composed by the `head` plugin). Recomputes
9891
- * title/meta/canonical/JSON-LD/hreflang/`<html lang>` once and applies them.
9892
- * The `head` API is accepted to bind the structural dependency (spec/09 deps).
9893
- *
9894
- * @param _head - The head plugin API (dependency binding; composition reused via the fetched doc).
9895
- * @param doc - The fetched document parsed from the navigated page's HTML.
9896
- * @example
9897
- * syncHead(headApi, parsedDoc);
9898
- */
9899
- function syncHead(_head, doc) {
9900
- if (typeof document === "undefined") return;
9901
- const newTitle = doc.querySelector("title")?.textContent;
9902
- if (newTitle) document.title = newTitle;
9903
- const newLang = doc.documentElement.lang;
9904
- if (newLang) document.documentElement.lang = newLang;
9905
- for (const selector of META_SELECTORS) syncElement(selector, doc);
9906
- for (const selector of REPLACE_ALL_SELECTORS) replaceAllBySelector(selector, doc);
9907
- }
9908
- //#endregion
9909
9909
  //#region src/plugins/spa/progress.ts
9910
9910
  /** Delay before the bar appears, so fast navigations show no indicator. */
9911
9911
  const START_DELAY_MS = 150;
@@ -10312,7 +10312,7 @@ const defaultSpaConfig = {
10312
10312
  swapSelector: "main > section",
10313
10313
  viewTransitions: false,
10314
10314
  progressBar: true,
10315
- components: []
10315
+ islands: []
10316
10316
  };
10317
10317
  /**
10318
10318
  * Whether a selector is syntactically valid (parseable by the DOM). Falls back
@@ -10334,8 +10334,8 @@ function isValidSelector(selector) {
10334
10334
  }
10335
10335
  /**
10336
10336
  * Validates the spa config and applies defaults (Part-3 errors on an empty or
10337
- * syntactically-invalid `swapSelector`). Component-hook validation runs later in
10338
- * `createComponent` when the components are registered.
10337
+ * syntactically-invalid `swapSelector`). Island-hook validation runs later in
10338
+ * `createIsland` when the islands are registered.
10339
10339
  *
10340
10340
  * @param config - The raw spa config to validate.
10341
10341
  * @returns The fully-resolved config with defaults applied.
@@ -10351,7 +10351,7 @@ function resolveSpaConfig(config) {
10351
10351
  swapSelector,
10352
10352
  viewTransitions: config.viewTransitions ?? false,
10353
10353
  progressBar: config.progressBar ?? true,
10354
- components: config.components ?? []
10354
+ islands: config.islands ?? []
10355
10355
  };
10356
10356
  }
10357
10357
  /**
@@ -10368,9 +10368,9 @@ function resolveSpaConfig(config) {
10368
10368
  */
10369
10369
  function createState(_ctx) {
10370
10370
  return {
10371
- registeredComponents: /* @__PURE__ */ new Map(),
10371
+ registeredIslands: /* @__PURE__ */ new Map(),
10372
10372
  instances: /* @__PURE__ */ new Map(),
10373
- componentApis: /* @__PURE__ */ new Map(),
10373
+ islandApis: /* @__PURE__ */ new Map(),
10374
10374
  currentUrl: "",
10375
10375
  destroyRouter: null,
10376
10376
  started: false,
@@ -10390,15 +10390,15 @@ function createState(_ctx) {
10390
10390
  /** Error prefix for spa kernel failures (spec/11 Part-3). */
10391
10391
  const ERROR_PREFIX = "[web]";
10392
10392
  /**
10393
- * Registers a component definition into state (last-registered-wins).
10393
+ * Registers a island definition into state (last-registered-wins).
10394
10394
  *
10395
- * @param state - The plugin state holding registeredComponents.
10396
- * @param component - The component definition to register.
10395
+ * @param state - The plugin state holding registeredIslands.
10396
+ * @param island - The island definition to register.
10397
10397
  * @example
10398
- * registerComponent(state, counter);
10398
+ * registerIsland(state, counter);
10399
10399
  */
10400
- function registerComponent(state, component) {
10401
- state.registeredComponents.set(component.name, component);
10400
+ function registerIsland(state, island) {
10401
+ state.registeredIslands.set(island.name, island);
10402
10402
  }
10403
10403
  /**
10404
10404
  * Resolve the current document URL (pathname + search), or `""` when headless.
@@ -10473,15 +10473,15 @@ function createSpaKernel(state, config, emit, deps) {
10473
10473
  });
10474
10474
  };
10475
10475
  /**
10476
- * Build the matched-route slice (params/meta/locale/url) for the component context at `path`,
10476
+ * Build the matched-route slice (params/meta/locale/url) for the island context at `path`,
10477
10477
  * so islands read their route's params/meta directly. An unmatched path yields an empty slice.
10478
10478
  *
10479
10479
  * @param path - The URL (pathname + search) to match.
10480
10480
  * @returns The route slice for the matched route.
10481
10481
  * @example
10482
- * scanAndMount(state, emit, resolved.swapSelector, componentRouteContext(pathname));
10482
+ * scanAndMount(state, emit, resolved.swapSelector, islandRouteContext(pathname));
10483
10483
  */
10484
- const componentRouteContext = (path) => {
10484
+ const islandRouteContext = (path) => {
10485
10485
  const matchPath = path.split("?")[0] ?? path;
10486
10486
  const hit = deps.router.match(matchPath);
10487
10487
  const locale = hit?.params.lang ?? (typeof document === "undefined" ? "" : document.documentElement.lang) ?? "";
@@ -10510,7 +10510,7 @@ function createSpaKernel(state, config, emit, deps) {
10510
10510
  syncHead(deps.head, doc);
10511
10511
  unmountPageSpecific(state, emit);
10512
10512
  if (!swapRegion(doc, resolved.swapSelector, resolved.viewTransitions, () => {
10513
- const routeSlice = componentRouteContext(pathname);
10513
+ const routeSlice = islandRouteContext(pathname);
10514
10514
  scanAndMount(state, emit, resolved.swapSelector, routeSlice);
10515
10515
  notifyNavEnd(state, routeSlice);
10516
10516
  }, applyPendingScroll)) {
@@ -10523,7 +10523,7 @@ function createSpaKernel(state, config, emit, deps) {
10523
10523
  emit("spa:navigated", { url: pathname });
10524
10524
  };
10525
10525
  /**
10526
- * Begin a navigation: start progress, notify components, emit navigate.
10526
+ * Begin a navigation: start progress, notify islands, emit navigate.
10527
10527
  *
10528
10528
  * @param pathname - The destination pathname.
10529
10529
  * @example
@@ -10609,11 +10609,11 @@ function createSpaKernel(state, config, emit, deps) {
10609
10609
  const commitDataRender = async (pathname, resolvedRender, signal) => {
10610
10610
  if (signal?.aborted) return;
10611
10611
  const { route, vnode, routeContext, region } = resolvedRender;
10612
- const { renderVNode } = await Promise.resolve().then(() => require("./render-KdufA3_b.cjs"));
10612
+ const { renderVNode } = await Promise.resolve().then(() => require("./render-DHUcHCYs.cjs"));
10613
10613
  if (signal?.aborted) return;
10614
10614
  syncDataHead(deps.head, route, routeContext);
10615
10615
  unmountPageSpecific(state, emit);
10616
- const routeSlice = componentRouteContext(pathname);
10616
+ const routeSlice = islandRouteContext(pathname);
10617
10617
  /**
10618
10618
  * Render the VNode into the region and re-mount its islands in one paint — the
10619
10619
  * swap body handed to `runSwap` (optionally wrapped in a View Transition).
@@ -10671,14 +10671,14 @@ function createSpaKernel(state, config, emit, deps) {
10671
10671
  * await bootRender("/b/abc123");
10672
10672
  */
10673
10673
  const bootRender = async (pathname) => {
10674
- const routeSlice = componentRouteContext(pathname);
10674
+ const routeSlice = islandRouteContext(pathname);
10675
10675
  const resolvedRender = await resolveDataRender(pathname);
10676
10676
  if (resolvedRender === false) {
10677
10677
  scanAndMount(state, emit, resolved.swapSelector, routeSlice);
10678
10678
  return;
10679
10679
  }
10680
10680
  const { vnode, region } = resolvedRender;
10681
- const { renderVNode } = await Promise.resolve().then(() => require("./render-KdufA3_b.cjs"));
10681
+ const { renderVNode } = await Promise.resolve().then(() => require("./render-DHUcHCYs.cjs"));
10682
10682
  renderVNode(vnode, region);
10683
10683
  scanAndMount(state, emit, resolved.swapSelector, routeSlice);
10684
10684
  };
@@ -10706,13 +10706,13 @@ function createSpaKernel(state, config, emit, deps) {
10706
10706
  };
10707
10707
  return {
10708
10708
  /**
10709
- * Register config components and seed currentUrl from the document.
10709
+ * Register config islands and seed currentUrl from the document.
10710
10710
  *
10711
10711
  * @example
10712
10712
  * kernel.init();
10713
10713
  */
10714
10714
  init() {
10715
- for (const component of resolved.components) registerComponent(state, component);
10715
+ for (const island of resolved.islands) registerIsland(state, island);
10716
10716
  state.currentUrl = currentLocationUrl();
10717
10717
  },
10718
10718
  /**
@@ -10730,18 +10730,18 @@ function createSpaKernel(state, config, emit, deps) {
10730
10730
  const matchPath = state.currentUrl.split("?")[0] ?? state.currentUrl;
10731
10731
  const hit = deps.router.match(matchPath);
10732
10732
  if (hit?.route._handlers.render && isClientOnlyRoute(deps.router.mode(), hit.route)) bootRender(state.currentUrl);
10733
- else scanAndMount(state, emit, resolved.swapSelector, componentRouteContext(state.currentUrl));
10733
+ else scanAndMount(state, emit, resolved.swapSelector, islandRouteContext(state.currentUrl));
10734
10734
  state.started = true;
10735
10735
  },
10736
10736
  /**
10737
- * Register a component definition (last-registered-wins).
10737
+ * Register a island definition (last-registered-wins).
10738
10738
  *
10739
- * @param component - The component definition to register.
10739
+ * @param island - The island definition to register.
10740
10740
  * @example
10741
10741
  * kernel.register(counter);
10742
10742
  */
10743
- register(component) {
10744
- registerComponent(state, component);
10743
+ register(island) {
10744
+ registerIsland(state, island);
10745
10745
  },
10746
10746
  /**
10747
10747
  * Process a navigation to `path` (fetch then swap; full reload on error).
@@ -10755,13 +10755,13 @@ function createSpaKernel(state, config, emit, deps) {
10755
10755
  navigate(path).catch(() => {});
10756
10756
  },
10757
10757
  /**
10758
- * Scan the swap region and mount components for matching elements.
10758
+ * Scan the swap region and mount islands for matching elements.
10759
10759
  *
10760
10760
  * @example
10761
10761
  * kernel.scan();
10762
10762
  */
10763
10763
  scan() {
10764
- scanAndMount(state, emit, resolved.swapSelector, componentRouteContext(state.currentUrl));
10764
+ scanAndMount(state, emit, resolved.swapSelector, islandRouteContext(state.currentUrl));
10765
10765
  },
10766
10766
  /**
10767
10767
  * Tear down router listeners, dispose all instances, reset boot state.
@@ -10780,7 +10780,7 @@ function createSpaKernel(state, config, emit, deps) {
10780
10780
  }
10781
10781
  /**
10782
10782
  * Builds the shared kernel from the plugin context, stores it on `ctx.state`,
10783
- * and runs its init step (validate config, register config.components, seed
10783
+ * and runs its init step (validate config, register config.islands, seed
10784
10784
  * currentUrl). Captures the OPTIONAL `data` reader when the `data` plugin is
10785
10785
  * composed (enabling client DATA navigation) — resolved by instance via
10786
10786
  * `ctx.require(dataPlugin)`, guarded by `ctx.has("data")` so `data` stays optional
@@ -10848,10 +10848,10 @@ function disposeSpa() {
10848
10848
  /**
10849
10849
  * @file `lazyEmbed` island — activates the static embed facades emitted by the
10850
10850
  * content pipeline's `::embed` directive (pipeline/embed.ts). Mounts on every
10851
- * `[data-component="lazy-embed"]` figure; a click on the facade's button swaps
10851
+ * `[data-island="lazy-embed"]` figure; a click on the facade's button swaps
10852
10852
  * it for the real `<iframe loading="lazy">`. Until that click the embedded
10853
10853
  * document costs the page nothing — no request, no third-party JS, no
10854
- * scroll-jacking. Register it in `pluginConfigs.spa.components`; all visual
10854
+ * scroll-jacking. Register it in `pluginConfigs.spa.islands`; all visual
10855
10855
  * chrome (`.lazy-embed*` classes) is consumer CSS.
10856
10856
  */
10857
10857
  /** CSS class on the injected `<iframe>` (consumer CSS sizes it). */
@@ -10904,7 +10904,7 @@ function onFacadeClick(event) {
10904
10904
  * Lazy-embed island: facade button click → real `<iframe loading="lazy">`.
10905
10905
  * The companion of the content pipeline's `::embed` directive.
10906
10906
  */
10907
- const lazyEmbed = createComponent("lazy-embed", {
10907
+ const lazyEmbed = createIsland("lazy-embed", {
10908
10908
  /**
10909
10909
  * Bind the activation click handler when a facade mounts.
10910
10910
  *
@@ -10930,18 +10930,18 @@ const lazyEmbed = createComponent("lazy-embed", {
10930
10930
  //#region src/plugins/spa/index.ts
10931
10931
  /**
10932
10932
  * @file spa — Complex Plugin (WIRING ONLY, ≤30 lines). All logic lives in the
10933
- * domain files (kernel/router/head/progress/components/lifecycle); index wires.
10933
+ * domain files (kernel/router/head/progress/islands/lifecycle); index wires.
10934
10934
  *
10935
10935
  * Depends: router, head.
10936
- * Emits: spa:navigate, spa:navigated, spa:component-mount, spa:component-unmount.
10936
+ * Emits: spa:navigate, spa:navigated, spa:island-mount, spa:island-unmount.
10937
10937
  * @see README.md
10938
10938
  */
10939
10939
  /**
10940
10940
  * SPA plugin — progressive client-side navigation layered over the static site:
10941
10941
  * swaps a page region on navigation, with an optional progress bar and View
10942
- * Transitions. Register interactive islands with {@link createComponent}. Depends
10943
- * on router and head; emits `spa:navigate`, `spa:navigated`, `spa:component-mount`,
10944
- * and `spa:component-unmount`.
10942
+ * Transitions. Register interactive islands with {@link createIsland}. Depends
10943
+ * on router and head; emits `spa:navigate`, `spa:navigated`, `spa:island-mount`,
10944
+ * and `spa:island-unmount`.
10945
10945
  *
10946
10946
  * @example Enable view transitions and a custom swap region
10947
10947
  * ```ts
@@ -11924,8 +11924,8 @@ function EmbedFacadeButton(props) {
11924
11924
  //#region src/plugins/content/pipeline/embed.ts
11925
11925
  /** CSS class on the `<figure>` facade wrapping each embed. */
11926
11926
  const EMBED_FIGURE_CLASS = "lazy-embed";
11927
- /** `data-component` name binding the facade to the `lazyEmbed` SPA island. */
11928
- const EMBED_COMPONENT_NAME = "lazy-embed";
11927
+ /** `data-island` name binding the facade to the `lazyEmbed` SPA island. */
11928
+ const EMBED_ISLAND_NAME = "lazy-embed";
11929
11929
  /**
11930
11930
  * Type guard for an `::embed` leaf directive.
11931
11931
  *
@@ -12035,7 +12035,7 @@ function collectAttributes$1(attributes) {
12035
12035
  * ```
12036
12036
  */
12037
12037
  function embedFacadeHtml(facade, props, dimensions) {
12038
- return `<figure class="${EMBED_FIGURE_CLASS}" data-component="${EMBED_COMPONENT_NAME}" data-embed-src="${escapeAttribute(props.src)}" data-embed-title="${escapeAttribute(props.title)}"${dimensions ? ` data-embed-width="${dimensions.width}" data-embed-height="${dimensions.height}" style="aspect-ratio: ${dimensions.width} / ${dimensions.height}; max-width: ${dimensions.width}px;"` : ""}>${(0, preact_render_to_string.renderToString)((0, preact.h)(facade, props))}</figure>`;
12038
+ return `<figure class="${EMBED_FIGURE_CLASS}" data-island="${EMBED_ISLAND_NAME}" data-embed-src="${escapeAttribute(props.src)}" data-embed-title="${escapeAttribute(props.title)}"${dimensions ? ` data-embed-width="${dimensions.width}" data-embed-height="${dimensions.height}" style="aspect-ratio: ${dimensions.width} / ${dimensions.height}; max-width: ${dimensions.width}px;"` : ""}>${(0, preact_render_to_string.renderToString)((0, preact.h)(facade, props))}</figure>`;
12039
12039
  }
12040
12040
  /**
12041
12041
  * Normalize the provider's `embed` config value (`boolean | options`) to a plain
@@ -12148,7 +12148,7 @@ function GalleryTrack(props) {
12148
12148
  *
12149
12149
  * Rewrites `::gallery{src="./images/dir/" caption="…"}` leaf directives into a
12150
12150
  * static swipeable image set at the mdast stage (BEFORE the remark-rehype bridge):
12151
- * a framework-owned `<div class="gallery" data-component="gallery">` carrying the
12151
+ * a framework-owned `<div class="gallery" data-island="gallery">` carrying the
12152
12152
  * island hook, wrapping inner content rendered (at build time, to static markup)
12153
12153
  * by a Preact component — the built-in {@link GalleryTrack} by default, or a
12154
12154
  * consumer component via `gallery.component`.
@@ -12160,12 +12160,12 @@ function GalleryTrack(props) {
12160
12160
  * transform reads `<contentDir>/<slug>/<src>` from disk, sorts its images, and
12161
12161
  * resolves each to its shared `/<slug>/<dir>/<file>` URL (identical from every
12162
12162
  * locale page, mirroring co-located images). The companion gallery SPA island
12163
- * (consumer-provided) wires swipe/keyboard/lightbox on `[data-component="gallery"]`.
12163
+ * (consumer-provided) wires swipe/keyboard/lightbox on `[data-island="gallery"]`.
12164
12164
  */
12165
12165
  /** CSS class on the `<div>` wrapping each gallery. */
12166
12166
  const GALLERY_WRAPPER_CLASS = "gallery";
12167
- /** `data-component` name binding the gallery to its SPA island. */
12168
- const GALLERY_COMPONENT_NAME = "gallery";
12167
+ /** `data-island` name binding the gallery to its SPA island. */
12168
+ const GALLERY_ISLAND_NAME = "gallery";
12169
12169
  /** Image file extensions a gallery folder expands over. */
12170
12170
  const IMAGE_EXTENSIONS = new Set([
12171
12171
  ".webp",
@@ -12258,7 +12258,7 @@ function collectAttributes(attributes) {
12258
12258
  }
12259
12259
  /**
12260
12260
  * Build the static gallery HTML for one directive: the framework-owned `<div>`
12261
- * (island hook in `data-component`) wrapping the component's inner content, SSR'd
12261
+ * (island hook in `data-island`) wrapping the component's inner content, SSR'd
12262
12262
  * to static markup.
12263
12263
  *
12264
12264
  * @param component - The gallery component (default {@link GalleryTrack}).
@@ -12272,7 +12272,7 @@ function collectAttributes(attributes) {
12272
12272
  * ```
12273
12273
  */
12274
12274
  function galleryHtml(component, slides, caption, attributes) {
12275
- return `<div class="${GALLERY_WRAPPER_CLASS}" data-component="${GALLERY_COMPONENT_NAME}">${(0, preact_render_to_string.renderToString)((0, preact.h)(component, {
12275
+ return `<div class="${GALLERY_WRAPPER_CLASS}" data-island="${GALLERY_ISLAND_NAME}">${(0, preact_render_to_string.renderToString)((0, preact.h)(component, {
12276
12276
  slides,
12277
12277
  caption,
12278
12278
  attributes
@@ -13257,7 +13257,7 @@ Object.defineProperty(exports, "cloudflareBindings", {
13257
13257
  });
13258
13258
  exports.contentPlugin = contentPlugin;
13259
13259
  exports.createApp = createApp;
13260
- exports.createComponent = createComponent;
13260
+ exports.createIsland = createIsland;
13261
13261
  exports.createPlugin = createPlugin;
13262
13262
  exports.createUrls = createUrls;
13263
13263
  exports.dataPlugin = dataPlugin;