@storyblok/astro 6.0.0-next.2 → 6.0.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.
package/README.md CHANGED
@@ -46,7 +46,7 @@ npm install @storyblok/astro
46
46
  ```
47
47
 
48
48
  > [!NOTE]
49
- > With pnpm, hoist Storyblok dependencies publicly with `.npmrc`. For more information, check pnpm documentation on [here](https://pnpm.io/npmrc).
49
+ > With pnpm, hoist Storyblok dependencies publicly with `.npmrc`. For more information, please refer to the [pnpm documentation](https://pnpm.io/npmrc).
50
50
 
51
51
  Add the following code to `astro.config.mjs` and replace the `accessToken` with the preview API token of your Storyblok space.
52
52
 
@@ -110,15 +110,15 @@ storyblok({
110
110
  ```
111
111
 
112
112
  > [!WARNING]
113
- > For spaces created in the United States or China, the `region` parameter **must** be specified.
113
+ > The `region` parameter **must** be specified unless the space was created in the EU.
114
114
 
115
115
  ## Getting started
116
116
 
117
117
  ### 1. Creating and linking your components to the Storyblok Visual Editor
118
118
 
119
- In order to link your Astro components to their equivalents you created in Storyblok:
119
+ Link your Astro components to their equivalents created in Storyblok with the following steps.
120
120
 
121
- First, you need to load them globally by specifying their name and their path in `astro.config.mjs`:
121
+ First, load the components globally by specifying their name and their path in `astro.config.mjs`:
122
122
 
123
123
  ```js
124
124
  components: {
@@ -164,7 +164,7 @@ const { blok } = Astro.props
164
164
  </div>
165
165
  ```
166
166
 
167
- Finally, you can use the provided `<StoryblokComponent>` for nested components; it will automatically render them (if they have been registered globally beforehand):
167
+ Finally, you can use the provided `<StoryblokComponent>` for nested components; it will automatically render them (if they are registered globally):
168
168
 
169
169
  ```jsx
170
170
  ---
@@ -219,7 +219,7 @@ const story = data.story;
219
219
  ```
220
220
 
221
221
  > [!NOTE]
222
- > The available methods are described in the [storyblok-js-client] repository(https://github.com/storyblok/storyblok-js-client#method-storyblokget)
222
+ > The available methods are described in the [storyblok-js-client](https://github.com/storyblok/storyblok-js-client#method-storyblokget) repository.
223
223
 
224
224
  #### Dynamic Routing
225
225
 
@@ -281,13 +281,77 @@ bridge: {
281
281
  - `resolveLinks` may be needed to resolve link fields.
282
282
 
283
283
  > [!NOTE]
284
- > `resolveRelations` and `resolveLinks` will not have any effect in Astro, since the Storyblok Bridge is configured to reload the page. Thus, all the requests needed will be performed after the reload.
284
+ > `resolveRelations` and `resolveLinks` will only become effective if the live preview feature is used (`getLiveStory()`).
285
285
 
286
286
  The provided options will be used when initializing the Storyblok Bridge. You can find more information about the Storyblok Bridge and its configuration options on the [In Depth Storyblok Bridge guide](https://www.storyblok.com/docs/guide/in-depth/storyblok-latest-js-v2?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro).
287
287
 
288
288
  If you want to deploy a dedicated preview environment with the Bridge enabled, allowing users of the Storyblok CMS to see their changes being reflected on the frontend directly without having to rebuild the static site, you can enable Server Side Rendering for that particular use case. More information can be found in the [Astro Docs](https://docs.astro.build/en/guides/server-side-rendering/).
289
289
 
290
- ### Rendering Rich Text
290
+ ## Enabling Live Preview for Storyblok's Visual Editor
291
+
292
+ The Astro SDK provides a live preview feature, designed to offer real-time editing capabilities for an enhanced user experience in Storyblok's Visual Editor.
293
+
294
+ > [!NOTE]
295
+ > To utilize the Astro Storyblok Live feature, Astro must be configured to run in SSR mode.
296
+
297
+ To activate the live preview feature, follow these steps:
298
+
299
+ 1. Set `livePreview` to `true` in your `astro.config.mjs` file.
300
+
301
+ ```js
302
+ //astro.config.mjs
303
+ export default defineConfig({
304
+ integrations: [
305
+ storyblok({
306
+ accessToken: "OsvN..",
307
+ livePreview: true,
308
+ }),
309
+ ],
310
+ output: "server", // Astro must be configured to run in SSR mode
311
+ });
312
+ ```
313
+
314
+ 2. Additionally, use `getLiveStory` on your Astro pages.
315
+
316
+ ```jsx
317
+ //pages/[...slug].astro
318
+ ---
319
+ import { getLiveStory, useStoryblokApi } from '@storyblok/astro';
320
+ import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
321
+
322
+ const { slug } = Astro.params;
323
+ let story = null;
324
+
325
+ const liveStory = await getLiveStory(Astro);
326
+ if (liveStory) {
327
+ story = liveStory;
328
+ } else {
329
+ const sbApi = useStoryblokApi();
330
+ const { data } = await sbApi.get(`cdn/stories/${slug || 'home'}`, {
331
+ version: 'draft',
332
+ resolve_relations: ['featured-articles.posts'],
333
+ });
334
+ story = data?.story;
335
+ }
336
+ // If you are using `resolve_relations` or `resolve_links`, you must also pass them to the Bridge configuration in `astro.config.mjs`.
337
+ ---
338
+
339
+ <StoryblokComponent blok={story.content} />
340
+ ```
341
+ ## Dom update event
342
+
343
+ ```js
344
+ //page.astro
345
+
346
+ <script>
347
+ document.addEventListener('storyblok-live-preview-updated', () => {
348
+ // Here is the callback we could run code every time the body is updated via live preview
349
+ console.log('Live preview: body updated');
350
+ // Example regenerated all your css
351
+ });
352
+ </script>
353
+ ```
354
+ ## Rendering Rich Text
291
355
 
292
356
  > [!NOTE]
293
357
  > While @storyblok/astro provides basic richtext rendering capabilities, for advanced use cases, it is highly recommended to use [storyblok-rich-text-astro-renderer](https://github.com/NordSecurity/storyblok-rich-text-astro-renderer).
@@ -346,62 +410,6 @@ const renderedRichText = renderRichText(blok.text, {
346
410
 
347
411
  Returns the instance of the `storyblok-js-client`.
348
412
 
349
- ## Enabling Live Preview for Storyblok's Visual Editor
350
-
351
- The Astro SDK now provides a live preview feature, designed to offer real-time editing capabilities for an enhanced user experience in Storyblok's Visual Editor.
352
-
353
- > [!NOTE]
354
- > To utilize the Astro Storyblok Live feature, Astro must be configured to run in SSR mode.
355
-
356
- To activate the experimental live preview feature, follow these steps:
357
-
358
- 1. Set `livePreview` to `true` within your `astro.config.mjs` file.
359
-
360
- ```js
361
- //astro.config.mjs
362
- export default defineConfig({
363
- integrations: [
364
- storyblok({
365
- accessToken: "OsvN..",
366
- livePreview: true,
367
- }),
368
- ],
369
- output: "server", // Astro must be configured to run in SSR mode
370
- });
371
- ```
372
-
373
- 2. Additionally, please use `getLiveStory` on your Astro pages for live story fetching.
374
-
375
- ```jsx
376
- //pages/[...slug].astro
377
- ---
378
- import {
379
- getLiveStory,
380
- useStoryblokApi,
381
- type ISbStoryData,
382
- } from '@storyblok/astro';
383
- import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
384
-
385
- const { slug } = Astro.params;
386
- let story: ISbStoryData | null = null;
387
-
388
- const liveStory = await getLiveStory(Astro);
389
- if (liveStory) {
390
- story = liveStory;
391
- } else {
392
- const sbApi = useStoryblokApi();
393
- const { data } = await sbApi.get(`cdn/stories/${slug || 'home'}`, {
394
- version: 'draft',
395
- resolve_relations: ['featured-articles.posts'],
396
- });
397
- story = data?.story;
398
- }
399
- // If you are using `resolve_relations` or `resolve_links`, you must also pass them to the Bridge configuration in `astro.config.mjs`.
400
- ---
401
-
402
- <StoryblokComponent blok={story.content} />
403
- ```
404
-
405
413
  ## The Storyblok JavaScript SDK Ecosystem
406
414
 
407
415
  ![A visual representation of the Storyblok JavaScript SDK Ecosystem](https://a.storyblok.com/f/88751/2400x1350/be4a4a4180/sdk-ecosystem.png/m/1200x0)
@@ -436,4 +444,4 @@ Please review our [Contributing Guidelines](https://github.com/storyblok/.github
436
444
 
437
445
  This project employs [semantic-release](https://semantic-release.gitbook.io/semantic-release/) to generate new versions based on commit messages, following the Angular Commit Message Convention.
438
446
 
439
- When using playgrounds during development, ensure the build is running in watch mode for an efficient workflow.
447
+ When using playgrounds during development, ensure the build is running in watch mode for an efficient workflow.
@@ -1,7 +1,7 @@
1
1
  import { ISbRichtext, ISbStoryData, SbRichTextOptions, StoryblokBridgeConfigV2, StoryblokClient } from '../types';
2
2
  import { AstroGlobal } from 'astro';
3
3
  export declare function useStoryblokApi(): StoryblokClient;
4
- export declare function getLiveStory(Astro: AstroGlobal): Promise<ISbStoryData<import('@storyblok/js').StoryblokComponentType<string> & {
4
+ export declare function getLiveStory(Astro: Readonly<AstroGlobal>): Promise<ISbStoryData<import('@storyblok/js').StoryblokComponentType<string> & {
5
5
  [index: string]: any;
6
6
  }> | null>;
7
7
  export declare function renderRichText(data?: ISbRichtext, options?: SbRichTextOptions): string;
@@ -6,7 +6,7 @@ export const onRequest = defineMiddleware(async ({ locals, request }, next) => {
6
6
  // First do a basic check if its coming from within storyblok
7
7
  const isStoryblokRequest
8
8
  = url.searchParams.has('_storyblok')
9
- && url.searchParams.has('_storyblok_c');
9
+ && url.searchParams.has('_storyblok_c');
10
10
 
11
11
  if (isStoryblokRequest) {
12
12
  try {
@@ -609,22 +609,20 @@ function je(r) {
609
609
  `
610
610
  ), e.bridge && !e.livePreview && o(
611
611
  "page",
612
- `
613
- import { loadStoryblokBridge } from "@storyblok/astro";
614
- loadStoryblokBridge().then(() => {
615
- const { StoryblokBridge, location } = window;
616
- ${t}
617
- storyblokInstance.on(["published", "change"], (event) => {
618
- if (!event.slugChanged) {
619
- location.reload(true);
620
- }
621
- });
612
+ `import { loadStoryblokBridge } from "@storyblok/astro";
613
+ loadStoryblokBridge().then(() => {
614
+ const { StoryblokBridge, location } = window;
615
+ ${t}
616
+ storyblokInstance.on(["published", "change"], (event) => {
617
+ if (!event.slugChanged) {
618
+ location.reload(true);
619
+ }
622
620
  });
621
+ });
623
622
  `
624
623
  ), e.livePreview && (o(
625
624
  "page",
626
- `
627
- import { loadStoryblokBridge, handleStoryblokMessage } from "@storyblok/astro";
625
+ `import { loadStoryblokBridge, handleStoryblokMessage } from "@storyblok/astro";
628
626
  loadStoryblokBridge().then(() => {
629
627
  const { StoryblokBridge, location } = window;
630
628
  ${t}
@@ -43,19 +43,17 @@ Detailed information can be found here: https://github.com/storyblok/storyblok-a
43
43
  }`),""}optimizeImages(e,t){let o=0,s=0,n="",a="";typeof t!="boolean"&&(typeof t.width=="number"&&t.width>0&&(n+=`width="${t.width}" `,o=t.width),typeof t.height=="number"&&t.height>0&&(n+=`height="${t.height}" `,s=t.height),(t.loading==="lazy"||t.loading==="eager")&&(n+=`loading="${t.loading}" `),typeof t.class=="string"&&t.class.length>0&&(n+=`class="${t.class}" `),t.filters&&(typeof t.filters.blur=="number"&&t.filters.blur>=0&&t.filters.blur<=100&&(a+=`:blur(${t.filters.blur})`),typeof t.filters.brightness=="number"&&t.filters.brightness>=-100&&t.filters.brightness<=100&&(a+=`:brightness(${t.filters.brightness})`),t.filters.fill&&(t.filters.fill.match(/[0-9A-F]{6}/gi)||t.filters.fill==="transparent")&&(a+=`:fill(${t.filters.fill})`),t.filters.format&&["webp","png","jpeg"].includes(t.filters.format)&&(a+=`:format(${t.filters.format})`),typeof t.filters.grayscale=="boolean"&&t.filters.grayscale&&(a+=":grayscale()"),typeof t.filters.quality=="number"&&t.filters.quality>=0&&t.filters.quality<=100&&(a+=`:quality(${t.filters.quality})`),t.filters.rotate&&[90,180,270].includes(t.filters.rotate)&&(a+=`:rotate(${t.filters.rotate})`),a.length>0&&(a=`/filters${a}`))),n.length>0&&(e=e.replace(/<img/g,`<img ${n.trim()}`));const l=o>0||s>0||a.length>0?`${o}x${s}${a}`:"";return e=e.replace(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g,`a.storyblok.com/f/$1/$2.$3/m/${l}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,i=>{var c,d;const f=i.match(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g);if(f&&f.length>0){const h={srcset:(c=t.srcset)==null?void 0:c.map(g=>{if(typeof g=="number")return`//${f}/m/${g}x0${a} ${g}w`;if(typeof g=="object"&&g.length===2){let w=0,R=0;return typeof g[0]=="number"&&(w=g[0]),typeof g[1]=="number"&&(R=g[1]),`//${f}/m/${w}x${R}${a} ${w}w`}return""}).join(", "),sizes:(d=t.sizes)==null?void 0:d.map(g=>g).join(", ")};let k="";return h.srcset&&(k+=`srcset="${h.srcset}" `),h.sizes&&(k+=`sizes="${h.sizes}" `),i.replace(/<img/g,`<img ${k.trim()}`)}return i})),e}renderNode(e){const t=[];e.marks&&e.marks.forEach(s=>{const n=this.getMatchingMark(s);n&&n.tag!==""&&t.push(this.renderOpeningTag(n.tag))});const o=this.getMatchingNode(e);return o&&o.tag&&t.push(this.renderOpeningTag(o.tag)),e.content?e.content.forEach(s=>{t.push(this.renderNode(s))}):e.text?t.push(me(e.text)):o&&o.singleTag?t.push(this.renderTag(o.singleTag," /")):o&&o.html?t.push(o.html):e.type==="emoji"&&t.push(this.renderEmoji(e)),o&&o.tag&&t.push(this.renderClosingTag(o.tag)),e.marks&&e.marks.slice(0).reverse().forEach(s=>{const n=this.getMatchingMark(s);n&&n.tag!==""&&t.push(this.renderClosingTag(n.tag))}),t.join("")}renderTag(e,t){return e.constructor===String?`<${e}${t}>`:e.map(o=>{if(o.constructor===String)return`<${o}${t}>`;{let s=`<${o.tag}`;if(o.attrs){for(const n in o.attrs)if(Object.prototype.hasOwnProperty.call(o.attrs,n)){const a=o.attrs[n];a!==null&&(s+=` ${n}="${a}"`)}}return`${s}${t}>`}}).join("")}renderOpeningTag(e){return this.renderTag(e,"")}renderClosingTag(e){return e.constructor===String?`</${e}>`:e.slice(0).reverse().map(t=>t.constructor===String?`</${t}>`:`</${t.tag}>`).join("")}getMatchingNode(e){const t=this.nodes[e.type];if(typeof t=="function")return t(e)}getMatchingMark(e){const t=this.marks[e.type];if(typeof t=="function")return t(e)}renderEmoji(e){if(e.attrs.emoji)return e.attrs.emoji;const t=[{tag:"img",attrs:{src:e.attrs.fallbackImage,draggable:"false",loading:"lazy",align:"absmiddle"}}];return this.renderTag(t," /")}}const L=ke,we=r=>{if(typeof r!="object"||typeof r._editable>"u")return{};try{const e=JSON.parse(r._editable.replace(/^<!--#storyblok#/,"").replace(/-->$/,""));return e?{"data-blok-c":JSON.stringify(e),"data-blok-uid":e.id+"-"+e.uid}:{}}catch{return{}}};let $e,ve="https://app.storyblok.com/f/storyblok-v2-latest.js";const Ce=(r,e)=>{r.addNode("blok",t=>{let o="";return t.attrs.body.forEach(s=>{o+=e(s.component,s)}),{html:o}})},Se=r=>!r||!(r!=null&&r.content.some(e=>e.content||e.type==="blok"||e.type==="horizontal_rule")),Ie=(r,e,t)=>{let o=t||$e;if(!o){console.error("Please initialize the Storyblok SDK before calling the renderRichText function");return}return Se(r)?"":(e&&(o=new L(e.schema),e.resolver&&Ce(o,e.resolver)),o.render(r,{},!1))},Te=()=>U(ve);function Ae(){if(!(globalThis!=null&&globalThis.storyblokApiInstance))throw new Error("storyblokApiInstance has not been initialized correctly");return globalThis.storyblokApiInstance}async function Ee(r){let e=null;return r&&r.locals._storyblok_preview_data&&(e=r.locals._storyblok_preview_data),e}function Le(r,e){var o;const t=(o=globalThis==null?void 0:globalThis.storyblokApiInstance)==null?void 0:o.richTextResolver;if(!t)throw new Error("Please initialize the Storyblok SDK before calling the renderRichText function");return Ie(r,e,t)}function xe(r){return typeof r=="object"?`const storyblokInstance = new StoryblokBridge(${JSON.stringify(r)});`:"const storyblokInstance = new StoryblokBridge();"}function Re(r){const e={useCustomApi:!1,bridge:!0,componentsDir:"src",enableFallbackComponent:!1,livePreview:!1,...r},t=xe(e.bridge);return{name:"@storyblok/astro",hooks:{"astro:config:setup":({injectScript:o,updateConfig:s,addDevToolbarApp:n,addMiddleware:a,config:l})=>{if(s({vite:{plugins:[F(e.accessToken,e.useCustomApi,e.apiOptions),B(e.componentsDir,e.components,e.enableFallbackComponent,e.customFallbackComponent),D(e)]}}),e.livePreview&&(l==null?void 0:l.output)!=="server")throw new Error("To utilize the Astro Storyblok Live feature, Astro must be configured to run in SSR mode. Please disable this feature or switch Astro to SSR mode.");o("page-ssr",`
44
44
  import { storyblokApiInstance } from "virtual:storyblok-init";
45
45
  globalThis.storyblokApiInstance = storyblokApiInstance;
46
- `),e.bridge&&!e.livePreview&&o("page",`
47
- import { loadStoryblokBridge } from "@storyblok/astro";
48
- loadStoryblokBridge().then(() => {
49
- const { StoryblokBridge, location } = window;
50
- ${t}
51
- storyblokInstance.on(["published", "change"], (event) => {
52
- if (!event.slugChanged) {
53
- location.reload(true);
54
- }
55
- });
46
+ `),e.bridge&&!e.livePreview&&o("page",`import { loadStoryblokBridge } from "@storyblok/astro";
47
+ loadStoryblokBridge().then(() => {
48
+ const { StoryblokBridge, location } = window;
49
+ ${t}
50
+ storyblokInstance.on(["published", "change"], (event) => {
51
+ if (!event.slugChanged) {
52
+ location.reload(true);
53
+ }
56
54
  });
57
- `),e.livePreview&&(o("page",`
58
- import { loadStoryblokBridge, handleStoryblokMessage } from "@storyblok/astro";
55
+ });
56
+ `),e.livePreview&&(o("page",`import { loadStoryblokBridge, handleStoryblokMessage } from "@storyblok/astro";
59
57
  loadStoryblokBridge().then(() => {
60
58
  const { StoryblokBridge, location } = window;
61
59
  ${t}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@storyblok/astro",
3
3
  "type": "module",
4
- "version": "6.0.0-next.2",
4
+ "version": "6.0.0",
5
5
  "private": false,
6
6
  "packageManager": "pnpm@9.13.2",
7
7
  "description": "Official Astro integration for the Storyblok Headless CMS",
@@ -71,7 +71,7 @@
71
71
  "astro": "^3.0.0 || ^4.0.0 || ^5.0.0"
72
72
  },
73
73
  "dependencies": {
74
- "@storyblok/js": "^3.1.9",
74
+ "@storyblok/js": "3.1.9",
75
75
  "camelcase": "^8.0.0"
76
76
  },
77
77
  "devDependencies": {
@@ -80,6 +80,7 @@
80
80
  "@cypress/vite-dev-server": "^5.2.0",
81
81
  "@rollup/plugin-dynamic-import-vars": "^2.1.5",
82
82
  "@storyblok/eslint-config": "^0.3.0",
83
+ "@types/lodash.mergewith": "^4.6.9",
83
84
  "@types/node": "22.10.2",
84
85
  "astro": "^5.0.9",
85
86
  "cypress": "^13.15.2",