@storyblok/astro 10.0.1 → 10.2.0

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.
@@ -6,9 +6,8 @@ interface Props extends SbAstroRichTextRenderContext {
6
6
  document: SbRichTextInput;
7
7
  }
8
8
 
9
- const { document, components, optimizeImage } = Astro.props;
10
-
9
+ const { document, components, optimizeImage, data } = Astro.props;
11
10
  const nodes = normalizeNodes(document);
12
11
  ---
13
12
 
14
- <RenderChildren nodes={nodes} options={{ components, optimizeImage }} />
13
+ <RenderChildren nodes={nodes} options={{ components, optimizeImage, data }} />
@@ -20,7 +20,7 @@ const Custom = components ? components[linkMark.type] : undefined;
20
20
 
21
21
  {
22
22
  isValidAstroComponent(Custom) ? (
23
- <Custom {...linkMark}>
23
+ <Custom {...linkMark} context={options}>
24
24
  <RenderLinkInner nodes={nodes} options={options} />
25
25
  </Custom>
26
26
  ) : (
@@ -19,16 +19,22 @@ interface Props {
19
19
  }
20
20
  const { node, options } = Astro.props;
21
21
  const components = options.components;
22
- const Custom = components && node.type !== 'text' ? components[node.type] : undefined;
22
+ const Custom = components ? components[node.type] : undefined;
23
+
24
+ // When passing context to a custom component, exclude that component type
25
+ // to prevent infinite loops if the custom component uses StoryblokRichText internally
26
+ const contextForCustom = Custom
27
+ ? { ...options, components: { ...components, [node.type]: undefined } }
28
+ : options;
23
29
  ---
24
30
 
25
31
  {
26
- node.type === 'text' ? (
27
- <RenderTextNodeWithMarks node={node} marks={node.marks} options={options} />
28
- ) : isValidAstroComponent(Custom) ? (
29
- <Custom {...node} context={options}>
30
- {node.content && <RenderChildren nodes={node.content} options={options} />}
32
+ isValidAstroComponent(Custom) ? (
33
+ <Custom {...node} context={contextForCustom}>
34
+ {node.type !== 'text' && node.content && <RenderChildren nodes={node.content} options={options} />}
31
35
  </Custom>
36
+ ) : node.type === 'text' ? (
37
+ <RenderTextNodeWithMarks node={node} marks={node.marks} options={options} />
32
38
  ) : node.type === 'image' ? (
33
39
  <RenderImage node={node} options={options} />
34
40
  ) : node.type === 'blok' ? (
@@ -23,7 +23,7 @@ const MarkComponent = mark && components ? components[mark.type] : undefined;
23
23
  reversedMarks.length === 0 ? (
24
24
  node.text
25
25
  ) : isValidAstroComponent(MarkComponent) ? (
26
- <MarkComponent {...mark}>
26
+ <MarkComponent {...mark} context={options}>
27
27
  <Astro.self node={node} marks={rest} options={options} />
28
28
  </MarkComponent>
29
29
  ) : (
package/dist/index.js CHANGED
@@ -113,13 +113,15 @@ function C(e, t, n, r) {
113
113
  };
114
114
  }
115
115
  function w(e, t, n) {
116
+ let r = `${s(e)}/storyblok/**/*.astro`, i = [...n];
117
+ t && i.push(t);
118
+ let a = i.map((e) => e.importStatement), o = i.map((e) => e.wrapperDefinition), c = i.map((e) => e.registrationCall);
116
119
  return `
117
- // Import utilities and fallback component
118
120
  import { toCamelCase } from '@storyblok/astro';
121
+ ${a.join("\n ")}
122
+
123
+ const modules = import.meta.glob('${r}', { eager: true });
119
124
 
120
- // Dynamically import all Storyblok components using Vite's glob import
121
- const modules = import.meta.glob('${`${s(e)}/storyblok/**/*.astro`}', { eager: true });
122
- // Process imported modules into a components object
123
125
  const storyblokComponents = {};
124
126
  const createComponentLoader = (module) => {
125
127
  return async () => module?.default ?? module;
@@ -131,25 +133,24 @@ function w(e, t, n) {
131
133
  get: () => createComponentLoader(component),
132
134
  });
133
135
  };
136
+
134
137
  for (const filePath in modules) {
135
- // Extract component name from file path (remove extension)
136
138
  const fileName = filePath.split('/').pop();
137
- const componentName = toCamelCase(fileName?.replace(/\.[^/.]+$/, '') ?? '');
139
+ const componentName = toCamelCase(fileName?.replace(/\\.[^/.]+$/, '') ?? '');
138
140
  if (componentName) {
139
141
  registerComponent(componentName, modules[filePath]);
140
142
  }
141
143
  }
142
-
143
- // Manual components
144
- ${n.join("\n\n")}
145
- // Add fallback component if enabled
146
- ${t}
147
- // Export the components object for use in Storyblok initialization
144
+
145
+ ${o.join("\n ")}
146
+
147
+ ${c.join("\n ")}
148
+
148
149
  export { storyblokComponents };
149
150
  `.trim();
150
151
  }
151
152
  async function ee(e, t, n, r) {
152
- if (!n) return "";
153
+ if (!n) return null;
153
154
  if (!r) return D({
154
155
  componentName: "FallbackComponent",
155
156
  importPath: "@storyblok/astro/FallbackComponent.astro"
@@ -181,10 +182,12 @@ function E(e, t) {
181
182
  return o(`${s(e)}${s(t)}`);
182
183
  }
183
184
  function D({ componentName: e, importPath: t }) {
184
- return `
185
- import ${e} from '${t}';
186
- registerComponent('${e}', ${e});
187
- `.trim();
185
+ let n = `__${e}_component__`, r = `__${e}_wrapper__`;
186
+ return {
187
+ importStatement: `import ${n} from '${t}';`,
188
+ wrapperDefinition: `const ${r} = { get default() { return ${n}; } };`,
189
+ registrationCall: `registerComponent('${e}', ${r});`
190
+ };
188
191
  }
189
192
  //#endregion
190
193
  //#region src/lib/storyblok-integration.ts
@@ -949,13 +952,22 @@ function dt(e, t) {
949
952
  return n?.length ? pt(n, t) : "";
950
953
  }
951
954
  function q(e, t) {
955
+ let n = e.type !== "text" && e.content ? pt(e.content, t) : "", r = t?.renderers?.[e.type];
956
+ if (r) {
957
+ let i = t?.renderers?.[e.type] ? {
958
+ ...t,
959
+ renderers: {
960
+ ...t.renderers,
961
+ [e.type]: void 0
962
+ }
963
+ } : t;
964
+ return r({
965
+ ...e,
966
+ children: n,
967
+ context: i
968
+ });
969
+ }
952
970
  if (e.type === "text") return mt(e, e.marks, t);
953
- let n = e.content ? pt(e.content, t) : "", r = t?.renderers?.[e.type];
954
- if (r) return r({
955
- ...e,
956
- children: n,
957
- context: t
958
- });
959
971
  if (e.type === "blok") return console.warn("\"blok\" nodes require a custom renderer in renderRichText."), "";
960
972
  let i = G(e);
961
973
  if (!i) return n;
@@ -1001,7 +1013,8 @@ function ht(e, t, n) {
1001
1013
  let r = n?.renderers?.[t.type];
1002
1014
  if (r) return r({
1003
1015
  ...t,
1004
- children: e
1016
+ children: e,
1017
+ context: n
1005
1018
  });
1006
1019
  let i = G(t);
1007
1020
  return i ? `<${i}${J(t.type, t.attrs)}>${e}</${i}>` : e;
@@ -1015,7 +1028,8 @@ function gt(e, t, n, r, i) {
1015
1028
  let o = i?.renderers?.[r.type];
1016
1029
  if (o) return o({
1017
1030
  ...r,
1018
- children: a
1031
+ children: a,
1032
+ context: i
1019
1033
  });
1020
1034
  let s = G(r);
1021
1035
  return s ? `<${s}${J(r.type, r.attrs)}>${a}</${s}>` : a;
@@ -1611,7 +1625,7 @@ var Ht = class {
1611
1625
  }
1612
1626
  return { storyblokApi: new Ut(t) };
1613
1627
  }, Jt = (e) => {
1614
- if (typeof e != "object" || typeof e._editable > "u") return {};
1628
+ if (typeof e != "object" || typeof e._editable != "string") return {};
1615
1629
  try {
1616
1630
  let t = JSON.parse(e._editable.replace(/^<!--#storyblok#/, "").replace(/-->$/, ""));
1617
1631
  return t ? {
@@ -6,6 +6,7 @@ export type SbAstroRichTextComponentMap = {
6
6
  export interface SbAstroRichTextRenderContext {
7
7
  optimizeImage?: boolean | SbRichTextImageOptions;
8
8
  components?: SbAstroRichTextComponentMap;
9
+ data?: unknown;
9
10
  }
10
11
  export type SbAstroRichTextProps<T extends SbRichTextElement> = SbRichTextElementByType<SbAstroRichTextRenderContext>[T];
11
12
  export declare function isValidAstroComponent(component: unknown): component is AstroComponentFactory;
@@ -1,8 +1,32 @@
1
1
  import { Plugin } from 'vite';
2
2
  /**
3
- * Vite plugin that automatically imports Storyblok components from a specified directory
4
- * and merges them with optional user-provided component mappings.
5
- *
6
- * @returns Vite plugin object
3
+ * Vite plugin that auto-imports Storyblok components from a directory
4
+ * and merges them with user-provided component mappings.
7
5
  */
8
6
  export declare function vitePluginImportStoryblokComponents(components: Record<string, string>, componentsDir: string, enableFallbackComponent: boolean, customFallbackComponent?: string): Plugin;
7
+ export interface ComponentRegistrationParts {
8
+ importStatement: string;
9
+ wrapperDefinition: string;
10
+ registrationCall: string;
11
+ }
12
+ /**
13
+ * Generates the virtual module code with:
14
+ * - Static imports at the top for proper hoisting
15
+ * - Glob-imported components from storyblok folder
16
+ * - Manual and fallback component registrations
17
+ */
18
+ export declare function generateModuleCode(componentsDir: string, fallbackRegistration: ComponentRegistrationParts | null, manualRegistrations: ComponentRegistrationParts[]): string;
19
+ interface CreateComponentRegistrationPartsOptions {
20
+ componentName: string;
21
+ importPath: string;
22
+ }
23
+ /**
24
+ * Generates structured registration parts for a component.
25
+ *
26
+ * Uses a getter wrapper to avoid TDZ (Temporal Dead Zone) errors.
27
+ * When Vite bundles modules, direct references to imported components
28
+ * can cause "Cannot access 'X' before initialization" errors.
29
+ * The getter defers access until the component is actually needed.
30
+ */
31
+ export declare function createComponentRegistrationParts({ componentName, importPath, }: CreateComponentRegistrationPartsOptions): ComponentRegistrationParts;
32
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@storyblok/astro",
3
3
  "type": "module",
4
- "version": "10.0.1",
4
+ "version": "10.2.0",
5
5
  "private": false,
6
6
  "description": "Official Astro integration for the Storyblok Headless CMS",
7
7
  "author": "Storyblok",
@@ -51,8 +51,8 @@
51
51
  "dependencies": {
52
52
  "camelcase": "^8.0.0",
53
53
  "morphdom": "^2.7.8",
54
- "@storyblok/richtext": "5.0.1",
55
- "@storyblok/js": "6.0.1"
54
+ "@storyblok/js": "6.2.0",
55
+ "@storyblok/richtext": "5.2.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@cypress/vite-dev-server": "^6.0.3",
@@ -73,7 +73,7 @@
73
73
  "vite-plugin-dts": "^4.5.3",
74
74
  "vite-plugin-static-copy": "^4.1.1",
75
75
  "vitest": "^3.1.3",
76
- "@storyblok/eslint-config": "0.5.1"
76
+ "@storyblok/eslint-config": "0.6.0"
77
77
  },
78
78
  "eslintConfig": {
79
79
  "env": {