@ilha/astro 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -1,7 +1,22 @@
1
+ import ilha, { raw } from "ilha";
2
+
1
3
  //#region src/client.ts
4
+ const RAW = Symbol.for("ilha.raw");
2
5
  function isMountable(Component) {
3
6
  return !!Component && typeof Component.mount === "function";
4
7
  }
8
+ function isRawHtml(value) {
9
+ return !!(value && typeof value === "object" && RAW in value);
10
+ }
11
+ function wrapPlainAsIsland(Component, merged) {
12
+ return ilha.render(() => {
13
+ const result = Component(merged);
14
+ if (result == null) return raw("");
15
+ if (typeof result === "string") return raw(result);
16
+ if (isRawHtml(result)) return raw(result.value);
17
+ return raw("");
18
+ });
19
+ }
5
20
  var client_default = (element) => async (Component, props, slotted, _metadata) => {
6
21
  if (!element.hasAttribute("ssr")) {
7
22
  if (isMountable(Component)) {
@@ -19,6 +34,16 @@ var client_default = (element) => async (Component, props, slotted, _metadata) =
19
34
  if (typeof Component !== "function") return;
20
35
  const merged = { ...props };
21
36
  for (const [name, value] of Object.entries(slotted ?? {})) merged[name === "default" ? "children" : name] = value;
37
+ const nestedHost = element.querySelector("[data-ilha]");
38
+ if (nestedHost?.querySelector("[data-ilha-slot]")) {
39
+ try {
40
+ const unmount = wrapPlainAsIsland(Component, merged).mount(nestedHost);
41
+ element.addEventListener("astro:unmount", () => unmount(), { once: true });
42
+ } catch {
43
+ throw new Error(`[@ilha/astro] Failed to mount nested islands inside plain component — expected a function that returns ilha RawHtml/string.`);
44
+ }
45
+ return;
46
+ }
22
47
  try {
23
48
  Component(merged);
24
49
  } catch {
package/dist/server.js CHANGED
@@ -1,3 +1,5 @@
1
+ import ilha, { raw } from "ilha";
2
+
1
3
  //#region src/server.ts
2
4
  const ISLAND = Symbol.for("ilha.island");
3
5
  const RAW = Symbol.for("ilha.raw");
@@ -7,6 +9,28 @@ function isIsland(Component) {
7
9
  function isRawHtml(value) {
8
10
  return !!(value && typeof value === "object" && RAW in value);
9
11
  }
12
+ function resultToHtml(result) {
13
+ if (typeof result === "string") return result;
14
+ if (isRawHtml(result)) return result.value;
15
+ }
16
+ /** True when plain SSR emitted nested island slot hosts that need a parent mount ctx. */
17
+ function hasNestedIslandSlots(html) {
18
+ return html.includes("data-ilha-slot");
19
+ }
20
+ /**
21
+ * Wrap a plain function so its render runs under an island render ctx.
22
+ * Nested islands then get unique `data-ilha-slot` ids and can be mounted
23
+ * when the shell hydrates on the client.
24
+ */
25
+ function wrapPlainAsIsland(Component, merged) {
26
+ return ilha.render(() => {
27
+ const result = Component(merged);
28
+ if (result == null) return raw("");
29
+ if (typeof result === "string") return raw(result);
30
+ if (isRawHtml(result)) return raw(result.value);
31
+ return raw("");
32
+ });
33
+ }
10
34
  function toRawHtml(value) {
11
35
  return {
12
36
  [RAW]: true,
@@ -33,12 +57,21 @@ async function resolveProps(props) {
33
57
  for (const [key, value] of Object.entries(props)) resolved[key] = await resolvePropValue(value);
34
58
  return resolved;
35
59
  }
36
- async function renderPlainComponent(Component, props, slots) {
60
+ async function mergePlainProps(props, slots) {
37
61
  const merged = await resolveProps(props);
38
62
  for (const [name, value] of Object.entries(slots)) merged[name === "default" ? "children" : name] = toRawHtml(value);
39
- const result = Component(merged);
40
- if (typeof result === "string") return result;
41
- if (isRawHtml(result)) return result.value;
63
+ return merged;
64
+ }
65
+ async function renderPlainComponent(Component, props, slots, metadata) {
66
+ const merged = await mergePlainProps(props, slots);
67
+ const html = resultToHtml(Component(merged));
68
+ if (html === void 0) return void 0;
69
+ if (!hasNestedIslandSlots(html)) return html;
70
+ return wrapPlainAsIsland(Component, merged).hydratable({}, {
71
+ name: metadata?.displayName ?? "IlhaPlain",
72
+ snapshot: true,
73
+ skipOnMount: true
74
+ });
42
75
  }
43
76
  async function check(Component, props, slots) {
44
77
  if (isIsland(Component)) return true;
@@ -55,7 +88,7 @@ async function renderToStaticMarkup(Component, props, slots, metadata) {
55
88
  snapshot: true,
56
89
  skipOnMount: true
57
90
  }) };
58
- const html = await renderPlainComponent(Component, props, slots);
91
+ const html = await renderPlainComponent(Component, props, slots, metadata);
59
92
  if (html === void 0) throw new Error(`[@ilha/astro] Unable to render "${metadata?.displayName ?? "component"}" — expected an ilha island or a function returning ilha RawHtml/string.`);
60
93
  return { html };
61
94
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ilha/astro",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Astro integration for Ilha islands",
5
5
  "keywords": [
6
6
  "astro-component",
@@ -51,11 +51,11 @@
51
51
  "test": "bun test"
52
52
  },
53
53
  "devDependencies": {
54
- "astro": "^7.1.3",
55
- "ilha": "^0.9.5"
54
+ "astro": "^7.1.6",
55
+ "ilha": "^0.10.0"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "astro": "^7.0.0",
59
- "ilha": ">=0.9.5"
59
+ "ilha": ">=0.10.0"
60
60
  }
61
61
  }