@farm.js/islx 0.0.8 → 0.0.9

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/client.mjs CHANGED
@@ -1,31 +1,7 @@
1
- import { a as defineClientHooks, c as setClientHooks, d as valueHeaders, i as setActionNavigator, l as createValueStore, n as decodeActionReference, o as emit, r as setActionInterceptor, s as hookEventName, t as createServerReference, u as getValueStore } from "./_chunks/actions-C-IwUCKU.mjs";
2
- import { C as RENDER_HEADER, I as readPostedAction, L as stripRuntimeFields } from "./_chunks/wire-QEQWBr5s.mjs";
1
+ import { a as defineClientHooks, c as setClientHooks, d as valueHeaders, i as setActionNavigator, l as createValueStore, n as decodeActionReference, o as emit, r as setActionInterceptor, s as hookEventName, t as createServerReference, u as getValueStore } from "./_chunks/actions-DAzd4PpV.mjs";
2
+ import { n as enhanceForms } from "./_chunks/forms-CCDY9QHC.mjs";
3
+ import { w as RENDER_HEADER } from "./_chunks/wire-UUwZlUJZ.mjs";
3
4
  import { i as REPLAYABLE_SELECTOR, n as PENDING_INTERACTIONS, r as PREHYDRATION_SCRIPT, t as INTERACTION_EVENT } from "./_chunks/prehydration-zEYsfFxW.mjs";
4
- // src/client/forms.ts
5
- /**
6
- * Forms written in server components submit without reloading the page once JavaScript runs.
7
- * No island owns them, so nothing else would: a submit of a form that posts an action is sent as
8
- * a call, and the page refreshes as after any action, keeping island state. Forms inside islands
9
- * are React's, which handles them first.
10
- */
11
- let enhanced = false;
12
- /** Starts handling server-component forms on this page. Safe to call more than once. */
13
- function enhanceForms() {
14
- if (enhanced) return;
15
- enhanced = true;
16
- document.addEventListener("submit", (event) => {
17
- if (event.defaultPrevented || !(event.target instanceof HTMLFormElement)) return;
18
- const form = event.target;
19
- const submitter = event.submitter ?? null;
20
- const data = new FormData(form, submitter);
21
- const posted = readPostedAction(data);
22
- if (!posted) return;
23
- event.preventDefault();
24
- stripRuntimeFields(data);
25
- form.setAttribute("aria-busy", "true");
26
- createServerReference(posted.id, posted.token)(data).then(() => form.reset()).catch((error) => console.error("[islx] The form's action failed:", error)).finally(() => form.removeAttribute("aria-busy"));
27
- });
28
- }
29
5
  // src/client/navigation.ts
30
6
  /**
31
7
  * Moving between pages without loading a new document. A click on a same-site link fetches the
@@ -1,4 +1,5 @@
1
1
  import { a as getActionId, i as TransformActionsResult, n as AstNode, o as hasModuleDirective, r as TransformActionsOptions, s as transformActions, t as ActionCompileError } from "./_chunks/actions-BCtIGvrP.mjs";
2
+ import MagicString from "magic-string";
2
3
 
3
4
  // src/compiler/infer.d.ts
4
5
  interface InferOptions {
@@ -21,4 +22,15 @@ interface Inference {
21
22
  }
22
23
  /** Infers when the islands `file` exports hydrate; `code` is its source. */
23
24
  declare function inferStrategy(file: string, code: string, options: InferOptions): Inference;
24
- export { ActionCompileError, type AstNode, type InferOptions, type Inference, type TransformActionsOptions, type TransformActionsResult, getActionId, hasModuleDirective, inferStrategy, transformActions };
25
+ /** The rewrite for a framework's own transform: the module's new code and map, or null. */
26
+ declare function rewriteFormStatusImports(options: {
27
+ code: string;
28
+ id: string;
29
+ parse(code: string): AstNode;
30
+ /** The module islx's React entry resolves as. Default `@farm.js/islx/react`. */
31
+ from?: string;
32
+ }): {
33
+ code: string;
34
+ map: ReturnType<MagicString["generateMap"]>;
35
+ } | null;
36
+ export { ActionCompileError, type AstNode, type InferOptions, type Inference, type TransformActionsOptions, type TransformActionsResult, getActionId, hasModuleDirective, inferStrategy, rewriteFormStatusImports, transformActions };
package/dist/compiler.mjs CHANGED
@@ -1 +1 @@
1
- export { n as ActionCompileError, r as getActionId, i as hasModuleDirective, t as inferStrategy, a as transformActions } from "./_chunks/infer-BIVT5aDz.mjs";
1
+ export { i as ActionCompileError, a as getActionId, o as hasModuleDirective, r as inferStrategy, n as rewriteFormStatusImports, s as transformActions } from "./_chunks/form-status-CRfnB7WT.mjs";
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { A as VALUES_HEADER, C as RENDER_HEADER, D as TAG_BOUND, E as TAG, F as getTag, I as readPostedAction, L as stripRuntimeFields, M as VALUE_SCRIPT_TYPE, N as attachmentField, O as TAG_VALUE, P as formFieldName, S as REFERENCE_TAG, T as SLOT_TAG, _ as MAX_HELD_VALUES, a as BLOB_TAG, b as PROMISE_TAG, c as CHUNK_SCRIPT_TYPE, d as FORM_REF_PREFIX, f as FORM_STATE_SCRIPT_TYPE, g as LAYOUTS_HEADER, h as ISLAND_ELEMENT, i as ACTION_TAG, j as VALUE_KEY_PATTERN, k as TREE_SCRIPT_TYPE, l as FORM_DATA_TAG, m as HYDRATED_ATTRIBUTE, n as ACTION_KEY_FIELD, o as BOUND_FIELD, p as HTML_ELEMENT, r as ACTION_STALE_HEADER, s as CALL_FIELD, t as ACTION_HEADER, u as FORM_FIELD_PREFIX, v as OBJECT_TAG, w as SLOT_ELEMENT, x as PROPS_SCRIPT_TYPE, y as PROMISE_SCRIPT_TYPE } from "./_chunks/wire-Dipqh-EB.mjs";
1
+ import { A as TAG_BOUND, B as stripRuntimeFields, C as REFERENCE_TAG, D as SLOT_TEMPLATE_ELEMENT, E as SLOT_TAG, F as VALUE_SCRIPT_TYPE, I as attachmentField, L as formFieldName, M as TREE_SCRIPT_TYPE, N as VALUES_HEADER, O as SLOT_TREE_FIELD, P as VALUE_KEY_PATTERN, R as getTag, S as PROPS_SCRIPT_TYPE, T as SLOT_ELEMENT, _ as LAYOUTS_HEADER, a as BLOB_TAG, b as PROMISE_SCRIPT_TYPE, c as CHUNK_SCRIPT_TYPE, d as FORM_REF_PREFIX, f as FORM_STATE_SCRIPT_TYPE, g as ISLAND_ELEMENT, h as ID_POSITION_ATTRIBUTE, i as ACTION_TAG, j as TAG_VALUE, k as TAG, l as FORM_DATA_TAG, m as HYDRATED_ATTRIBUTE, n as ACTION_KEY_FIELD, o as BOUND_FIELD, p as HTML_ELEMENT, r as ACTION_STALE_HEADER, s as CALL_FIELD, t as ACTION_HEADER, u as FORM_FIELD_PREFIX, v as MAX_HELD_VALUES, w as RENDER_HEADER, x as PROMISE_TAG, y as OBJECT_TAG, z as readPostedAction } from "./_chunks/wire-1d6wqOia.mjs";
2
2
  import { a as decode, c as encodeLeaf, d as plainObject, f as tagged, i as NOT_A_VALUE, l as fromBase64, n as EncodeError, o as decodeTagged, p as toBase64, r as EncodeOptions, s as encode, t as DecodeOptions, u as needsObjectTag } from "./_chunks/codec-CK8kZp4u.mjs";
3
- export { ACTION_HEADER, ACTION_KEY_FIELD, ACTION_STALE_HEADER, ACTION_TAG, BLOB_TAG, BOUND_FIELD, CALL_FIELD, CHUNK_SCRIPT_TYPE, type DecodeOptions, EncodeError, type EncodeOptions, FORM_DATA_TAG, FORM_FIELD_PREFIX, FORM_REF_PREFIX, FORM_STATE_SCRIPT_TYPE, HTML_ELEMENT, HYDRATED_ATTRIBUTE, ISLAND_ELEMENT, LAYOUTS_HEADER, MAX_HELD_VALUES, NOT_A_VALUE, OBJECT_TAG, PROMISE_SCRIPT_TYPE, PROMISE_TAG, PROPS_SCRIPT_TYPE, REFERENCE_TAG, RENDER_HEADER, SLOT_ELEMENT, SLOT_TAG, TAG, TAG_BOUND, TAG_VALUE, TREE_SCRIPT_TYPE, VALUES_HEADER, VALUE_KEY_PATTERN, VALUE_SCRIPT_TYPE, attachmentField, decode, decodeTagged, encode, encodeLeaf, formFieldName, fromBase64, getTag, needsObjectTag, plainObject, readPostedAction, stripRuntimeFields, tagged, toBase64 };
3
+ export { ACTION_HEADER, ACTION_KEY_FIELD, ACTION_STALE_HEADER, ACTION_TAG, BLOB_TAG, BOUND_FIELD, CALL_FIELD, CHUNK_SCRIPT_TYPE, type DecodeOptions, EncodeError, type EncodeOptions, FORM_DATA_TAG, FORM_FIELD_PREFIX, FORM_REF_PREFIX, FORM_STATE_SCRIPT_TYPE, HTML_ELEMENT, HYDRATED_ATTRIBUTE, ID_POSITION_ATTRIBUTE, ISLAND_ELEMENT, LAYOUTS_HEADER, MAX_HELD_VALUES, NOT_A_VALUE, OBJECT_TAG, PROMISE_SCRIPT_TYPE, PROMISE_TAG, PROPS_SCRIPT_TYPE, REFERENCE_TAG, RENDER_HEADER, SLOT_ELEMENT, SLOT_TAG, SLOT_TEMPLATE_ELEMENT, SLOT_TREE_FIELD, TAG, TAG_BOUND, TAG_VALUE, TREE_SCRIPT_TYPE, VALUES_HEADER, VALUE_KEY_PATTERN, VALUE_SCRIPT_TYPE, attachmentField, decode, decodeTagged, encode, encodeLeaf, formFieldName, fromBase64, getTag, needsObjectTag, plainObject, readPostedAction, stripRuntimeFields, tagged, toBase64 };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { A as VALUES_HEADER, C as RENDER_HEADER, D as TAG_BOUND, E as TAG, F as getTag, I as readPostedAction, L as stripRuntimeFields, M as VALUE_SCRIPT_TYPE, N as attachmentField, O as TAG_VALUE, P as formFieldName, S as REFERENCE_TAG, T as SLOT_TAG, _ as MAX_HELD_VALUES, a as BLOB_TAG, b as PROMISE_TAG, c as CHUNK_SCRIPT_TYPE, d as FORM_REF_PREFIX, f as FORM_STATE_SCRIPT_TYPE, g as LAYOUTS_HEADER, h as ISLAND_ELEMENT, i as ACTION_TAG, j as VALUE_KEY_PATTERN, k as TREE_SCRIPT_TYPE, l as FORM_DATA_TAG, m as HYDRATED_ATTRIBUTE, n as ACTION_KEY_FIELD, o as BOUND_FIELD, p as HTML_ELEMENT, r as ACTION_STALE_HEADER, s as CALL_FIELD, t as ACTION_HEADER, u as FORM_FIELD_PREFIX, v as OBJECT_TAG, w as SLOT_ELEMENT, x as PROPS_SCRIPT_TYPE, y as PROMISE_SCRIPT_TYPE } from "./_chunks/wire-QEQWBr5s.mjs";
2
- import { a as encode, c as needsObjectTag, d as tagged, f as toBase64, i as decodeTagged, l as plainObject, n as NOT_A_VALUE, o as encodeLeaf, r as decode, s as fromBase64, t as EncodeError } from "./_chunks/codec-C8to-RQW.mjs";
3
- export { ACTION_HEADER, ACTION_KEY_FIELD, ACTION_STALE_HEADER, ACTION_TAG, BLOB_TAG, BOUND_FIELD, CALL_FIELD, CHUNK_SCRIPT_TYPE, EncodeError, FORM_DATA_TAG, FORM_FIELD_PREFIX, FORM_REF_PREFIX, FORM_STATE_SCRIPT_TYPE, HTML_ELEMENT, HYDRATED_ATTRIBUTE, ISLAND_ELEMENT, LAYOUTS_HEADER, MAX_HELD_VALUES, NOT_A_VALUE, OBJECT_TAG, PROMISE_SCRIPT_TYPE, PROMISE_TAG, PROPS_SCRIPT_TYPE, REFERENCE_TAG, RENDER_HEADER, SLOT_ELEMENT, SLOT_TAG, TAG, TAG_BOUND, TAG_VALUE, TREE_SCRIPT_TYPE, VALUES_HEADER, VALUE_KEY_PATTERN, VALUE_SCRIPT_TYPE, attachmentField, decode, decodeTagged, encode, encodeLeaf, formFieldName, fromBase64, getTag, needsObjectTag, plainObject, readPostedAction, stripRuntimeFields, tagged, toBase64 };
1
+ import { A as TAG_BOUND, B as stripRuntimeFields, C as REFERENCE_TAG, D as SLOT_TEMPLATE_ELEMENT, E as SLOT_TAG, F as VALUE_SCRIPT_TYPE, I as attachmentField, L as formFieldName, M as TREE_SCRIPT_TYPE, N as VALUES_HEADER, O as SLOT_TREE_FIELD, P as VALUE_KEY_PATTERN, R as getTag, S as PROPS_SCRIPT_TYPE, T as SLOT_ELEMENT, _ as LAYOUTS_HEADER, a as BLOB_TAG, b as PROMISE_SCRIPT_TYPE, c as CHUNK_SCRIPT_TYPE, d as FORM_REF_PREFIX, f as FORM_STATE_SCRIPT_TYPE, g as ISLAND_ELEMENT, h as ID_POSITION_ATTRIBUTE, i as ACTION_TAG, j as TAG_VALUE, k as TAG, l as FORM_DATA_TAG, m as HYDRATED_ATTRIBUTE, n as ACTION_KEY_FIELD, o as BOUND_FIELD, p as HTML_ELEMENT, r as ACTION_STALE_HEADER, s as CALL_FIELD, t as ACTION_HEADER, u as FORM_FIELD_PREFIX, v as MAX_HELD_VALUES, w as RENDER_HEADER, x as PROMISE_TAG, y as OBJECT_TAG, z as readPostedAction } from "./_chunks/wire-UUwZlUJZ.mjs";
2
+ import { a as encode, c as needsObjectTag, d as tagged, f as toBase64, i as decodeTagged, l as plainObject, n as NOT_A_VALUE, o as encodeLeaf, r as decode, s as fromBase64, t as EncodeError } from "./_chunks/codec-DDpUvgRo.mjs";
3
+ export { ACTION_HEADER, ACTION_KEY_FIELD, ACTION_STALE_HEADER, ACTION_TAG, BLOB_TAG, BOUND_FIELD, CALL_FIELD, CHUNK_SCRIPT_TYPE, EncodeError, FORM_DATA_TAG, FORM_FIELD_PREFIX, FORM_REF_PREFIX, FORM_STATE_SCRIPT_TYPE, HTML_ELEMENT, HYDRATED_ATTRIBUTE, ID_POSITION_ATTRIBUTE, ISLAND_ELEMENT, LAYOUTS_HEADER, MAX_HELD_VALUES, NOT_A_VALUE, OBJECT_TAG, PROMISE_SCRIPT_TYPE, PROMISE_TAG, PROPS_SCRIPT_TYPE, REFERENCE_TAG, RENDER_HEADER, SLOT_ELEMENT, SLOT_TAG, SLOT_TEMPLATE_ELEMENT, SLOT_TREE_FIELD, TAG, TAG_BOUND, TAG_VALUE, TREE_SCRIPT_TYPE, VALUES_HEADER, VALUE_KEY_PATTERN, VALUE_SCRIPT_TYPE, attachmentField, decode, decodeTagged, encode, encodeLeaf, formFieldName, fromBase64, getTag, needsObjectTag, plainObject, readPostedAction, stripRuntimeFields, tagged, toBase64 };
@@ -1,5 +1,5 @@
1
1
  import { a as scheduleHydration, i as isIslandStrategy, n as IslandStrategy, r as ScheduleOptions, t as ISLAND_STRATEGIES } from "../_chunks/schedule-Dw14dW0H.mjs";
2
- import { m as HYDRATED_ATTRIBUTE } from "../_chunks/wire-Dipqh-EB.mjs";
2
+ import { m as HYDRATED_ATTRIBUTE } from "../_chunks/wire-1d6wqOia.mjs";
3
3
  import { t as ValueStore } from "../_chunks/value-store-Dm-7xJ6W.mjs";
4
4
  import { a as ServerTreeLayoutOptions, c as createServerTreeLayout, g as isolateIslands, i as ServerTreeLayout, n as PAYLOAD_ONLY_ATTRIBUTE, r as ServerTreeElementOptions, s as createServerTreeElement, u as updateServerTrees, v as withinClientRoot } from "../_chunks/tree-CV13RsJv.mjs";
5
5
  import * as React from "react";
@@ -1,9 +1,8 @@
1
- import { d as valueHeaders, o as emit, t as createServerReference, u as getValueStore } from "../_chunks/actions-C-IwUCKU.mjs";
2
- import { i as decodeTagged, n as NOT_A_VALUE, r as decode, u as setOwn } from "../_chunks/codec-C8to-RQW.mjs";
3
- import { F as getTag, f as FORM_STATE_SCRIPT_TYPE, h as ISLAND_ELEMENT, m as HYDRATED_ATTRIBUTE, w as SLOT_ELEMENT, x as PROPS_SCRIPT_TYPE, y as PROMISE_SCRIPT_TYPE } from "../_chunks/wire-QEQWBr5s.mjs";
4
- import { i as getContexts, o as isolateIslands, u as withinClientRoot } from "../_chunks/island-DXAGP4FN.mjs";
5
- import { i as createServerTreeLayout, n as PAYLOAD_ONLY_ATTRIBUTE, o as updateServerTrees, r as createServerTreeElement } from "../_chunks/tree-BQphP23Y.mjs";
6
- import { n as isIslandStrategy, r as scheduleHydration, t as ISLAND_STRATEGIES } from "../_chunks/schedule-Cwn9vQL0.mjs";
1
+ import { d as valueHeaders, o as emit, t as createServerReference, u as getValueStore } from "../_chunks/actions-DAzd4PpV.mjs";
2
+ import { i as decodeTagged, n as NOT_A_VALUE, r as decode, u as setOwn } from "../_chunks/codec-DDpUvgRo.mjs";
3
+ import { D as SLOT_TEMPLATE_ELEMENT, R as getTag, S as PROPS_SCRIPT_TYPE, T as SLOT_ELEMENT, b as PROMISE_SCRIPT_TYPE, f as FORM_STATE_SCRIPT_TYPE, g as ISLAND_ELEMENT, m as HYDRATED_ATTRIBUTE } from "../_chunks/wire-UUwZlUJZ.mjs";
4
+ import { _ as atIdPosition, a as isolateIslands, d as PAYLOAD_ONLY_ATTRIBUTE, f as createServerTreeElement, g as updateServerTrees, i as getContexts, l as withinClientRoot, m as createSlotTree, p as createServerTreeLayout, v as parseIdPosition } from "../_chunks/island-viWIOM1k.mjs";
5
+ import { n as isIslandStrategy, r as scheduleHydration, t as ISLAND_STRATEGIES } from "../_chunks/schedule-IK9_RwZC.mjs";
7
6
  import * as React from "react";
8
7
  import { hydrateRoot } from "react-dom/client";
9
8
  // src/react/hydrate.ts
@@ -39,6 +38,37 @@ function readFormState(document) {
39
38
  */
40
39
  const revivedValues = /* @__PURE__ */ new WeakMap();
41
40
  let slotsRevived = 0;
41
+ /**
42
+ * A slot's server HTML: inside the island where it placed the slot, or in the template after its
43
+ * props for a slot it had not placed.
44
+ */
45
+ function findSlot(container, name) {
46
+ for (const slot of container.querySelectorAll(SLOT_ELEMENT)) if (slot.getAttribute("name") === name) return slot;
47
+ const id = container.getAttribute("props");
48
+ for (const template of container.ownerDocument.querySelectorAll(`${SLOT_TEMPLATE_ELEMENT}[for]`)) {
49
+ if (template.getAttribute("for") !== id) continue;
50
+ for (const slot of template.content.querySelectorAll(SLOT_ELEMENT)) if (slot.getAttribute("name") === name) return slot;
51
+ }
52
+ return null;
53
+ }
54
+ /** Each island's slots that carry server trees, rebuilt before the island hydrates. */
55
+ const preparedSlots = /* @__PURE__ */ new WeakMap();
56
+ /** The names of the slots in `value` that carry server trees. */
57
+ function collectTreeSlots(value, names, seen = /* @__PURE__ */ new Set()) {
58
+ if (!value || typeof value !== "object" || seen.has(value)) return;
59
+ seen.add(value);
60
+ const object = value;
61
+ if (object["$"] === "s" && object["t"] === 1 && typeof object["v"] === "string") {
62
+ names.add(object["v"]);
63
+ return;
64
+ }
65
+ for (const entry of Array.isArray(value) ? value : Object.values(object)) collectTreeSlots(entry, names, seen);
66
+ }
67
+ /** Whether `container` sits inside another island below `scope`. */
68
+ function insideAnotherIsland(container, scope) {
69
+ for (let node = container.parentElement; node && node !== scope; node = node.parentElement) if (node.matches(ISLAND_SELECTOR)) return true;
70
+ return false;
71
+ }
42
72
  /** Turns travelled props back into values: slots keep their server HTML, actions become callable. */
43
73
  function revive(value, container, values) {
44
74
  if (value && typeof value === "object") {
@@ -70,11 +100,16 @@ function reviveUncached(value, container, values) {
70
100
  if (tag === "s" && typeof object["v"] === "string") {
71
101
  slotsRevived++;
72
102
  const name = object["v"];
73
- let html = "";
74
- for (const slot of container.querySelectorAll(SLOT_ELEMENT)) if (slot.getAttribute("name") === name) {
75
- html = slot.innerHTML;
76
- break;
103
+ if (object["t"] === 1) {
104
+ const tree = preparedSlots.get(container)?.get(name);
105
+ if (tree === void 0) throw new Error(`the server tree of slot ${name} was not prepared`);
106
+ return React.createElement(SLOT_ELEMENT, {
107
+ key: name,
108
+ name,
109
+ style: { display: "contents" }
110
+ }, tree);
77
111
  }
112
+ const html = findSlot(container, name)?.innerHTML ?? "";
78
113
  return React.createElement(SLOT_ELEMENT, {
79
114
  key: name,
80
115
  name,
@@ -277,14 +312,43 @@ function createHydrationRuntime(options) {
277
312
  }, [onCommit]);
278
313
  return children;
279
314
  }
280
- const element = (Component, props, restore, onCommit) => {
281
- const { graph } = getContexts();
282
- const inner = React.createElement(Component, props);
283
- return React.createElement(graph.Provider, { value: true }, React.createElement(Boundary, { onError: restore }, React.createElement(Committed, {
315
+ const element = (container, Component, props, restore, position, onCommit) => {
316
+ const { graph, container: containerContext } = getContexts();
317
+ const component = React.createElement(Component, props);
318
+ const inner = position && atIdPosition(position, component) || component;
319
+ return React.createElement(graph.Provider, { value: true }, React.createElement(containerContext.Provider, { value: container }, React.createElement(Boundary, { onError: restore }, React.createElement(Committed, {
284
320
  onCommit,
285
321
  children: options.wrap ? options.wrap(inner) : inner
286
- })));
322
+ }))));
287
323
  };
324
+ const ServerHtml = createServerHtml({
325
+ hydrate,
326
+ dispose
327
+ });
328
+ /** Rebuilds the server trees of an island's slots, loading their client modules. */
329
+ async function prepareSlots(container, id) {
330
+ const text = findPropsScript(container, id)?.textContent ?? "";
331
+ if (!text.includes(`"t":1`)) return;
332
+ let parsed = JSON.parse(text);
333
+ if (text.includes(`"\$":"r"`)) {
334
+ values.ingest(container.ownerDocument);
335
+ parsed = values.resolve(parsed);
336
+ }
337
+ const names = /* @__PURE__ */ new Set();
338
+ collectTreeSlots(parsed, names);
339
+ const trees = /* @__PURE__ */ new Map();
340
+ await Promise.all(Array.from(names, async (name) => {
341
+ const slot = findSlot(container, name);
342
+ const tree = slot && await createSlotTree(slot, name, {
343
+ load: options.load,
344
+ ServerHtml,
345
+ values
346
+ });
347
+ if (!tree) throw new Error(`slot ${name} has no server tree`);
348
+ trees.set(name, tree);
349
+ }));
350
+ preparedSlots.set(container, trees);
351
+ }
288
352
  /** An island's props, with values, slots and actions revived. */
289
353
  function readProps(container, id) {
290
354
  const script = findPropsScript(container, id);
@@ -310,7 +374,7 @@ function createHydrationRuntime(options) {
310
374
  if (scope instanceof Document) watchStream(scope);
311
375
  const candidates = Array.from(scope.querySelectorAll(ISLAND_SELECTOR));
312
376
  if (scope instanceof Element && scope.matches(ISLAND_SELECTOR)) candidates.unshift(scope);
313
- const islands = candidates.filter((container) => !roots.has(container) && !pending.has(container) && !container.parentElement?.closest(ISLAND_SELECTOR) && !container.closest(STREAM_STAGING) && !awaitsStreamedContent(container));
377
+ const islands = candidates.filter((container) => !roots.has(container) && !pending.has(container) && !insideAnotherIsland(container, scope) && !container.closest(STREAM_STAGING) && !awaitsStreamedContent(container));
314
378
  await Promise.all(islands.map(async (container) => {
315
379
  const src = container.getAttribute("src");
316
380
  const id = container.getAttribute("props");
@@ -348,7 +412,10 @@ function createHydrationRuntime(options) {
348
412
  if (controller.signal.aborted || !container.isConnected) return;
349
413
  const Component = module[exportName];
350
414
  if (typeof Component !== "function" && (typeof Component !== "object" || Component === null)) throw new Error(`${src} has no export ${exportName}`);
415
+ await prepareSlots(container, id);
416
+ if (controller.signal.aborted || !container.isConnected) return;
351
417
  const props = readProps(container, id);
418
+ const position = parseIdPosition(findPropsScript(container, id)?.getAttribute("ids"));
352
419
  let failure;
353
420
  const restore = (error) => {
354
421
  if (failure !== void 0) return;
@@ -364,8 +431,9 @@ function createHydrationRuntime(options) {
364
431
  strategy,
365
432
  duration: performance.now() - scheduledAt
366
433
  });
367
- const root = hydrateRoot(container, element(Component, props, restore, onCommit), {
434
+ const root = hydrateRoot(container, element(container, Component, props, restore, position, onCommit), {
368
435
  formState,
436
+ ...position ? { identifierPrefix: position.prefix } : {},
369
437
  onUncaughtError: restore,
370
438
  onRecoverableError(error) {
371
439
  if (disposing && isEarlyUpdate(error)) return;
@@ -374,6 +442,7 @@ function createHydrationRuntime(options) {
374
442
  }
375
443
  });
376
444
  roots.set(container, {
445
+ position,
377
446
  root,
378
447
  Component,
379
448
  src,
@@ -433,7 +502,7 @@ function createHydrationRuntime(options) {
433
502
  if (!previous || !record || !id) continue;
434
503
  try {
435
504
  const props = readProps(container, id);
436
- record.root.render(element(record.Component, props, record.restore));
505
+ record.root.render(element(previous, record.Component, props, record.restore, record.position));
437
506
  record.props = props;
438
507
  container.replaceWith(previous);
439
508
  carried++;
@@ -454,7 +523,7 @@ function createHydrationRuntime(options) {
454
523
  continue;
455
524
  }
456
525
  record.Component = Component;
457
- record.root.render(element(record.Component, record.props, record.restore));
526
+ record.root.render(element(container, record.Component, record.props, record.restore, record.position));
458
527
  updated++;
459
528
  }
460
529
  return updated;
@@ -1,12 +1,11 @@
1
- import { a as encode } from "../_chunks/codec-C8to-RQW.mjs";
2
- import { f as FORM_STATE_SCRIPT_TYPE } from "../_chunks/wire-QEQWBr5s.mjs";
1
+ import { a as encode } from "../_chunks/codec-DDpUvgRo.mjs";
2
+ import { f as FORM_STATE_SCRIPT_TYPE } from "../_chunks/wire-UUwZlUJZ.mjs";
3
3
  import { RUNTIME_GLOBAL } from "../boot.mjs";
4
4
  import { r as PREHYDRATION_SCRIPT } from "../_chunks/prehydration-zEYsfFxW.mjs";
5
- import { i as encodeActionReference } from "../_chunks/actions-CvQ0-zjg.mjs";
5
+ import { i as encodeActionReference } from "../_chunks/actions-DzIPDecd.mjs";
6
6
  import { t as getBuildDefaults } from "../_chunks/build-COIcs7wm.mjs";
7
- import { a as parseHeldValues, n as addressValues, o as selectValuesToSend, r as escapeScriptJson } from "../_chunks/values-37UIzxM0.mjs";
8
- import { c as setIslandServerHook, i as getContexts, l as setRenderStateResolver, n as createIsland, o as isolateIslands, r as getClientReference, s as runtimeTagged, t as IslandsProvider, u as withinClientRoot } from "../_chunks/island-DXAGP4FN.mjs";
9
- import { a as renderServerTree, n as PAYLOAD_ONLY_ATTRIBUTE, t as Outlet } from "../_chunks/tree-BQphP23Y.mjs";
7
+ import { a as parseHeldValues, n as addressValues, o as selectValuesToSend, r as escapeScriptJson } from "../_chunks/values-gxhIei_m.mjs";
8
+ import { a as isolateIslands, c as setRenderStateResolver, d as PAYLOAD_ONLY_ATTRIBUTE, h as renderServerTree, i as getContexts, l as withinClientRoot, n as createIsland, o as runtimeTagged, r as getClientReference, s as setIslandServerHook, t as IslandsProvider, u as Outlet } from "../_chunks/island-viWIOM1k.mjs";
10
9
  import * as React from "react";
11
10
  // src/react/server.ts
12
11
  /**
package/dist/react.d.mts CHANGED
@@ -1,3 +1,7 @@
1
1
  import { f as IslandRenderState, g as isolateIslands, l as renderServerTree, m as createIsland, o as ServerTreeRenderOptions, p as IslandsProvider, t as Outlet, v as withinClientRoot } from "./_chunks/tree-CV13RsJv.mjs";
2
2
  import { n as IslandStrategy } from "./_chunks/schedule-Dw14dW0H.mjs";
3
- export { type IslandRenderState, type IslandStrategy, IslandsProvider, Outlet, type ServerTreeRenderOptions, createIsland, isolateIslands, renderServerTree, withinClientRoot };
3
+ import * as ReactDOM from "react-dom";
4
+
5
+ // src/react/form-status.d.ts
6
+ declare function useFormStatus(): ReactDOM.FormStatus;
7
+ export { type IslandRenderState, type IslandStrategy, IslandsProvider, Outlet, type ServerTreeRenderOptions, createIsland, isolateIslands, renderServerTree, useFormStatus, withinClientRoot };
package/dist/react.mjs CHANGED
@@ -1,3 +1,22 @@
1
- import { n as createIsland, o as isolateIslands, t as IslandsProvider, u as withinClientRoot } from "./_chunks/island-DXAGP4FN.mjs";
2
- import { a as renderServerTree, t as Outlet } from "./_chunks/tree-BQphP23Y.mjs";
3
- export { IslandsProvider, Outlet, createIsland, isolateIslands, renderServerTree, withinClientRoot };
1
+ import { a as isolateIslands, h as renderServerTree, i as getContexts, l as withinClientRoot, n as createIsland, t as IslandsProvider, u as Outlet } from "./_chunks/island-viWIOM1k.mjs";
2
+ import { i as subscribeServerForms, r as getServerFormStatus, t as IDLE_FORM_STATUS } from "./_chunks/forms-CCDY9QHC.mjs";
3
+ import * as React from "react";
4
+ import * as ReactDOM from "react-dom";
5
+ // src/react/form-status.ts
6
+ /**
7
+ * `useFormStatus` for islands. React reports the status of the React `<form>` around a component,
8
+ * but a form written in a server component is server HTML: an island inside it is a React root of
9
+ * its own, with no form above it, so React's hook never sees the form submit. The compiler points
10
+ * client modules' `useFormStatus` from `react-dom` here.
11
+ *
12
+ * Forms do not nest, so an island inside a `<form>` element has no React form of its own around
13
+ * its components: that server form is the one, and `enhanceForms` reports its submissions.
14
+ * Anywhere else this is React's hook.
15
+ */
16
+ function useFormStatus() {
17
+ const status = ReactDOM.useFormStatus();
18
+ const form = React.useContext(getContexts().container)?.parentElement?.closest("form") ?? null;
19
+ const server = React.useSyncExternalStore(subscribeServerForms, () => form ? getServerFormStatus(form) : IDLE_FORM_STATUS, () => IDLE_FORM_STATUS);
20
+ return form ? server : status;
21
+ }
22
+ export { IslandsProvider, Outlet, createIsland, isolateIslands, renderServerTree, useFormStatus, withinClientRoot };
package/dist/server.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { a as parseHeldValues, i as hashValue, n as addressValues, o as selectValuesToSend, r as escapeScriptJson, t as VALUE_MIN_LENGTH } from "./_chunks/values-37UIzxM0.mjs";
2
- import { a as getActionReference, c as resolveAction, d as generateActionKey, f as sealBound, i as encodeActionReference, l as SealError, n as configureActionKeys, o as registerInlineAction, p as unsealBound, r as decodeActionReference, s as registerServerReference, t as bindInlineAction, u as createActionKeys } from "./_chunks/actions-CvQ0-zjg.mjs";
3
- import { a as encode, r as decode } from "./_chunks/codec-C8to-RQW.mjs";
4
- import { I as readPostedAction, L as stripRuntimeFields, N as attachmentField, n as ACTION_KEY_FIELD, o as BOUND_FIELD, r as ACTION_STALE_HEADER, s as CALL_FIELD, t as ACTION_HEADER } from "./_chunks/wire-QEQWBr5s.mjs";
1
+ import { a as parseHeldValues, i as hashValue, n as addressValues, o as selectValuesToSend, r as escapeScriptJson, t as VALUE_MIN_LENGTH } from "./_chunks/values-gxhIei_m.mjs";
2
+ import { a as getActionReference, c as resolveAction, d as generateActionKey, f as sealBound, i as encodeActionReference, l as SealError, n as configureActionKeys, o as registerInlineAction, p as unsealBound, r as decodeActionReference, s as registerServerReference, t as bindInlineAction, u as createActionKeys } from "./_chunks/actions-DzIPDecd.mjs";
3
+ import { a as encode, r as decode } from "./_chunks/codec-DDpUvgRo.mjs";
4
+ import { B as stripRuntimeFields, I as attachmentField, n as ACTION_KEY_FIELD, o as BOUND_FIELD, r as ACTION_STALE_HEADER, s as CALL_FIELD, t as ACTION_HEADER, z as readPostedAction } from "./_chunks/wire-UUwZlUJZ.mjs";
5
5
  import { n as setBuildDefaults, t as getBuildDefaults } from "./_chunks/build-COIcs7wm.mjs";
6
6
  // src/server/hooks.ts
7
7
  const HOOKS_KEY = Symbol.for("islx.server.hooks");
@@ -1,6 +1,6 @@
1
- import { t as IslandsProvider } from "../_chunks/island-DXAGP4FN.mjs";
2
- import { A as VALUES_HEADER, C as RENDER_HEADER } from "../_chunks/wire-QEQWBr5s.mjs";
3
- import { a as parseHeldValues } from "../_chunks/values-37UIzxM0.mjs";
1
+ import { t as IslandsProvider } from "../_chunks/island-viWIOM1k.mjs";
2
+ import { N as VALUES_HEADER, w as RENDER_HEADER } from "../_chunks/wire-UUwZlUJZ.mjs";
3
+ import { a as parseHeldValues } from "../_chunks/values-gxhIei_m.mjs";
4
4
  import * as React from "react";
5
5
  import { StartServer } from "@tanstack/react-start/server";
6
6
  import { createSsrStreamResponse, defineHandlerCallback, getSsrStatus, renderRouterToStream, transformReadableStreamWithRouter } from "@tanstack/react-router/ssr/server";
@@ -1,4 +1,4 @@
1
- import { n as ENTRY_ID, r as islx } from "./_chunks/vite-0bH_ZDys.mjs";
1
+ import { n as ENTRY_ID, r as islx } from "./_chunks/vite-CHB6B8tP.mjs";
2
2
  import { normalizePath } from "vite";
3
3
  // src/tanstack-start/index.ts
4
4
  /**
package/dist/vite.mjs CHANGED
@@ -1 +1 @@
1
- export { t as BOOT_ID, n as ENTRY_ID, r as default, r as islx, i as resolveDirectives, a as serializeHooks } from "./_chunks/vite-0bH_ZDys.mjs";
1
+ export { t as BOOT_ID, n as ENTRY_ID, r as default, r as islx, i as resolveDirectives, a as serializeHooks } from "./_chunks/vite-CHB6B8tP.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farm.js/islx",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "A renderer-agnostic wire format for server-rendered islands: typed props, values sent once, server actions, and partial navigations.",
5
5
  "keywords": [
6
6
  "islands",