@croct/plug-react 0.4.0 → 0.4.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.
@@ -1,6 +1,6 @@
1
- import { FunctionComponent } from 'react';
1
+ import { FunctionComponent, PropsWithChildren } from 'react';
2
2
  import { Configuration, Plug } from '@croct/plug';
3
- export declare type CroctProviderProps = Configuration & Required<Pick<Configuration, 'appId'>>;
3
+ export declare type CroctProviderProps = PropsWithChildren<Configuration & Required<Pick<Configuration, 'appId'>>>;
4
4
  export declare const CroctContext: import("react").Context<{
5
5
  plug: Plug;
6
6
  } | null>;
package/README.md CHANGED
@@ -33,16 +33,16 @@ The React Plug library provides components and hooks for personalizing applicati
33
33
  - **Blazing-fast queries**: double-digit millisecond latency for real-time evaluations.
34
34
  - **Playground integration**: one-click to connect, no configuration needed.
35
35
 
36
- Check out the [Storybook](https://croct-tech.github.io/plug-react) to see some minimal examples in action,
36
+ Check out the [Storybook](https://croct-tech.github.io/plug-react) to see some minimal examples in action,
37
37
  or the [example folder](examples) for full code examples.
38
38
 
39
39
  ## Getting Started
40
40
 
41
41
  The following steps will walk you through installing the library and integrating it into your application.
42
42
 
43
- This guide assumes you're already familiar with some key concepts and tools around Croct, like
44
- Contextual Query Language (CQL) and the playground. If you're not,
45
- [this 15-minute quickstart](https://croct.link/plug-js/quick-start) that will give you a hands-on overview of
43
+ This guide assumes you're already familiar with some key concepts and tools around Croct, like
44
+ Contextual Query Language (CQL) and the playground. If you're not,
45
+ [this 15-minute quickstart](https://croct.link/plug-js/quick-start) that will give you a hands-on overview of
46
46
  all the terms and tools you need to get started.
47
47
 
48
48
  ### Installation
@@ -57,10 +57,10 @@ npm install @croct/plug-react
57
57
 
58
58
  ### Plugging in
59
59
 
60
- You connect Croct to React with the `<CroctProvider/ >` component. The `<CroctProvider/ >` uses a regular React's
60
+ You connect Croct to React with the `<CroctProvider />` component. The `<CroctProvider />` uses a regular React's
61
61
  `<Context.Provider />` to wrap your React app and make the SDK available anywhere in your component tree.
62
62
 
63
- We suggest putting the `<CroctProvider/ >` somewhere high in your app, above any component that might be personalized,
63
+ We suggest putting the `<CroctProvider />` somewhere high in your app, above any component that might be personalized,
64
64
  ideally in the top-level `<App/>` component.
65
65
 
66
66
  ```tsx
@@ -69,7 +69,7 @@ import {CroctProvider} from '@croct/plug-react';
69
69
 
70
70
  function App() {
71
71
  return (
72
- <CroctProvider appId="00000000-0000-0000-0000-000000000000">
72
+ <CroctProvider appId="<APP_ID>">
73
73
  <div>
74
74
  <h1>My first personalized app 🚀</h1>
75
75
  </div>
@@ -80,6 +80,9 @@ function App() {
80
80
  render(<App />, document.getElementById('root'));
81
81
  ```
82
82
 
83
+ > Replace `<APP_ID>` with your public app ID that you can find at Workspaces > Applications > Setup.
84
+ > In case you don't have an account yet, you can use the sandbox application ID `00000000-0000-0000-0000-000000000000`
85
+
83
86
  ### Evaluating expressions
84
87
 
85
88
  Once your application is plugged in, you're ready to start personalizing your components using the `<Personalization />`
@@ -90,7 +93,7 @@ to conditionally renders a different button depending on the user's persona.
90
93
 
91
94
  ![Evaluation Example](https://user-images.githubusercontent.com/943036/116588852-6a114200-a8f2-11eb-9d88-c346f002e2a1.png)
92
95
 
93
- Let's first implement the use-case using the `<Personalization/>` component. It takes an expression (e.g. `user's persona`)
96
+ Let's first implement the use-case using the `<Personalization />` component. It takes an expression (e.g. `user's persona`)
94
97
  and a render function, which tells the component how to render the UI, depending on the evaluation result.
95
98
 
96
99
  This is what our component would look like:
@@ -156,9 +159,9 @@ export default function OnboardingPage(): ReactElement {
156
159
  }
157
160
  ```
158
161
 
159
- If you run the application and there is no persona assigned to your profile, you will see the button for non-developers
162
+ If you run the application and there is no persona assigned to your profile, you will see the button for non-developers
160
163
  — otherwise, the button for sharing the code with developers.
161
- Check out [Accessing the Plug instance](#accessing-the-plug-instance) for an example of how to save information in a
164
+ Check out [Accessing the Plug instance](#accessing-the-plug-instance) for an example of how to save information in a
162
165
  user's profile.
163
166
 
164
167
  #### Fault tolerance
@@ -183,7 +186,7 @@ export default function OnboardingPage(): ReactElement {
183
186
  return (
184
187
  <Suspense fallback="✨ Personalizing...">
185
188
  {/* Using the <Personalization /> component */}
186
- <Personalization expression="user's persona is 'developer'" falback={false}>
189
+ <Personalization expression="user's persona is 'developer'" fallback={false}>
187
190
  {(isDeveloper: boolean) => (
188
191
  <Fragment>
189
192
  {isDeveloper && <a href="/docs">View docs</a>}
@@ -202,23 +205,23 @@ For a full list of the available options, please refer to the [API documentation
202
205
 
203
206
  ### Using slots
204
207
 
205
- Evaluating expression is a flexible and powerful way to customize your UI. However, for components whose content
206
- changes too often, this approach can be overkill. For those cases, we encourage you to use the Slots feature instead.
207
- Using slots gives your team the flexibility to change the content or personalization rules whenever needed without
208
+ Evaluating expression is a flexible and powerful way to customize your UI. However, for components whose content
209
+ changes too often, this approach can be overkill. For those cases, we encourage you to use the Slots feature instead.
210
+ Using slots gives your team the flexibility to change the content or personalization rules whenever needed without
208
211
  touching the component code.
209
212
 
210
213
  ![Slot Example](https://user-images.githubusercontent.com/943036/116586841-44833900-a8f0-11eb-8d32-acec2eacee01.png)
211
214
 
212
- To render a slot, all you need to do is provide the `id` you configured in your Croct workspace. Based on the
213
- slot's personalization rules and the user's context, the component will decide which content show to that user.
214
- Notice that there's no logic on the client-side, meaning that your marketing or product team can freely change the
215
+ To render a slot, all you need to do is provide the `id` you configured in your Croct workspace. Based on the
216
+ slot's personalization rules and the user's context, the component will decide which content show to that user.
217
+ Notice that there's no logic on the client-side, meaning that your marketing or product team can freely change the
215
218
  slot content as they need without requiring an update to your React app.
216
219
 
217
- For the next example, we assume that you have already defined a slot with id `home-banner` in your Croct workspace
220
+ For the next example, we assume that you have already defined a slot with id `home-banner` in your Croct workspace
218
221
  with the following structure:
219
222
 
220
223
  ```ts
221
- type HomeBanner = {
224
+ type HomeBannerContent = {
222
225
  title: string,
223
226
  subtitle: string,
224
227
  cta: {
@@ -236,11 +239,20 @@ Here's how to use the `<Slot />` component:
236
239
  import {ReactElement, Suspense} from 'react';
237
240
  import {Slot} from '@croct/plug-react';
238
241
 
242
+ type HomeBannerContent = {
243
+ title: string,
244
+ subtitle: string,
245
+ cta: {
246
+ label: string,
247
+ link: string,
248
+ },
249
+ };
250
+
239
251
  export default function OnboardingPage(): ReactElement {
240
252
  return (
241
253
  <Suspense fallback="✨ Personalizing content...">
242
254
  <Slot id="home-banner">
243
- {({title, subtitle, cta}: HomeBanner) => (
255
+ {({title, subtitle, cta}: HomeBannerContent) => (
244
256
  <div>
245
257
  <strong>{title}</strong>
246
258
  <p>{subtitle}</p>
@@ -259,17 +271,26 @@ To avoid the component from suspending while loading, you can provide an `initia
259
271
  import {ReactElement} from 'react';
260
272
  import {Slot} from '@croct/plug-react';
261
273
 
274
+ type HomeBannerContent = {
275
+ title: string,
276
+ subtitle: string,
277
+ cta: {
278
+ label: string,
279
+ link: string,
280
+ },
281
+ };
282
+
262
283
  export default function OnboardingPage(): ReactElement {
263
284
  return (
264
285
  <Slot id="home-banner" initial={null}>
265
- {(props: HomeBanner|null) => (
286
+ {(props: HomeBannerContent|null) => (
266
287
  props === null
267
288
  ? '✨ Personalizing...'
268
289
  : (
269
290
  <div>
270
- <strong>{title}</strong>
271
- <p>{subtitle}</p>
272
- <a href={cta.link}>{cta.label}</a>
291
+ <strong>{props.title}</strong>
292
+ <p>{props.subtitle}</p>
293
+ <a href={props.cta.link}>{props.cta.label}</a>
273
294
  </div>
274
295
  )
275
296
  )}
@@ -284,8 +305,17 @@ And here's an example using the `useContent` hook:
284
305
  import {ReactElement, Suspense} from 'react';
285
306
  import {useContent} from '@croct/plug-react';
286
307
 
308
+ type HomeBannerContent = {
309
+ title: string,
310
+ subtitle: string,
311
+ cta: {
312
+ label: string,
313
+ link: string,
314
+ },
315
+ };
316
+
287
317
  function HomeBanner(): ReactElement {
288
- const banner = useContent<HomeBanner>('home-banner');
318
+ const {title, subtitle, cta} = useContent<HomeBannerContent>('home-banner');
289
319
 
290
320
  return (
291
321
  <div>
@@ -313,7 +343,16 @@ The following example shows how you can specify a fallback state for the `home-b
313
343
  import {ReactElement, Suspense} from 'react';
314
344
  import {Slot, useContent} from '@croct/plug-react';
315
345
 
316
- const fallbackBanner: HomeBanner = {
346
+ type HomeBannerContent = {
347
+ title: string,
348
+ subtitle: string,
349
+ cta: {
350
+ label: string,
351
+ link: string,
352
+ },
353
+ };
354
+
355
+ const fallbackBanner: HomeBannerContent = {
317
356
  title: 'Default title',
318
357
  subtitle: 'Default subtitle',
319
358
  cta: {
@@ -323,7 +362,7 @@ const fallbackBanner: HomeBanner = {
323
362
  };
324
363
 
325
364
  function HomeBanner(): ReactElement {
326
- const {title, subtitle, cta} = useContent<HomeBanner>('home-banner', {fallback: fallbackBanner});
365
+ const {title, subtitle, cta} = useContent<HomeBannerContent>('home-banner', {fallback: fallbackBanner});
327
366
 
328
367
  return (
329
368
  <div>
@@ -339,7 +378,7 @@ export default function HomePage(): ReactElement {
339
378
  <Suspense fallback="Personalizing content...">
340
379
  {/* Using the <Slot /> component */}
341
380
  <Slot id="home-banner" fallback={fallbackBanner}>
342
- {({title, subtitle, cta}: HomeBanner) => (
381
+ {({title, subtitle, cta}: HomeBannerContent) => (
343
382
  <div>
344
383
  <strong>{title}</strong>
345
384
  <p>{subtitle}</p>
@@ -355,15 +394,15 @@ export default function HomePage(): ReactElement {
355
394
  }
356
395
  ```
357
396
 
358
- Again, we strongly recommend always providing a value for the `fallback` property. For a full list of the available options,
397
+ Again, we strongly recommend always providing a value for the `fallback` property. For a full list of the available options,
359
398
  please refer to the [API documentation](#component-api-reference).
360
399
 
361
400
  #### 💡 ProTip
362
401
 
363
- In the previous examples, you may have noticed that we specified the content type in the `userFetch` call and in the
364
- `<Slot />` component's render function to have the benefit of strong typing.
402
+ In the previous examples, you may have noticed that we specified the content type in the `userFetch` call and in the
403
+ `<Slot />` component's render function to have the benefit of strong typing.
365
404
 
366
- For an even more robust approach, you can also declare the type of all available slots in a single declaration file
405
+ For an even more robust approach, you can also declare the type of all available slots in a single declaration file
367
406
  using module augmentation as follows:
368
407
 
369
408
  ```ts
@@ -385,16 +424,16 @@ slot IDs and content properties as a bonus:
385
424
 
386
425
  ### Server-side rendering
387
426
 
388
- You can use the same components and hooks on the server-side by simply providing an `initial` state which is used to
389
- pre-render on the server - the personalization happens transparently on the client during the initial render.
427
+ You can use the same components and hooks on the server-side by simply providing an `initial` state which is used to
428
+ pre-render on the server - the personalization happens transparently on the client during the initial render.
390
429
  That means it's SEO friendly and can be cached with no performance overhead.
391
430
 
392
- Notice that the methods exposed by the Plug work only on the client-side. Therefore, if you are using [`useCroct`](#usecroct),
431
+ Notice that the methods exposed by the Plug work only on the client-side. Therefore, if you are using [`useCroct`](#usecroct),
393
432
  the operations have to be executed inside the `useEffect` hook or client-side callbacks, such as `onClick` or `onChange`, for example.
394
433
 
395
434
  ### Accessing the Plug instance
396
435
 
397
- This library is built on top of the PlugJS. You can access the Plug instance through the `useCroct` hook to track events,
436
+ This library is built on top of the PlugJS. You can access the Plug instance through the `useCroct` hook to track events,
398
437
  login and logout users, and more.
399
438
 
400
439
  In the following example we use the `useCroct` to get the Plug instance and set an attribute to the user profile:
@@ -423,7 +462,7 @@ This reference documents all components available in the library.
423
462
  ### &lt;CroctProvider /&gt;
424
463
 
425
464
  The `<CroctProvider />` component leverages [React's Context API](https://reactjs.org/docs/context.html) to
426
- make a configured [Plug instance](https://github.com/croct-tech/plug-js/blob/master/docs/plug.md) available throughout
465
+ make a configured [Plug instance](https://github.com/croct-tech/plug-js/blob/master/docs/plug.md) available throughout
427
466
  a React component tree.
428
467
 
429
468
  #### Properties
@@ -454,7 +493,7 @@ import {CroctProvider} from '@croct/plug-react';
454
493
 
455
494
  function App() {
456
495
  return (
457
- <CroctProvider appId="00000000-0000-0000-0000-000000000000">
496
+ <CroctProvider appId="<APP_ID>">
458
497
  <div>
459
498
  <h1>My first personalized app 🚀</h1>
460
499
  </div>
@@ -463,6 +502,8 @@ function App() {
463
502
  }
464
503
  ```
465
504
 
505
+ > Replace "<APP_ID>" with your public app ID that you can find at Workspaces > Applications > API Keys.
506
+
466
507
  ### &lt;Personalization /&gt;
467
508
 
468
509
  The `<Personalization />` component evaluates and renders a CQL query.
@@ -586,7 +627,7 @@ These are the currently supported options:
586
627
 
587
628
  | Option | Type | Description
588
629
  |--------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
589
- | `fallback` | Result | The value returned when the evaluation fails. If not specified, the hook will throw an exception in case of failures.
630
+ | `fallback` | Result | The value returned when the evaluation fails. If not specified, the hook will throw an exception in case of failures.
590
631
  | `timeout` | number | The maximum evaluation time in milliseconds. Once reached, the evaluation will fail.
591
632
  | `attributes` | JSON | The map of attributes to inject in the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` you can reference them in expressions like `context's cities include location's city`.
592
633
  | `cacheKey` | string | An identifier that allows keeping the cached result separate from other cached items. By default, the cache key is formed from the expression and attributes.
@@ -635,8 +676,17 @@ Here's a simple example showing how to fetch the content for a banner:
635
676
  import {ReactElement} from 'react';
636
677
  import {useContent} from '@croct/plug-react';
637
678
 
638
- function HeroBanner(): ReactElement {
639
- const {title, subtitle} = useContent<HeroBanner>('hero');
679
+ type HomeBannerContent = {
680
+ title: string,
681
+ subtitle: string,
682
+ cta: {
683
+ label: string,
684
+ link: string,
685
+ },
686
+ };
687
+
688
+ export default function HeroBanner(): ReactElement {
689
+ const {title, subtitle} = useContent<HomeBannerContent>('hero');
640
690
 
641
691
  return (
642
692
  <div>
package/index.js CHANGED
@@ -24,7 +24,7 @@ function _objectWithoutPropertiesLoose(source, excluded) {
24
24
  function isSsr() {
25
25
  return typeof window === 'undefined';
26
26
  }
27
- var croct = !isSsr() ? csrPlug__default['default'] : new Proxy(csrPlug__default['default'], {
27
+ var croct = !isSsr() ? csrPlug__default["default"] : new Proxy(csrPlug__default["default"], {
28
28
  get(_, property) {
29
29
  switch (property) {
30
30
  case 'initialized':
@@ -44,13 +44,14 @@ var croct = !isSsr() ? csrPlug__default['default'] : new Proxy(csrPlug__default[
44
44
 
45
45
  });
46
46
 
47
+ var _excluded$4 = ["children"];
47
48
  var CroctContext = /*#__PURE__*/react.createContext(null);
48
49
  CroctContext.displayName = 'CroctContext';
49
50
  var CroctProvider = _ref => {
50
51
  var {
51
52
  children
52
53
  } = _ref,
53
- configuration = _objectWithoutPropertiesLoose(_ref, ["children"]);
54
+ configuration = _objectWithoutPropertiesLoose(_ref, _excluded$4);
54
55
 
55
56
  var parent = react.useContext(CroctContext);
56
57
 
@@ -74,11 +75,10 @@ var CroctProvider = _ref => {
74
75
  croct.unplug();
75
76
  };
76
77
  }, []);
77
- return jsxRuntime.jsx(CroctContext.Provider, Object.assign({
78
- value: context
79
- }, {
78
+ return jsxRuntime.jsx(CroctContext.Provider, {
79
+ value: context,
80
80
  children: children
81
- }), void 0);
81
+ });
82
82
  };
83
83
 
84
84
  class Cache {
@@ -154,6 +154,7 @@ class Cache {
154
154
 
155
155
  }
156
156
 
157
+ var _excluded$3 = ["initial"];
157
158
  var cache = new Cache(60 * 1000);
158
159
  function useLoader(_ref) {
159
160
  var _cache$get;
@@ -161,7 +162,7 @@ function useLoader(_ref) {
161
162
  var {
162
163
  initial
163
164
  } = _ref,
164
- options = _objectWithoutPropertiesLoose(_ref, ["initial"]);
165
+ options = _objectWithoutPropertiesLoose(_ref, _excluded$3);
165
166
 
166
167
  var loadedValue = (_cache$get = cache.get(options.cacheKey)) == null ? void 0 : _cache$get.result;
167
168
  var [value, setValue] = react.useState(loadedValue !== undefined ? loadedValue : initial);
@@ -171,16 +172,17 @@ function useLoader(_ref) {
171
172
  try {
172
173
  setValue(cache.load(options));
173
174
  } catch (result) {
174
- if (typeof (result == null ? void 0 : result.then) !== 'function') {
175
- setValue(undefined);
175
+ if (result instanceof Promise) {
176
+ result.then(resolvedValue => {
177
+ if (!isUnmounted) {
178
+ setValue(resolvedValue);
179
+ }
180
+ });
176
181
  return;
177
182
  }
178
183
 
179
- result.then(resolvedValue => {
180
- if (!isUnmounted) {
181
- setValue(resolvedValue);
182
- }
183
- });
184
+ setValue(undefined);
185
+ return;
184
186
  }
185
187
  }
186
188
 
@@ -206,6 +208,8 @@ function useCroct() {
206
208
  return context.plug;
207
209
  }
208
210
 
211
+ var _excluded$2 = ["cacheKey", "fallback", "initial", "expiration"];
212
+
209
213
  function cleanEvaluationOptions(options) {
210
214
  var result = {};
211
215
 
@@ -231,7 +235,7 @@ function useCsrEvaluation(expression, options) {
231
235
  initial,
232
236
  expiration
233
237
  } = options,
234
- evaluationOptions = _objectWithoutPropertiesLoose(options, ["cacheKey", "fallback", "initial", "expiration"]);
238
+ evaluationOptions = _objectWithoutPropertiesLoose(options, _excluded$2);
235
239
 
236
240
  var croct = useCroct();
237
241
  return useLoader({
@@ -297,30 +301,32 @@ function useSsrContent(_, _temp) {
297
301
 
298
302
  var useContent = isSsr() ? useSsrContent : useCsrContent;
299
303
 
304
+ var _excluded$1 = ["expression", "children"];
300
305
  function Personalization(props) {
301
306
  var {
302
307
  expression,
303
308
  children
304
309
  } = props,
305
- options = _objectWithoutPropertiesLoose(props, ["expression", "children"]);
310
+ options = _objectWithoutPropertiesLoose(props, _excluded$1);
306
311
 
307
312
  var result = useEvaluation(expression, options);
308
313
  return jsxRuntime.jsx(react.Fragment, {
309
314
  children: children(result)
310
- }, void 0);
315
+ });
311
316
  }
312
317
 
318
+ var _excluded = ["id", "children"];
313
319
  var Slot = props => {
314
320
  var {
315
321
  id,
316
322
  children
317
323
  } = props,
318
- options = _objectWithoutPropertiesLoose(props, ["id", "children"]);
324
+ options = _objectWithoutPropertiesLoose(props, _excluded);
319
325
 
320
326
  var data = useContent(id, options);
321
327
  return jsxRuntime.jsx(react.Fragment, {
322
328
  children: children(data)
323
- }, void 0);
329
+ });
324
330
  };
325
331
 
326
332
  exports.CroctContext = CroctContext;
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/ssr-polyfills.ts","../src/CroctProvider.tsx","../src/hooks/Cache.ts","../src/hooks/useLoader.ts","../src/hooks/useCroct.ts","../src/hooks/useEvaluation.ts","../src/hooks/useContent.ts","../src/components/Personalization/index.tsx","../src/components/Slot/index.tsx"],"sourcesContent":["import csrPlug, {Plug} from '@croct/plug';\n\nexport function isSsr(): boolean {\n return typeof window === 'undefined';\n}\n\nexport const croct: Plug = !isSsr() ? csrPlug : new Proxy(csrPlug, {\n get(_, property: keyof Plug) {\n switch (property) {\n case 'initialized':\n return false;\n\n case 'plug':\n return () => {\n // no-op\n };\n\n case 'unplug':\n return () => Promise.resolve();\n\n default:\n throw new Error(\n `Property croct.${String(property)} is not supported on server-side (SSR). Consider refactoring `\n + 'the logic as a side-effect (useEffect) or a client-side callback (onClick, onChange, etc).',\n );\n }\n },\n});\n\n","import {createContext, FunctionComponent, PropsWithChildren, ReactElement, useContext, useEffect, useMemo} from 'react';\nimport {Configuration, Plug} from '@croct/plug';\nimport {croct} from './ssr-polyfills';\n\nexport type CroctProviderProps = PropsWithChildren<Configuration & Required<Pick<Configuration, 'appId'>>>;\n\nexport const CroctContext = createContext<{plug: Plug}|null>(null);\nCroctContext.displayName = 'CroctContext';\n\nexport const CroctProvider: FunctionComponent<CroctProviderProps> = ({children, ...configuration}): ReactElement => {\n const parent = useContext(CroctContext);\n\n if (parent !== null) {\n throw new Error(\n 'You cannot render <CroctProvider> inside another <CroctProvider>. '\n + 'Croct should only be initialized once in the application.',\n );\n }\n\n const context = useMemo(() => ({\n get plug() {\n if (!croct.initialized) {\n croct.plug(configuration);\n }\n\n return croct;\n },\n }), [configuration]);\n\n useEffect(() => {\n croct.plug(configuration);\n\n return () => {\n croct.unplug();\n };\n }, []);\n\n return (\n <CroctContext.Provider value={context}>\n {children}\n </CroctContext.Provider>\n );\n};\n","export type EntryLoader<R> = (...args: any) => Promise<R>;\n\nexport type EntryOptions<R> = {\n cacheKey: string,\n loader: EntryLoader<R>,\n fallback?: R,\n expiration?: number,\n};\n\ntype Entry<R = any> = {\n promise: Promise<any>,\n result?: R,\n dispose: () => void,\n timeout?: number,\n error?: any,\n};\n\nexport class Cache {\n private readonly cache: Record<string, Entry> = {};\n\n private readonly defaultExpiration: number;\n\n public constructor(defaultExpiration: number) {\n this.defaultExpiration = defaultExpiration;\n }\n\n public load<R>(configuration: EntryOptions<R>): R {\n const {cacheKey, loader, fallback, expiration = this.defaultExpiration} = configuration;\n\n const cachedEntry = this.get<R>(cacheKey);\n\n if (cachedEntry !== undefined) {\n if (cachedEntry.error !== undefined) {\n if (fallback !== undefined) {\n return fallback;\n }\n\n throw cachedEntry.error;\n }\n\n if (cachedEntry.result !== undefined) {\n return cachedEntry.result;\n }\n\n throw cachedEntry.promise;\n }\n\n const entry: Entry<R> = {\n dispose: () => {\n if (entry.timeout !== undefined || expiration < 0) {\n return;\n }\n\n entry.timeout = window.setTimeout(\n (): void => {\n delete this.cache[cacheKey];\n },\n expiration,\n );\n },\n promise: loader()\n .then((result): R => {\n entry.result = result;\n\n return result;\n })\n .catch(error => {\n entry.error = error;\n })\n .finally(() => {\n entry.dispose();\n }),\n };\n\n this.cache[cacheKey] = entry;\n\n throw entry.promise;\n }\n\n public get<R>(cacheKey: string): Entry<R>|undefined {\n const entry = this.cache[cacheKey];\n\n if (entry === undefined) {\n return undefined;\n }\n\n if (entry.timeout !== undefined) {\n clearTimeout(entry.timeout);\n\n delete entry.timeout;\n\n entry.dispose();\n }\n\n return entry;\n }\n}\n","import {useEffect, useState} from 'react';\nimport {Cache, EntryOptions} from './Cache';\n\nconst cache = new Cache(60 * 1000);\n\nexport type CacheOptions<R> = EntryOptions<R> & {\n initial?: R,\n};\n\nexport function useLoader<R>({initial, ...options}: CacheOptions<R>): R {\n const loadedValue: R|undefined = cache.get<R>(options.cacheKey)?.result;\n const [value, setValue] = useState(loadedValue !== undefined ? loadedValue : initial);\n const [isUnmounted, setUnmounted] = useState(false);\n\n useEffect(\n () => {\n if (initial !== undefined) {\n try {\n setValue(cache.load(options));\n } catch (result: unknown) {\n if (result instanceof Promise) {\n result.then((resolvedValue: R) => {\n if (!isUnmounted) {\n setValue(resolvedValue);\n }\n });\n\n return;\n }\n\n setValue(undefined);\n\n return;\n }\n }\n\n return () => {\n setUnmounted(true);\n };\n },\n [],\n );\n\n if (value === undefined) {\n return cache.load(options);\n }\n\n return value;\n}\n","import {Plug} from '@croct/plug';\nimport {useContext} from 'react';\nimport {CroctContext} from '../CroctProvider';\n\nexport function useCroct(): Plug {\n const context = useContext(CroctContext);\n\n if (context === null) {\n throw new Error('useCroct() can only be used in the context of a <CroctProvider> component.');\n }\n\n return context.plug;\n}\n","import {JsonValue} from '@croct/plug/sdk/json';\nimport {EvaluationOptions} from '@croct/sdk/facade/evaluatorFacade';\nimport {useLoader} from './useLoader';\nimport {useCroct} from './useCroct';\nimport {isSsr} from '../ssr-polyfills';\n\nfunction cleanEvaluationOptions(options: EvaluationOptions): EvaluationOptions {\n const result: EvaluationOptions = {};\n\n for (const [key, value] of Object.entries(options)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n\n return result;\n}\n\nexport type UseEvaluationOptions<I, F> = EvaluationOptions & {\n initial?: I,\n fallback?: F,\n cacheKey?: string,\n expiration?: number,\n};\n\ntype UseEvaluationHook = <T extends JsonValue, I = T, F = T>(\n expression: string,\n options?: UseEvaluationOptions<I, F>,\n) => T | I | F;\n\nfunction useCsrEvaluation<T = JsonValue, I = T, F = T>(\n expression: string,\n options: UseEvaluationOptions<I, F> = {},\n): T | I | F {\n const {cacheKey, fallback, initial, expiration, ...evaluationOptions} = options;\n const croct = useCroct();\n\n return useLoader<T | I | F>({\n cacheKey: `useEvaluation:${cacheKey ?? ''}:${expression}:${JSON.stringify(options.attributes ?? '')}`,\n loader: () => croct.evaluate<T & JsonValue>(expression, cleanEvaluationOptions(evaluationOptions)),\n initial: initial,\n fallback: fallback,\n expiration: expiration,\n });\n}\n\nfunction useSsrEvaluation<T = JsonValue, I = T, F = T>(\n _: string,\n {initial}: UseEvaluationOptions<I, F> = {},\n): T | I | F {\n if (initial === undefined) {\n throw new Error('The initial value is required for server-side rendering (SSR).');\n }\n\n return initial;\n}\n\nexport const useEvaluation: UseEvaluationHook = isSsr() ? useSsrEvaluation : useCsrEvaluation;\n","import {SlotContent, SlotId, SlotMap} from '@croct/plug/fetch';\nimport {NullableJsonObject} from '@croct/plug/sdk/json';\nimport {useLoader} from './useLoader';\nimport {useCroct} from './useCroct';\nimport {isSsr} from '../ssr-polyfills';\n\nexport type UseContentOptions<I, F> = {\n fallback?: F,\n initial?: I,\n cacheKey?: string,\n expiration?: number,\n};\n\nfunction useCsrContent<I, F>(id: SlotId, options: UseContentOptions<I, F> = {}): SlotContent<SlotId> | I | F {\n const {fallback, initial, cacheKey, expiration} = options;\n const croct = useCroct();\n\n return useLoader({\n cacheKey: `useContent:${cacheKey ?? ''}:${id}`,\n loader: () => croct.fetch<SlotContent<SlotId>>(id).then(({payload}) => payload),\n initial: initial,\n fallback: fallback,\n expiration: expiration,\n });\n}\n\nfunction useSsrContent<I, F>(_: SlotId, {initial}: UseContentOptions<I, F> = {}): SlotContent<SlotId> | I | F {\n if (initial === undefined) {\n throw new Error('The initial value is required for server-side rendering (SSR).');\n }\n\n return initial;\n}\n\ntype UseContentHook = {\n <P extends NullableJsonObject, I = P, F = P>(\n id: keyof SlotMap extends never ? string : never,\n options?: UseContentOptions<I, F>\n ): P | I | F,\n\n <S extends keyof SlotMap>(\n id: S,\n options?: UseContentOptions<never, never>\n ): SlotContent<S>,\n\n <I, S extends keyof SlotMap>(\n id: S,\n options?: UseContentOptions<I, never>\n ): SlotContent<S> | I,\n\n <F, S extends keyof SlotMap>(\n id: S,\n options?: UseContentOptions<never, F>\n ): SlotContent<S> | F,\n\n <I, F, S extends keyof SlotMap>(\n id: S,\n options?: UseContentOptions<I, F>\n ): SlotContent<S> | I | F,\n};\n\nexport const useContent: UseContentHook = isSsr() ? useSsrContent : useCsrContent;\n","import {ReactChild, ReactElement, Fragment} from 'react';\nimport {JsonValue} from '@croct/plug/sdk/json';\nimport {UseEvaluationOptions, useEvaluation} from '../../hooks';\n\ntype Renderer<T> = (result: T) => ReactChild;\n\nexport type PersonalizationProps<T extends JsonValue = JsonValue, I = T, F = T> = UseEvaluationOptions<I, F> & {\n expression: string,\n children: Renderer<T | I | F>,\n};\n\nexport function Personalization<T extends JsonValue, I, F>(\n props:\n Extract<T | I | F, JsonValue> extends never\n ? PersonalizationProps\n : PersonalizationProps<T, I, F>,\n): ReactElement;\n\nexport function Personalization<I, F>(props: PersonalizationProps<JsonValue, I, F>): ReactElement {\n const {expression, children, ...options} = props;\n const result = useEvaluation(expression, options);\n\n return (<Fragment>{children(result)}</Fragment>);\n}\n","import {Fragment, ReactChild, ReactElement} from 'react';\nimport {SlotContent, SlotId, SlotMap} from '@croct/plug/fetch';\nimport {NullableJsonObject} from '@croct/plug/sdk/json';\nimport {useContent, UseContentOptions} from '../../hooks';\n\ntype Renderer<P> = (props: P) => ReactChild;\n\nexport type SlotProps<P, I = P, F = P, S extends SlotId = SlotId> = UseContentOptions<I, F> & {\n id: S,\n children: Renderer<P | I | F>,\n};\n\ntype SlotComponent = {\n <P, I, F>(\n props:\n Extract<P | I | F, NullableJsonObject> extends never\n ? SlotProps<NullableJsonObject, never, never, keyof SlotMap extends never ? string : never>\n : SlotProps<P, I, F, keyof SlotMap extends never ? string : never>\n ): ReactElement,\n\n <S extends keyof SlotMap>(props: SlotProps<SlotContent<S>, never, never, S>): ReactElement,\n\n <I, S extends keyof SlotMap>(props: SlotProps<SlotContent<S>, I, never, S>): ReactElement,\n\n <F, S extends keyof SlotMap>(props: SlotProps<SlotContent<S>, never, F, S>): ReactElement,\n\n <I, F, S extends keyof SlotMap>(props: SlotProps<SlotContent<S>, I, F, S>): ReactElement,\n\n (props: SlotProps<void, void, void>): ReactElement,\n};\n\nexport const Slot: SlotComponent = <I, F>(props: SlotProps<NullableJsonObject, I, F>): ReactElement => {\n const {id, children, ...options} = props;\n const data: SlotContent<SlotId> | I | F = useContent(id, options);\n\n return <Fragment>{children(data)}</Fragment>;\n};\n"],"names":["isSsr","window","croct","csrPlug","Proxy","get","_","property","Promise","resolve","Error","String","CroctContext","createContext","displayName","CroctProvider","children","configuration","_excluded","parent","useContext","context","useMemo","plug","initialized","useEffect","unplug","_jsx","Provider","value","Cache","constructor","defaultExpiration","cache","load","cacheKey","loader","fallback","expiration","cachedEntry","undefined","error","result","promise","entry","dispose","timeout","setTimeout","then","catch","finally","clearTimeout","useLoader","initial","options","loadedValue","setValue","useState","isUnmounted","setUnmounted","resolvedValue","useCroct","cleanEvaluationOptions","key","Object","entries","useCsrEvaluation","expression","evaluationOptions","JSON","stringify","attributes","evaluate","useSsrEvaluation","useEvaluation","useCsrContent","id","fetch","payload","useSsrContent","useContent","Personalization","props","Fragment","Slot","data"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;SAEgBA,QAAK;EACjB,OAAO,OAAOC,MAAP,KAAkB,WAAzB,CAAA;AACH,CAAA;AAEM,IAAMC,KAAK,GAAS,CAACF,KAAK,EAAN,GAAWG,2BAAX,GAAqB,IAAIC,KAAJ,CAAUD,2BAAV,EAAmB;AAC/DE,EAAAA,GAAG,CAACC,CAAD,EAAIC,QAAJ,EAAwB;AACvB,IAAA,QAAQA,QAAR;AACI,MAAA,KAAK,aAAL;AACI,QAAA,OAAO,KAAP,CAAA;;AAEJ,MAAA,KAAK,MAAL;AACI,QAAA,OAAO,MAAK;SAAZ,CAAA;;AAIJ,MAAA,KAAK,QAAL;AACI,QAAA,OAAO,MAAMC,OAAO,CAACC,OAAR,EAAb,CAAA;;AAEJ,MAAA;QACI,MAAM,IAAIC,KAAJ,CACF,iBAAkBC,GAAAA,MAAM,CAACJ,QAAD,CAAxB,GACE,+DAAA,GAAA,4FAFA,CAAN,CAAA;AAbR,KAAA;AAkBH,GAAA;;AApB8D,CAAnB,CAAzC;;;ICAMK,YAAY,gBAAGC,mBAAa,CAAoB,IAApB,EAAlC;AACPD,YAAY,CAACE,WAAb,GAA2B,cAA3B,CAAA;AAEO,IAAMC,aAAa,GAA0C,IAA+C,IAAA;EAAA,IAA9C;AAACC,IAAAA,QAAAA;GAA6C,GAAA,IAAA;AAAA,MAAhCC,aAAgC,GAAA,6BAAA,CAAA,IAAA,EAAAC,WAAA,CAAA,CAAA;;AAC/G,EAAA,IAAMC,MAAM,GAAGC,gBAAU,CAACR,YAAD,CAAzB,CAAA;;EAEA,IAAIO,MAAM,KAAK,IAAf,EAAqB;AACjB,IAAA,MAAM,IAAIT,KAAJ,CACF,oEAAA,GACE,2DAFA,CAAN,CAAA;AAIH,GAAA;;AAED,EAAA,IAAMW,OAAO,GAAGC,aAAO,CAAC,OAAO;AAC3B,IAAA,IAAIC,IAAJ,GAAQ;AACJ,MAAA,IAAI,CAACrB,KAAK,CAACsB,WAAX,EAAwB;QACpBtB,KAAK,CAACqB,IAAN,CAAWN,aAAX,CAAA,CAAA;AACH,OAAA;;AAED,MAAA,OAAOf,KAAP,CAAA;AACH,KAAA;;AAP0B,GAAP,CAAD,EAQnB,CAACe,aAAD,CARmB,CAAvB,CAAA;AAUAQ,EAAAA,eAAS,CAAC,MAAK;IACXvB,KAAK,CAACqB,IAAN,CAAWN,aAAX,CAAA,CAAA;AAEA,IAAA,OAAO,MAAK;AACRf,MAAAA,KAAK,CAACwB,MAAN,EAAA,CAAA;KADJ,CAAA;GAHK,EAMN,EANM,CAAT,CAAA;AAQA,EAAA,OACIC,cAAA,CAACf,YAAY,CAACgB,QAAd,EAAsB;AAACC,IAAAA,KAAK,EAAER,OAAR;AAAeL,IAAAA,QAAA,EAChCA,QAAAA;AADiB,GAAtB,CADJ,CAAA;AAKH;;MCzBYc,MAAK;EAKdC,WAAA,CAAmBC,iBAAnB,EAA4C;IAAA,IAJ3BC,CAAAA,KAI2B,GAJI,EAIJ,CAAA;AAAA,IAAA,IAAA,CAF3BD,iBAE2B,GAAA,KAAA,CAAA,CAAA;IACxC,IAAKA,CAAAA,iBAAL,GAAyBA,iBAAzB,CAAA;AACH,GAAA;;EAEME,IAAI,CAAIjB,aAAJ,EAAkC;IACzC,IAAM;MAACkB,QAAD;MAAWC,MAAX;MAAmBC,QAAnB;AAA6BC,MAAAA,UAAU,GAAG,IAAKN,CAAAA,iBAAAA;AAA/C,KAAA,GAAoEf,aAA1E,CAAA;AAEA,IAAA,IAAMsB,WAAW,GAAG,IAAA,CAAKlC,GAAL,CAAY8B,QAAZ,CAApB,CAAA;;IAEA,IAAII,WAAW,KAAKC,SAApB,EAA+B;AAC3B,MAAA,IAAID,WAAW,CAACE,KAAZ,KAAsBD,SAA1B,EAAqC;QACjC,IAAIH,QAAQ,KAAKG,SAAjB,EAA4B;AACxB,UAAA,OAAOH,QAAP,CAAA;AACH,SAAA;;QAED,MAAME,WAAW,CAACE,KAAlB,CAAA;AACH,OAAA;;AAED,MAAA,IAAIF,WAAW,CAACG,MAAZ,KAAuBF,SAA3B,EAAsC;QAClC,OAAOD,WAAW,CAACG,MAAnB,CAAA;AACH,OAAA;;MAED,MAAMH,WAAW,CAACI,OAAlB,CAAA;AACH,KAAA;;AAED,IAAA,IAAMC,KAAK,GAAa;AACpBC,MAAAA,OAAO,EAAE,MAAK;QACV,IAAID,KAAK,CAACE,OAAN,KAAkBN,SAAlB,IAA+BF,UAAU,GAAG,CAAhD,EAAmD;AAC/C,UAAA,OAAA;AACH,SAAA;;AAEDM,QAAAA,KAAK,CAACE,OAAN,GAAgB7C,MAAM,CAAC8C,UAAP,CACZ,MAAW;AACP,UAAA,OAAO,IAAKd,CAAAA,KAAL,CAAWE,QAAX,CAAP,CAAA;SAFQ,EAIZG,UAJY,CAAhB,CAAA;OANgB;AAapBK,MAAAA,OAAO,EAAEP,MAAM,EAAA,CACVY,IADI,CACEN,MAAD,IAAc;QAChBE,KAAK,CAACF,MAAN,GAAeA,MAAf,CAAA;AAEA,QAAA,OAAOA,MAAP,CAAA;AACH,OALI,CAMJO,CAAAA,KANI,CAMER,KAAK,IAAG;QACXG,KAAK,CAACH,KAAN,GAAcA,KAAd,CAAA;OAPC,CAAA,CASJS,OATI,CASI,MAAK;AACVN,QAAAA,KAAK,CAACC,OAAN,EAAA,CAAA;OAVC,CAAA;KAbb,CAAA;AA2BA,IAAA,IAAA,CAAKZ,KAAL,CAAWE,QAAX,CAAA,GAAuBS,KAAvB,CAAA;IAEA,MAAMA,KAAK,CAACD,OAAZ,CAAA;AACH,GAAA;;EAEMtC,GAAG,CAAI8B,QAAJ,EAAoB;AAC1B,IAAA,IAAMS,KAAK,GAAG,IAAA,CAAKX,KAAL,CAAWE,QAAX,CAAd,CAAA;;IAEA,IAAIS,KAAK,KAAKJ,SAAd,EAAyB;AACrB,MAAA,OAAOA,SAAP,CAAA;AACH,KAAA;;AAED,IAAA,IAAII,KAAK,CAACE,OAAN,KAAkBN,SAAtB,EAAiC;AAC7BW,MAAAA,YAAY,CAACP,KAAK,CAACE,OAAP,CAAZ,CAAA;MAEA,OAAOF,KAAK,CAACE,OAAb,CAAA;AAEAF,MAAAA,KAAK,CAACC,OAAN,EAAA,CAAA;AACH,KAAA;;AAED,IAAA,OAAOD,KAAP,CAAA;AACH,GAAA;;AA9Ea;;;ACdlB,IAAMX,KAAK,GAAG,IAAIH,KAAJ,CAAU,EAAA,GAAK,IAAf,CAAd,CAAA;AAMM,SAAUsB,SAAV,CAA6D,IAAA,EAAA;AAAA,EAAA,IAAA,UAAA,CAAA;;EAAA,IAAtC;AAACC,IAAAA,OAAAA;GAAqC,GAAA,IAAA;AAAA,MAAzBC,OAAyB,GAAA,6BAAA,CAAA,IAAA,EAAApC,WAAA,CAAA,CAAA;;AAC/D,EAAA,IAAMqC,WAAW,GAAA,CAAA,UAAA,GAAgBtB,KAAK,CAAC5B,GAAN,CAAaiD,OAAO,CAACnB,QAArB,CAAhB,KAAgB,IAAA,GAAA,KAAA,CAAA,GAAA,UAAA,CAAgCO,MAAjE,CAAA;AACA,EAAA,IAAM,CAACb,KAAD,EAAQ2B,QAAR,IAAoBC,cAAQ,CAACF,WAAW,KAAKf,SAAhB,GAA4Be,WAA5B,GAA0CF,OAA3C,CAAlC,CAAA;EACA,IAAM,CAACK,WAAD,EAAcC,YAAd,IAA8BF,cAAQ,CAAC,KAAD,CAA5C,CAAA;AAEAhC,EAAAA,eAAS,CACL,MAAK;IACD,IAAI4B,OAAO,KAAKb,SAAhB,EAA2B;MACvB,IAAI;AACAgB,QAAAA,QAAQ,CAACvB,KAAK,CAACC,IAAN,CAAWoB,OAAX,CAAD,CAAR,CAAA;OADJ,CAEE,OAAOZ,MAAP,EAAwB;QACtB,IAAIA,MAAM,YAAYlC,OAAtB,EAA+B;AAC3BkC,UAAAA,MAAM,CAACM,IAAP,CAAaY,aAAD,IAAqB;YAC7B,IAAI,CAACF,WAAL,EAAkB;cACdF,QAAQ,CAACI,aAAD,CAAR,CAAA;AACH,aAAA;WAHL,CAAA,CAAA;AAMA,UAAA,OAAA;AACH,SAAA;;QAEDJ,QAAQ,CAAChB,SAAD,CAAR,CAAA;AAEA,QAAA,OAAA;AACH,OAAA;AACJ,KAAA;;AAED,IAAA,OAAO,MAAK;MACRmB,YAAY,CAAC,IAAD,CAAZ,CAAA;KADJ,CAAA;GAtBC,EA0BL,EA1BK,CAAT,CAAA;;EA6BA,IAAI9B,KAAK,KAAKW,SAAd,EAAyB;AACrB,IAAA,OAAOP,KAAK,CAACC,IAAN,CAAWoB,OAAX,CAAP,CAAA;AACH,GAAA;;AAED,EAAA,OAAOzB,KAAP,CAAA;AACH;;SC5CegC,WAAQ;AACpB,EAAA,IAAMxC,OAAO,GAAGD,gBAAU,CAACR,YAAD,CAA1B,CAAA;;EAEA,IAAIS,OAAO,KAAK,IAAhB,EAAsB;AAClB,IAAA,MAAM,IAAIX,KAAJ,CAAU,4EAAV,CAAN,CAAA;AACH,GAAA;;EAED,OAAOW,OAAO,CAACE,IAAf,CAAA;AACH;;;;ACND,SAASuC,sBAAT,CAAgCR,OAAhC,EAA0D;EACtD,IAAMZ,MAAM,GAAsB,EAAlC,CAAA;;AAEA,EAAA,KAAK,IAAM,CAACqB,GAAD,EAAMlC,KAAN,CAAX,IAA2BmC,MAAM,CAACC,OAAP,CAAeX,OAAf,CAA3B,EAAoD;IAChD,IAAIzB,KAAK,KAAKW,SAAd,EAAyB;AACrBE,MAAAA,MAAM,CAACqB,GAAD,CAAN,GAAclC,KAAd,CAAA;AACH,KAAA;AACJ,GAAA;;AAED,EAAA,OAAOa,MAAP,CAAA;AACH,CAAA;;AAcD,SAASwB,gBAAT,CACIC,UADJ,EAEIb,OAFJ,EAE4C;AAAA,EAAA,IAAA,mBAAA,CAAA;;AAAA,EAAA,IAAxCA,OAAwC,KAAA,KAAA,CAAA,EAAA;AAAxCA,IAAAA,OAAwC,GAAF,EAAE,CAAA;AAAA,GAAA;;EAExC,IAAM;IAACnB,QAAD;IAAWE,QAAX;IAAqBgB,OAArB;AAA8Bf,IAAAA,UAAAA;AAA9B,GAAA,GAAkEgB,OAAxE;MAAmDc,iBAAnD,iCAAwEd,OAAxE,EAAApC,WAAA,CAAA,CAAA;;EACA,IAAMhB,KAAK,GAAG2D,QAAQ,EAAtB,CAAA;AAEA,EAAA,OAAOT,SAAS,CAAY;AACxBjB,IAAAA,QAAQ,sBAAmBA,QAAnB,IAAA,IAAA,GAAmBA,QAAnB,GAA+B,EAA/B,UAAqCgC,UAArC,GAAA,GAAA,GAAmDE,IAAI,CAACC,SAAL,CAAehB,CAAAA,mBAAAA,GAAAA,OAAO,CAACiB,UAAvB,KAAA,IAAA,GAAA,mBAAA,GAAqC,EAArC,CADnC;AAExBnC,IAAAA,MAAM,EAAE,MAAMlC,KAAK,CAACsE,QAAN,CAA8BL,UAA9B,EAA0CL,sBAAsB,CAACM,iBAAD,CAAhE,CAFU;AAGxBf,IAAAA,OAAO,EAAEA,OAHe;AAIxBhB,IAAAA,QAAQ,EAAEA,QAJc;AAKxBC,IAAAA,UAAU,EAAEA,UAAAA;AALY,GAAZ,CAAhB,CAAA;AAOH,CAAA;;AAED,SAASmC,gBAAT,CACInE,CADJ,EAE8C,KAAA,EAAA;EAAA,IAA1C;AAAC+C,IAAAA,OAAAA;AAAD,GAA0C,sBAAF,EAAE,GAAA,KAAA,CAAA;;EAE1C,IAAIA,OAAO,KAAKb,SAAhB,EAA2B;AACvB,IAAA,MAAM,IAAI9B,KAAJ,CAAU,gEAAV,CAAN,CAAA;AACH,GAAA;;AAED,EAAA,OAAO2C,OAAP,CAAA;AACH,CAAA;;IAEYqB,aAAa,GAAsB1E,KAAK,EAAKyE,GAAAA,gBAAL,GAAwBP;;AC5C7E,SAASS,aAAT,CAA6BC,EAA7B,EAAyCtB,OAAzC,EAA8E;AAAA,EAAA,IAArCA,OAAqC,KAAA,KAAA,CAAA,EAAA;AAArCA,IAAAA,OAAqC,GAAF,EAAE,CAAA;AAAA,GAAA;;EAC1E,IAAM;IAACjB,QAAD;IAAWgB,OAAX;IAAoBlB,QAApB;AAA8BG,IAAAA,UAAAA;AAA9B,GAAA,GAA4CgB,OAAlD,CAAA;EACA,IAAMpD,KAAK,GAAG2D,QAAQ,EAAtB,CAAA;AAEA,EAAA,OAAOT,SAAS,CAAC;AACbjB,IAAAA,QAAQ,mBAAgBA,QAAhB,IAAA,IAAA,GAAgBA,QAAhB,GAA4B,EAA5B,UAAkCyC,EAD7B;IAEbxC,MAAM,EAAE,MAAMlC,KAAK,CAAC2E,KAAN,CAAiCD,EAAjC,CAAqC5B,CAAAA,IAArC,CAA0C,IAAA,IAAA;MAAA,IAAC;AAAC8B,QAAAA,OAAAA;OAAF,GAAA,IAAA,CAAA;AAAA,MAAA,OAAeA,OAAf,CAAA;AAAA,KAA1C,CAFD;AAGbzB,IAAAA,OAAO,EAAEA,OAHI;AAIbhB,IAAAA,QAAQ,EAAEA,QAJG;AAKbC,IAAAA,UAAU,EAAEA,UAAAA;AALC,GAAD,CAAhB,CAAA;AAOH,CAAA;;AAED,SAASyC,aAAT,CAA6BzE,CAA7B,EAA+E,KAAA,EAAA;EAAA,IAAvC;AAAC+C,IAAAA,OAAAA;AAAD,GAAuC,sBAAF,EAAE,GAAA,KAAA,CAAA;;EAC3E,IAAIA,OAAO,KAAKb,SAAhB,EAA2B;AACvB,IAAA,MAAM,IAAI9B,KAAJ,CAAU,gEAAV,CAAN,CAAA;AACH,GAAA;;AAED,EAAA,OAAO2C,OAAP,CAAA;AACH,CAAA;;IA6BY2B,UAAU,GAAmBhF,KAAK,EAAK+E,GAAAA,aAAL,GAAqBJ;;;AC3C9D,SAAUM,eAAV,CAAgCC,KAAhC,EAA4E;EAC9E,IAAM;IAACf,UAAD;AAAanD,IAAAA,QAAAA;AAAb,GAAA,GAAqCkE,KAA3C;MAAgC5B,OAAhC,iCAA2C4B,KAA3C,EAAAhE,WAAA,CAAA,CAAA;;AACA,EAAA,IAAMwB,MAAM,GAAGgC,aAAa,CAACP,UAAD,EAAab,OAAb,CAA5B,CAAA;EAEA,OAAQ3B,cAAC,CAAAwD,cAAA,EAAU;IAAAnE,QAAA,EAAAA,QAAQ,CAAC0B,MAAD,CAAA;AAAR,GAAV,CAAT,CAAA;AACH;;;ACQY0C,IAAAA,IAAI,GAAyBF,KAAP,IAAmE;EAClG,IAAM;IAACN,EAAD;AAAK5D,IAAAA,QAAAA;AAAL,GAAA,GAA6BkE,KAAnC;MAAwB5B,OAAxB,iCAAmC4B,KAAnC,EAAA,SAAA,CAAA,CAAA;;AACA,EAAA,IAAMG,IAAI,GAAgCL,UAAU,CAACJ,EAAD,EAAKtB,OAAL,CAApD,CAAA;EAEA,OAAO3B,cAAA,CAACwD,cAAD,EAAW;IAAAnE,QAAA,EAAAA,QAAQ,CAACqE,IAAD,CAAA;AAAR,GAAX,CAAP,CAAA;AACH;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@croct/plug-react",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "React components and hooks to plug your React applications into Croct.",
5
5
  "author": {
6
6
  "name": "Croct",
@@ -38,50 +38,55 @@
38
38
  "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
39
39
  },
40
40
  "dependencies": {
41
- "@croct/plug": "^0.10.0"
41
+ "@croct/plug": "^0.10.1"
42
42
  },
43
43
  "devDependencies": {
44
- "@babel/core": "^7.13.13",
45
- "@babel/preset-env": "^7.13.12",
46
- "@babel/preset-react": "^7.13.13",
47
- "@babel/preset-typescript": "^7.13.0",
48
- "@storybook/addon-actions": "^6.2.3",
49
- "@storybook/addon-essentials": "^6.4.13",
50
- "@storybook/addon-links": "^6.2.3",
51
- "@storybook/react": "^6.4.13",
52
- "@testing-library/jest-dom": "^5.12.0",
53
- "@testing-library/react": "^11.2.7",
54
- "@testing-library/react-hooks": "^7.0.0",
55
- "@types/jest": "^26.0.22",
56
- "@types/node": "^14.14.37",
57
- "@types/react": "^16.0.0",
58
- "@types/react-dom": "^16.0.0",
59
- "@typescript-eslint/eslint-plugin": "^4.25.0",
60
- "@typescript-eslint/parser": "^4.25.0",
44
+ "@babel/core": "^7.18.5",
45
+ "@babel/preset-env": "^7.18.2",
46
+ "@babel/preset-react": "^7.17.12",
47
+ "@babel/preset-typescript": "^7.17.12",
48
+ "@storybook/addon-actions": "^6.5.9",
49
+ "@storybook/addon-essentials": "^6.5.9",
50
+ "@storybook/addon-links": "^6.5.9",
51
+ "@storybook/builder-webpack5": "^6.5.9",
52
+ "@storybook/manager-webpack5": "^6.5.9",
53
+ "@storybook/react": "^6.5.9",
54
+ "@testing-library/jest-dom": "^5.16.4",
55
+ "@testing-library/react": "^13.3.0",
56
+ "@testing-library/react-hooks": "^8.0.0",
57
+ "@types/jest": "^28.1.2",
58
+ "@types/node": "^16.11.41",
59
+ "@types/react": "^18.0.14",
60
+ "@types/react-dom": "^18.0.5",
61
+ "@typescript-eslint/eslint-plugin": "^5.28.0",
62
+ "@typescript-eslint/parser": "^5.28.0",
61
63
  "babel-eslint": "^10.1.0",
62
- "babel-jest": "^26.6.3",
63
- "babel-loader": "8.1.0",
64
- "eslint": "^7.27.0",
65
- "eslint-config-airbnb-base": "^14.2.1",
66
- "eslint-config-standard": "^16.0.2",
64
+ "babel-jest": "^28.1.1",
65
+ "babel-loader": "^8.2.5",
66
+ "eslint": "^8.17.0",
67
+ "eslint-config-airbnb-base": "^15.0.0",
68
+ "eslint-config-standard": "^17.0.0",
67
69
  "eslint-config-standard-react": "^11.0.1",
68
- "eslint-plugin-import": "^2.22.1",
69
- "eslint-plugin-jest": "^24.3.2",
70
+ "eslint-plugin-import": "^2.26.0",
71
+ "eslint-plugin-jest": "^26.5.3",
72
+ "eslint-plugin-n": "^15.2.3",
70
73
  "eslint-plugin-node": "^11.1.0",
71
- "eslint-plugin-promise": "^4.3.1",
72
- "eslint-plugin-react": "^7.23.2",
74
+ "eslint-plugin-promise": "^6.0.0",
75
+ "eslint-plugin-react": "^7.30.0",
73
76
  "eslint-plugin-standard": "^5.0.0",
74
- "jest": "26.6.0",
75
- "jest-environment-node": "^26.6.2",
76
- "microbundle": "^0.13.3",
77
- "react": "^16.0.0",
78
- "react-dom": "^16.0.0",
79
- "ts-node": "^10.0.0",
80
- "typescript": "^4.1.5",
81
- "webpack": "^5.39.1"
77
+ "jest": "^28.1.1",
78
+ "jest-environment-jsdom": "^28.1.1",
79
+ "jest-environment-node": "^28.1.1",
80
+ "microbundle": "^0.15.0",
81
+ "react": "^18.2.0",
82
+ "react-dom": "^18.2.0",
83
+ "ts-node": "^10.8.1",
84
+ "typescript": "^4.7.3",
85
+ "webpack": "^5.73.0"
82
86
  },
83
87
  "files": [
84
88
  "**/*.js",
89
+ "**/*.js.map",
85
90
  "**/*.ts"
86
91
  ]
87
92
  }
package/index.modern.js DELETED
@@ -1,308 +0,0 @@
1
- import { jsx } from 'react/jsx-runtime';
2
- import { createContext, useContext, useMemo, useEffect, useState, Fragment } from 'react';
3
- import csrPlug from '@croct/plug';
4
-
5
- function _objectWithoutPropertiesLoose(source, excluded) {
6
- if (source == null) return {};
7
- var target = {};
8
- var sourceKeys = Object.keys(source);
9
- var key, i;
10
-
11
- for (i = 0; i < sourceKeys.length; i++) {
12
- key = sourceKeys[i];
13
- if (excluded.indexOf(key) >= 0) continue;
14
- target[key] = source[key];
15
- }
16
-
17
- return target;
18
- }
19
-
20
- function isSsr() {
21
- return typeof window === 'undefined';
22
- }
23
- const croct = !isSsr() ? csrPlug : new Proxy(csrPlug, {
24
- get(_, property) {
25
- switch (property) {
26
- case 'initialized':
27
- return false;
28
-
29
- case 'plug':
30
- return () => {// no-op
31
- };
32
-
33
- case 'unplug':
34
- return () => Promise.resolve();
35
-
36
- default:
37
- throw new Error(`Property croct.${String(property)} is not supported on server-side (SSR). Consider refactoring ` + 'the logic as a side-effect (useEffect) or a client-side callback (onClick, onChange, etc).');
38
- }
39
- }
40
-
41
- });
42
-
43
- const CroctContext = /*#__PURE__*/createContext(null);
44
- CroctContext.displayName = 'CroctContext';
45
- const CroctProvider = _ref => {
46
- let {
47
- children
48
- } = _ref,
49
- configuration = _objectWithoutPropertiesLoose(_ref, ["children"]);
50
-
51
- const parent = useContext(CroctContext);
52
-
53
- if (parent !== null) {
54
- throw new Error('You cannot render <CroctProvider> inside another <CroctProvider>. ' + 'Croct should only be initialized once in the application.');
55
- }
56
-
57
- const context = useMemo(() => ({
58
- get plug() {
59
- if (!croct.initialized) {
60
- croct.plug(configuration);
61
- }
62
-
63
- return croct;
64
- }
65
-
66
- }), [configuration]);
67
- useEffect(() => {
68
- croct.plug(configuration);
69
- return () => {
70
- croct.unplug();
71
- };
72
- }, []);
73
- return jsx(CroctContext.Provider, Object.assign({
74
- value: context
75
- }, {
76
- children: children
77
- }), void 0);
78
- };
79
-
80
- class Cache {
81
- constructor(defaultExpiration) {
82
- this.cache = {};
83
- this.defaultExpiration = void 0;
84
- this.defaultExpiration = defaultExpiration;
85
- }
86
-
87
- load(configuration) {
88
- const {
89
- cacheKey,
90
- loader,
91
- fallback,
92
- expiration = this.defaultExpiration
93
- } = configuration;
94
- const cachedEntry = this.get(cacheKey);
95
-
96
- if (cachedEntry !== undefined) {
97
- if (cachedEntry.error !== undefined) {
98
- if (fallback !== undefined) {
99
- return fallback;
100
- }
101
-
102
- throw cachedEntry.error;
103
- }
104
-
105
- if (cachedEntry.result !== undefined) {
106
- return cachedEntry.result;
107
- }
108
-
109
- throw cachedEntry.promise;
110
- }
111
-
112
- const entry = {
113
- dispose: () => {
114
- if (entry.timeout !== undefined || expiration < 0) {
115
- return;
116
- }
117
-
118
- entry.timeout = window.setTimeout(() => {
119
- delete this.cache[cacheKey];
120
- }, expiration);
121
- },
122
- promise: loader().then(result => {
123
- entry.result = result;
124
- return result;
125
- }).catch(error => {
126
- entry.error = error;
127
- }).finally(() => {
128
- entry.dispose();
129
- })
130
- };
131
- this.cache[cacheKey] = entry;
132
- throw entry.promise;
133
- }
134
-
135
- get(cacheKey) {
136
- const entry = this.cache[cacheKey];
137
-
138
- if (entry === undefined) {
139
- return undefined;
140
- }
141
-
142
- if (entry.timeout !== undefined) {
143
- clearTimeout(entry.timeout);
144
- delete entry.timeout;
145
- entry.dispose();
146
- }
147
-
148
- return entry;
149
- }
150
-
151
- }
152
-
153
- const cache = new Cache(60 * 1000);
154
- function useLoader(_ref) {
155
- var _cache$get;
156
-
157
- let {
158
- initial
159
- } = _ref,
160
- options = _objectWithoutPropertiesLoose(_ref, ["initial"]);
161
-
162
- const loadedValue = (_cache$get = cache.get(options.cacheKey)) == null ? void 0 : _cache$get.result;
163
- const [value, setValue] = useState(loadedValue !== undefined ? loadedValue : initial);
164
- const [isUnmounted, setUnmounted] = useState(false);
165
- useEffect(() => {
166
- if (initial !== undefined) {
167
- try {
168
- setValue(cache.load(options));
169
- } catch (result) {
170
- if (typeof (result == null ? void 0 : result.then) !== 'function') {
171
- setValue(undefined);
172
- return;
173
- }
174
-
175
- result.then(resolvedValue => {
176
- if (!isUnmounted) {
177
- setValue(resolvedValue);
178
- }
179
- });
180
- }
181
- }
182
-
183
- return () => {
184
- setUnmounted(true);
185
- };
186
- }, []);
187
-
188
- if (value === undefined) {
189
- return cache.load(options);
190
- }
191
-
192
- return value;
193
- }
194
-
195
- function useCroct() {
196
- const context = useContext(CroctContext);
197
-
198
- if (context === null) {
199
- throw new Error('useCroct() can only be used in the context of a <CroctProvider> component.');
200
- }
201
-
202
- return context.plug;
203
- }
204
-
205
- function cleanEvaluationOptions(options) {
206
- const result = {};
207
-
208
- for (const [key, value] of Object.entries(options)) {
209
- if (value !== undefined) {
210
- result[key] = value;
211
- }
212
- }
213
-
214
- return result;
215
- }
216
-
217
- function useCsrEvaluation(expression, options = {}) {
218
- var _options$attributes;
219
-
220
- const {
221
- cacheKey,
222
- fallback,
223
- initial,
224
- expiration
225
- } = options,
226
- evaluationOptions = _objectWithoutPropertiesLoose(options, ["cacheKey", "fallback", "initial", "expiration"]);
227
-
228
- const croct = useCroct();
229
- return useLoader({
230
- cacheKey: `useEvaluation:${cacheKey != null ? cacheKey : ''}:${expression}:${JSON.stringify((_options$attributes = options.attributes) != null ? _options$attributes : '')}`,
231
- loader: () => croct.evaluate(expression, cleanEvaluationOptions(evaluationOptions)),
232
- initial: initial,
233
- fallback: fallback,
234
- expiration: expiration
235
- });
236
- }
237
-
238
- function useSsrEvaluation(_, {
239
- initial
240
- } = {}) {
241
- if (initial === undefined) {
242
- throw new Error('The initial value is required for server-side rendering (SSR).');
243
- }
244
-
245
- return initial;
246
- }
247
-
248
- const useEvaluation = isSsr() ? useSsrEvaluation : useCsrEvaluation;
249
-
250
- function useCsrContent(id, options = {}) {
251
- const {
252
- fallback,
253
- initial,
254
- cacheKey,
255
- expiration
256
- } = options;
257
- const croct = useCroct();
258
- return useLoader({
259
- cacheKey: `useContent:${cacheKey != null ? cacheKey : ''}:${id}`,
260
- loader: () => croct.fetch(id).then(({
261
- payload
262
- }) => payload),
263
- initial: initial,
264
- fallback: fallback,
265
- expiration: expiration
266
- });
267
- }
268
-
269
- function useSsrContent(_, {
270
- initial
271
- } = {}) {
272
- if (initial === undefined) {
273
- throw new Error('The initial value is required for server-side rendering (SSR).');
274
- }
275
-
276
- return initial;
277
- }
278
-
279
- const useContent = isSsr() ? useSsrContent : useCsrContent;
280
-
281
- function Personalization(props) {
282
- const {
283
- expression,
284
- children
285
- } = props,
286
- options = _objectWithoutPropertiesLoose(props, ["expression", "children"]);
287
-
288
- const result = useEvaluation(expression, options);
289
- return jsx(Fragment, {
290
- children: children(result)
291
- }, void 0);
292
- }
293
-
294
- const Slot = props => {
295
- const {
296
- id,
297
- children
298
- } = props,
299
- options = _objectWithoutPropertiesLoose(props, ["id", "children"]);
300
-
301
- const data = useContent(id, options);
302
- return jsx(Fragment, {
303
- children: children(data)
304
- }, void 0);
305
- };
306
-
307
- export { CroctContext, CroctProvider, Personalization, Slot, useContent, useCroct, useEvaluation };
308
- //# sourceMappingURL=index.modern.js.map