@storyblok/react 4.7.0 → 5.0.1
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 +103 -103
- package/dist/common/index.d.ts +1 -1
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common.js +1 -1
- package/dist/common.mjs +12 -14
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +37 -39
- package/dist/index2.js +1 -1
- package/dist/index2.mjs +18 -20
- package/dist/richtext.mjs +3 -3
- package/dist/rsc/common.d.ts +1 -1
- package/dist/rsc/common.d.ts.map +1 -1
- package/dist/rsc.js +1 -1
- package/dist/rsc.mjs +17 -19
- package/dist/storyblok-js.js +1 -24
- package/dist/storyblok-js.mjs +471 -793
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +32 -51
package/README.md
CHANGED
|
@@ -31,12 +31,15 @@
|
|
|
31
31
|
</p>
|
|
32
32
|
|
|
33
33
|
## Kickstart a new project
|
|
34
|
+
|
|
34
35
|
Are you eager to dive into coding? **[Follow these steps to kickstart a new project with Storyblok and React](https://www.storyblok.com/technologies?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react#react)**, and get started in just a few minutes!
|
|
35
36
|
|
|
36
37
|
## 5-minute Tutorial
|
|
38
|
+
|
|
37
39
|
Are you looking for a hands-on, step-by-step tutorial? The **[React 5-minute Tutorial](https://www.storyblok.com/tp/headless-cms-react?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react)** has you covered! It provides comprehensive instructions on how to set up a Storyblok space and connect it to your React project.
|
|
38
40
|
|
|
39
41
|
## Ultimate Tutorial
|
|
42
|
+
|
|
40
43
|
Are you looking for a hands-on, step-by-step tutorial? The **[Next.js Ultimate Tutorial](https://www.storyblok.com/tp/nextjs-headless-cms-ultimate-tutorial?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react)** has you covered! It provides comprehensive instructions on building a complete, multilingual website using Storyblok and Next.js from start to finish.
|
|
41
44
|
|
|
42
45
|
## Installation
|
|
@@ -63,15 +66,15 @@ Install the file from the CDN:
|
|
|
63
66
|
Register the plugin on your application and add the [access token](https://www.storyblok.com/docs/api/content-delivery/v2/getting-started/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
67
|
|
|
65
68
|
```js
|
|
66
|
-
import { apiPlugin, storyblokInit } from
|
|
69
|
+
import { apiPlugin, storyblokInit } from "@storyblok/react";
|
|
67
70
|
|
|
68
71
|
/** Import your components */
|
|
69
|
-
import Page from
|
|
70
|
-
import Teaser from
|
|
72
|
+
import Page from "./components/Page";
|
|
73
|
+
import Teaser from "./components/Teaser";
|
|
71
74
|
// import FallbackComponent from "./components/FallbackComponent";
|
|
72
75
|
|
|
73
76
|
storyblokInit({
|
|
74
|
-
accessToken:
|
|
77
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
75
78
|
use: [apiPlugin],
|
|
76
79
|
components: {
|
|
77
80
|
page: Page,
|
|
@@ -82,7 +85,7 @@ storyblokInit({
|
|
|
82
85
|
// richText: {},
|
|
83
86
|
// enableFallbackComponent: false,
|
|
84
87
|
// customFallbackComponent: FallbackComponent,
|
|
85
|
-
})
|
|
88
|
+
});
|
|
86
89
|
```
|
|
87
90
|
|
|
88
91
|
> 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 +109,16 @@ Possible values:
|
|
|
106
109
|
Full example for a space created in the US:
|
|
107
110
|
|
|
108
111
|
```js
|
|
109
|
-
import { apiPlugin, storyblokInit } from
|
|
112
|
+
import { apiPlugin, storyblokInit } from "@storyblok/react";
|
|
110
113
|
|
|
111
114
|
storyblokInit({
|
|
112
|
-
accessToken:
|
|
115
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
113
116
|
use: [apiPlugin],
|
|
114
117
|
apiOptions: {
|
|
115
|
-
region:
|
|
118
|
+
region: "us",
|
|
116
119
|
},
|
|
117
120
|
components: {},
|
|
118
|
-
})
|
|
121
|
+
});
|
|
119
122
|
```
|
|
120
123
|
|
|
121
124
|
> Note: For spaces created in the United States or China, the `region` parameter **must** be specified.
|
|
@@ -129,7 +132,7 @@ storyblokInit({
|
|
|
129
132
|
For every component you've defined in your Storyblok space, call the `storyblokEditable` function with the blok content:
|
|
130
133
|
|
|
131
134
|
```js
|
|
132
|
-
import { storyblokEditable } from
|
|
135
|
+
import { storyblokEditable } from "@storyblok/react";
|
|
133
136
|
|
|
134
137
|
const Feature = ({ blok }) => {
|
|
135
138
|
return (
|
|
@@ -139,10 +142,10 @@ const Feature = ({ blok }) => {
|
|
|
139
142
|
<p>{blok.description}</p>
|
|
140
143
|
</div>
|
|
141
144
|
</div>
|
|
142
|
-
)
|
|
143
|
-
}
|
|
145
|
+
);
|
|
146
|
+
};
|
|
144
147
|
|
|
145
|
-
export default Feature
|
|
148
|
+
export default Feature;
|
|
146
149
|
```
|
|
147
150
|
|
|
148
151
|
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 +167,19 @@ The initalization remains the same when you work with React. You can intialze th
|
|
|
164
167
|
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
168
|
|
|
166
169
|
```js
|
|
167
|
-
import { StoryblokComponent, useStoryblok } from
|
|
170
|
+
import { StoryblokComponent, useStoryblok } from "@storyblok/react";
|
|
168
171
|
|
|
169
172
|
function App() {
|
|
170
|
-
const story = useStoryblok(
|
|
173
|
+
const story = useStoryblok("react", { version: "draft" });
|
|
171
174
|
|
|
172
175
|
if (!story?.content) {
|
|
173
|
-
return <div>Loading...</div
|
|
176
|
+
return <div>Loading...</div>;
|
|
174
177
|
}
|
|
175
178
|
|
|
176
|
-
return <StoryblokComponent blok={story.content}
|
|
179
|
+
return <StoryblokComponent blok={story.content} />;
|
|
177
180
|
}
|
|
178
181
|
|
|
179
|
-
export default App
|
|
182
|
+
export default App;
|
|
180
183
|
```
|
|
181
184
|
|
|
182
185
|
`StoryblokComponent` renders the route components dynamically, using the list of components loaded during the initialization inside the `storyblokInit` function.
|
|
@@ -186,13 +189,13 @@ This is how you can pass the Bridge options as a third parameter to `useStoryblo
|
|
|
186
189
|
```js
|
|
187
190
|
useStoryblok(
|
|
188
191
|
story.id,
|
|
189
|
-
{ version:
|
|
192
|
+
{ version: "draft", resolveRelations: ["Article.author"] },
|
|
190
193
|
{
|
|
191
|
-
resolveRelations: [
|
|
192
|
-
resolveLinks:
|
|
194
|
+
resolveRelations: ["Article.author"],
|
|
195
|
+
resolveLinks: "url",
|
|
193
196
|
preventClicks: true,
|
|
194
|
-
}
|
|
195
|
-
)
|
|
197
|
+
},
|
|
198
|
+
);
|
|
196
199
|
```
|
|
197
200
|
|
|
198
201
|
**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)**
|
|
@@ -212,13 +215,13 @@ Here's how you can fetch data from Storyblok with `cache: "no-store"`:
|
|
|
212
215
|
|
|
213
216
|
```typescript
|
|
214
217
|
export async function fetchData() {
|
|
215
|
-
const sbParams: ISbStoriesParams = { version:
|
|
218
|
+
const sbParams: ISbStoriesParams = { version: "draft" };
|
|
216
219
|
|
|
217
|
-
const storyblokApi: StoryblokClient = getStoryblokApi()
|
|
220
|
+
const storyblokApi: StoryblokClient = getStoryblokApi();
|
|
218
221
|
|
|
219
222
|
return storyblokApi.get(`cdn/stories/home`, sbParams, {
|
|
220
|
-
cache:
|
|
221
|
-
})
|
|
223
|
+
cache: "no-store", // This prevents Next.js 13, 14 default caching behaviour
|
|
224
|
+
});
|
|
222
225
|
}
|
|
223
226
|
```
|
|
224
227
|
|
|
@@ -234,12 +237,12 @@ Create a new file `lib/storyblok.js` and initialize the SDK. Make sure you expor
|
|
|
234
237
|
|
|
235
238
|
```js
|
|
236
239
|
// lib/storyblok.js
|
|
237
|
-
import Page from
|
|
238
|
-
import Teaser from
|
|
239
|
-
import { apiPlugin, storyblokInit } from
|
|
240
|
+
import Page from "@/components/Page";
|
|
241
|
+
import Teaser from "@/components/Teaser";
|
|
242
|
+
import { apiPlugin, storyblokInit } from "@storyblok/react/rsc";
|
|
240
243
|
|
|
241
244
|
export const getStoryblokApi = storyblokInit({
|
|
242
|
-
accessToken:
|
|
245
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
243
246
|
use: [apiPlugin],
|
|
244
247
|
components: {
|
|
245
248
|
teaser: Teaser,
|
|
@@ -252,8 +255,8 @@ In `app/layout.jsx`, wrap your whole app using a `StoryblokProvider` component (
|
|
|
252
255
|
|
|
253
256
|
```js
|
|
254
257
|
// app/layout.jsx
|
|
255
|
-
import { apiPlugin, storyblokInit } from
|
|
256
|
-
import StoryblokProvider from
|
|
258
|
+
import { apiPlugin, storyblokInit } from "@storyblok/react/rsc";
|
|
259
|
+
import StoryblokProvider from "../components/StoryblokProvider";
|
|
257
260
|
|
|
258
261
|
export default function RootLayout({ children }) {
|
|
259
262
|
return (
|
|
@@ -262,7 +265,7 @@ export default function RootLayout({ children }) {
|
|
|
262
265
|
<body>{children}</body>
|
|
263
266
|
</html>
|
|
264
267
|
</StoryblokProvider>
|
|
265
|
-
)
|
|
268
|
+
);
|
|
266
269
|
}
|
|
267
270
|
```
|
|
268
271
|
|
|
@@ -272,9 +275,9 @@ Create the `components/StoryblokProvider.jsx` file. Re-initalize the connection
|
|
|
272
275
|
|
|
273
276
|
```js
|
|
274
277
|
// components/StoryblokProvider.jsx
|
|
275
|
-
|
|
278
|
+
"use client";
|
|
276
279
|
|
|
277
|
-
import { getStoryblokApi } from
|
|
280
|
+
import { getStoryblokApi } from "@/lib/storyblok";
|
|
278
281
|
|
|
279
282
|
export default function StoryblokProvider({ children }) {
|
|
280
283
|
getStoryblokApi();
|
|
@@ -321,11 +324,14 @@ const bridgeOptions = { resolveRelations: ['article.author'] }
|
|
|
321
324
|
> When you render components, you must use `StoryblokServerComponent` exported from `@storyblok/react/rsc` instead of `StoryblokComponent`, even when you declare a client component with `"use client"`. This is because the components are always rendered on the server side.
|
|
322
325
|
|
|
323
326
|
```jsx
|
|
324
|
-
import {
|
|
327
|
+
import {
|
|
328
|
+
storyblokEditable,
|
|
329
|
+
StoryblokServerComponent,
|
|
330
|
+
} from "@storyblok/react/rsc";
|
|
325
331
|
|
|
326
332
|
const Page = ({ blok }) => (
|
|
327
333
|
<main {...storyblokEditable(blok)}>
|
|
328
|
-
{blok.body.map(nestedBlok => (
|
|
334
|
+
{blok.body.map((nestedBlok) => (
|
|
329
335
|
<StoryblokServerComponent blok={nestedBlok} key={nestedBlok._uid} />
|
|
330
336
|
))}
|
|
331
337
|
</main>
|
|
@@ -350,11 +356,11 @@ The initalization remains the same when you work with Next.js. You can intialze
|
|
|
350
356
|
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.
|
|
351
357
|
|
|
352
358
|
```js
|
|
353
|
-
import { getStoryblokApi } from
|
|
359
|
+
import { getStoryblokApi } from "@storyblok/react";
|
|
354
360
|
|
|
355
361
|
// At the required place
|
|
356
|
-
const storyblokApi = getStoryblokApi()
|
|
357
|
-
const { data } = await storyblokApi.get(
|
|
362
|
+
const storyblokApi = getStoryblokApi();
|
|
363
|
+
const { data } = await storyblokApi.get("cdn/stories", { version: "draft" });
|
|
358
364
|
```
|
|
359
365
|
|
|
360
366
|
> 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.
|
|
@@ -364,16 +370,16 @@ const { data } = await storyblokApi.get('cdn/stories', { version: 'draft' })
|
|
|
364
370
|
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.
|
|
365
371
|
|
|
366
372
|
```js
|
|
367
|
-
import { StoryblokComponent, useStoryblokState } from
|
|
373
|
+
import { StoryblokComponent, useStoryblokState } from "@storyblok/react";
|
|
368
374
|
|
|
369
375
|
export default function Home({ story: initialStory }) {
|
|
370
|
-
const story = useStoryblokState(initialStory)
|
|
376
|
+
const story = useStoryblokState(initialStory);
|
|
371
377
|
|
|
372
378
|
if (!story.content) {
|
|
373
|
-
return <div>Loading...</div
|
|
379
|
+
return <div>Loading...</div>;
|
|
374
380
|
}
|
|
375
381
|
|
|
376
|
-
return <StoryblokComponent blok={story.content}
|
|
382
|
+
return <StoryblokComponent blok={story.content} />;
|
|
377
383
|
}
|
|
378
384
|
```
|
|
379
385
|
|
|
@@ -384,23 +390,23 @@ import {
|
|
|
384
390
|
getStoryblokApi,
|
|
385
391
|
StoryblokComponent,
|
|
386
392
|
useStoryblokState,
|
|
387
|
-
} from
|
|
393
|
+
} from "@storyblok/react";
|
|
388
394
|
|
|
389
395
|
export default function Home({ story: initialStory }) {
|
|
390
|
-
const story = useStoryblokState(initialStory)
|
|
396
|
+
const story = useStoryblokState(initialStory);
|
|
391
397
|
|
|
392
398
|
if (!story.content) {
|
|
393
|
-
return <div>Loading...</div
|
|
399
|
+
return <div>Loading...</div>;
|
|
394
400
|
}
|
|
395
401
|
|
|
396
|
-
return <StoryblokComponent blok={story.content}
|
|
402
|
+
return <StoryblokComponent blok={story.content} />;
|
|
397
403
|
}
|
|
398
404
|
|
|
399
405
|
export async function getStaticProps({ preview = false }) {
|
|
400
|
-
const storyblokApi = getStoryblokApi()
|
|
406
|
+
const storyblokApi = getStoryblokApi();
|
|
401
407
|
const { data } = await storyblokApi.get(`cdn/stories/react`, {
|
|
402
|
-
version:
|
|
403
|
-
})
|
|
408
|
+
version: "draft",
|
|
409
|
+
});
|
|
404
410
|
|
|
405
411
|
return {
|
|
406
412
|
props: {
|
|
@@ -408,7 +414,7 @@ export async function getStaticProps({ preview = false }) {
|
|
|
408
414
|
preview,
|
|
409
415
|
},
|
|
410
416
|
revalidate: 3600, // revalidate every hour
|
|
411
|
-
}
|
|
417
|
+
};
|
|
412
418
|
}
|
|
413
419
|
```
|
|
414
420
|
|
|
@@ -489,10 +495,10 @@ You can use an `apiOptions` object. This is passed down to the [storyblok-js-cli
|
|
|
489
495
|
|
|
490
496
|
```js
|
|
491
497
|
storyblokInit({
|
|
492
|
-
accessToken:
|
|
498
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
493
499
|
apiOptions: {
|
|
494
500
|
// storyblok-js-client config object
|
|
495
|
-
cache: { type:
|
|
501
|
+
cache: { type: "memory" },
|
|
496
502
|
},
|
|
497
503
|
use: [apiPlugin],
|
|
498
504
|
components: {
|
|
@@ -501,13 +507,13 @@ storyblokInit({
|
|
|
501
507
|
grid: Grid,
|
|
502
508
|
feature: Feature,
|
|
503
509
|
},
|
|
504
|
-
})
|
|
510
|
+
});
|
|
505
511
|
```
|
|
506
512
|
|
|
507
513
|
If you prefer to use your own fetch method, just remove the `apiPlugin` and `storyblok-js-client` won't be added to your application.
|
|
508
514
|
|
|
509
515
|
```js
|
|
510
|
-
storyblokInit({})
|
|
516
|
+
storyblokInit({});
|
|
511
517
|
```
|
|
512
518
|
|
|
513
519
|
### Storyblok Bridge
|
|
@@ -515,14 +521,14 @@ storyblokInit({})
|
|
|
515
521
|
If you don't use `registerStoryblokBridge`, you still have access to the raw `window.StoryblokBridge`:
|
|
516
522
|
|
|
517
523
|
```js
|
|
518
|
-
const sbBridge = new window.StoryblokBridge(options)
|
|
524
|
+
const sbBridge = new window.StoryblokBridge(options);
|
|
519
525
|
|
|
520
|
-
sbBridge.on([
|
|
526
|
+
sbBridge.on(["input", "published", "change"], (event) => {
|
|
521
527
|
// ...
|
|
522
|
-
})
|
|
528
|
+
});
|
|
523
529
|
```
|
|
524
530
|
|
|
525
|
-
## Rendering Rich Text
|
|
531
|
+
## Rendering Rich Text
|
|
526
532
|
|
|
527
533
|
> [!WARNING]
|
|
528
534
|
> We have identified issues with richtext and Types on React 19 and Next.js 15. As a temporary measure, we advise you to continue using React 18 and Next.js 14 until we have fully resolved the issues.
|
|
@@ -607,19 +613,19 @@ function App() {
|
|
|
607
613
|
</a>
|
|
608
614
|
);
|
|
609
615
|
},
|
|
610
|
-
[BlockTypes.CODE_BLOCK]: (node) =>
|
|
611
|
-
<CodeBlock
|
|
616
|
+
[BlockTypes.CODE_BLOCK]: (node) =>
|
|
617
|
+
<CodeBlock
|
|
612
618
|
class={node?.attrs?.class}
|
|
613
619
|
>
|
|
614
|
-
{node.children}
|
|
620
|
+
{node.children}
|
|
615
621
|
</CodeBlock>;
|
|
616
622
|
}
|
|
617
623
|
|
|
618
624
|
return (
|
|
619
625
|
<div>
|
|
620
|
-
<StoryblokRichText
|
|
626
|
+
<StoryblokRichText
|
|
621
627
|
doc={story.content.richText}
|
|
622
|
-
resolvers={resolvers}
|
|
628
|
+
resolvers={resolvers}
|
|
623
629
|
/>
|
|
624
630
|
</div>
|
|
625
631
|
);
|
|
@@ -634,53 +640,53 @@ function App() {
|
|
|
634
640
|
You can easily render rich text by using the `renderRichText` function that comes with `@storyblok/react`:
|
|
635
641
|
|
|
636
642
|
```js
|
|
637
|
-
import { renderRichText } from
|
|
643
|
+
import { renderRichText } from "@storyblok/react";
|
|
638
644
|
|
|
639
|
-
const renderedRichText = renderRichText(blok.richtext)
|
|
645
|
+
const renderedRichText = renderRichText(blok.richtext);
|
|
640
646
|
```
|
|
641
647
|
|
|
642
648
|
You can set a **custom Schema and component resolver globally** at init time by using the `richText` init option:
|
|
643
649
|
|
|
644
650
|
```js
|
|
645
|
-
import { RichTextSchema, storyblokInit } from
|
|
646
|
-
import cloneDeep from
|
|
651
|
+
import { RichTextSchema, storyblokInit } from "@storyblok/react";
|
|
652
|
+
import cloneDeep from "clone-deep";
|
|
647
653
|
|
|
648
|
-
const mySchema = cloneDeep(RichTextSchema) // you can make a copy of the default RichTextSchema
|
|
654
|
+
const mySchema = cloneDeep(RichTextSchema); // you can make a copy of the default RichTextSchema
|
|
649
655
|
// ... and edit the nodes and marks, or add your own.
|
|
650
656
|
// Check the base RichTextSchema source here https://github.com/storyblok/storyblok-js-client/blob/main/src/schema.ts
|
|
651
657
|
|
|
652
658
|
storyblokInit({
|
|
653
|
-
accessToken:
|
|
659
|
+
accessToken: "<your-token>",
|
|
654
660
|
richText: {
|
|
655
661
|
schema: mySchema,
|
|
656
662
|
resolver: (component, blok) => {
|
|
657
663
|
switch (component) {
|
|
658
|
-
case
|
|
659
|
-
return `<div class="my-component-class">${blok.text}</div
|
|
664
|
+
case "my-custom-component":
|
|
665
|
+
return `<div class="my-component-class">${blok.text}</div>`;
|
|
660
666
|
default:
|
|
661
|
-
return
|
|
667
|
+
return "Resolver not defined";
|
|
662
668
|
}
|
|
663
669
|
},
|
|
664
670
|
},
|
|
665
|
-
})
|
|
671
|
+
});
|
|
666
672
|
```
|
|
667
673
|
|
|
668
674
|
You can also set a **custom Schema and component resolver only once** by passing the options as the second parameter to `renderRichText` function:
|
|
669
675
|
|
|
670
676
|
```js
|
|
671
|
-
import { renderRichText } from
|
|
677
|
+
import { renderRichText } from "@storyblok/react";
|
|
672
678
|
|
|
673
679
|
renderRichText(blok.richTextField, {
|
|
674
680
|
schema: mySchema,
|
|
675
681
|
resolver: (component, blok) => {
|
|
676
682
|
switch (component) {
|
|
677
|
-
case
|
|
678
|
-
return `<div class="my-component-class">${blok.text}</div
|
|
683
|
+
case "my-custom-component":
|
|
684
|
+
return `<div class="my-component-class">${blok.text}</div>`;
|
|
679
685
|
default:
|
|
680
|
-
return `Component ${component} not found
|
|
686
|
+
return `Component ${component} not found`;
|
|
681
687
|
}
|
|
682
688
|
},
|
|
683
|
-
})
|
|
689
|
+
});
|
|
684
690
|
```
|
|
685
691
|
|
|
686
692
|
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.
|
|
@@ -700,7 +706,7 @@ storyblokInit({
|
|
|
700
706
|
components: {
|
|
701
707
|
// all your React components
|
|
702
708
|
},
|
|
703
|
-
})
|
|
709
|
+
});
|
|
704
710
|
```
|
|
705
711
|
|
|
706
712
|
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.
|
|
@@ -713,24 +719,24 @@ Storyblok's React SDK automatically renders these predefined components based on
|
|
|
713
719
|
2. **React's `react.lazy`**:
|
|
714
720
|
React offers a built-in solution called `react.lazy` for code splitting. Instead of directly importing components, you can do the following:
|
|
715
721
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
722
|
+
```javascript
|
|
723
|
+
"use client";
|
|
724
|
+
import { apiPlugin, storyblokInit } from "@storyblok/react/rsc";
|
|
725
|
+
import { lazy } from "react";
|
|
720
726
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
727
|
+
const lazyComponents = {
|
|
728
|
+
page: lazy(() => import("./components/Page")),
|
|
729
|
+
// other lazy-loaded components
|
|
730
|
+
};
|
|
725
731
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
+
storyblokInit({
|
|
733
|
+
accessToken,
|
|
734
|
+
use: [apiPlugin],
|
|
735
|
+
components: lazyComponents,
|
|
736
|
+
});
|
|
737
|
+
```
|
|
732
738
|
|
|
733
|
-
|
|
739
|
+
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).
|
|
734
740
|
|
|
735
741
|
3. **Using `@loadable/component`**:
|
|
736
742
|
For cases where SSR is needed, or in general, you can use the `@loadable/component` library, which offers similar functionality and better SSR support. This library is framework-agnostic and can be used with any React framework. [Loadable Components Documentation](https://loadable-components.com/docs/getting-started/)
|
|
@@ -762,12 +768,6 @@ By using these techniques, you can ensure that only the necessary components and
|
|
|
762
768
|
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?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react#code-of-conduct).
|
|
763
769
|
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.
|
|
764
770
|
|
|
765
|
-
Please run `simple-git-hooks` after cloning the repository to enable the pre-commit hooks.
|
|
766
|
-
|
|
767
|
-
```bash
|
|
768
|
-
pnpm simple-git-hook
|
|
769
|
-
```
|
|
770
|
-
|
|
771
771
|
## License
|
|
772
772
|
|
|
773
773
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/dist/common/index.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export declare const getCustomFallbackComponent: () => import('react').ElementTy
|
|
|
8
8
|
export declare const storyblokInit: (pluginOptions?: SbReactSDKOptions) => void;
|
|
9
9
|
export { useStoryblokApi as getStoryblokApi };
|
|
10
10
|
export { default as StoryblokComponent } from './storyblok-component';
|
|
11
|
-
export { apiPlugin, BlockTypes, loadStoryblokBridge, MarkTypes, registerStoryblokBridge, renderRichText,
|
|
11
|
+
export { apiPlugin, BlockTypes, loadStoryblokBridge, MarkTypes, registerStoryblokBridge, renderRichText, richTextResolver, storyblokEditable, type StoryblokRichTextImageOptimizationOptions, type StoryblokRichTextNode, type StoryblokRichTextNodeResolver, type StoryblokRichTextNodeTypes, type StoryblokRichTextOptions, type StoryblokRichTextResolvers, TextTypes, useStoryblokBridge, } from '@storyblok/js';
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,cAAc,UAAU,CAAC;AAOzB,eAAO,MAAM,eAAe,QAAO,eAQlC,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,kBAAkB,oBAAoB,yBAGnE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,cAAc,MAAM,0FAOhD,CAAC;AAEF,eAAO,MAAM,0BAA0B,eAAgC,CAAC;AACxE,eAAO,MAAM,0BAA0B,qFAAgC,CAAC;AAExE,eAAO,MAAM,aAAa,GAAI,gBAAe,iBAAsB,SAOlE,CAAC;AAEF,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,CAAC;AAE9C,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EACL,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,SAAS,EACT,uBAAuB,EACvB,cAAc,EACd,gBAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,cAAc,UAAU,CAAC;AAOzB,eAAO,MAAM,eAAe,QAAO,eAQlC,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,kBAAkB,oBAAoB,yBAGnE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,cAAc,MAAM,0FAOhD,CAAC;AAEF,eAAO,MAAM,0BAA0B,eAAgC,CAAC;AACxE,eAAO,MAAM,0BAA0B,qFAAgC,CAAC;AAExE,eAAO,MAAM,aAAa,GAAI,gBAAe,iBAAsB,SAOlE,CAAC;AAEF,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,CAAC;AAE9C,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EACL,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,SAAS,EACT,uBAAuB,EACvB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,yCAAyC,EAC9C,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,SAAS,EACT,kBAAkB,GACnB,MAAM,eAAe,CAAC"}
|
package/dist/common.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./storyblok-js.js"),c=require("./server-component.js");let t=null;const n=new Map;let l=!1,s=null;globalThis.storyCache=globalThis.storyCache?globalThis.storyCache:new Map;const a=()=>(t||console.error("You can't use getStoryblokApi if you're not loading apiPlugin."),t),b=o=>(Object.entries(o).forEach(([r,i])=>{n.set(r,i)}),n),k=o=>n.has(o)?n.get(o):(console.error(`Component ${o} doesn't exist.`),!1),g=()=>l,y=()=>s,u=(o={})=>{if(t)return()=>t;const{storyblokApi:r}=e.storyblokInit(o);return t=r,o.components&&b(o.components),l=o.enableFallbackComponent,s=o.customFallbackComponent,()=>r};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.StoryblokServerComponent=c;exports.getComponent=k;exports.getCustomFallbackComponent=y;exports.getEnableFallbackComponent=g;exports.getStoryblokApi=a;exports.setComponents=b;exports.storyblokInit=u;exports.useStoryblokApi=a;
|
package/dist/common.mjs
CHANGED
|
@@ -1,35 +1,33 @@
|
|
|
1
1
|
import { storyblokInit as a } from "./storyblok-js.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { default as
|
|
2
|
+
import { apiPlugin as C, loadStoryblokBridge as f, registerStoryblokBridge as d, renderRichText as h, storyblokEditable as S, registerStoryblokBridge as F } from "./storyblok-js.mjs";
|
|
3
|
+
import { default as A } from "./server-component.mjs";
|
|
4
4
|
let e = null;
|
|
5
5
|
const r = /* @__PURE__ */ new Map();
|
|
6
6
|
let n = !1, l = null;
|
|
7
7
|
globalThis.storyCache = globalThis.storyCache ? globalThis.storyCache : /* @__PURE__ */ new Map();
|
|
8
8
|
const i = () => (e || console.error(
|
|
9
9
|
"You can't use getStoryblokApi if you're not loading apiPlugin."
|
|
10
|
-
), e),
|
|
10
|
+
), e), b = (o) => (Object.entries(o).forEach(([t, s]) => {
|
|
11
11
|
r.set(t, s);
|
|
12
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
13
|
if (e)
|
|
14
14
|
return () => e;
|
|
15
15
|
const { storyblokApi: t } = a(o);
|
|
16
|
-
return e = t, o.components &&
|
|
16
|
+
return e = t, o.components && b(o.components), n = o.enableFallbackComponent, l = o.customFallbackComponent, () => t;
|
|
17
17
|
};
|
|
18
18
|
export {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
B as StoryblokServerComponent,
|
|
22
|
-
h as apiPlugin,
|
|
19
|
+
A as StoryblokServerComponent,
|
|
20
|
+
C as apiPlugin,
|
|
23
21
|
k as getComponent,
|
|
24
22
|
p as getCustomFallbackComponent,
|
|
25
23
|
m as getEnableFallbackComponent,
|
|
26
24
|
i as getStoryblokApi,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
f as loadStoryblokBridge,
|
|
26
|
+
d as registerStoryblokBridge,
|
|
27
|
+
h as renderRichText,
|
|
28
|
+
b as setComponents,
|
|
29
|
+
S as storyblokEditable,
|
|
32
30
|
u as storyblokInit,
|
|
33
31
|
i as useStoryblokApi,
|
|
34
|
-
|
|
32
|
+
F as useStoryblokBridge
|
|
35
33
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ISbStoriesParams, ISbStoryData, StoryblokBridgeConfigV2 } from './types';
|
|
2
2
|
import { useStoryblokRichText } from './richtext';
|
|
3
|
-
export declare const useStoryblok: (slug: string, apiOptions?: ISbStoriesParams, bridgeOptions?: StoryblokBridgeConfigV2) => ISbStoryData<import('
|
|
3
|
+
export declare const useStoryblok: (slug: string, apiOptions?: ISbStoriesParams, bridgeOptions?: StoryblokBridgeConfigV2) => ISbStoryData<import('storyblok-js-client').ISbComponentType<string> & {
|
|
4
4
|
[index: string]: any;
|
|
5
5
|
}>;
|
|
6
6
|
export * from './common/client';
|
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"),
|
|
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("./richtext.js"),S=require("./client.js"),d=require("./storyblok-rich-text.js"),g=require("./utils.js"),T=require("./storyblok-component.js"),p=(n,r={},t={})=>{const[u,i]=y.useState({}),k=typeof window<"u"&&typeof window.storyblokRegisterEvent<"u",s=o.useStoryblokApi();return y.useEffect(()=>{if(!s){console.error("You can't use useStoryblok if you're not loading apiPlugin.");return}async function b(){const{data:l}=await s.get(`cdn/stories/${n}`,r);i(l.story),k&&l.story.id&&e.registerStoryblokBridge(l.story.id,a=>i(a),t)}b()},[n,JSON.stringify(r),s]),s?(t.resolveRelations=t.resolveRelations??r.resolve_relations,t.resolveLinks=t.resolveLinks??r.resolve_links,u):null},R=c.useStoryblokRichText;exports.BlockTypes=e.BlockTypes;exports.MarkTypes=e.MarkTypes;exports.TextTypes=e.TextTypes;exports.apiPlugin=e.apiPlugin;exports.loadStoryblokBridge=e.loadStoryblokBridge;exports.registerStoryblokBridge=e.registerStoryblokBridge;exports.renderRichText=e.renderRichText;exports.richTextResolver=e.richTextResolver;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.useStoryblokRichText=c.useStoryblokRichText;exports.useStoryblokState=S.useStoryblokState;exports.StoryblokRichText=d;exports.convertAttributesInElement=g.convertAttributesInElement;exports.StoryblokComponent=T;exports.useStoryblok=p;exports.useStoryblokRichTextResolver=R;
|