@storyblok/react 1.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 +225 -0
- package/dist/storyblok-react.js +5 -0
- package/dist/storyblok-react.mjs +524 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
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>
|
|
6
|
+
<p align="center">
|
|
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>.
|
|
8
|
+
</p>
|
|
9
|
+
<br />
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://npmjs.com/package/@storyblok/react">
|
|
14
|
+
<img src="https://img.shields.io/npm/v/@storyblok/react/latest.svg?style=flat-square" alt="Storyblok React" />
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://npmjs.com/package/@storyblok/react" rel="nofollow">
|
|
17
|
+
<img src="https://img.shields.io/npm/dt/@storyblok/react.svg?style=flat-square" alt="npm">
|
|
18
|
+
</a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<a href="https://discord.gg/jKrbAMz">
|
|
23
|
+
<img src="https://img.shields.io/discord/700316478792138842?label=Join%20Our%20Discord%20Community&style=appveyor&logo=discord&color=09b3af">
|
|
24
|
+
</a>
|
|
25
|
+
<a href="https://twitter.com/intent/follow?screen_name=storyblok">
|
|
26
|
+
<img src="https://img.shields.io/badge/Follow-%40storyblok-09b3af?style=appveyor&logo=twitter" alt="Follow @Storyblok" />
|
|
27
|
+
</a>
|
|
28
|
+
<a href="https://app.storyblok.com/#!/signup?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react">
|
|
29
|
+
<img src="https://img.shields.io/badge/Try%20Storyblok-Free-09b3af?style=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAHqADAAQAAAABAAAAHgAAAADpiRU/AAACRElEQVRIDWNgGGmAEd3D3Js3LPrP8D8WXZwSPiMjw6qvPoHhyGYwIXNAbGpbCjbzP0MYuj0YFqMroBV/wCxmIeSju64eDNzMBJUxvP/9i2Hnq5cM1devMnz984eQsQwETeRhYWHgIcJiXqC6VHlFBjUeXgav40cIWkz1oLYXFmGwFBImaDFBHyObcOzdW4aSq5eRhRiE2dgYlpuYoYSKJi8vw3GgWnyAJIs/AuPu4scPGObd/fqVQZ+PHy7+6udPOBsXgySLDfn5GRYYmaKYJcXBgWLpsx8/GPa8foWiBhuHJIsl2DkYQqWksZkDFgP5PObcKYYff//iVAOTIDlx/QPqRMb/YSYBaWlOToZIaVkGZmAZSQiQ5OPtwHwacuo4iplMQEu6tXUZMhSUGDiYmBjylFQYvv/7x9B04xqKOnQOyT5GN+Df//8M59ASXKyMHLoyDD5JPtbj42OYrm+EYgg70JfuYuIoYmLs7AwMjIzA+uY/zjAnyWJpDk6GOFnCvrn86SOwmsNtKciVFAc1ileBHFDC67lzG10Yg0+SjzF0ownsf/OaofvOLYaDQJoQIGix94ljv1gIZI8Pv38zPvj2lQWYf3HGKbpDCFp85v07NnRN1OBTPY6JdRSGxcCw2k6sZuLVMZ5AV4s1TozPnGGFKbz+/PE7IJsHmC//MDMyhXBw8e6FyRFLv3Z0/IKuFqvFyIqAzd1PwBzJw8jAGPfVx38JshwlbIygxmYY43/GQmpais0ODDHuzevLMARHBcgIAQAbOJHZW0/EyQAAAABJRU5ErkJggg==" alt="Follow @Storyblok" />
|
|
30
|
+
</a>
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
## 🚀 Usage
|
|
34
|
+
|
|
35
|
+
> If you are first-time user of the Storyblok, read the [Getting Started](https://www.storyblok.com/docs/guide/getting-started?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react) guide to get a project ready in less than 5 minutes.
|
|
36
|
+
|
|
37
|
+
### Installation
|
|
38
|
+
|
|
39
|
+
Install `@storyblok/react`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @storyblok/react
|
|
43
|
+
// yarn add @storyblok/react
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### From a CDN
|
|
47
|
+
|
|
48
|
+
Install the file from the CDN:
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<script src="https://unpkg.com/@storyblok/react"></script>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Initialization
|
|
55
|
+
|
|
56
|
+
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:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
import { storyblokInit, apiPlugin } from "@storyblok/react";
|
|
60
|
+
|
|
61
|
+
storyblokInit({
|
|
62
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
63
|
+
// bridge: false,
|
|
64
|
+
// apiOptions: { },
|
|
65
|
+
use: [apiPlugin],
|
|
66
|
+
components: {
|
|
67
|
+
page: Page,
|
|
68
|
+
teaser: Teaser,
|
|
69
|
+
grid: Grid,
|
|
70
|
+
feature: Feature,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
> Add all your components to the components object in the `storyblokInit` function.
|
|
76
|
+
|
|
77
|
+
That's it! All the features are enabled for you: the _Api Client_ for interacting with [Storyblok CDN API](https://www.storyblok.com/docs/api/content-delivery#topics/introduction?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react), and _Storyblok Bridge_ for [real-time visual editing experience](https://www.storyblok.com/docs/guide/essentials/visual-editor?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react).
|
|
78
|
+
|
|
79
|
+
> You can enable/disable some of these features if you don't need them, so you save some KB. Please read the "Features and API" section
|
|
80
|
+
|
|
81
|
+
### Getting Started
|
|
82
|
+
|
|
83
|
+
`@storyblok/react` does three actions when you initialize it:
|
|
84
|
+
|
|
85
|
+
- Provides a `useStoryblokApi` object in your app, which is an instance of [storyblok-js-client](https://github.com/storyblok/storyblok-js-client).
|
|
86
|
+
- Loads [Storyblok Bridge](https://www.storyblok.com/docs/Guides/storyblok-latest-js?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react) for real-time visual updates.
|
|
87
|
+
- Provides a `storyblokEditable` function to link editable components to the Storyblok Visual Editor.
|
|
88
|
+
|
|
89
|
+
#### 1. Fetching Content
|
|
90
|
+
|
|
91
|
+
Inject `storyblokApi`:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
import { storyblokInit, apiPlugin } from "@storyblok/react";
|
|
95
|
+
|
|
96
|
+
const { useStoryblokApi } = storyblokInit({
|
|
97
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
98
|
+
// bridge: false,
|
|
99
|
+
// apiOptions: { },
|
|
100
|
+
use: [apiPlugin],
|
|
101
|
+
components: {
|
|
102
|
+
page: Page,
|
|
103
|
+
teaser: Teaser,
|
|
104
|
+
grid: Grid,
|
|
105
|
+
feature: Feature,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const { data } = await storyblokApi.get("cdn/stories", { version: "draft" });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
> Note: if you don't use `apiPlugin`, you can use your prefered method or function to fetch your data.
|
|
113
|
+
|
|
114
|
+
#### 2. Listen to Storyblok Visual Editor events
|
|
115
|
+
|
|
116
|
+
Use `useStoryblok` to get the new story every time is triggered a `change` event from the Visual Editor. You need to pass the `slug` as first param, and `apiOptions` as second param to update the new story. `bridgeOptions` (third param) is optional param if you want to set the options for bridge by yourself:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
import { useStoryblok, StoryblokComponent } from "@storyblok/react";
|
|
120
|
+
|
|
121
|
+
function App() {
|
|
122
|
+
const story = useStoryblok("react", { version: "draft" });
|
|
123
|
+
|
|
124
|
+
if (!story?.content) {
|
|
125
|
+
return <div>Loading...</div>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return <StoryblokComponent blok={story.content} />;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default App;
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
You can pass Bridge options as a third parameter as well:
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
useStoryblok(story.id, (story) => (state.story = story), {
|
|
138
|
+
resolveRelations: ["Article.author"],
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### 3. Link your components to Storyblok Visual Editor
|
|
143
|
+
|
|
144
|
+
For every component you've defined in your Storyblok space, call the `storyblokEditable` function with the blok content:
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
import { storyblokEditable } from "@storyblok/react";
|
|
148
|
+
|
|
149
|
+
const Feature = ({ blok }) => {
|
|
150
|
+
return (
|
|
151
|
+
<div {...storyblokEditable(blok)} key={blok._uid} data-test="feature">
|
|
152
|
+
<div>
|
|
153
|
+
<div>{blok.name}</div>
|
|
154
|
+
<p>{blok.description}</p>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default Feature;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Where `blok` is the actual blok data coming from [Storblok's Content Delivery API](https://www.storyblok.com/docs/api/content-delivery?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react).
|
|
164
|
+
|
|
165
|
+
### Features and API
|
|
166
|
+
|
|
167
|
+
You can **choose the features to use** when you initialize the plugin. In that way, you can improve Web Performance by optimizing your page load and save some bytes.
|
|
168
|
+
|
|
169
|
+
#### Storyblok API
|
|
170
|
+
|
|
171
|
+
You can use an `apiOptions` object. This is passed down to the (storyblok-js-client config object](https://github.com/storyblok/storyblok-js-client#class-storyblok):
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
const { useStoryblokApi } = storyblokInit({
|
|
175
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
176
|
+
apiOptions: {
|
|
177
|
+
// storyblok-js-client config object
|
|
178
|
+
cache: { type: "memory" },
|
|
179
|
+
},
|
|
180
|
+
use: [apiPlugin],
|
|
181
|
+
components: {
|
|
182
|
+
page: Page,
|
|
183
|
+
teaser: Teaser,
|
|
184
|
+
grid: Grid,
|
|
185
|
+
feature: Feature,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
If you prefer to use your own fetch method, just remove the `apiPlugin` and `storyblok-js-client` won't be added to your application.
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
storyblokInit({});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Storyblok Bridge
|
|
197
|
+
|
|
198
|
+
If you don't use `useSbBridge`, you have still access to the raw `window.StoryblokBridge`:
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
const sbBridge = new window.StoryblokBridge(options);
|
|
202
|
+
|
|
203
|
+
sbBridge.on(["input", "published", "change"], (event) => {
|
|
204
|
+
// ...
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 🔗 Related Links
|
|
209
|
+
|
|
210
|
+
- **[Storyblok Technology Hub](https://www.storyblok.com/technologies?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react)**: Storyblok integrates with every framework so that you are free to choose the best fit for your project. We prepared the technology hub so that you can find selected beginner tutorials, videos, boilerplates, and even cheatsheets all in one place.
|
|
211
|
+
- **[Getting Started](https://www.storyblok.com/docs/guide/getting-started?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-react)**: Get a project ready in less than 5 minutes.
|
|
212
|
+
- **[Storyblok CLI](https://github.com/storyblok/storyblok)**: A simple CLI for scaffolding Storyblok projects and fieldtypes.
|
|
213
|
+
- **[Storyblok Next.js Technology Hub](https://www.storyblok.com/tc/nextjs)**: Learn how to develop your own Next.js applications that use Storyblok APIs to retrieve and manage content.
|
|
214
|
+
|
|
215
|
+
## ℹ️ More Resources
|
|
216
|
+
|
|
217
|
+
### Support
|
|
218
|
+
|
|
219
|
+
- Bugs or Feature Requests? [Submit an issue](/../../issues/new).
|
|
220
|
+
- Do you have questions about Storyblok or you need help? [Join our Discord Community](https://discord.gg/jKrbAMz).
|
|
221
|
+
|
|
222
|
+
### Contributing
|
|
223
|
+
|
|
224
|
+
Please see our [contributing guidelines](https://github.com/storyblok/.github/blob/main/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).
|
|
225
|
+
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.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
var ne=Object.defineProperty;var v=Object.getOwnPropertySymbols;var I=Object.prototype.hasOwnProperty,x=Object.prototype.propertyIsEnumerable;var M=(l,h,p)=>h in l?ne(l,h,{enumerable:!0,configurable:!0,writable:!0,value:p}):l[h]=p,N=(l,h)=>{for(var p in h||(h={}))I.call(h,p)&&M(l,p,h[p]);if(v)for(var p of v(h))x.call(h,p)&&M(l,p,h[p]);return l};var q=(l,h)=>{var p={};for(var f in l)I.call(l,f)&&h.indexOf(f)<0&&(p[f]=l[f]);if(l!=null&&v)for(var f of v(l))h.indexOf(f)<0&&x.call(l,f)&&(p[f]=l[f]);return p};(function(l,h){typeof exports=="object"&&typeof module!="undefined"?h(exports,require("react"),require("axios")):typeof define=="function"&&define.amd?define(["exports","react","axios"],h):(l=typeof globalThis!="undefined"?globalThis:l||self,h(l.storyblokReact={},l.React,l.t))})(this,function(l,h,p){"use strict";function f(s){return s&&typeof s=="object"&&"default"in s?s:{default:s}}var E=f(h),B=f(p),L=Object.defineProperty,U=Object.defineProperties,V=Object.getOwnPropertyDescriptors,R=Object.getOwnPropertySymbols,D=Object.prototype.hasOwnProperty,J=Object.prototype.propertyIsEnumerable,O=(s,e,t)=>e in s?L(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t,g=(s,e)=>{for(var t in e||(e={}))D.call(e,t)&&O(s,t,e[t]);if(R)for(var t of R(e))J.call(e,t)&&O(s,t,e[t]);return s},_=(s,e)=>U(s,V(e));let P=!1;const j=[],Y=s=>new Promise((e,t)=>{if(typeof window=="undefined"||(window.storyblokRegisterEvent=o=>{if(window.location===window.parent.location){console.warn("You are not in Draft Mode or in the Visual Editor.");return}P?o():j.push(o)},document.getElementById("storyblok-javascript-bridge")))return;const r=document.createElement("script");r.async=!0,r.src=s,r.id="storyblok-javascript-bridge",r.onerror=o=>t(o),r.onload=o=>{j.forEach(n=>n()),P=!0,e(o)},document.getElementsByTagName("head")[0].appendChild(r)});/*!
|
|
2
|
+
* storyblok-js-client v0.0.0-development
|
|
3
|
+
* Universal JavaScript SDK for Storyblok's API
|
|
4
|
+
* (c) 2020-2022 Stobylok Team
|
|
5
|
+
*/function C(s){return typeof s=="number"&&s==s&&s!==1/0&&s!==-1/0}function A(s,e,t){if(!C(e))throw new TypeError("Expected `limit` to be a finite number");if(!C(t))throw new TypeError("Expected `interval` to be a finite number");var r=[],o=[],n=0,i=function(){n++;var u=setTimeout(function(){n--,r.length>0&&i(),o=o.filter(function(d){return d!==u})},t);o.indexOf(u)<0&&o.push(u);var c=r.shift();c.resolve(s.apply(c.self,c.args))},a=function(){var u=arguments,c=this;return new Promise(function(d,k){r.push({resolve:d,reject:k,args:u,self:c}),n<e&&i()})};return a.abort=function(){o.forEach(clearTimeout),o=[],r.forEach(function(u){u.reject(new throttle.AbortError)}),r.length=0},a}A.AbortError=function(){Error.call(this,"Throttled function aborted"),this.name="AbortError"};const z=function(s,e){if(!s)return null;let t={};for(let r in s){let o=s[r];e.indexOf(r)>-1&&o!==null&&(t[r]=o)}return t};var H={nodes:{horizontal_rule:s=>({singleTag:"hr"}),blockquote:s=>({tag:"blockquote"}),bullet_list:s=>({tag:"ul"}),code_block:s=>({tag:["pre",{tag:"code",attrs:s.attrs}]}),hard_break:s=>({singleTag:"br"}),heading:s=>({tag:"h"+s.attrs.level}),image:s=>({singleTag:[{tag:"img",attrs:z(s.attrs,["src","alt","title"])}]}),list_item:s=>({tag:"li"}),ordered_list:s=>({tag:"ol"}),paragraph:s=>({tag:"p"})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"strike"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link(s){const e=g({},s.attrs),{linktype:t="url"}=s.attrs;return t==="email"&&(e.href="mailto:"+e.href),e.anchor&&(e.href=`${e.href}#${e.anchor}`,delete e.anchor),{tag:[{tag:"a",attrs:e}]}},styled:s=>({tag:[{tag:"span",attrs:s.attrs}]})}};class F{constructor(e){e||(e=H),this.marks=e.marks||[],this.nodes=e.nodes||[]}addNode(e,t){this.nodes[e]=t}addMark(e,t){this.marks[e]=t}render(e={}){if(e.content&&Array.isArray(e.content)){let t="";return e.content.forEach(r=>{t+=this.renderNode(r)}),t}return console.warn("The render method must receive an object with a content field, which is an array"),""}renderNode(e){let t=[];e.marks&&e.marks.forEach(o=>{const n=this.getMatchingMark(o);n&&t.push(this.renderOpeningTag(n.tag))});const r=this.getMatchingNode(e);return r&&r.tag&&t.push(this.renderOpeningTag(r.tag)),e.content?e.content.forEach(o=>{t.push(this.renderNode(o))}):e.text?t.push(function(o){const n={"&":"&","<":"<",">":">",'"':""","'":"'"},i=/[&<>"']/g,a=RegExp(i.source);return o&&a.test(o)?o.replace(i,u=>n[u]):o}(e.text)):r&&r.singleTag?t.push(this.renderTag(r.singleTag," /")):r&&r.html&&t.push(r.html),r&&r.tag&&t.push(this.renderClosingTag(r.tag)),e.marks&&e.marks.slice(0).reverse().forEach(o=>{const n=this.getMatchingMark(o);n&&t.push(this.renderClosingTag(n.tag))}),t.join("")}renderTag(e,t){return e.constructor===String?`<${e}${t}>`:e.map(r=>{if(r.constructor===String)return`<${r}${t}>`;{let o="<"+r.tag;if(r.attrs)for(let n in r.attrs){let i=r.attrs[n];i!==null&&(o+=` ${n}="${i}"`)}return`${o}${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){if(typeof this.nodes[e.type]=="function")return this.nodes[e.type](e)}getMatchingMark(e){if(typeof this.marks[e.type]=="function")return this.marks[e.type](e)}}const G=(s=0,e=s)=>{const t=Math.abs(e-s)||0,r=s<e?1:-1;return((o=0,n)=>[...Array(o)].map(n))(t,(o,n)=>n*r+s)},w=(s,e,t)=>{const r=[];for(const o in s){if(!Object.prototype.hasOwnProperty.call(s,o))continue;const n=s[o],i=t?"":encodeURIComponent(o);let a;a=typeof n=="object"?w(n,e?e+encodeURIComponent("["+i+"]"):i,Array.isArray(n)):(e?e+encodeURIComponent("["+i+"]"):i)+"="+encodeURIComponent(n),r.push(a)}return r.join("&")};let b={},y={};class Q{constructor(e,t){if(!t){let n=e.region?"-"+e.region:"",i=e.https===!1?"http":"https";t=e.oauthToken===void 0?`${i}://api${n}.storyblok.com/v2`:`${i}://api${n}.storyblok.com/v1`}let r=Object.assign({},e.headers),o=5;e.oauthToken!==void 0&&(r.Authorization=e.oauthToken,o=3),e.rateLimit!==void 0&&(o=e.rateLimit),this.richTextResolver=new F(e.richTextSchema),typeof e.componentResolver=="function"&&this.setComponentResolver(e.componentResolver),this.maxRetries=e.maxRetries||5,this.throttle=A(this.throttledRequest,o,1e3),this.accessToken=e.accessToken,this.relations={},this.links={},this.cache=e.cache||{clear:"manual"},this.client=B.default.create({baseURL:t,timeout:e.timeout||0,headers:r,proxy:e.proxy||!1}),e.responseInterceptor&&this.client.interceptors.response.use(n=>e.responseInterceptor(n))}setComponentResolver(e){this.richTextResolver.addNode("blok",t=>{let r="";return t.attrs.body.forEach(o=>{r+=e(o.component,o)}),{html:r}})}parseParams(e={}){return e.version||(e.version="published"),e.token||(e.token=this.getToken()),e.cv||(e.cv=y[e.token]),Array.isArray(e.resolve_relations)&&(e.resolve_relations=e.resolve_relations.join(",")),e}factoryParamOptions(e,t={}){return((r="")=>r.indexOf("/cdn/")>-1)(e)?this.parseParams(t):t}makeRequest(e,t,r,o){const n=this.factoryParamOptions(e,((i={},a=25,u=1)=>_(g({},i),{per_page:a,page:u}))(t,r,o));return this.cacheResponse(e,n)}get(e,t){let r="/"+e;const o=this.factoryParamOptions(r,t);return this.cacheResponse(r,o)}async getAll(e,t={},r){const o=t.per_page||25,n="/"+e,i=n.split("/");r=r||i[i.length-1];const a=await this.makeRequest(n,t,o,1),u=Math.ceil(a.total/o);return((c=[],d)=>c.map(d).reduce((k,se)=>[...k,...se],[]))([a,...await(async(c=[],d)=>Promise.all(c.map(d)))(G(1,u),async c=>this.makeRequest(n,t,o,c+1))],c=>Object.values(c.data[r]))}post(e,t){let r="/"+e;return this.throttle("post",r,t)}put(e,t){let r="/"+e;return this.throttle("put",r,t)}delete(e,t){let r="/"+e;return this.throttle("delete",r,t)}getStories(e){return this.get("cdn/stories",e)}getStory(e,t){return this.get("cdn/stories/"+e,t)}setToken(e){this.accessToken=e}getToken(){return this.accessToken}_cleanCopy(e){return JSON.parse(JSON.stringify(e))}_insertLinks(e,t){const r=e[t];r&&r.fieldtype=="multilink"&&r.linktype=="story"&&typeof r.id=="string"&&this.links[r.id]?r.story=this._cleanCopy(this.links[r.id]):r&&r.linktype==="story"&&typeof r.uuid=="string"&&this.links[r.uuid]&&(r.story=this._cleanCopy(this.links[r.uuid]))}_insertRelations(e,t,r){if(r.indexOf(e.component+"."+t)>-1){if(typeof e[t]=="string")this.relations[e[t]]&&(e[t]=this._cleanCopy(this.relations[e[t]]));else if(e[t].constructor===Array){let o=[];e[t].forEach(n=>{this.relations[n]&&o.push(this._cleanCopy(this.relations[n]))}),e[t]=o}}}iterateTree(e,t){let r=o=>{if(o!=null){if(o.constructor===Array)for(let n=0;n<o.length;n++)r(o[n]);else if(o.constructor===Object){if(o._stopResolving)return;for(let n in o)(o.component&&o._uid||o.type==="link")&&(this._insertRelations(o,n,t),this._insertLinks(o,n)),r(o[n])}}};r(e.content)}async resolveLinks(e,t){let r=[];if(e.link_uuids){const o=e.link_uuids.length;let n=[];const i=50;for(let a=0;a<o;a+=i){const u=Math.min(o,a+i);n.push(e.link_uuids.slice(a,u))}for(let a=0;a<n.length;a++)(await this.getStories({per_page:i,language:t.language,version:t.version,by_uuids:n[a].join(",")})).data.stories.forEach(u=>{r.push(u)})}else r=e.links;r.forEach(o=>{this.links[o.uuid]=_(g({},o),{_stopResolving:!0})})}async resolveRelations(e,t){let r=[];if(e.rel_uuids){const o=e.rel_uuids.length;let n=[];const i=50;for(let a=0;a<o;a+=i){const u=Math.min(o,a+i);n.push(e.rel_uuids.slice(a,u))}for(let a=0;a<n.length;a++)(await this.getStories({per_page:i,language:t.language,version:t.version,by_uuids:n[a].join(",")})).data.stories.forEach(u=>{r.push(u)})}else r=e.rels;r.forEach(o=>{this.relations[o.uuid]=_(g({},o),{_stopResolving:!0})})}async resolveStories(e,t){let r=[];t.resolve_relations!==void 0&&t.resolve_relations.length>0&&(r=t.resolve_relations.split(","),await this.resolveRelations(e,t)),["1","story","url"].indexOf(t.resolve_links)>-1&&await this.resolveLinks(e,t);for(const o in this.relations)this.iterateTree(this.relations[o],r);e.story?this.iterateTree(e.story,r):e.stories.forEach(o=>{this.iterateTree(o,r)})}cacheResponse(e,t,r){return r===void 0&&(r=0),new Promise(async(o,n)=>{let i=w({url:e,params:t}),a=this.cacheProvider();if(this.cache.clear==="auto"&&t.version==="draft"&&await this.flushCache(),t.version==="published"&&e!="/cdn/spaces/me"){const c=await a.get(i);if(c)return o(c)}try{let c=await this.throttle("get",e,{params:t,paramsSerializer:k=>w(k)}),d={data:c.data,headers:c.headers};if(c.headers["per-page"]&&(d=Object.assign({},d,{perPage:parseInt(c.headers["per-page"]),total:parseInt(c.headers.total)})),c.status!=200)return n(c);(d.data.story||d.data.stories)&&await this.resolveStories(d.data,t),t.version==="published"&&e!="/cdn/spaces/me"&&a.set(i,d),d.data.cv&&(t.version=="draft"&&y[t.token]!=d.data.cv&&this.flushCache(),y[t.token]=d.data.cv),o(d)}catch(c){if(c.response&&c.response.status===429&&(r+=1)<this.maxRetries)return console.log(`Hit rate limit. Retrying in ${r} seconds.`),await(u=1e3*r,new Promise(d=>setTimeout(d,u))),this.cacheResponse(e,t,r).then(o).catch(n);n(c)}var u})}throttledRequest(e,t,r){return this.client[e](t,r)}cacheVersions(){return y}cacheVersion(){return y[this.accessToken]}setCacheVersion(e){this.accessToken&&(y[this.accessToken]=e)}cacheProvider(){switch(this.cache.type){case"memory":return{get:e=>b[e],getAll:()=>b,set(e,t){b[e]=t},flush(){b={}}};default:return{get(){},getAll(){},set(){},flush(){}}}}async flushCache(){return await this.cacheProvider().flush(),this}}var W=(s={})=>{const{apiOptions:e}=s;if(!e.accessToken){console.error("You need to provide an access token to interact with Storyblok API. Read https://www.storyblok.com/docs/api/content-delivery#topics/authentication");return}return{storyblokApi:new Q(e)}},X=s=>{if(typeof s!="object"||typeof s._editable=="undefined")return{};const e=JSON.parse(s._editable.replace(/^<!--#storyblok#/,"").replace(/-->$/,""));return{"data-blok-c":JSON.stringify(e),"data-blok-uid":e.id+"-"+e.uid}};const T=(s,e,t={})=>{if(typeof window!="undefined"){if(typeof window.storyblokRegisterEvent=="undefined"){console.error("Storyblok Bridge is disabled. Please enable it to use it. Read https://github.com/storyblok/storyblok-js");return}window.storyblokRegisterEvent(()=>{new window.StoryblokBridge(t).on(["input","published","change"],o=>{o.action=="input"&&o.story.id===s?e(o.story):window.location.reload()})})}},Z=(s={})=>{const{bridge:e,accessToken:t,use:r=[],apiOptions:o={}}=s;o.accessToken=o.accessToken||t;const n={bridge:e,apiOptions:o};let i={};return r.forEach(a=>{i=g(g({},i),a(n))}),e!==!1&&Y("https://app.storyblok.com/f/storyblok-v2-latest.js"),i},K=t=>{var r=t,{blok:s}=r,e=q(r,["blok"]);if(!s)return console.error("Please provide a 'blok' property to the StoryblokComponent"),E.default.createElement("div",null,"Please provide a blok property to the StoryblokComponent");const o=$(s.component);return o?E.default.createElement(o,N({blok:s},e)):""},ee=(s,e={},t={})=>{let[r,o]=h.useState({});return m?(T(r.id,n=>o(n),t),h.useEffect(async()=>{const{data:n}=await m.get(`cdn/stories/${s}`,e);o(n.story)},[]),r):(console.error("You can't use useStoryblok if you're not loading apiPlugin."),null)},te=(s={},e={})=>{let[t,r]=h.useState(s);return h.useEffect(()=>{T(t.id,o=>r(o),e)},[]),t};let m=null;const re=()=>(m||console.error("You can't use useStoryblokApi if you're not loading apiPlugin."),m);let S={};const $=s=>S[s]?S[s]:(console.error(`Component ${s} doesn't exist.`),!1),oe=(s={})=>{const{storyblokApi:e}=Z(s);m=e,S=s.components};l.StoryblokComponent=K,l.apiPlugin=W,l.getComponent=$,l.storyblokEditable=X,l.storyblokInit=oe,l.useStoryblok=ee,l.useStoryblokApi=re,l.useStoryblokBridge=T,l.useStoryblokState=te,Object.defineProperties(l,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a2, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a2, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a2, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a2;
|
|
16
|
+
};
|
|
17
|
+
var __objRest = (source, exclude) => {
|
|
18
|
+
var target = {};
|
|
19
|
+
for (var prop in source)
|
|
20
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
21
|
+
target[prop] = source[prop];
|
|
22
|
+
if (source != null && __getOwnPropSymbols)
|
|
23
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
24
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
25
|
+
target[prop] = source[prop];
|
|
26
|
+
}
|
|
27
|
+
return target;
|
|
28
|
+
};
|
|
29
|
+
import React, { useState, useEffect } from "react";
|
|
30
|
+
import t from "axios";
|
|
31
|
+
var __defProp2 = Object.defineProperty;
|
|
32
|
+
var __defProps = Object.defineProperties;
|
|
33
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
34
|
+
var __getOwnPropSymbols2 = Object.getOwnPropertySymbols;
|
|
35
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
36
|
+
var __propIsEnum2 = Object.prototype.propertyIsEnumerable;
|
|
37
|
+
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
38
|
+
var __spreadValues2 = (a2, b) => {
|
|
39
|
+
for (var prop in b || (b = {}))
|
|
40
|
+
if (__hasOwnProp2.call(b, prop))
|
|
41
|
+
__defNormalProp2(a2, prop, b[prop]);
|
|
42
|
+
if (__getOwnPropSymbols2)
|
|
43
|
+
for (var prop of __getOwnPropSymbols2(b)) {
|
|
44
|
+
if (__propIsEnum2.call(b, prop))
|
|
45
|
+
__defNormalProp2(a2, prop, b[prop]);
|
|
46
|
+
}
|
|
47
|
+
return a2;
|
|
48
|
+
};
|
|
49
|
+
var __spreadProps = (a2, b) => __defProps(a2, __getOwnPropDescs(b));
|
|
50
|
+
let loaded = false;
|
|
51
|
+
const callbacks = [];
|
|
52
|
+
const loadBridge = (src) => {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
if (typeof window === "undefined")
|
|
55
|
+
return;
|
|
56
|
+
window.storyblokRegisterEvent = (cb) => {
|
|
57
|
+
if (window.location === window.parent.location) {
|
|
58
|
+
console.warn("You are not in Draft Mode or in the Visual Editor.");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!loaded)
|
|
62
|
+
callbacks.push(cb);
|
|
63
|
+
else
|
|
64
|
+
cb();
|
|
65
|
+
};
|
|
66
|
+
if (document.getElementById("storyblok-javascript-bridge"))
|
|
67
|
+
return;
|
|
68
|
+
const script = document.createElement("script");
|
|
69
|
+
script.async = true;
|
|
70
|
+
script.src = src;
|
|
71
|
+
script.id = "storyblok-javascript-bridge";
|
|
72
|
+
script.onerror = (error) => reject(error);
|
|
73
|
+
script.onload = (ev) => {
|
|
74
|
+
callbacks.forEach((cb) => cb());
|
|
75
|
+
loaded = true;
|
|
76
|
+
resolve(ev);
|
|
77
|
+
};
|
|
78
|
+
document.getElementsByTagName("head")[0].appendChild(script);
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
/*!
|
|
82
|
+
* storyblok-js-client v0.0.0-development
|
|
83
|
+
* Universal JavaScript SDK for Storyblok's API
|
|
84
|
+
* (c) 2020-2022 Stobylok Team
|
|
85
|
+
*/
|
|
86
|
+
function e(t2) {
|
|
87
|
+
return typeof t2 == "number" && (t2 == t2 && t2 !== 1 / 0 && t2 !== -1 / 0);
|
|
88
|
+
}
|
|
89
|
+
function r(t2, r2, s2) {
|
|
90
|
+
if (!e(r2))
|
|
91
|
+
throw new TypeError("Expected `limit` to be a finite number");
|
|
92
|
+
if (!e(s2))
|
|
93
|
+
throw new TypeError("Expected `interval` to be a finite number");
|
|
94
|
+
var n2 = [], i2 = [], o2 = 0, a2 = function() {
|
|
95
|
+
o2++;
|
|
96
|
+
var e2 = setTimeout(function() {
|
|
97
|
+
o2--, n2.length > 0 && a2(), i2 = i2.filter(function(t3) {
|
|
98
|
+
return t3 !== e2;
|
|
99
|
+
});
|
|
100
|
+
}, s2);
|
|
101
|
+
i2.indexOf(e2) < 0 && i2.push(e2);
|
|
102
|
+
var r3 = n2.shift();
|
|
103
|
+
r3.resolve(t2.apply(r3.self, r3.args));
|
|
104
|
+
}, l2 = function() {
|
|
105
|
+
var t3 = arguments, e2 = this;
|
|
106
|
+
return new Promise(function(s3, i3) {
|
|
107
|
+
n2.push({ resolve: s3, reject: i3, args: t3, self: e2 }), o2 < r2 && a2();
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
return l2.abort = function() {
|
|
111
|
+
i2.forEach(clearTimeout), i2 = [], n2.forEach(function(t3) {
|
|
112
|
+
t3.reject(new throttle.AbortError());
|
|
113
|
+
}), n2.length = 0;
|
|
114
|
+
}, l2;
|
|
115
|
+
}
|
|
116
|
+
r.AbortError = function() {
|
|
117
|
+
Error.call(this, "Throttled function aborted"), this.name = "AbortError";
|
|
118
|
+
};
|
|
119
|
+
const s = function(t2, e2) {
|
|
120
|
+
if (!t2)
|
|
121
|
+
return null;
|
|
122
|
+
let r2 = {};
|
|
123
|
+
for (let s2 in t2) {
|
|
124
|
+
let n2 = t2[s2];
|
|
125
|
+
e2.indexOf(s2) > -1 && n2 !== null && (r2[s2] = n2);
|
|
126
|
+
}
|
|
127
|
+
return r2;
|
|
128
|
+
};
|
|
129
|
+
var n = { nodes: { horizontal_rule: (t2) => ({ singleTag: "hr" }), blockquote: (t2) => ({ tag: "blockquote" }), bullet_list: (t2) => ({ tag: "ul" }), code_block: (t2) => ({ tag: ["pre", { tag: "code", attrs: t2.attrs }] }), hard_break: (t2) => ({ singleTag: "br" }), heading: (t2) => ({ tag: "h" + t2.attrs.level }), image: (t2) => ({ singleTag: [{ tag: "img", attrs: s(t2.attrs, ["src", "alt", "title"]) }] }), list_item: (t2) => ({ tag: "li" }), ordered_list: (t2) => ({ tag: "ol" }), paragraph: (t2) => ({ tag: "p" }) }, marks: { bold: () => ({ tag: "b" }), strike: () => ({ tag: "strike" }), underline: () => ({ tag: "u" }), strong: () => ({ tag: "strong" }), code: () => ({ tag: "code" }), italic: () => ({ tag: "i" }), link(t2) {
|
|
130
|
+
const e2 = __spreadValues2({}, t2.attrs), { linktype: r2 = "url" } = t2.attrs;
|
|
131
|
+
return r2 === "email" && (e2.href = "mailto:" + e2.href), e2.anchor && (e2.href = `${e2.href}#${e2.anchor}`, delete e2.anchor), { tag: [{ tag: "a", attrs: e2 }] };
|
|
132
|
+
}, styled: (t2) => ({ tag: [{ tag: "span", attrs: t2.attrs }] }) } };
|
|
133
|
+
class i {
|
|
134
|
+
constructor(t2) {
|
|
135
|
+
t2 || (t2 = n), this.marks = t2.marks || [], this.nodes = t2.nodes || [];
|
|
136
|
+
}
|
|
137
|
+
addNode(t2, e2) {
|
|
138
|
+
this.nodes[t2] = e2;
|
|
139
|
+
}
|
|
140
|
+
addMark(t2, e2) {
|
|
141
|
+
this.marks[t2] = e2;
|
|
142
|
+
}
|
|
143
|
+
render(t2 = {}) {
|
|
144
|
+
if (t2.content && Array.isArray(t2.content)) {
|
|
145
|
+
let e2 = "";
|
|
146
|
+
return t2.content.forEach((t3) => {
|
|
147
|
+
e2 += this.renderNode(t3);
|
|
148
|
+
}), e2;
|
|
149
|
+
}
|
|
150
|
+
return console.warn("The render method must receive an object with a content field, which is an array"), "";
|
|
151
|
+
}
|
|
152
|
+
renderNode(t2) {
|
|
153
|
+
let e2 = [];
|
|
154
|
+
t2.marks && t2.marks.forEach((t3) => {
|
|
155
|
+
const r3 = this.getMatchingMark(t3);
|
|
156
|
+
r3 && e2.push(this.renderOpeningTag(r3.tag));
|
|
157
|
+
});
|
|
158
|
+
const r2 = this.getMatchingNode(t2);
|
|
159
|
+
return r2 && r2.tag && e2.push(this.renderOpeningTag(r2.tag)), t2.content ? t2.content.forEach((t3) => {
|
|
160
|
+
e2.push(this.renderNode(t3));
|
|
161
|
+
}) : t2.text ? e2.push(function(t3) {
|
|
162
|
+
const e3 = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }, r3 = /[&<>"']/g, s2 = RegExp(r3.source);
|
|
163
|
+
return t3 && s2.test(t3) ? t3.replace(r3, (t4) => e3[t4]) : t3;
|
|
164
|
+
}(t2.text)) : r2 && r2.singleTag ? e2.push(this.renderTag(r2.singleTag, " /")) : r2 && r2.html && e2.push(r2.html), r2 && r2.tag && e2.push(this.renderClosingTag(r2.tag)), t2.marks && t2.marks.slice(0).reverse().forEach((t3) => {
|
|
165
|
+
const r3 = this.getMatchingMark(t3);
|
|
166
|
+
r3 && e2.push(this.renderClosingTag(r3.tag));
|
|
167
|
+
}), e2.join("");
|
|
168
|
+
}
|
|
169
|
+
renderTag(t2, e2) {
|
|
170
|
+
if (t2.constructor === String)
|
|
171
|
+
return `<${t2}${e2}>`;
|
|
172
|
+
return t2.map((t3) => {
|
|
173
|
+
if (t3.constructor === String)
|
|
174
|
+
return `<${t3}${e2}>`;
|
|
175
|
+
{
|
|
176
|
+
let r2 = "<" + t3.tag;
|
|
177
|
+
if (t3.attrs)
|
|
178
|
+
for (let e3 in t3.attrs) {
|
|
179
|
+
let s2 = t3.attrs[e3];
|
|
180
|
+
s2 !== null && (r2 += ` ${e3}="${s2}"`);
|
|
181
|
+
}
|
|
182
|
+
return `${r2}${e2}>`;
|
|
183
|
+
}
|
|
184
|
+
}).join("");
|
|
185
|
+
}
|
|
186
|
+
renderOpeningTag(t2) {
|
|
187
|
+
return this.renderTag(t2, "");
|
|
188
|
+
}
|
|
189
|
+
renderClosingTag(t2) {
|
|
190
|
+
if (t2.constructor === String)
|
|
191
|
+
return `</${t2}>`;
|
|
192
|
+
return t2.slice(0).reverse().map((t3) => t3.constructor === String ? `</${t3}>` : `</${t3.tag}>`).join("");
|
|
193
|
+
}
|
|
194
|
+
getMatchingNode(t2) {
|
|
195
|
+
if (typeof this.nodes[t2.type] == "function")
|
|
196
|
+
return this.nodes[t2.type](t2);
|
|
197
|
+
}
|
|
198
|
+
getMatchingMark(t2) {
|
|
199
|
+
if (typeof this.marks[t2.type] == "function")
|
|
200
|
+
return this.marks[t2.type](t2);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const o = (t2 = 0, e2 = t2) => {
|
|
204
|
+
const r2 = Math.abs(e2 - t2) || 0, s2 = t2 < e2 ? 1 : -1;
|
|
205
|
+
return ((t3 = 0, e3) => [...Array(t3)].map(e3))(r2, (e3, r3) => r3 * s2 + t2);
|
|
206
|
+
}, a = (t2, e2, r2) => {
|
|
207
|
+
const s2 = [];
|
|
208
|
+
for (const n2 in t2) {
|
|
209
|
+
if (!Object.prototype.hasOwnProperty.call(t2, n2))
|
|
210
|
+
continue;
|
|
211
|
+
const i2 = t2[n2], o2 = r2 ? "" : encodeURIComponent(n2);
|
|
212
|
+
let l2;
|
|
213
|
+
l2 = typeof i2 == "object" ? a(i2, e2 ? e2 + encodeURIComponent("[" + o2 + "]") : o2, Array.isArray(i2)) : (e2 ? e2 + encodeURIComponent("[" + o2 + "]") : o2) + "=" + encodeURIComponent(i2), s2.push(l2);
|
|
214
|
+
}
|
|
215
|
+
return s2.join("&");
|
|
216
|
+
};
|
|
217
|
+
let l = {}, c = {};
|
|
218
|
+
class StoryblokClient {
|
|
219
|
+
constructor(e2, s2) {
|
|
220
|
+
if (!s2) {
|
|
221
|
+
let t2 = e2.region ? "-" + e2.region : "", r2 = e2.https === false ? "http" : "https";
|
|
222
|
+
s2 = e2.oauthToken === void 0 ? `${r2}://api${t2}.storyblok.com/v2` : `${r2}://api${t2}.storyblok.com/v1`;
|
|
223
|
+
}
|
|
224
|
+
let n2 = Object.assign({}, e2.headers), o2 = 5;
|
|
225
|
+
e2.oauthToken !== void 0 && (n2.Authorization = e2.oauthToken, o2 = 3), e2.rateLimit !== void 0 && (o2 = e2.rateLimit), this.richTextResolver = new i(e2.richTextSchema), typeof e2.componentResolver == "function" && this.setComponentResolver(e2.componentResolver), this.maxRetries = e2.maxRetries || 5, this.throttle = r(this.throttledRequest, o2, 1e3), this.accessToken = e2.accessToken, this.relations = {}, this.links = {}, this.cache = e2.cache || { clear: "manual" }, this.client = t.create({ baseURL: s2, timeout: e2.timeout || 0, headers: n2, proxy: e2.proxy || false }), e2.responseInterceptor && this.client.interceptors.response.use((t2) => e2.responseInterceptor(t2));
|
|
226
|
+
}
|
|
227
|
+
setComponentResolver(t2) {
|
|
228
|
+
this.richTextResolver.addNode("blok", (e2) => {
|
|
229
|
+
let r2 = "";
|
|
230
|
+
return e2.attrs.body.forEach((e3) => {
|
|
231
|
+
r2 += t2(e3.component, e3);
|
|
232
|
+
}), { html: r2 };
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
parseParams(t2 = {}) {
|
|
236
|
+
return t2.version || (t2.version = "published"), t2.token || (t2.token = this.getToken()), t2.cv || (t2.cv = c[t2.token]), Array.isArray(t2.resolve_relations) && (t2.resolve_relations = t2.resolve_relations.join(",")), t2;
|
|
237
|
+
}
|
|
238
|
+
factoryParamOptions(t2, e2 = {}) {
|
|
239
|
+
return ((t3 = "") => t3.indexOf("/cdn/") > -1)(t2) ? this.parseParams(e2) : e2;
|
|
240
|
+
}
|
|
241
|
+
makeRequest(t2, e2, r2, s2) {
|
|
242
|
+
const n2 = this.factoryParamOptions(t2, ((t3 = {}, e3 = 25, r3 = 1) => __spreadProps(__spreadValues2({}, t3), { per_page: e3, page: r3 }))(e2, r2, s2));
|
|
243
|
+
return this.cacheResponse(t2, n2);
|
|
244
|
+
}
|
|
245
|
+
get(t2, e2) {
|
|
246
|
+
let r2 = "/" + t2;
|
|
247
|
+
const s2 = this.factoryParamOptions(r2, e2);
|
|
248
|
+
return this.cacheResponse(r2, s2);
|
|
249
|
+
}
|
|
250
|
+
async getAll(t2, e2 = {}, r2) {
|
|
251
|
+
const s2 = e2.per_page || 25, n2 = "/" + t2, i2 = n2.split("/");
|
|
252
|
+
r2 = r2 || i2[i2.length - 1];
|
|
253
|
+
const a2 = await this.makeRequest(n2, e2, s2, 1), l2 = Math.ceil(a2.total / s2);
|
|
254
|
+
return ((t3 = [], e3) => t3.map(e3).reduce((t4, e4) => [...t4, ...e4], []))([a2, ...await (async (t3 = [], e3) => Promise.all(t3.map(e3)))(o(1, l2), async (t3) => this.makeRequest(n2, e2, s2, t3 + 1))], (t3) => Object.values(t3.data[r2]));
|
|
255
|
+
}
|
|
256
|
+
post(t2, e2) {
|
|
257
|
+
let r2 = "/" + t2;
|
|
258
|
+
return this.throttle("post", r2, e2);
|
|
259
|
+
}
|
|
260
|
+
put(t2, e2) {
|
|
261
|
+
let r2 = "/" + t2;
|
|
262
|
+
return this.throttle("put", r2, e2);
|
|
263
|
+
}
|
|
264
|
+
delete(t2, e2) {
|
|
265
|
+
let r2 = "/" + t2;
|
|
266
|
+
return this.throttle("delete", r2, e2);
|
|
267
|
+
}
|
|
268
|
+
getStories(t2) {
|
|
269
|
+
return this.get("cdn/stories", t2);
|
|
270
|
+
}
|
|
271
|
+
getStory(t2, e2) {
|
|
272
|
+
return this.get("cdn/stories/" + t2, e2);
|
|
273
|
+
}
|
|
274
|
+
setToken(t2) {
|
|
275
|
+
this.accessToken = t2;
|
|
276
|
+
}
|
|
277
|
+
getToken() {
|
|
278
|
+
return this.accessToken;
|
|
279
|
+
}
|
|
280
|
+
_cleanCopy(t2) {
|
|
281
|
+
return JSON.parse(JSON.stringify(t2));
|
|
282
|
+
}
|
|
283
|
+
_insertLinks(t2, e2) {
|
|
284
|
+
const r2 = t2[e2];
|
|
285
|
+
r2 && r2.fieldtype == "multilink" && r2.linktype == "story" && typeof r2.id == "string" && this.links[r2.id] ? r2.story = this._cleanCopy(this.links[r2.id]) : r2 && r2.linktype === "story" && typeof r2.uuid == "string" && this.links[r2.uuid] && (r2.story = this._cleanCopy(this.links[r2.uuid]));
|
|
286
|
+
}
|
|
287
|
+
_insertRelations(t2, e2, r2) {
|
|
288
|
+
if (r2.indexOf(t2.component + "." + e2) > -1) {
|
|
289
|
+
if (typeof t2[e2] == "string")
|
|
290
|
+
this.relations[t2[e2]] && (t2[e2] = this._cleanCopy(this.relations[t2[e2]]));
|
|
291
|
+
else if (t2[e2].constructor === Array) {
|
|
292
|
+
let r3 = [];
|
|
293
|
+
t2[e2].forEach((t3) => {
|
|
294
|
+
this.relations[t3] && r3.push(this._cleanCopy(this.relations[t3]));
|
|
295
|
+
}), t2[e2] = r3;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
iterateTree(t2, e2) {
|
|
300
|
+
let r2 = (t3) => {
|
|
301
|
+
if (t3 != null) {
|
|
302
|
+
if (t3.constructor === Array)
|
|
303
|
+
for (let e3 = 0; e3 < t3.length; e3++)
|
|
304
|
+
r2(t3[e3]);
|
|
305
|
+
else if (t3.constructor === Object) {
|
|
306
|
+
if (t3._stopResolving)
|
|
307
|
+
return;
|
|
308
|
+
for (let s2 in t3)
|
|
309
|
+
(t3.component && t3._uid || t3.type === "link") && (this._insertRelations(t3, s2, e2), this._insertLinks(t3, s2)), r2(t3[s2]);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
r2(t2.content);
|
|
314
|
+
}
|
|
315
|
+
async resolveLinks(t2, e2) {
|
|
316
|
+
let r2 = [];
|
|
317
|
+
if (t2.link_uuids) {
|
|
318
|
+
const s2 = t2.link_uuids.length;
|
|
319
|
+
let n2 = [];
|
|
320
|
+
const i2 = 50;
|
|
321
|
+
for (let e3 = 0; e3 < s2; e3 += i2) {
|
|
322
|
+
const r3 = Math.min(s2, e3 + i2);
|
|
323
|
+
n2.push(t2.link_uuids.slice(e3, r3));
|
|
324
|
+
}
|
|
325
|
+
for (let t3 = 0; t3 < n2.length; t3++) {
|
|
326
|
+
(await this.getStories({ per_page: i2, language: e2.language, version: e2.version, by_uuids: n2[t3].join(",") })).data.stories.forEach((t4) => {
|
|
327
|
+
r2.push(t4);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
} else
|
|
331
|
+
r2 = t2.links;
|
|
332
|
+
r2.forEach((t3) => {
|
|
333
|
+
this.links[t3.uuid] = __spreadProps(__spreadValues2({}, t3), { _stopResolving: true });
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
async resolveRelations(t2, e2) {
|
|
337
|
+
let r2 = [];
|
|
338
|
+
if (t2.rel_uuids) {
|
|
339
|
+
const s2 = t2.rel_uuids.length;
|
|
340
|
+
let n2 = [];
|
|
341
|
+
const i2 = 50;
|
|
342
|
+
for (let e3 = 0; e3 < s2; e3 += i2) {
|
|
343
|
+
const r3 = Math.min(s2, e3 + i2);
|
|
344
|
+
n2.push(t2.rel_uuids.slice(e3, r3));
|
|
345
|
+
}
|
|
346
|
+
for (let t3 = 0; t3 < n2.length; t3++) {
|
|
347
|
+
(await this.getStories({ per_page: i2, language: e2.language, version: e2.version, by_uuids: n2[t3].join(",") })).data.stories.forEach((t4) => {
|
|
348
|
+
r2.push(t4);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
} else
|
|
352
|
+
r2 = t2.rels;
|
|
353
|
+
r2.forEach((t3) => {
|
|
354
|
+
this.relations[t3.uuid] = __spreadProps(__spreadValues2({}, t3), { _stopResolving: true });
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
async resolveStories(t2, e2) {
|
|
358
|
+
let r2 = [];
|
|
359
|
+
e2.resolve_relations !== void 0 && e2.resolve_relations.length > 0 && (r2 = e2.resolve_relations.split(","), await this.resolveRelations(t2, e2)), ["1", "story", "url"].indexOf(e2.resolve_links) > -1 && await this.resolveLinks(t2, e2);
|
|
360
|
+
for (const t3 in this.relations)
|
|
361
|
+
this.iterateTree(this.relations[t3], r2);
|
|
362
|
+
t2.story ? this.iterateTree(t2.story, r2) : t2.stories.forEach((t3) => {
|
|
363
|
+
this.iterateTree(t3, r2);
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
cacheResponse(t2, e2, r2) {
|
|
367
|
+
return r2 === void 0 && (r2 = 0), new Promise(async (s2, n2) => {
|
|
368
|
+
let i2 = a({ url: t2, params: e2 }), o2 = this.cacheProvider();
|
|
369
|
+
if (this.cache.clear === "auto" && e2.version === "draft" && await this.flushCache(), e2.version === "published" && t2 != "/cdn/spaces/me") {
|
|
370
|
+
const t3 = await o2.get(i2);
|
|
371
|
+
if (t3)
|
|
372
|
+
return s2(t3);
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
let r3 = await this.throttle("get", t2, { params: e2, paramsSerializer: (t3) => a(t3) }), l3 = { data: r3.data, headers: r3.headers };
|
|
376
|
+
if (r3.headers["per-page"] && (l3 = Object.assign({}, l3, { perPage: parseInt(r3.headers["per-page"]), total: parseInt(r3.headers.total) })), r3.status != 200)
|
|
377
|
+
return n2(r3);
|
|
378
|
+
(l3.data.story || l3.data.stories) && await this.resolveStories(l3.data, e2), e2.version === "published" && t2 != "/cdn/spaces/me" && o2.set(i2, l3), l3.data.cv && (e2.version == "draft" && c[e2.token] != l3.data.cv && this.flushCache(), c[e2.token] = l3.data.cv), s2(l3);
|
|
379
|
+
} catch (i3) {
|
|
380
|
+
if (i3.response && i3.response.status === 429 && (r2 += 1) < this.maxRetries)
|
|
381
|
+
return console.log(`Hit rate limit. Retrying in ${r2} seconds.`), await (l2 = 1e3 * r2, new Promise((t3) => setTimeout(t3, l2))), this.cacheResponse(t2, e2, r2).then(s2).catch(n2);
|
|
382
|
+
n2(i3);
|
|
383
|
+
}
|
|
384
|
+
var l2;
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
throttledRequest(t2, e2, r2) {
|
|
388
|
+
return this.client[t2](e2, r2);
|
|
389
|
+
}
|
|
390
|
+
cacheVersions() {
|
|
391
|
+
return c;
|
|
392
|
+
}
|
|
393
|
+
cacheVersion() {
|
|
394
|
+
return c[this.accessToken];
|
|
395
|
+
}
|
|
396
|
+
setCacheVersion(t2) {
|
|
397
|
+
this.accessToken && (c[this.accessToken] = t2);
|
|
398
|
+
}
|
|
399
|
+
cacheProvider() {
|
|
400
|
+
switch (this.cache.type) {
|
|
401
|
+
case "memory":
|
|
402
|
+
return { get: (t2) => l[t2], getAll: () => l, set(t2, e2) {
|
|
403
|
+
l[t2] = e2;
|
|
404
|
+
}, flush() {
|
|
405
|
+
l = {};
|
|
406
|
+
} };
|
|
407
|
+
default:
|
|
408
|
+
return { get() {
|
|
409
|
+
}, getAll() {
|
|
410
|
+
}, set() {
|
|
411
|
+
}, flush() {
|
|
412
|
+
} };
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
async flushCache() {
|
|
416
|
+
return await this.cacheProvider().flush(), this;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
var api = (options = {}) => {
|
|
420
|
+
const { apiOptions } = options;
|
|
421
|
+
if (!apiOptions.accessToken) {
|
|
422
|
+
console.error("You need to provide an access token to interact with Storyblok API. Read https://www.storyblok.com/docs/api/content-delivery#topics/authentication");
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const storyblokApi = new StoryblokClient(apiOptions);
|
|
426
|
+
return { storyblokApi };
|
|
427
|
+
};
|
|
428
|
+
var editable = (blok) => {
|
|
429
|
+
if (typeof blok !== "object" || typeof blok._editable === "undefined") {
|
|
430
|
+
return {};
|
|
431
|
+
}
|
|
432
|
+
const options = JSON.parse(blok._editable.replace(/^<!--#storyblok#/, "").replace(/-->$/, ""));
|
|
433
|
+
return {
|
|
434
|
+
"data-blok-c": JSON.stringify(options),
|
|
435
|
+
"data-blok-uid": options.id + "-" + options.uid
|
|
436
|
+
};
|
|
437
|
+
};
|
|
438
|
+
const useStoryblokBridge = (id, cb, options = {}) => {
|
|
439
|
+
if (typeof window === "undefined") {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
if (typeof window.storyblokRegisterEvent === "undefined") {
|
|
443
|
+
console.error("Storyblok Bridge is disabled. Please enable it to use it. Read https://github.com/storyblok/storyblok-js");
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
window.storyblokRegisterEvent(() => {
|
|
447
|
+
const sbBridge = new window.StoryblokBridge(options);
|
|
448
|
+
sbBridge.on(["input", "published", "change"], (event) => {
|
|
449
|
+
if (event.action == "input" && event.story.id === id) {
|
|
450
|
+
cb(event.story);
|
|
451
|
+
} else {
|
|
452
|
+
window.location.reload();
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
const storyblokInit$1 = (pluginOptions = {}) => {
|
|
458
|
+
const { bridge, accessToken, use = [], apiOptions = {} } = pluginOptions;
|
|
459
|
+
apiOptions.accessToken = apiOptions.accessToken || accessToken;
|
|
460
|
+
const options = { bridge, apiOptions };
|
|
461
|
+
let result = {};
|
|
462
|
+
use.forEach((pluginFactory) => {
|
|
463
|
+
result = __spreadValues2(__spreadValues2({}, result), pluginFactory(options));
|
|
464
|
+
});
|
|
465
|
+
if (bridge !== false) {
|
|
466
|
+
loadBridge("https://app.storyblok.com/f/storyblok-v2-latest.js");
|
|
467
|
+
}
|
|
468
|
+
return result;
|
|
469
|
+
};
|
|
470
|
+
const StoryblokComponent = (_a) => {
|
|
471
|
+
var _b = _a, { blok } = _b, restProps = __objRest(_b, ["blok"]);
|
|
472
|
+
if (!blok) {
|
|
473
|
+
console.error("Please provide a 'blok' property to the StoryblokComponent");
|
|
474
|
+
return /* @__PURE__ */ React.createElement("div", null, "Please provide a blok property to the StoryblokComponent");
|
|
475
|
+
}
|
|
476
|
+
const Component = getComponent(blok.component);
|
|
477
|
+
if (!Component) {
|
|
478
|
+
return "";
|
|
479
|
+
}
|
|
480
|
+
return /* @__PURE__ */ React.createElement(Component, __spreadValues({
|
|
481
|
+
blok
|
|
482
|
+
}, restProps));
|
|
483
|
+
};
|
|
484
|
+
const useStoryblok = (slug, apiOptions = {}, bridgeOptions = {}) => {
|
|
485
|
+
let [story, setStory] = useState({});
|
|
486
|
+
if (!storyblokApiInstance) {
|
|
487
|
+
console.error("You can't use useStoryblok if you're not loading apiPlugin.");
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
useStoryblokBridge(story.id, (story2) => setStory(story2), bridgeOptions);
|
|
491
|
+
useEffect(async () => {
|
|
492
|
+
const { data } = await storyblokApiInstance.get(`cdn/stories/${slug}`, apiOptions);
|
|
493
|
+
setStory(data.story);
|
|
494
|
+
}, []);
|
|
495
|
+
return story;
|
|
496
|
+
};
|
|
497
|
+
const useStoryblokState = (initialStory = {}, bridgeOptions = {}) => {
|
|
498
|
+
let [story, setStory] = useState(initialStory);
|
|
499
|
+
useEffect(() => {
|
|
500
|
+
useStoryblokBridge(story.id, (story2) => setStory(story2), bridgeOptions);
|
|
501
|
+
}, []);
|
|
502
|
+
return story;
|
|
503
|
+
};
|
|
504
|
+
let storyblokApiInstance = null;
|
|
505
|
+
const useStoryblokApi = () => {
|
|
506
|
+
if (!storyblokApiInstance) {
|
|
507
|
+
console.error("You can't use useStoryblokApi if you're not loading apiPlugin.");
|
|
508
|
+
}
|
|
509
|
+
return storyblokApiInstance;
|
|
510
|
+
};
|
|
511
|
+
let componentsMap = {};
|
|
512
|
+
const getComponent = (componentKey) => {
|
|
513
|
+
if (!componentsMap[componentKey]) {
|
|
514
|
+
console.error(`Component ${componentKey} doesn't exist.`);
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
return componentsMap[componentKey];
|
|
518
|
+
};
|
|
519
|
+
const storyblokInit = (pluginOptions = {}) => {
|
|
520
|
+
const { storyblokApi } = storyblokInit$1(pluginOptions);
|
|
521
|
+
storyblokApiInstance = storyblokApi;
|
|
522
|
+
componentsMap = pluginOptions.components;
|
|
523
|
+
};
|
|
524
|
+
export { StoryblokComponent, api as apiPlugin, getComponent, editable as storyblokEditable, storyblokInit, useStoryblok, useStoryblokApi, useStoryblokBridge, useStoryblokState };
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@storyblok/react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SDK to integrate Storyblok into your project using React.",
|
|
5
|
+
"main": "./dist/storyblok-react.js",
|
|
6
|
+
"module": "./dist/storyblok-react.mjs",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/storyblok-react.mjs",
|
|
13
|
+
"require": "./dist/storyblok-react.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "vite build --watch",
|
|
18
|
+
"build": "vite build",
|
|
19
|
+
"test": "npm run test:unit && npm run test:e2e",
|
|
20
|
+
"test:unit": "jest __tests__",
|
|
21
|
+
"test:e2e": "cypress run-ct",
|
|
22
|
+
"test:e2e-watch": "cypress open-ct",
|
|
23
|
+
"prepublishOnly": "npm run build && cp ../README.md ./"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@storyblok/js": "^1.0.3"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@babel/core": "^7.15.0",
|
|
30
|
+
"@babel/preset-env": "^7.16.11",
|
|
31
|
+
"@cypress/react": "^5.12.3",
|
|
32
|
+
"@cypress/vite-dev-server": "^2.2.2",
|
|
33
|
+
"@vitejs/plugin-react": "^1.1.4",
|
|
34
|
+
"babel-jest": "^26.6.3",
|
|
35
|
+
"cypress": "^9.5.0",
|
|
36
|
+
"eslint-plugin-cypress": "^2.12.1",
|
|
37
|
+
"eslint-plugin-jest": "^25.2.4",
|
|
38
|
+
"jest": "^26.6.3",
|
|
39
|
+
"react": "17.0.2",
|
|
40
|
+
"vite": "^2.8.4"
|
|
41
|
+
},
|
|
42
|
+
"babel": {
|
|
43
|
+
"presets": [
|
|
44
|
+
[
|
|
45
|
+
"@babel/preset-env",
|
|
46
|
+
{
|
|
47
|
+
"targets": {
|
|
48
|
+
"node": "current"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"jest": {
|
|
55
|
+
"moduleFileExtensions": [
|
|
56
|
+
"js",
|
|
57
|
+
"json"
|
|
58
|
+
],
|
|
59
|
+
"transform": {
|
|
60
|
+
"^.+\\.js$": "babel-jest"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"release": {
|
|
64
|
+
"branches": [
|
|
65
|
+
"main",
|
|
66
|
+
"feature/v1"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"repository": {
|
|
70
|
+
"type": "git",
|
|
71
|
+
"url": "https://github.com/storyblok/storyblok-react"
|
|
72
|
+
},
|
|
73
|
+
"author": "Storyblok",
|
|
74
|
+
"bugs": {
|
|
75
|
+
"url": "https://github.com/storyblok/storyblok-react/issues"
|
|
76
|
+
},
|
|
77
|
+
"homepage": "https://github.com/storyblok/storyblok-react",
|
|
78
|
+
"publishConfig": {
|
|
79
|
+
"access": "public"
|
|
80
|
+
}
|
|
81
|
+
}
|