@storyblok/react 3.0.14 → 4.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
@@ -1,8 +1,8 @@
1
1
  <div align="center">
2
- <a href="https://www.storyblok.com?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react" align="center">
3
- <img src="https://a.storyblok.com/f/88751/1776x360/ccc1c50c67/sb-react.png" alt="Storyblok Logo">
4
- </a>
5
- <h1 align="center">@storyblok/react</h1>
2
+ <a href="https://www.storyblok.com?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react" align="center">
3
+ <img src="https://a.storyblok.com/f/88751/1776x360/ccc1c50c67/sb-react.png" alt="Storyblok Logo">
4
+ </a>
5
+ <h1 align="center">@storyblok/react</h1>
6
6
  <p align="center">
7
7
  The React plugin you need to interact with <a href="http://www.storyblok.com?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react" target="_blank">Storyblok API</a> and enable the <a href="https://www.storyblok.com/docs/guide/essentials/visual-editor?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react" target="_blank">Real-time Visual Editing Experience</a>. This package helps you integrate Storyblok with React along with all types of React based frameworks like Next.js, Remix etc. This SDK also includes the support for React Server Side Components.
8
8
  </p>
@@ -63,15 +63,15 @@ Install the file from the CDN:
63
63
  Register the plugin on your application and add the [access token](https://www.storyblok.com/docs/api/content-delivery#topics/authentication?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react) of your Storyblok space. You can also add the `apiPlugin` in case that you want to use the Storyblok API Client:
64
64
 
65
65
  ```js
66
- import { storyblokInit, apiPlugin } from "@storyblok/react";
66
+ import { apiPlugin, storyblokInit } from '@storyblok/react'
67
67
 
68
68
  /** Import your components */
69
- import Page from "./components/Page";
70
- import Teaser from "./components/Teaser";
69
+ import Page from './components/Page'
70
+ import Teaser from './components/Teaser'
71
71
  // import FallbackComponent from "./components/FallbackComponent";
72
72
 
73
73
  storyblokInit({
74
- accessToken: "YOUR_ACCESS_TOKEN",
74
+ accessToken: 'YOUR_ACCESS_TOKEN',
75
75
  use: [apiPlugin],
76
76
  components: {
77
77
  page: Page,
@@ -82,7 +82,7 @@ storyblokInit({
82
82
  // richText: {},
83
83
  // enableFallbackComponent: false,
84
84
  // customFallbackComponent: FallbackComponent,
85
- });
85
+ })
86
86
  ```
87
87
 
88
88
  > Note: This is the general way for initalizing the SDK, the initialization might be a little different depending upon the framework. You can see how everything works according to the framework in their respective sections below.
@@ -106,16 +106,16 @@ Possible values:
106
106
  Full example for a space created in the US:
107
107
 
108
108
  ```js
109
- import { storyblokInit, apiPlugin } from "@storyblok/react";
109
+ import { apiPlugin, storyblokInit } from '@storyblok/react'
110
110
 
111
111
  storyblokInit({
112
- accessToken: "YOUR_ACCESS_TOKEN",
112
+ accessToken: 'YOUR_ACCESS_TOKEN',
113
113
  use: [apiPlugin],
114
114
  apiOptions: {
115
- region: "us",
115
+ region: 'us',
116
116
  },
117
117
  components: {},
118
- });
118
+ })
119
119
  ```
120
120
 
121
121
  > Note: For spaces created in the United States or China, the `region` parameter **must** be specified.
@@ -129,7 +129,7 @@ storyblokInit({
129
129
  For every component you've defined in your Storyblok space, call the `storyblokEditable` function with the blok content:
130
130
 
131
131
  ```js
132
- import { storyblokEditable } from "@storyblok/react";
132
+ import { storyblokEditable } from '@storyblok/react'
133
133
 
134
134
  const Feature = ({ blok }) => {
135
135
  return (
@@ -139,10 +139,10 @@ const Feature = ({ blok }) => {
139
139
  <p>{blok.description}</p>
140
140
  </div>
141
141
  </div>
142
- );
143
- };
142
+ )
143
+ }
144
144
 
145
- export default Feature;
145
+ export default Feature
146
146
  ```
147
147
 
148
148
  Where `blok` is the actual blok data coming from [Storyblok's Content Delivery API](https://www.storyblok.com/docs/api/content-delivery?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react).
@@ -164,19 +164,19 @@ The initalization remains the same when you work with React. You can intialze th
164
164
  Use `useStoryblok` to fetch the content as well as enable live editing. You need to pass the `slug` as the first parameter, `apiOptions` as the second parameter, and `bridgeOptions` as the third parameter, which is optional if you want to set the options for the bridge by yourself. Check the available [apiOptions](https://github.com/storyblok/storyblok-js-client#class-storyblok) (passed to `storyblok-js-client`) and [bridgeOptions](https://www.storyblok.com/docs/Guides/storyblok-latest-js?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-nuxt) (passed to the Storyblok Bridge).
165
165
 
166
166
  ```js
167
- import { useStoryblok, StoryblokComponent } from "@storyblok/react";
167
+ import { StoryblokComponent, useStoryblok } from '@storyblok/react'
168
168
 
169
169
  function App() {
170
- const story = useStoryblok("react", { version: "draft" });
170
+ const story = useStoryblok('react', { version: 'draft' })
171
171
 
172
172
  if (!story?.content) {
173
- return <div>Loading...</div>;
173
+ return <div>Loading...</div>
174
174
  }
175
175
 
176
- return <StoryblokComponent blok={story.content} />;
176
+ return <StoryblokComponent blok={story.content} />
177
177
  }
178
178
 
179
- export default App;
179
+ export default App
180
180
  ```
181
181
 
182
182
  `StoryblokComponent` renders the route components dynamically, using the list of components loaded during the initialization inside the `storyblokInit` function.
@@ -186,13 +186,13 @@ This is how you can pass the Bridge options as a third parameter to `useStoryblo
186
186
  ```js
187
187
  useStoryblok(
188
188
  story.id,
189
- { version: "draft", resolveRelations: ["Article.author"] },
189
+ { version: 'draft', resolveRelations: ['Article.author'] },
190
190
  {
191
- resolveRelations: ["Article.author"],
192
- resolveLinks: "url",
191
+ resolveRelations: ['Article.author'],
192
+ resolveLinks: 'url',
193
193
  preventClicks: true,
194
194
  }
195
- );
195
+ )
196
196
  ```
197
197
 
198
198
  **Check out our React Boilerplate [here](https://github.com/storyblok/storyblok-react-boilerplate), or read on how to add Storyblok to React in 5 mins [here](https://www.storyblok.com/tp/headless-cms-react)**
@@ -210,19 +210,19 @@ For more details, refer to the Next.js documentation on [opting out of caching](
210
210
 
211
211
  Here's how you can fetch data from Storyblok with `cache: "no-store"`:
212
212
 
213
- ```javascript
213
+ ```typescript
214
214
  export async function fetchData() {
215
- let sbParams: ISbStoriesParams = { version: "draft" };
215
+ const sbParams: ISbStoriesParams = { version: 'draft' }
216
216
 
217
- const storyblokApi: StoryblokClient = getStoryblokApi();
217
+ const storyblokApi: StoryblokClient = getStoryblokApi()
218
218
 
219
219
  return storyblokApi.get(`cdn/stories/home`, sbParams, {
220
- cache: "no-store", // This prevents Next.js 13, 14 default caching behaviour
221
- });
220
+ cache: 'no-store', // This prevents Next.js 13, 14 default caching behaviour
221
+ })
222
222
  }
223
223
  ```
224
224
 
225
- ## Next.js using App Router - Live Editing support
225
+ ## Next.js using App Router
226
226
 
227
227
  The components in the `app` directory are by default React Server Side Components, which limits the reactivity. You can enable Storyblok Visual Editor's live editing with React Server Components by rendering them inside a wrapper (`StoryblokPovider`) on the client. The SDK allows you to take full advantage of the Live Editing, but the use of Server Side Components is partial, which will be still better than the older Next.js approach performance-wise. The next section explains about how to use complete server side approach.
228
228
 
@@ -230,16 +230,30 @@ The components in the `app` directory are by default React Server Side Component
230
230
 
231
231
  ### 1. Initialize
232
232
 
233
- In `app/layout.jsx`, call the `storyblokInit` function, but without loading the component list (we will do that on the client). Wrap your whole app using a `StoryblokProvider` component (this provider is created in the next step) :
233
+ Create a new file `lib/storyblok.js` and initialize the SDK. Make sure you export the `getStoryblokApi` function, which is an instance of [storyblok-js-client](https://github.com/storyblok/storyblok-js-client) that is shared by client and server components.
234
234
 
235
235
  ```js
236
- import { storyblokInit, apiPlugin } from "@storyblok/react/rsc";
237
- import StoryblokProvider from "../components/StoryblokProvider";
236
+ // lib/storyblok.js
237
+ import Page from '@/components/Page';
238
+ import Teaser from '@/components/Teaser';
239
+ import { apiPlugin, storyblokInit } from '@storyblok/react/rsc';
238
240
 
239
- storyblokInit({
240
- accessToken: "YOUR_ACCESS_TOKEN",
241
+ export const getStoryblokApi = storyblokInit({
242
+ accessToken: 'YOUR_ACCESS_TOKEN',
241
243
  use: [apiPlugin],
244
+ components: {
245
+ teaser: Teaser,
246
+ page: Page,
247
+ },
242
248
  });
249
+ ```
250
+
251
+ In `app/layout.jsx`, wrap your whole app using a `StoryblokProvider` component (this provider is created in the next step) :
252
+
253
+ ```js
254
+ // app/layout.jsx
255
+ import { apiPlugin, storyblokInit } from '@storyblok/react/rsc'
256
+ import StoryblokProvider from '../components/StoryblokProvider'
243
257
 
244
258
  export default function RootLayout({ children }) {
245
259
  return (
@@ -248,47 +262,34 @@ export default function RootLayout({ children }) {
248
262
  <body>{children}</body>
249
263
  </html>
250
264
  </StoryblokProvider>
251
- );
265
+ )
252
266
  }
253
267
  ```
254
268
 
255
269
  ### 2. Create StoryblokProvider and Import your Storyblok Components
256
270
 
257
- Create the `components/StoryblokProvider.jsx` file. Re-initalize the connection with Storyblok (this time, on the client) using `storyblokInit`, and import your Storyblok components:
271
+ Create the `components/StoryblokProvider.jsx` file. Re-initalize the connection with Storyblok (this time, on the client) using the `getStoryblokApi` function imported from the `lib/storyblok` file. This will enable the client-side compoenents to interact with the Storyblok API, including the Visual Editor.
258
272
 
259
273
  ```js
260
- /** 1. Tag it as a client component */
261
- "use client";
262
- import { storyblokInit, apiPlugin } from "@storyblok/react/rsc";
274
+ // components/StoryblokProvider.jsx
275
+ 'use client';
263
276
 
264
- /** 2. Import your components */
265
- import Page from "../components/Page";
266
- import Teaser from "../components/Teaser";
267
-
268
- /** 3. Initialize it as usual */
269
- storyblokInit({
270
- accessToken: "YOUR_ACCESS_TOKEN",
271
- use: [apiPlugin],
272
- components: {
273
- teaser: Teaser,
274
- page: Page,
275
- },
276
- });
277
+ import { getStoryblokApi } from '@/lib/storyblok';
277
278
 
278
279
  export default function StoryblokProvider({ children }) {
280
+ getStoryblokApi();
279
281
  return children;
280
282
  }
281
283
  ```
282
284
 
283
- > Note: it's necessary to re-initialize here as well, as to enable the live editing experience inside the Visual Editor you need to initialize the lib universally (client + server).
284
-
285
285
  ### 3. Fetch Content and Render Components
286
286
 
287
- The `getStoryblokApi` function, which is an instance of [storyblok-js-client](https://github.com/storyblok/storyblok-js-client) can be used to fetch the data from the Storyblok API. This should be imported from `@storyblok/react/rsc`.
288
- You can render the content of your route with the `StoryblokStory` component, which will automatically handle the Visual Editor live events when editing the story. In `app/page.jsx`, use them as follows:
287
+ The `getStoryblokApi` function can now be used inside your Story components to fetch the data from Storyblok. In `app/page.jsx`, use it as follows:
289
288
 
290
289
  ```js
291
- import { getStoryblokApi, StoryblokStory } from "@storyblok/react/rsc";
290
+ import { StoryblokClient, ISbStoriesParams } from '@storyblok/react';
291
+ import { StoryblokStory } from '@storyblok/react/rsc';
292
+ import { getStoryblokApi } from '@/lib/storyblok'; // Remember to import from the local file
292
293
 
293
294
  export default async function Home() {
294
295
  const { data } = await fetchData();
@@ -301,95 +302,25 @@ export default async function Home() {
301
302
  }
302
303
 
303
304
  export async function fetchData() {
304
- const storyblokApi = getStoryblokApi();
305
- return storyblokApi.get(`cdn/stories/home`, { version: "draft" });
305
+ let sbParams: ISbStoriesParams = { version: 'draft' };
306
+
307
+ const storyblokApi: StoryblokClient = getStoryblokApi();
308
+ return storyblokApi.get(`cdn/stories/home`, sbParams);
306
309
  }
307
310
  ```
308
311
 
309
312
  `StoryblokStory` keeps the state for thet story behind the scenes and uses `StoryblokComponent` to render the route components dynamically, using the list of components loaded during the initialization inside the `storyblokInit` function. You can use the `StoryblokComponent` inside the components to render the nested components dynamically. You can also pass bridge options to `StoryblokStory` using the prop `bridgeOptions`.
310
313
 
311
- ```js
312
- const bridgeOptions = { resolveRelations: ["article.author"] };
314
+ ```jsx
315
+ const bridgeOptions = { resolveRelations: ['article.author'] }
313
316
 
314
- <StoryblokStory story={data.story} bridgeOptions={bridgeOptions} />;
317
+ <StoryblokStory story={data.story} bridgeOptions={bridgeOptions} />
315
318
  ```
316
319
 
317
320
  > Note: To use this approach (with `getStoryblokApi`), you need to include the `apiPlugin` module when calling `storyblokInit` function. If you don't use `apiPlugin`, you can use your preferred method or function to fetch your data.
318
321
 
319
322
  To try this setup, take a look at the [Next 13 Live Editing Playground](https://github.com/arorachakit/storyblok-react/tree/main/playground-next13-live-editing) in this repo.
320
323
 
321
- ## Next.js using App Router - Full React Server Components
322
-
323
- If you want to use the Next.js `app` directory approach, and React Server Components exclusively with everything on the server side, follow this approach.
324
-
325
- > The SDK has a special module for RSC. Always import `@storyblok/react/rsc` while using Server Components.
326
-
327
- **Limitation** - Real-time editing won't work if all the components are rendered on the server. Although, you can see the changes applied in the Visual Editor whenever you save or publish the changes applied to the story.
328
-
329
- ### 1. Initialize and Import your Storyblok Components
330
-
331
- The initialzation remains the same here as well. Please refer to the above section about "Initialization" for more information about `storyblokInit` function.
332
- In `app/layout.jsx`, call the `storyblokInit` function and use the new `StoryblokBridgeLoader` component to set up the Storyblok bridge. This Bridge Loader can be imported from `@storyblok/react/bridge-loader`:
333
-
334
- ```js
335
- import { storyblokInit, apiPlugin, StoryblokBridgeLoader } from "@storyblok/react/rsc";
336
-
337
- import Page from "../components/Page";
338
- import Teaser from "../components/Teaser";
339
-
340
- storyblokInit({
341
- accessToken: "YOUR_ACCESS_TOKEN",
342
- use: [apiPlugin],
343
- components: {
344
- teaser: Teaser,
345
- page: Page,
346
- },
347
- });
348
-
349
- export default RootLayout({ children }) =>{
350
- const bridgeOptions = { resolveRelations: ["article.author"] };
351
-
352
- return (
353
- <html lang="en">
354
- <body>{children}</body>
355
- <StoryblokBridgeLoader options={bridgeOptions} />
356
- </html>
357
- );
358
- }
359
- ```
360
-
361
- As the name says, `StoryblokBridgeLoader` loads the bridge on the client. It helps you see the dotted lines and allows you to still click on the components inside the Visual Editor to open their schema. You can pass the bridge options using the `options` prop.
362
-
363
- ### 2. Fetch Content and Render Components
364
-
365
- The `getStoryblokApi` function, is an instance of [storyblok-js-client](https://github.com/storyblok/storyblok-js-client) can be used to fetch the data from the Storyblok API. This is imported from `@storyblok/react/rsc`.
366
- Go to the route you want to fetch data from and use it as follows:
367
-
368
- ```js
369
- import { getStoryblokApi, StoryblokComponent } from "@storyblok/react/rsc";
370
-
371
- export default async function Home() {
372
- const { data } = await fetchData();
373
-
374
- return (
375
- <div>
376
- <h1>Story: {data.story.id}</h1>
377
- <StoryblokComponent blok={data.story.content} />
378
- </div>
379
- );
380
- }
381
-
382
- export async function fetchData() {
383
- const storyblokApi = getStoryblokApi();
384
- return storyblokApi.get(`cdn/stories/home`, { version: "draft" });
385
- }
386
- ```
387
-
388
- > Note: To use this approach (with `getStoryblokApi`), you need to include the `apiPlugin` module when calling `storyblokInit` function. If you don't use `apiPlugin`, you can use your preferred method or function to fetch your data.
389
-
390
- `StoryblokComponent` renders the route components dynamically, using the list of components loaded during the initialization inside the `storyblokInit` function.
391
- To try it, take a look at the [Next 13 RSC Playground](https://github.com/arorachakit/storyblok-react/tree/main/playground-next13-rsc) in this repo.
392
-
393
324
  ## Next.js using Pages Router
394
325
 
395
326
  In this section, we'll see how to use the React SDK with the `pages` directory approach.
@@ -401,11 +332,11 @@ The initalization remains the same when you work with Next.js. You can intialze
401
332
  The SDK provides a `getStoryblokApi` object in your app, which is an instance of [storyblok-js-client](https://github.com/storyblok/storyblok-js-client). This can be used to fetch the content from Storyblok. You can use it in functions like `getStaticProps`, `getStaticPaths`, `getServerSideProps` etc.
402
333
 
403
334
  ```js
404
- import { getStoryblokApi } from "@storyblok/react";
335
+ import { getStoryblokApi } from '@storyblok/react'
405
336
 
406
337
  // At the required place
407
- const storyblokApi = getStoryblokApi();
408
- const { data } = await storyblokApi.get("cdn/stories", { version: "draft" });
338
+ const storyblokApi = getStoryblokApi()
339
+ const { data } = await storyblokApi.get('cdn/stories', { version: 'draft' })
409
340
  ```
410
341
 
411
342
  > Note: To use this approach, you need to include the `apiPlugin` module when calling `storyblokInit` function. If you don't use `apiPlugin`, you can use your preferred method or function to fetch your data.
@@ -415,16 +346,16 @@ const { data } = await storyblokApi.get("cdn/stories", { version: "draft" });
415
346
  The SDK also provides you with the `useStoryblokState` hook. It works similarly to `useStoryblok` for live editing, but it doesn't fetch the content. Instead, it receives a story object as the first parameter. You can also pass the Bridge Options as the second parameter.
416
347
 
417
348
  ```js
418
- import { useStoryblokState, StoryblokComponent } from "@storyblok/react";
349
+ import { StoryblokComponent, useStoryblokState } from '@storyblok/react'
419
350
 
420
351
  export default function Home({ story: initialStory }) {
421
- const story = useStoryblokState(initialStory);
352
+ const story = useStoryblokState(initialStory)
422
353
 
423
354
  if (!story.content) {
424
- return <div>Loading...</div>;
355
+ return <div>Loading...</div>
425
356
  }
426
357
 
427
- return <StoryblokComponent blok={story.content} />;
358
+ return <StoryblokComponent blok={story.content} />
428
359
  }
429
360
  ```
430
361
 
@@ -432,26 +363,26 @@ In this case, the story is being passed as a prop that can be coming from where
432
363
 
433
364
  ```js
434
365
  import {
435
- useStoryblokState,
436
366
  getStoryblokApi,
437
367
  StoryblokComponent,
438
- } from "@storyblok/react";
368
+ useStoryblokState,
369
+ } from '@storyblok/react'
439
370
 
440
371
  export default function Home({ story: initialStory }) {
441
- const story = useStoryblokState(initialStory);
372
+ const story = useStoryblokState(initialStory)
442
373
 
443
374
  if (!story.content) {
444
- return <div>Loading...</div>;
375
+ return <div>Loading...</div>
445
376
  }
446
377
 
447
- return <StoryblokComponent blok={story.content} />;
378
+ return <StoryblokComponent blok={story.content} />
448
379
  }
449
380
 
450
381
  export async function getStaticProps({ preview = false }) {
451
- const storyblokApi = getStoryblokApi();
452
- let { data } = await storyblokApi.get(`cdn/stories/react`, {
453
- version: "draft",
454
- });
382
+ const storyblokApi = getStoryblokApi()
383
+ const { data } = await storyblokApi.get(`cdn/stories/react`, {
384
+ version: 'draft',
385
+ })
455
386
 
456
387
  return {
457
388
  props: {
@@ -459,7 +390,7 @@ export async function getStaticProps({ preview = false }) {
459
390
  preview,
460
391
  },
461
392
  revalidate: 3600, // revalidate every hour
462
- };
393
+ }
463
394
  }
464
395
  ```
465
396
 
@@ -540,10 +471,10 @@ You can use an `apiOptions` object. This is passed down to the [storyblok-js-cli
540
471
 
541
472
  ```js
542
473
  storyblokInit({
543
- accessToken: "YOUR_ACCESS_TOKEN",
474
+ accessToken: 'YOUR_ACCESS_TOKEN',
544
475
  apiOptions: {
545
476
  // storyblok-js-client config object
546
- cache: { type: "memory" },
477
+ cache: { type: 'memory' },
547
478
  },
548
479
  use: [apiPlugin],
549
480
  components: {
@@ -552,13 +483,13 @@ storyblokInit({
552
483
  grid: Grid,
553
484
  feature: Feature,
554
485
  },
555
- });
486
+ })
556
487
  ```
557
488
 
558
489
  If you prefer to use your own fetch method, just remove the `apiPlugin` and `storyblok-js-client` won't be added to your application.
559
490
 
560
491
  ```js
561
- storyblokInit({});
492
+ storyblokInit({})
562
493
  ```
563
494
 
564
495
  ### Storyblok Bridge
@@ -566,11 +497,11 @@ storyblokInit({});
566
497
  If you don't use `registerStoryblokBridge`, you still have access to the raw `window.StoryblokBridge`:
567
498
 
568
499
  ```js
569
- const sbBridge = new window.StoryblokBridge(options);
500
+ const sbBridge = new window.StoryblokBridge(options)
570
501
 
571
- sbBridge.on(["input", "published", "change"], (event) => {
502
+ sbBridge.on(['input', 'published', 'change'], (event) => {
572
503
  // ...
573
- });
504
+ })
574
505
  ```
575
506
 
576
507
  ### Rendering Rich Text
@@ -578,54 +509,53 @@ sbBridge.on(["input", "published", "change"], (event) => {
578
509
  You can easily render rich text by using the `renderRichText` function that comes with `@storyblok/react`:
579
510
 
580
511
  ```js
581
- import { renderRichText } from "@storyblok/react";
512
+ import { renderRichText } from '@storyblok/react'
582
513
 
583
- const renderedRichText = renderRichText(blok.richtext);
514
+ const renderedRichText = renderRichText(blok.richtext)
584
515
  ```
585
516
 
586
517
  You can set a **custom Schema and component resolver globally** at init time by using the `richText` init option:
587
518
 
588
519
  ```js
589
- import { RichTextSchema, storyblokInit } from "@storyblok/react";
590
- import cloneDeep from "clone-deep";
520
+ import { RichTextSchema, storyblokInit } from '@storyblok/react'
521
+ import cloneDeep from 'clone-deep'
591
522
 
592
- const mySchema = cloneDeep(RichTextSchema); // you can make a copy of the default RichTextSchema
523
+ const mySchema = cloneDeep(RichTextSchema) // you can make a copy of the default RichTextSchema
593
524
  // ... and edit the nodes and marks, or add your own.
594
525
  // Check the base RichTextSchema source here https://github.com/storyblok/storyblok-js-client/blob/main/src/schema.ts
595
526
 
596
527
  storyblokInit({
597
- accessToken: "<your-token>",
528
+ accessToken: '<your-token>',
598
529
  richText: {
599
530
  schema: mySchema,
600
531
  resolver: (component, blok) => {
601
532
  switch (component) {
602
- case "my-custom-component":
603
- return `<div class="my-component-class">${blok.text}</div>`;
533
+ case 'my-custom-component':
534
+ return `<div class="my-component-class">${blok.text}</div>`
604
535
  default:
605
- return "Resolver not defined";
536
+ return 'Resolver not defined'
606
537
  }
607
538
  },
608
539
  },
609
- });
540
+ })
610
541
  ```
611
542
 
612
543
  You can also set a **custom Schema and component resolver only once** by passing the options as the second parameter to `renderRichText` function:
613
544
 
614
545
  ```js
615
- import { renderRichText } from "@storyblok/react";
546
+ import { renderRichText } from '@storyblok/react'
616
547
 
617
548
  renderRichText(blok.richTextField, {
618
549
  schema: mySchema,
619
550
  resolver: (component, blok) => {
620
551
  switch (component) {
621
- case "my-custom-component":
622
- return `<div class="my-component-class">${blok.text}</div>`;
623
- break;
552
+ case 'my-custom-component':
553
+ return `<div class="my-component-class">${blok.text}</div>`
624
554
  default:
625
- return `Component ${component} not found`;
555
+ return `Component ${component} not found`
626
556
  }
627
557
  },
628
- });
558
+ })
629
559
  ```
630
560
 
631
561
  We also recommend using the [Storyblok Rich Text Renderer for React by Claus](https://github.com/claus/storyblok-rich-text-react-renderer) for rendering your Storyblok rich text content to React elements and Next.js applications.
@@ -645,36 +575,36 @@ storyblokInit({
645
575
  components: {
646
576
  // all your React components
647
577
  },
648
- });
578
+ })
649
579
  ```
650
580
 
651
581
  Storyblok's React SDK automatically renders these predefined components based on your page content. While this is convenient, it can lead to larger bundle sizes and slower page speeds, especially for larger sites or when using heavy JavaScript libraries that are only needed on specific pages or a specific component.
652
582
 
653
583
  ### Solutions
654
584
 
655
- 1. **Storyblok's `setComponents` Function**:
585
+ 1. **Storyblok's `setComponents` Function**:
656
586
  Storyblok SDK provides a function called `setComponents` that allows you to load only the components needed for each route instead of defining all components during initialization. This approach is useful but might not be practical if you use a catch-all route, which is common in many React frameworks.
657
587
 
658
- 2. **React's `react.lazy`**:
588
+ 2. **React's `react.lazy`**:
659
589
  React offers a built-in solution called `react.lazy` for code splitting. Instead of directly importing components, you can do the following:
660
-
590
+
661
591
  ```javascript
662
- "use client";
663
- import { storyblokInit, apiPlugin } from "@storyblok/react/rsc";
664
- import { lazy } from "react";
665
-
592
+ 'use client'
593
+ import { apiPlugin, storyblokInit } from '@storyblok/react/rsc'
594
+ import { lazy } from 'react'
595
+
666
596
  const lazyComponents = {
667
- page: lazy(() => import("./components/Page")),
597
+ page: lazy(() => import('./components/Page')),
668
598
  // other lazy-loaded components
669
- };
670
-
599
+ }
600
+
671
601
  storyblokInit({
672
602
  accessToken,
673
603
  use: [apiPlugin],
674
604
  components: lazyComponents,
675
- });
605
+ })
676
606
  ```
677
-
607
+
678
608
  This approach enables automatic code splitting and loads only the necessary JavaScript for each page. However, `react.lazy` has some limitations when used with SSR (Server-Side Rendering).
679
609
 
680
610
  3. **Using `@loadable/component`**:
@@ -706,3 +636,7 @@ By using these techniques, you can ensure that only the necessary components and
706
636
 
707
637
  Please see our [contributing guidelines](https://github.com/storyblok/.github/blob/master/contributing.md) and our [code of conduct](https://www.storyblok.com/trust-center#code-of-conduct?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react).
708
638
  This project use [semantic-release](https://semantic-release.gitbook.io/semantic-release/) for generate new versions by using commit messages and we use the Angular Convention to naming the commits. Check [this question](https://semantic-release.gitbook.io/semantic-release/support/faq#how-can-i-change-the-type-of-commits-that-trigger-a-release) about it in semantic-release FAQ.
639
+
640
+ ## License
641
+
642
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
package/dist/client.js CHANGED
@@ -1 +1,2 @@
1
+ "use client";
1
2
  "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react"),b=require("./storyblok-js.js"),f=(e=null,o={})=>{const[u,s]=d.useState(e),r=(e==null?void 0:e.internalId)??(e==null?void 0:e.id)??0,t=typeof window<"u"&&typeof window.storyblokRegisterEvent<"u";return d.useEffect(()=>{s(e),!(!t||!e)&&b.registerStoryblokBridge(r,c=>s(c),o)},[e]),u};exports.useStoryblokState=f;
package/dist/client.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { useState as c, useEffect as p } from "react";
2
3
  import { registerStoryblokBridge as b } from "./storyblok-js.mjs";
3
4
  const n = (e = null, d = {}) => {
package/dist/common.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./storyblok-js.js"),b=require("./server-component.js");let t=null;const n=new Map;let l=!1,s=null;globalThis.storyCache=new Map;const a=()=>(t||console.error("You can't use getStoryblokApi if you're not loading apiPlugin."),t),c=e=>(Object.entries(e).forEach(([r,i])=>{n.set(r,i)}),n),k=e=>n.has(e)?n.get(e):(console.error(`Component ${e} doesn't exist.`),!1),m=()=>l,u=()=>s,g=(e={})=>{if(t)return()=>t;const{storyblokApi:r}=o.storyblokInit(e);return t=r,e.components&&c(e.components),l=e.enableFallbackComponent,s=e.customFallbackComponent,()=>r};exports.RichTextResolver=o.RichTextResolver;exports.RichTextSchema=o.RichTextSchema;exports.apiPlugin=o.apiPlugin;exports.loadStoryblokBridge=o.loadStoryblokBridge;exports.registerStoryblokBridge=o.registerStoryblokBridge;exports.renderRichText=o.renderRichText;exports.storyblokEditable=o.storyblokEditable;exports.useStoryblokBridge=o.registerStoryblokBridge;exports.StoryblokServerComponent=b;exports.getComponent=k;exports.getCustomFallbackComponent=u;exports.getEnableFallbackComponent=m;exports.getStoryblokApi=a;exports.setComponents=c;exports.storyblokInit=g;exports.useStoryblokApi=a;
@@ -0,0 +1,35 @@
1
+ import { storyblokInit as a } from "./storyblok-js.mjs";
2
+ import { RichTextResolver as g, RichTextSchema as C, apiPlugin as d, loadStoryblokBridge as S, registerStoryblokBridge as h, renderRichText as x, storyblokEditable as F, registerStoryblokBridge as A } from "./storyblok-js.mjs";
3
+ import { default as M } from "./server-component.mjs";
4
+ let e = null;
5
+ const r = /* @__PURE__ */ new Map();
6
+ let n = !1, l = null;
7
+ globalThis.storyCache = /* @__PURE__ */ new Map();
8
+ const i = () => (e || console.error(
9
+ "You can't use getStoryblokApi if you're not loading apiPlugin."
10
+ ), e), c = (o) => (Object.entries(o).forEach(([t, s]) => {
11
+ r.set(t, s);
12
+ }), r), k = (o) => r.has(o) ? r.get(o) : (console.error(`Component ${o} doesn't exist.`), !1), m = () => n, p = () => l, u = (o = {}) => {
13
+ if (e)
14
+ return () => e;
15
+ const { storyblokApi: t } = a(o);
16
+ return e = t, o.components && c(o.components), n = o.enableFallbackComponent, l = o.customFallbackComponent, () => t;
17
+ };
18
+ export {
19
+ g as RichTextResolver,
20
+ C as RichTextSchema,
21
+ M as StoryblokServerComponent,
22
+ d as apiPlugin,
23
+ k as getComponent,
24
+ p as getCustomFallbackComponent,
25
+ m as getEnableFallbackComponent,
26
+ i as getStoryblokApi,
27
+ S as loadStoryblokBridge,
28
+ h as registerStoryblokBridge,
29
+ x as renderRichText,
30
+ c as setComponents,
31
+ F as storyblokEditable,
32
+ u as storyblokInit,
33
+ i as useStoryblokApi,
34
+ A as useStoryblokBridge
35
+ };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("react"),e=require("./storyblok-js.js"),o=require("./index2.js"),c=require("./client.js"),S=require("./storyblok-component.js"),d=(s,r={},t={})=>{let[a,i]=y.useState({});const u=typeof window<"u"&&typeof window.storyblokRegisterEvent<"u",n=o.useStoryblokApi();return y.useEffect(()=>{if(!n){console.error("You can't use useStoryblok if you're not loading apiPlugin.");return}async function b(){const{data:l}=await n.get(`cdn/stories/${s}`,r);i(l.story),u&&l.story.id&&e.registerStoryblokBridge(l.story.id,k=>i(k),t)}b()},[s,JSON.stringify(r),n]),n?(t.resolveRelations=t.resolveRelations??r.resolve_relations,t.resolveLinks=t.resolveLinks??r.resolve_links,a):null};exports.RichTextResolver=e.RichTextResolver;exports.RichTextSchema=e.RichTextSchema;exports.apiPlugin=e.apiPlugin;exports.loadStoryblokBridge=e.loadStoryblokBridge;exports.registerStoryblokBridge=e.registerStoryblokBridge;exports.renderRichText=e.renderRichText;exports.storyblokEditable=e.storyblokEditable;exports.useStoryblokBridge=e.registerStoryblokBridge;exports.getComponent=o.getComponent;exports.getCustomFallbackComponent=o.getCustomFallbackComponent;exports.getEnableFallbackComponent=o.getEnableFallbackComponent;exports.getStoryblokApi=o.useStoryblokApi;exports.setComponents=o.setComponents;exports.storyblokInit=o.storyblokInit;exports.useStoryblokApi=o.useStoryblokApi;exports.useStoryblokState=c.useStoryblokState;exports.StoryblokComponent=S;exports.useStoryblok=d;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("react"),e=require("./storyblok-js.js"),o=require("./index2.js"),k=require("./client.js"),S=require("./storyblok-component.js"),d=(s,r={},t={})=>{const[a,i]=y.useState({}),u=typeof window<"u"&&typeof window.storyblokRegisterEvent<"u",n=o.useStoryblokApi();return y.useEffect(()=>{if(!n){console.error("You can't use useStoryblok if you're not loading apiPlugin.");return}async function b(){const{data:l}=await n.get(`cdn/stories/${s}`,r);i(l.story),u&&l.story.id&&e.registerStoryblokBridge(l.story.id,c=>i(c),t)}b()},[s,JSON.stringify(r),n]),n?(t.resolveRelations=t.resolveRelations??r.resolve_relations,t.resolveLinks=t.resolveLinks??r.resolve_links,a):null};exports.RichTextResolver=e.RichTextResolver;exports.RichTextSchema=e.RichTextSchema;exports.apiPlugin=e.apiPlugin;exports.loadStoryblokBridge=e.loadStoryblokBridge;exports.registerStoryblokBridge=e.registerStoryblokBridge;exports.renderRichText=e.renderRichText;exports.storyblokEditable=e.storyblokEditable;exports.useStoryblokBridge=e.registerStoryblokBridge;exports.getComponent=o.getComponent;exports.getCustomFallbackComponent=o.getCustomFallbackComponent;exports.getEnableFallbackComponent=o.getEnableFallbackComponent;exports.getStoryblokApi=o.useStoryblokApi;exports.setComponents=o.setComponents;exports.storyblokInit=o.storyblokInit;exports.useStoryblokApi=o.useStoryblokApi;exports.useStoryblokState=k.useStoryblokState;exports.StoryblokComponent=S;exports.useStoryblok=d;
package/dist/index.mjs CHANGED
@@ -6,8 +6,7 @@ import { getComponent as h, getCustomFallbackComponent as A, getEnableFallbackCo
6
6
  import { useStoryblokState as N } from "./client.mjs";
7
7
  import { default as _ } from "./storyblok-component.mjs";
8
8
  const b = (s, e = {}, o = {}) => {
9
- let [l, n] = f({});
10
- const i = typeof window < "u" && typeof window.storyblokRegisterEvent < "u", t = c();
9
+ const [l, n] = f({}), i = typeof window < "u" && typeof window.storyblokRegisterEvent < "u", t = c();
11
10
  return u(() => {
12
11
  if (!t) {
13
12
  console.error(
@@ -0,0 +1,2 @@
1
+ "use server";
2
+ "use strict";var n=Object.create;var a=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,s=Object.prototype.hasOwnProperty;var p=(e,t,i,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of d(t))!s.call(e,r)&&r!==i&&a(e,r,{get:()=>t[r],enumerable:!(o=c(t,r))||o.enumerable});return e};var v=(e,t,i)=>(i=e!=null?n(l(e)):{},p(t||!e||!e.__esModule?a(i,"default",{value:e,enumerable:!0}):i,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});async function u({story:e,pathToRevalidate:t}){if(!e||!t)return console.error("liveEditUpdateAction: story or pathToRevalidate is not provided");if(globalThis.storyCache.set(e.uuid,e),process.env.NEXT_RUNTIME)try{const{revalidatePath:i}=await import("next/cache");i(t)}catch(i){console.error("liveEditUpdateAction: error while revalidating path",i)}}exports.liveEditUpdateAction=u;
@@ -0,0 +1,15 @@
1
+ "use server";
2
+ async function r({ story: e, pathToRevalidate: i }) {
3
+ if (!e || !i)
4
+ return console.error("liveEditUpdateAction: story or pathToRevalidate is not provided");
5
+ if (globalThis.storyCache.set(e.uuid, e), process.env.NEXT_RUNTIME)
6
+ try {
7
+ const { revalidatePath: t } = await import("next/cache");
8
+ t(i);
9
+ } catch (t) {
10
+ console.error("liveEditUpdateAction: error while revalidating path", t);
11
+ }
12
+ }
13
+ export {
14
+ r as liveEditUpdateAction
15
+ };
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ "use strict";const r=require("./storyblok-js.js"),t=require("react"),o=require("./live-edit-update-action.js"),a=({story:e=null,bridgeOptions:i={}})=>{if(typeof window>"u")return null;const d=n=>{n&&t.startTransition(()=>{o.liveEditUpdateAction({story:n,pathToRevalidate:window.location.pathname})})},l=(e==null?void 0:e.internalId)??(e==null?void 0:e.id)??0;return t.useEffect(()=>{r.registerStoryblokBridge(l,n=>d(n),i)},[]),null};module.exports=a;
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { registerStoryblokBridge as d } from "./storyblok-js.mjs";
3
+ import { useEffect as l, startTransition as o } from "react";
4
+ import { liveEditUpdateAction as r } from "./live-edit-update-action.mjs";
5
+ const m = ({ story: n = null, bridgeOptions: i = {} }) => {
6
+ if (typeof window > "u")
7
+ return null;
8
+ const t = (e) => {
9
+ e && o(() => {
10
+ r({ story: e, pathToRevalidate: window.location.pathname });
11
+ });
12
+ }, a = (n == null ? void 0 : n.internalId) ?? (n == null ? void 0 : n.id) ?? 0;
13
+ return l(() => {
14
+ d(a, (e) => t(e), i);
15
+ }, []), null;
16
+ };
17
+ export {
18
+ m as default
19
+ };
package/dist/rsc.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./index2.js"),r=require("./story.js"),t=require("./bridge-loader.js"),l=require("./storyblok-component.js"),e=require("./storyblok-js.js");exports.getComponent=o.getComponent;exports.getCustomFallbackComponent=o.getCustomFallbackComponent;exports.getEnableFallbackComponent=o.getEnableFallbackComponent;exports.getStoryblokApi=o.useStoryblokApi;exports.setComponents=o.setComponents;exports.storyblokInit=o.storyblokInit;exports.useStoryblokApi=o.useStoryblokApi;exports.StoryblokStory=r;exports.BridgeLoader=t;exports.StoryblokBridgeLoader=t;exports.StoryblokComponent=l;exports.RichTextResolver=e.RichTextResolver;exports.RichTextSchema=e.RichTextSchema;exports.apiPlugin=e.apiPlugin;exports.loadStoryblokBridge=e.loadStoryblokBridge;exports.registerStoryblokBridge=e.registerStoryblokBridge;exports.renderRichText=e.renderRichText;exports.storyblokEditable=e.storyblokEditable;exports.useStoryblokBridge=e.registerStoryblokBridge;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./common.js"),t=require("./story.js"),r=require("./server-component.js"),e=require("./storyblok-js.js");exports.getComponent=o.getComponent;exports.getCustomFallbackComponent=o.getCustomFallbackComponent;exports.getEnableFallbackComponent=o.getEnableFallbackComponent;exports.getStoryblokApi=o.useStoryblokApi;exports.setComponents=o.setComponents;exports.storyblokInit=o.storyblokInit;exports.useStoryblokApi=o.useStoryblokApi;exports.StoryblokStory=t;exports.StoryblokServerComponent=r;exports.RichTextResolver=e.RichTextResolver;exports.RichTextSchema=e.RichTextSchema;exports.apiPlugin=e.apiPlugin;exports.loadStoryblokBridge=e.loadStoryblokBridge;exports.registerStoryblokBridge=e.registerStoryblokBridge;exports.renderRichText=e.renderRichText;exports.storyblokEditable=e.storyblokEditable;exports.useStoryblokBridge=e.registerStoryblokBridge;
package/dist/rsc.mjs CHANGED
@@ -1,26 +1,23 @@
1
- import { getComponent as t, getCustomFallbackComponent as r, getEnableFallbackComponent as l, useStoryblokApi as a, setComponents as i, storyblokInit as s, useStoryblokApi as b } from "./index2.mjs";
1
+ import { getComponent as t, getCustomFallbackComponent as r, getEnableFallbackComponent as l, useStoryblokApi as i, setComponents as a, storyblokInit as b, useStoryblokApi as s } from "./common.mjs";
2
2
  import { default as k } from "./story.mjs";
3
- import { default as p, default as g } from "./bridge-loader.mjs";
4
- import { default as m } from "./storyblok-component.mjs";
5
- import { RichTextResolver as f, RichTextSchema as u, apiPlugin as x, loadStoryblokBridge as c, registerStoryblokBridge as B, renderRichText as C, storyblokEditable as h, registerStoryblokBridge as R } from "./storyblok-js.mjs";
3
+ import { default as y } from "./server-component.mjs";
4
+ import { RichTextResolver as g, RichTextSchema as m, apiPlugin as d, loadStoryblokBridge as u, registerStoryblokBridge as x, renderRichText as c, storyblokEditable as f, registerStoryblokBridge as C } from "./storyblok-js.mjs";
6
5
  export {
7
- p as BridgeLoader,
8
- f as RichTextResolver,
9
- u as RichTextSchema,
10
- g as StoryblokBridgeLoader,
11
- m as StoryblokComponent,
6
+ g as RichTextResolver,
7
+ m as RichTextSchema,
8
+ y as StoryblokServerComponent,
12
9
  k as StoryblokStory,
13
- x as apiPlugin,
10
+ d as apiPlugin,
14
11
  t as getComponent,
15
12
  r as getCustomFallbackComponent,
16
13
  l as getEnableFallbackComponent,
17
- a as getStoryblokApi,
18
- c as loadStoryblokBridge,
19
- B as registerStoryblokBridge,
20
- C as renderRichText,
21
- i as setComponents,
22
- h as storyblokEditable,
23
- s as storyblokInit,
24
- b as useStoryblokApi,
25
- R as useStoryblokBridge
14
+ i as getStoryblokApi,
15
+ u as loadStoryblokBridge,
16
+ x as registerStoryblokBridge,
17
+ c as renderRichText,
18
+ a as setComponents,
19
+ f as storyblokEditable,
20
+ b as storyblokInit,
21
+ s as useStoryblokApi,
22
+ C as useStoryblokBridge
26
23
  };
@@ -0,0 +1 @@
1
+ "use strict";const e=require("react"),o=require("./common.js");require("./story.js");const c=e.forwardRef(({blok:t,...n},m)=>{if(!t)return console.error("Please provide a 'blok' property to the StoryblokComponent"),e.createElement("div",null,"Please provide a blok property to the StoryblokComponent");const r=o.getComponent(t.component);if(r)return e.createElement(r,{ref:m,blok:t,...n});if(o.getEnableFallbackComponent()){const l=o.getCustomFallbackComponent();return l?e.createElement(l,{blok:t,...n}):e.createElement(e.Fragment,null,e.createElement("p",null,"Component could not be found for blok"," ",e.createElement("strong",null,t.component),"! Is it configured correctly?"))}return e.createElement("div",null)});c.displayName="StoryblokComponent";module.exports=c;
@@ -0,0 +1,23 @@
1
+ import e, { forwardRef as m } from "react";
2
+ import { getComponent as a, getEnableFallbackComponent as p, getCustomFallbackComponent as c } from "./common.mjs";
3
+ import "./story.mjs";
4
+ const u = m(
5
+ ({ blok: t, ...o }, l) => {
6
+ if (!t)
7
+ return console.error(
8
+ "Please provide a 'blok' property to the StoryblokComponent"
9
+ ), /* @__PURE__ */ e.createElement("div", null, "Please provide a blok property to the StoryblokComponent");
10
+ const n = a(t.component);
11
+ if (n)
12
+ return /* @__PURE__ */ e.createElement(n, { ref: l, blok: t, ...o });
13
+ if (p()) {
14
+ const r = c();
15
+ return r ? /* @__PURE__ */ e.createElement(r, { blok: t, ...o }) : /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("p", null, "Component could not be found for blok", " ", /* @__PURE__ */ e.createElement("strong", null, t.component), "! Is it configured correctly?"));
16
+ }
17
+ return /* @__PURE__ */ e.createElement("div", null);
18
+ }
19
+ );
20
+ u.displayName = "StoryblokComponent";
21
+ export {
22
+ u as default
23
+ };
package/dist/story.js CHANGED
@@ -1,2 +1 @@
1
- "use client";
2
- "use strict";const t=require("react"),c=require("./client.js"),i=require("./storyblok-component.js"),l=t.forwardRef(({story:e,bridgeOptions:n,...o},r)=>(typeof e.content=="string"&&(e.content=JSON.parse(e.content)),e=c.useStoryblokState(e,n),t.createElement(i,{ref:r,blok:e.content,...o})));module.exports=l;
1
+ "use strict";const r=require("react");require("./common.js");const i=require("./live-editing.js"),l=require("./server-component.js"),a=r.forwardRef(({story:e,bridgeOptions:t,...n},o)=>{if(!e)return console.error("Please provide a 'story' property to the StoryblokServerComponent"),null;if(globalThis.storyCache.has(e.uuid)&&(e=globalThis.storyCache.get(e.uuid)),typeof e.content=="string")try{e.content=JSON.parse(e.content)}catch(c){console.error("An error occurred while trying to parse the story content",c),e.content={}}return r.createElement(r.Fragment,null,r.createElement(l,{ref:o,blok:e.content,...n}),r.createElement(i,{story:e,bridgeOptions:t}))});module.exports=a;
package/dist/story.mjs CHANGED
@@ -1,10 +1,25 @@
1
- "use client";
2
- import r, { forwardRef as f } from "react";
3
- import { useStoryblokState as m } from "./client.mjs";
4
- import a from "./storyblok-component.mjs";
5
- const S = f(
6
- ({ story: t, bridgeOptions: o, ...e }, n) => (typeof t.content == "string" && (t.content = JSON.parse(t.content)), t = m(t, o), /* @__PURE__ */ r.createElement(a, { ref: n, blok: t.content, ...e }))
1
+ import r, { forwardRef as c } from "react";
2
+ import "./common.mjs";
3
+ import a from "./live-editing.mjs";
4
+ import i from "./server-component.mjs";
5
+ const h = c(
6
+ ({ story: e, bridgeOptions: t, ...o }, n) => {
7
+ if (!e)
8
+ return console.error(
9
+ "Please provide a 'story' property to the StoryblokServerComponent"
10
+ ), null;
11
+ if (globalThis.storyCache.has(e.uuid) && (e = globalThis.storyCache.get(e.uuid)), typeof e.content == "string")
12
+ try {
13
+ e.content = JSON.parse(e.content);
14
+ } catch (l) {
15
+ console.error(
16
+ "An error occurred while trying to parse the story content",
17
+ l
18
+ ), e.content = {};
19
+ }
20
+ return /* @__PURE__ */ r.createElement(r.Fragment, null, /* @__PURE__ */ r.createElement(i, { ref: n, blok: e.content, ...o }), /* @__PURE__ */ r.createElement(a, { story: e, bridgeOptions: t }));
21
+ }
7
22
  );
8
23
  export {
9
- S as default
24
+ h as default
10
25
  };
@@ -1,2 +1,2 @@
1
- import type { TUseStoryblokState } from "../types";
1
+ import type { TUseStoryblokState } from '../types';
2
2
  export declare const useStoryblokState: TUseStoryblokState;
@@ -1,11 +1,11 @@
1
- import { SbReactComponentsMap, SbReactSDKOptions, StoryblokClient } from "../types";
1
+ import type { SbReactComponentsMap, SbReactSDKOptions, StoryblokClient } from '../types';
2
2
  export declare const useStoryblokApi: () => StoryblokClient;
3
3
  export declare const setComponents: (newComponentsMap: SbReactComponentsMap) => SbReactComponentsMap;
4
4
  export declare const getComponent: (componentKey: string) => false | import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements>;
5
5
  export declare const getEnableFallbackComponent: () => boolean;
6
6
  export declare const getCustomFallbackComponent: () => import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements>;
7
7
  export declare const storyblokInit: (pluginOptions?: SbReactSDKOptions) => void;
8
- export { default as StoryblokComponent } from "./storyblok-component";
8
+ export * from '../types';
9
9
  export { useStoryblokApi as getStoryblokApi };
10
- export { storyblokEditable, apiPlugin, loadStoryblokBridge, useStoryblokBridge, registerStoryblokBridge, renderRichText, RichTextResolver, RichTextSchema, } from "@storyblok/js";
11
- export * from "../types";
10
+ export { default as StoryblokComponent } from './storyblok-component';
11
+ export { apiPlugin, loadStoryblokBridge, registerStoryblokBridge, renderRichText, RichTextResolver, RichTextSchema, storyblokEditable, useStoryblokBridge, } from '@storyblok/js';
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import type { SbBlokData } from "../types";
1
+ import React from 'react';
2
+ import type { SbBlokData } from '../types';
3
3
  interface StoryblokComponentProps {
4
4
  blok: SbBlokData;
5
5
  [key: string]: unknown;
@@ -1,6 +1,6 @@
1
- import { ISbStoriesParams, StoryblokBridgeConfigV2, ISbStoryData } from "./types";
1
+ import type { ISbStoriesParams, ISbStoryData, StoryblokBridgeConfigV2 } from './types';
2
2
  export declare const useStoryblok: (slug: string, apiOptions?: ISbStoriesParams, bridgeOptions?: StoryblokBridgeConfigV2) => ISbStoryData<import("@storyblok/js").StoryblokComponentType<string> & {
3
3
  [index: string]: any;
4
4
  }>;
5
- export * from "./common";
6
- export * from "./common/client";
5
+ export * from './common';
6
+ export * from './common/client';
@@ -0,0 +1,11 @@
1
+ import type { SbReactComponentsMap, SbReactSDKOptions, StoryblokClient } from '../types';
2
+ export declare const useStoryblokApi: () => StoryblokClient;
3
+ export declare const setComponents: (newComponentsMap: SbReactComponentsMap) => Map<string, import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements>>;
4
+ export declare const getComponent: (componentKey: string) => React.ElementType | false;
5
+ export declare const getEnableFallbackComponent: () => boolean;
6
+ export declare const getCustomFallbackComponent: () => import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements>;
7
+ export declare const storyblokInit: (pluginOptions?: SbReactSDKOptions) => (() => StoryblokClient);
8
+ export * from '../types';
9
+ export { useStoryblokApi as getStoryblokApi };
10
+ export { default as StoryblokServerComponent } from './server-component';
11
+ export { apiPlugin, loadStoryblokBridge, registerStoryblokBridge, renderRichText, RichTextResolver, RichTextSchema, storyblokEditable, useStoryblokBridge, } from '@storyblok/js';
@@ -1,4 +1,2 @@
1
- export * from "../common";
2
- export { default as StoryblokStory } from "../story";
3
- export { default as BridgeLoader } from "../bridge-loader";
4
- export { default as StoryblokBridgeLoader } from "../bridge-loader";
1
+ export * from './common';
2
+ export { default as StoryblokStory } from './story';
@@ -0,0 +1,4 @@
1
+ export declare function liveEditUpdateAction({ story, pathToRevalidate }: {
2
+ story: any;
3
+ pathToRevalidate: any;
4
+ }): Promise<void>;
@@ -0,0 +1,5 @@
1
+ declare const StoryblokLiveEditing: ({ story, bridgeOptions }: {
2
+ story?: any;
3
+ bridgeOptions?: {};
4
+ }) => any;
5
+ export default StoryblokLiveEditing;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { SbBlokData } from '../types';
3
+ interface SbServerComponentProps {
4
+ blok: SbBlokData;
5
+ [key: string]: unknown;
6
+ }
7
+ declare const StoryblokServerComponent: React.ForwardRefExoticComponent<Omit<SbServerComponentProps, "ref"> & React.RefAttributes<HTMLElement>>;
8
+ export default StoryblokServerComponent;
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import { ISbStoryData, StoryblokBridgeConfigV2 } from "./types";
1
+ import React from 'react';
2
+ import type { ISbStoryData, StoryblokBridgeConfigV2 } from '../types';
3
3
  interface StoryblokStoryProps {
4
4
  story: ISbStoryData;
5
5
  bridgeOptions: StoryblokBridgeConfigV2;
@@ -1,6 +1,5 @@
1
- import React from "react";
2
- import { SbSDKOptions } from "@storyblok/js";
3
- import type { ISbStoryData, StoryblokBridgeConfigV2 } from "@storyblok/js";
1
+ import type React from 'react';
2
+ import type { ISbStoryData, SbSDKOptions, StoryblokBridgeConfigV2 } from '@storyblok/js';
4
3
  export interface SbReactComponentsMap {
5
4
  [key: string]: React.ElementType;
6
5
  }
@@ -10,4 +9,4 @@ export interface SbReactSDKOptions extends SbSDKOptions {
10
9
  customFallbackComponent?: React.ElementType;
11
10
  }
12
11
  export type TUseStoryblokState = <T = void>(initialStory: ISbStoryData<T> | null, bridgeOptions?: StoryblokBridgeConfigV2) => ISbStoryData<T> | null;
13
- export type { ISbConfig, ISbCache, ISbResult, ISbResponse, ISbError, ISbNode, ISbSchema, ThrottleFn, AsyncFn, ArrayFn, ISbContentMangmntAPI, ISbManagmentApiResult, ISbStories, ISbStory, ISbDimensions, ISbStoryData, ISbAlternateObject, ISbStoriesParams, ISbStoryParams, ISbRichtext, SbBlokData, SbBlokKeyDataTypes, SbRichTextOptions, SbSDKOptions, StoryblokBridgeConfigV2, StoryblokBridgeV2, StoryblokClient, StoryblokComponentType, useStoryblokBridge, } from "@storyblok/js";
12
+ export type { ArrayFn, AsyncFn, ISbAlternateObject, ISbCache, ISbConfig, ISbContentMangmntAPI, ISbDimensions, ISbError, ISbManagmentApiResult, ISbNode, ISbResponse, ISbResult, ISbRichtext, ISbSchema, ISbStories, ISbStoriesParams, ISbStory, ISbStoryData, ISbStoryParams, SbBlokData, SbBlokKeyDataTypes, SbRichTextOptions, SbSDKOptions, StoryblokBridgeConfigV2, StoryblokBridgeV2, StoryblokClient, StoryblokComponentType, ThrottleFn, useStoryblokBridge, } from '@storyblok/js';
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "@storyblok/react",
3
- "version": "3.0.14",
3
+ "version": "4.0.0",
4
4
  "description": "SDK to integrate Storyblok into your project using React.",
5
- "main": "./dist/index.js",
6
- "module": "./dist/index.mjs",
7
- "types": "./dist/types/index.d.ts",
8
- "files": [
9
- "dist"
10
- ],
5
+ "author": "Storyblok",
6
+ "homepage": "https://github.com/storyblok/storyblok-react",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/storyblok/storyblok-react"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/storyblok/storyblok-react/issues"
13
+ },
11
14
  "exports": {
12
15
  ".": {
13
16
  "types": "./dist/types/index.d.ts",
@@ -30,6 +33,12 @@
30
33
  "require": "./dist/story.js"
31
34
  }
32
35
  },
36
+ "main": "./dist/index.js",
37
+ "module": "./dist/index.mjs",
38
+ "types": "./dist/types/index.d.ts",
39
+ "files": [
40
+ "dist"
41
+ ],
33
42
  "scripts": {
34
43
  "dev": "vite build --watch",
35
44
  "build": "vite build && tsc --project tsconfig.json",
@@ -43,31 +52,32 @@
43
52
  "test:comp": "cypress run-ct",
44
53
  "prepublishOnly": "npm run build && cp ../README.md ./"
45
54
  },
55
+ "peerDependencies": {
56
+ "react": "^17.0.0 || ^18.0.0",
57
+ "react-dom": "^17.0.0 || ^18.0.0"
58
+ },
46
59
  "dependencies": {
47
- "@storyblok/js": "^3.1.1"
60
+ "@storyblok/js": "^3.1.1",
61
+ "next": "14.2.14"
48
62
  },
49
63
  "devDependencies": {
50
64
  "@babel/core": "^7.25.2",
51
65
  "@babel/preset-env": "^7.25.4",
52
66
  "@cypress/react": "^8.0.2",
53
- "@cypress/vite-dev-server": "^5.1.1",
67
+ "@cypress/vite-dev-server": "^5.2.0",
54
68
  "@tsconfig/recommended": "^1.0.7",
55
69
  "@types/react": "18.3.4",
56
70
  "@vitejs/plugin-react": "^4.3.1",
57
71
  "babel-jest": "^29.7.0",
58
- "cypress": "^13.13.3",
72
+ "cypress": "^13.14.2",
59
73
  "eslint-plugin-cypress": "^3.5.0",
60
- "eslint-plugin-jest": "^28.8.0",
74
+ "eslint-plugin-jest": "^28.8.3",
61
75
  "jest": "^29.7.0",
62
76
  "react": "^18.3.1",
63
77
  "react-dom": "^18.3.1",
64
78
  "rollup-plugin-preserve-directives": "^0.4.0",
65
79
  "start-server-and-test": "^2.0.5",
66
- "vite": "^5.4.2"
67
- },
68
- "peerDependencies": {
69
- "react": "^17.0.0 || ^18.0.0",
70
- "react-dom": "^17.0.0 || ^18.0.0"
80
+ "vite": "^5.4.3"
71
81
  },
72
82
  "babel": {
73
83
  "presets": [
@@ -95,15 +105,6 @@
95
105
  "main"
96
106
  ]
97
107
  },
98
- "repository": {
99
- "type": "git",
100
- "url": "https://github.com/storyblok/storyblok-react"
101
- },
102
- "author": "Storyblok",
103
- "bugs": {
104
- "url": "https://github.com/storyblok/storyblok-react/issues"
105
- },
106
- "homepage": "https://github.com/storyblok/storyblok-react",
107
108
  "publishConfig": {
108
109
  "access": "public"
109
110
  }
@@ -1,2 +0,0 @@
1
- "use client";
2
- "use strict";const o=require("react"),r=require("./storyblok-js.js"),t=async e=>{await r.loadStoryblokBridge(),new window.StoryblokBridge(e).on(["published","change"],()=>{window.location.reload()})},n=({options:e})=>(t(e),o.createElement(o.Fragment,null));module.exports=n;
@@ -1,11 +0,0 @@
1
- "use client";
2
- import o from "react";
3
- import { loadStoryblokBridge as r } from "./storyblok-js.mjs";
4
- const t = async (e) => {
5
- await r(), new window.StoryblokBridge(e).on(["published", "change"], () => {
6
- window.location.reload();
7
- });
8
- }, i = ({ options: e }) => (t(e), /* @__PURE__ */ o.createElement(o.Fragment, null));
9
- export {
10
- i as default
11
- };
@@ -1,8 +0,0 @@
1
- import React from "react";
2
- import { StoryblokBridgeConfigV2 } from "./types";
3
- interface StoryblokBridgeLoaderProps {
4
- options: StoryblokBridgeConfigV2;
5
- [key: string]: unknown;
6
- }
7
- declare const StoryblokBridgeLoader: ({ options }: StoryblokBridgeLoaderProps) => React.JSX.Element;
8
- export default StoryblokBridgeLoader;