@sitecore-content-sdk/react 1.2.0-canary.8 → 1.2.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.
Files changed (104) hide show
  1. package/LICENSE.txt +202 -202
  2. package/README.md +11 -11
  3. package/dist/cjs/components/ClientEditingChromesUpdate.js +52 -0
  4. package/dist/cjs/components/DefaultEmptyFieldEditingComponents.js +4 -4
  5. package/dist/cjs/components/DesignLibrary.js +85 -103
  6. package/dist/cjs/components/EditingScripts.js +1 -0
  7. package/dist/cjs/components/ErrorBoundary.js +1 -0
  8. package/dist/cjs/components/FEaaS/BYOCServerWrapper.js +28 -0
  9. package/dist/cjs/components/{BYOCComponent.js → FEaaS/BYOCWrapper.js} +17 -28
  10. package/dist/cjs/components/FEaaS/FEaaSSeverWrapper.js +34 -0
  11. package/dist/cjs/components/FEaaS/FEaaSWrapper.js +78 -0
  12. package/dist/cjs/components/{FEaaSComponent.js → FEaaS/feaas-utils.js} +18 -35
  13. package/dist/cjs/components/FEaaS/index.js +21 -0
  14. package/dist/cjs/components/FEaaS/models.js +7 -0
  15. package/dist/cjs/components/Link.js +1 -1
  16. package/dist/cjs/components/Placeholder/AppPlaceholder.js +76 -0
  17. package/dist/cjs/components/Placeholder/ClientComponentWrapper.js +21 -0
  18. package/dist/cjs/components/Placeholder/Placeholder.js +110 -0
  19. package/dist/cjs/components/Placeholder/index.js +25 -0
  20. package/dist/cjs/components/Placeholder/models.js +18 -0
  21. package/dist/cjs/components/Placeholder/placeholder-utils.js +215 -0
  22. package/dist/cjs/components/RichText.js +1 -0
  23. package/dist/cjs/components/Text.js +1 -0
  24. package/dist/cjs/enhancers/withAppPlaceholder.js +21 -0
  25. package/dist/cjs/enhancers/withEmptyFieldEditingComponent.js +12 -5
  26. package/dist/cjs/enhancers/withPlaceholder.js +8 -6
  27. package/dist/cjs/index.js +17 -11
  28. package/dist/cjs/rsc-utils/no-rsc.js +5 -0
  29. package/dist/cjs/rsc-utils/rsc.js +5 -0
  30. package/dist/esm/components/ClientEditingChromesUpdate.js +15 -0
  31. package/dist/esm/components/DefaultEmptyFieldEditingComponents.js +4 -4
  32. package/dist/esm/components/DesignLibrary.js +85 -102
  33. package/dist/esm/components/EditingScripts.js +1 -0
  34. package/dist/esm/components/ErrorBoundary.js +1 -0
  35. package/dist/esm/components/FEaaS/BYOCServerWrapper.js +21 -0
  36. package/dist/esm/components/{BYOCComponent.js → FEaaS/BYOCWrapper.js} +15 -26
  37. package/dist/esm/components/FEaaS/FEaaSSeverWrapper.js +27 -0
  38. package/dist/esm/components/FEaaS/FEaaSWrapper.js +37 -0
  39. package/dist/esm/components/{FEaaSComponent.js → FEaaS/feaas-utils.js} +16 -30
  40. package/dist/esm/components/FEaaS/index.js +6 -0
  41. package/dist/esm/components/FEaaS/models.js +4 -0
  42. package/dist/esm/components/Link.js +1 -1
  43. package/dist/esm/components/Placeholder/AppPlaceholder.js +69 -0
  44. package/dist/esm/components/Placeholder/ClientComponentWrapper.js +14 -0
  45. package/dist/esm/components/Placeholder/Placeholder.js +103 -0
  46. package/dist/esm/components/Placeholder/index.js +4 -0
  47. package/dist/esm/components/Placeholder/models.js +15 -0
  48. package/dist/esm/components/Placeholder/placeholder-utils.js +203 -0
  49. package/dist/esm/components/RichText.js +1 -0
  50. package/dist/esm/components/Text.js +1 -0
  51. package/dist/esm/enhancers/withAppPlaceholder.js +14 -0
  52. package/dist/esm/enhancers/withEmptyFieldEditingComponent.js +12 -5
  53. package/dist/esm/enhancers/withPlaceholder.js +8 -6
  54. package/dist/esm/index.js +5 -5
  55. package/dist/esm/rsc-utils/no-rsc.js +2 -0
  56. package/dist/esm/rsc-utils/rsc.js +2 -0
  57. package/package.json +16 -4
  58. package/types/components/ClientEditingChromesUpdate.d.ts +6 -0
  59. package/types/components/Date.d.ts +1 -1
  60. package/types/components/DefaultEmptyFieldEditingComponents.d.ts +8 -2
  61. package/types/components/DesignLibrary.d.ts +13 -13
  62. package/types/components/ErrorBoundary.d.ts +0 -1
  63. package/types/components/FEaaS/BYOCServerWrapper.d.ts +3 -0
  64. package/types/components/FEaaS/BYOCWrapper.d.ts +25 -0
  65. package/types/components/FEaaS/FEaaSSeverWrapper.d.ts +8 -0
  66. package/types/components/FEaaS/FEaaSWrapper.d.ts +7 -0
  67. package/types/components/FEaaS/feaas-utils.d.ts +21 -0
  68. package/types/components/FEaaS/index.d.ts +6 -0
  69. package/types/components/FEaaS/models.d.ts +125 -0
  70. package/types/components/Image.d.ts +1 -1
  71. package/types/components/Link.d.ts +1 -1
  72. package/types/components/Placeholder/AppPlaceholder.d.ts +10 -0
  73. package/types/components/Placeholder/ClientComponentWrapper.d.ts +9 -0
  74. package/types/components/Placeholder/Placeholder.d.ts +28 -0
  75. package/types/components/Placeholder/index.d.ts +5 -0
  76. package/types/components/Placeholder/models.d.ts +140 -0
  77. package/types/components/Placeholder/placeholder-utils.d.ts +53 -0
  78. package/types/components/RichText.d.ts +1 -1
  79. package/types/components/Text.d.ts +1 -1
  80. package/types/components/sharedTypes/components.d.ts +6 -0
  81. package/types/components/sharedTypes/props.d.ts +2 -2
  82. package/types/enhancers/withAppPlaceholder.d.ts +15 -0
  83. package/types/enhancers/withEmptyFieldEditingComponent.d.ts +3 -3
  84. package/types/enhancers/withPlaceholder.d.ts +2 -1
  85. package/types/index.d.ts +4 -5
  86. package/types/rsc-utils/no-rsc.d.ts +1 -0
  87. package/types/rsc-utils/rsc.d.ts +1 -0
  88. package/dist/cjs/components/BYOCWrapper.js +0 -22
  89. package/dist/cjs/components/FEaaSWrapper.js +0 -19
  90. package/dist/cjs/components/Placeholder.js +0 -68
  91. package/dist/cjs/components/PlaceholderCommon.js +0 -176
  92. package/dist/esm/components/BYOCWrapper.js +0 -15
  93. package/dist/esm/components/FEaaSWrapper.js +0 -12
  94. package/dist/esm/components/Placeholder.js +0 -62
  95. package/dist/esm/components/PlaceholderCommon.js +0 -169
  96. package/types/components/BYOCComponent.d.ts +0 -93
  97. package/types/components/BYOCWrapper.d.ts +0 -7
  98. package/types/components/FEaaSComponent.d.ts +0 -72
  99. package/types/components/FEaaSWrapper.d.ts +0 -4
  100. package/types/components/Placeholder.d.ts +0 -20
  101. package/types/components/PlaceholderCommon.d.ts +0 -89
  102. /package/dist/cjs/components/{PlaceholderMetadata.js → Placeholder/PlaceholderMetadata.js} +0 -0
  103. /package/dist/esm/components/{PlaceholderMetadata.js → Placeholder/PlaceholderMetadata.js} +0 -0
  104. /package/types/components/{PlaceholderMetadata.d.ts → Placeholder/PlaceholderMetadata.d.ts} +0 -0
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rsc = void 0;
4
+ // Always false constant to import in the non-RSC contexts using conditional imports
5
+ exports.rsc = false;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rsc = void 0;
4
+ // Always true constant to import in the RSC environment using conditional imports
5
+ exports.rsc = true;
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import { isEditorActive, resetEditorChromes } from '@sitecore-content-sdk/core/editing';
3
+ import React, { useEffect } from 'react';
4
+ /**
5
+ * Updates editing chromes in app router / RSC context.
6
+ * This ensures all the relevant Pages editing markup is applied once all client components are loaded.
7
+ */
8
+ export const ClientEditingChromesUpdate = () => {
9
+ useEffect(() => {
10
+ if (isEditorActive()) {
11
+ resetEditorChromes();
12
+ }
13
+ }, []);
14
+ return React.createElement(React.Fragment, null);
15
+ };
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- export const DefaultEmptyFieldEditingComponentText = () => {
3
- return React.createElement("span", null, "[No text in field]");
2
+ export const DefaultEmptyFieldEditingComponentText = (props) => {
3
+ return React.createElement(props.tag || 'span', props, '[No text in field]');
4
4
  };
5
- export const DefaultEmptyFieldEditingComponentImage = () => {
5
+ export const DefaultEmptyFieldEditingComponentImage = (props) => {
6
6
  const inlineStyles = {
7
7
  minWidth: '48px',
8
8
  minHeight: '48px',
@@ -10,5 +10,5 @@ export const DefaultEmptyFieldEditingComponentImage = () => {
10
10
  maxHeight: '400px',
11
11
  cursor: 'pointer',
12
12
  };
13
- return (React.createElement("img", { alt: "", src: 'data:image/svg+xml,%3Csvg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 240 240" style="enable-background:new 0 0 240 240;" xml:space="preserve"%3E%3Cstyle type="text/css"%3E .st0%7Bfill:none;%7D .st1%7Bfill:%23969696;%7D .st2%7Bfill:%23FFFFFF;%7D .st3%7Bfill:%23FFFFFF;stroke:%23FFFFFF;stroke-width:0.75;stroke-miterlimit:10;%7D%0A%3C/style%3E%3Cg%3E%3Crect class="st0" width="240" height="240"/%3E%3Cg%3E%3Cg%3E%3Crect x="20" y="20" class="st1" width="200" height="200"/%3E%3C/g%3E%3Cg%3E%3Ccircle class="st2" cx="174" cy="67" r="14"/%3E%3Cpath class="st2" d="M174,54c7.17,0,13,5.83,13,13s-5.83,13-13,13s-13-5.83-13-13S166.83,54,174,54 M174,52 c-8.28,0-15,6.72-15,15s6.72,15,15,15s15-6.72,15-15S182.28,52,174,52L174,52z"/%3E%3C/g%3E%3Cpolyline class="st3" points="29.5,179.25 81.32,122.25 95.41,137.75 137.23,91.75 209.5,179.75 "/%3E%3C/g%3E%3C/g%3E%3C/svg%3E', className: "scEmptyImage", style: inlineStyles }));
13
+ return (React.createElement("img", Object.assign({}, props, { alt: "", src: 'data:image/svg+xml,%3Csvg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 240 240" style="enable-background:new 0 0 240 240;" xml:space="preserve"%3E%3Cstyle type="text/css"%3E .st0%7Bfill:none;%7D .st1%7Bfill:%23969696;%7D .st2%7Bfill:%23FFFFFF;%7D .st3%7Bfill:%23FFFFFF;stroke:%23FFFFFF;stroke-width:0.75;stroke-miterlimit:10;%7D%0A%3C/style%3E%3Cg%3E%3Crect class="st0" width="240" height="240"/%3E%3Cg%3E%3Cg%3E%3Crect x="20" y="20" class="st1" width="200" height="200"/%3E%3C/g%3E%3Cg%3E%3Ccircle class="st2" cx="174" cy="67" r="14"/%3E%3Cpath class="st2" d="M174,54c7.17,0,13,5.83,13,13s-5.83,13-13,13s-13-5.83-13-13S166.83,54,174,54 M174,52 c-8.28,0-15,6.72-15,15s6.72,15,15,15s15-6.72,15-15S182.28,52,174,52L174,52z"/%3E%3C/g%3E%3Cpolyline class="st3" points="29.5,179.25 81.32,122.25 95.41,137.75 137.23,91.75 209.5,179.75 "/%3E%3C/g%3E%3C/g%3E%3C/svg%3E', className: `scEmptyImage ${props.className || ''}`, style: inlineStyles })));
14
14
  };
@@ -10,60 +10,36 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  /* eslint-disable jsdoc/require-param */
12
12
  /* eslint-disable prefer-const */
13
- import React, { useEffect, useMemo, useState } from 'react';
13
+ import React, { useEffect, useState } from 'react';
14
14
  import { Placeholder } from './Placeholder';
15
15
  import { EDITING_COMPONENT_ID, EDITING_COMPONENT_PLACEHOLDER, } from '@sitecore-content-sdk/core/layout';
16
16
  import { DesignLibraryStatus, getDesignLibraryStatusEvent, addComponentUpdateHandler, } from '@sitecore-content-sdk/core/editing';
17
17
  import * as codegen from '@sitecore-content-sdk/core/codegen';
18
18
  import { useSitecore } from '../enhancers/withSitecore';
19
+ import { PlaceholderMetadata } from './Placeholder';
19
20
  let { getDesignLibraryImportMapEvent, getDesignLibraryComponentPropsEvent, addComponentPreviewHandler, } = codegen;
20
21
  export const __mockDependencies = (mocks) => {
21
22
  addComponentPreviewHandler = mocks.addComponentPreviewHandler;
22
23
  };
23
- /**
24
- * This component is used to render the component in preview mode.
25
- * It is used to send the rendered event to the parent window and render the component.
26
- * Reacts on the update event from the parent window and re-renders the component.
27
- */
28
- const Preview = () => {
29
- const { page } = useSitecore();
30
- const { layout: { sitecore: { route }, }, } = page;
31
- const [renderKey, setRenderKey] = useState(0);
32
- const [rootUpdate, setRootUpdate] = useState(null);
33
- const rootComponent = route === null || route === void 0 ? void 0 : route.placeholders[EDITING_COMPONENT_PLACEHOLDER][0];
34
- // useEffect may execute multiple times on single render (i.e. in dev) - but we only want to fire ready event once
35
- let componentReady = false;
36
- // have an up-to-date layout state between re-renders (SSR re-render excluded)
37
- const persistedRoot = useMemo(() => (Object.assign(Object.assign({}, (rootComponent || {})), rootUpdate)), [rootComponent, rootUpdate]);
38
- route.placeholders[EDITING_COMPONENT_PLACEHOLDER][0] = persistedRoot;
39
- useEffect(() => {
40
- // useEffect will fire when components are ready - and we inform the whole wide world of it too
41
- if (!componentReady) {
42
- componentReady = true;
43
- window.top.postMessage(getDesignLibraryStatusEvent(DesignLibraryStatus.READY, rootComponent.uid), '*');
44
- }
45
- const unsubscribe = addComponentUpdateHandler(persistedRoot, (updatedRoot) => {
46
- setRootUpdate(Object.assign({}, updatedRoot));
47
- setRenderKey((key) => key + 1);
48
- });
49
- // useEffect will cleanup event handler on re-render
50
- return unsubscribe;
51
- }, []);
52
- useEffect(() => {
53
- // Send a rendered event only as effect of a component update command
54
- if (renderKey === 0) {
55
- return;
56
- }
57
- window.top.postMessage(getDesignLibraryStatusEvent(DesignLibraryStatus.RENDERED, rootComponent.uid), '*');
58
- }, [renderKey, rootComponent.uid]);
59
- return (React.createElement(React.Fragment, null,
60
- React.createElement("main", null,
61
- React.createElement("div", { id: EDITING_COMPONENT_ID }, route && (React.createElement(Placeholder, { name: EDITING_COMPONENT_PLACEHOLDER, rendering: route, key: renderKey }))))));
62
- };
63
24
  const sendErrorEvent = (uid, error, type) => {
64
25
  const errorEvent = codegen.getDesignLibraryComponentPreviewErrorEvent(uid, error, type);
65
26
  console.error('Component Library: sending error event', errorEvent);
66
- window.top.postMessage(errorEvent, '*');
27
+ if (typeof window !== 'undefined') {
28
+ const target = window.parent && window.parent !== window ? window.parent : window;
29
+ target.postMessage(errorEvent, '*');
30
+ }
31
+ };
32
+ const postToDL = (evt) => {
33
+ if (typeof window === 'undefined')
34
+ return;
35
+ const target = window.parent && window.parent !== window ? window.parent : window;
36
+ try {
37
+ console.log('Component Library: sending event', evt === null || evt === void 0 ? void 0 : evt.name, evt);
38
+ target.postMessage(evt, '*');
39
+ }
40
+ catch (err) {
41
+ console.error('Component Library: postMessage failed', err, evt);
42
+ }
67
43
  };
68
44
  class ErrorBoundary extends React.Component {
69
45
  constructor() {
@@ -91,36 +67,74 @@ class ErrorBoundary extends React.Component {
91
67
  }
92
68
  }
93
69
  /**
94
- * This component is used to render the component in variant generation mode.
95
- * It is used to send the import-map and component-props events to the parent window and render the dynamic component.
70
+ * Design Library component.
71
+ *
72
+ * Renders the **real** Sitecore component for `library` / `library-metadata` modes and,
73
+ * when generation is enabled (`page.mode.designLibrary.isVariantGeneration === true`),
74
+ * wires the **variant generation** handshake so the parent (DL Studio) can send
75
+ * generated code to preview and iterate on.
76
+ * @param {DesignLibraryProps} props
77
+ * @param {() => Promise<{ default: import('../codegen').ImportEntry[] }>} [props.loadImportMap] Optional async loader that resolves to the import-map used to resolve the generated component’s imports. Required when `isVariantGeneration` is true.
78
+ * @returns {JSX.Element} The preview surface, or `null` when not in Design Library mode.
96
79
  */
97
- export const VariantGeneration = (props) => {
80
+ export const DesignLibrary = ({ loadImportMap }) => {
81
+ var _a, _b;
98
82
  const { page } = useSitecore();
99
- const { layout: { sitecore: { route }, }, } = page;
100
- const rendering = route === null || route === void 0 ? void 0 : route.placeholders[EDITING_COMPONENT_PLACEHOLDER][0];
83
+ const route = page.layout.sitecore.route;
84
+ const rendering = (_a = route === null || route === void 0 ? void 0 : route.placeholders[EDITING_COMPONENT_PLACEHOLDER]) === null || _a === void 0 ? void 0 : _a[0];
85
+ const { isDesignLibrary } = page.mode;
86
+ const isVariantGeneration = (_b = page.mode.designLibrary) === null || _b === void 0 ? void 0 : _b.isVariantGeneration;
87
+ const [propsState, setPropsState] = useState({
88
+ fields: rendering === null || rendering === void 0 ? void 0 : rendering.fields,
89
+ params: rendering === null || rendering === void 0 ? void 0 : rendering.params,
90
+ });
101
91
  const [renderKey, setRenderKey] = useState(0);
102
92
  const [Component, setComponent] = useState(null);
93
+ const isGeneratedComponentActive = !!Component;
94
+ if (!isDesignLibrary)
95
+ return null;
103
96
  // eslint-disable-next-line react-hooks/rules-of-hooks
104
97
  useEffect(() => {
98
+ postToDL(getDesignLibraryStatusEvent(DesignLibraryStatus.READY, rendering.uid));
99
+ if (!isVariantGeneration) {
100
+ requestAnimationFrame(() => {
101
+ setRenderKey((k) => (k === 0 ? k + 1 : k));
102
+ });
103
+ }
104
+ const unsubUpdate = addComponentUpdateHandler(rendering, (updated) => {
105
+ setPropsState({ fields: updated.fields, params: updated.params });
106
+ setRenderKey((k) => k + 1);
107
+ });
108
+ // useEffect will cleanup event handler on re-render
109
+ return () => unsubUpdate && unsubUpdate();
110
+ }, [isVariantGeneration, rendering]);
111
+ // eslint-disable-next-line react-hooks/rules-of-hooks
112
+ useEffect(() => {
113
+ // Send a rendered event only as effect of a component update command
114
+ if (renderKey === 0)
115
+ return;
116
+ postToDL(getDesignLibraryStatusEvent(DesignLibraryStatus.RENDERED, rendering.uid));
117
+ }, [renderKey, rendering]);
118
+ // eslint-disable-next-line react-hooks/rules-of-hooks
119
+ useEffect(() => {
120
+ if (!isDesignLibrary || !isVariantGeneration)
121
+ return undefined;
105
122
  let cancelled = false;
106
123
  // since import map is loaded lazily, we only need to add preview event handler once the import map is loaded
107
124
  // unsubscribe function for useEffect cleanup will also be returned once importMap promise has been resolved or rejected
108
- let unsubscribe = undefined;
109
- const init = () => __awaiter(void 0, void 0, void 0, function* () {
110
- var _a;
111
- let importMap = undefined;
112
- if (!props.loadImportMap) {
113
- const errorMessage = 'No loadImportMap prop provided. Please provide a dynamic import map function for DesignLibrary.';
114
- sendErrorEvent(rendering.uid, errorMessage, codegen.DesignLibraryPreviewError.RenderInit);
125
+ let unsubscribe;
126
+ (() => __awaiter(void 0, void 0, void 0, function* () {
127
+ if (!loadImportMap) {
128
+ sendErrorEvent(rendering.uid, 'No loadImportMap provided', codegen.DesignLibraryPreviewError.RenderInit);
115
129
  return;
116
130
  }
131
+ let importMap;
117
132
  try {
118
- const importMapImport = yield props.loadImportMap();
119
- importMap = importMapImport.default;
133
+ const mod = yield loadImportMap();
134
+ importMap = mod.default;
120
135
  }
121
- catch (error) {
122
- const errorMessage = `Error loading import map: ${error}`;
123
- sendErrorEvent(rendering.uid, errorMessage, codegen.DesignLibraryPreviewError.RenderInit);
136
+ catch (e) {
137
+ sendErrorEvent(rendering.uid, `Error loading import map: ${e}`, codegen.DesignLibraryPreviewError.RenderInit);
124
138
  return;
125
139
  }
126
140
  // account for component being unmounted while resolving async import map
@@ -128,54 +142,23 @@ export const VariantGeneration = (props) => {
128
142
  return;
129
143
  unsubscribe = addComponentPreviewHandler(importMap, (error, Component) => {
130
144
  // Error event is already sent in the addComponentPreviewHandler
131
- if (error) {
145
+ if (error)
132
146
  return;
133
- }
134
- setRenderKey((key) => key + 1);
135
147
  setComponent(() => Component);
148
+ setRenderKey((k) => k + 1);
136
149
  });
137
150
  const importMapEvent = getDesignLibraryImportMapEvent(rendering.uid, importMap);
138
- console.debug('Component Library: sending event', importMapEvent);
139
- window.parent.postMessage(importMapEvent, '*');
140
- const componentPropsEvent = getDesignLibraryComponentPropsEvent(rendering.uid, rendering.fields, rendering.params);
141
- console.debug('Component Library: sending event', componentPropsEvent);
142
- window.top.postMessage(componentPropsEvent, '*');
143
- const readyEvent = getDesignLibraryStatusEvent(DesignLibraryStatus.READY, rendering.uid);
144
- console.debug('Component Library: sending event', readyEvent);
145
- (_a = window.top) === null || _a === void 0 ? void 0 : _a.postMessage(readyEvent, '*');
146
- });
147
- init();
148
- // return function that calls unsubsubribe - if the component was mounted correctly
151
+ postToDL(importMapEvent);
152
+ const propsEvent = getDesignLibraryComponentPropsEvent(rendering.uid, propsState.fields, propsState.params);
153
+ postToDL(propsEvent);
154
+ }))();
155
+ // return function that calls unsubscribe - if the component was mounted correctly
149
156
  return () => {
150
157
  cancelled = true;
151
- if (unsubscribe) {
152
- unsubscribe();
153
- }
158
+ unsubscribe && unsubscribe();
154
159
  };
155
- }, []);
156
- // eslint-disable-next-line react-hooks/rules-of-hooks
157
- useEffect(() => {
158
- var _a;
159
- // Send a rendered event only as effect of a component update command
160
- if (renderKey === 0)
161
- return undefined;
162
- const renderedEvent = getDesignLibraryStatusEvent(DesignLibraryStatus.RENDERED, rendering.uid);
163
- console.debug('Component Library: sending event', renderedEvent);
164
- (_a = window.top) === null || _a === void 0 ? void 0 : _a.postMessage(renderedEvent, '*');
165
- }, [renderKey, rendering === null || rendering === void 0 ? void 0 : rendering.uid]);
166
- return (React.createElement("main", null, Component ? (React.createElement(ErrorBoundary, { uid: rendering.uid, renderKey: renderKey },
167
- React.createElement(Component, { fields: rendering.fields, params: rendering.params, key: renderKey }))) : (React.createElement("div", null, "Loading preview..."))));
168
- };
169
- export const DesignLibrary = ({ loadImportMap }) => {
170
- var _a;
171
- const { page } = useSitecore();
172
- const { isDesignLibrary } = page.mode;
173
- const isVariantGeneration = (_a = page.mode.designLibrary) === null || _a === void 0 ? void 0 : _a.isVariantGeneration;
174
- if (!isDesignLibrary) {
175
- return null;
176
- }
177
- if (isVariantGeneration) {
178
- return React.createElement(VariantGeneration, { loadImportMap: loadImportMap });
179
- }
180
- return React.createElement(Preview, null);
160
+ }, [isVariantGeneration, rendering]);
161
+ return (React.createElement("main", null, isGeneratedComponentActive ? (React.createElement(ErrorBoundary, { uid: rendering.uid, renderKey: renderKey },
162
+ React.createElement(PlaceholderMetadata, { rendering: rendering },
163
+ React.createElement(Component, { fields: propsState.fields, params: propsState.params, key: renderKey })))) : (React.createElement("div", { id: EDITING_COMPONENT_ID }, route && (React.createElement(Placeholder, { name: EDITING_COMPONENT_PLACEHOLDER, rendering: route, key: renderKey }))))));
181
164
  };
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import React from 'react';
2
3
  import { useSitecore } from '../enhancers/withSitecore';
3
4
  import { getContentSdkPagesClientData } from '@sitecore-content-sdk/core/editing';
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import React, { Suspense } from 'react';
2
3
  import { withSitecore } from '../enhancers/withSitecore';
3
4
  class ErrorBoundary extends React.Component {
@@ -0,0 +1,21 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import React from 'react';
11
+ import { fetchBYOCComponentServerProps } from './feaas-utils';
12
+ import { BYOCWrapper } from './BYOCWrapper';
13
+ import { nonSerializedPlaceholderProps } from '../Placeholder/models';
14
+ export const BYOCServerWrapper = (props) => __awaiter(void 0, void 0, void 0, function* () {
15
+ var _a;
16
+ const params = ((_a = props.rendering) === null || _a === void 0 ? void 0 : _a.params) || {};
17
+ // only pass serializable props to the client BYOC component
18
+ const serializableProps = Object.fromEntries(Object.entries(props).filter(([key]) => !nonSerializedPlaceholderProps.includes(key)));
19
+ const finalProps = Object.assign(Object.assign({}, (yield fetchBYOCComponentServerProps(params))), serializableProps);
20
+ return React.createElement(BYOCWrapper, Object.assign({}, finalProps));
21
+ });
@@ -1,18 +1,8 @@
1
1
  'use client';
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  import React from 'react';
12
- import { getDataFromFields } from '../utils';
13
- import { MissingComponent } from './MissingComponent';
14
3
  import * as FEAAS from '@sitecore-feaas/clientside/react';
15
- export const BYOC_COMPONENT_RENDERING_NAME = 'BYOCComponent';
4
+ import { getDataFromFields } from '../../utils';
5
+ import { MissingComponent } from '../MissingComponent';
16
6
  const DefaultErrorComponent = (props) => {
17
7
  var _a;
18
8
  return (React.createElement("div", null,
@@ -20,11 +10,12 @@ const DefaultErrorComponent = (props) => {
20
10
  _a.message,
21
11
  "."));
22
12
  };
13
+ // BYOCComponent remains for backward compatibility and testing purposes
23
14
  /**
24
15
  * BYOCComponent facilitate the rendering of external components. It manages potential errors,
25
16
  * missing components, and customization of error messages or alternative rendering components.
26
17
  * @param {ByocComponentProps} props component props
27
- * @returns dynamicly rendered component or Missing Component error frame
18
+ * @returns dynamically rendered component or Missing Component error frame
28
19
  */
29
20
  export class BYOCComponent extends React.Component {
30
21
  constructor(props) {
@@ -76,17 +67,15 @@ export class BYOCComponent extends React.Component {
76
67
  }
77
68
  }
78
69
  /**
79
- * Fetches server component props required for server rendering, based on rendering params.
80
- * @param {BYOCComponentParams} params component params
70
+ * SXA wrapper for BYOC components
71
+ * @param {BYOCComponentProps} props component props
72
+ * @returns wrapped BYOC component
81
73
  */
82
- export function fetchBYOCComponentServerProps(params) {
83
- return __awaiter(this, void 0, void 0, function* () {
84
- const fetchDataOptions = params.ComponentDataOverride
85
- ? JSON.parse(params.ComponentDataOverride)
86
- : {};
87
- const fetchedData = yield FEAAS.DataSettings.fetch(fetchDataOptions || {});
88
- return {
89
- fetchedData,
90
- };
91
- });
92
- }
74
+ export const BYOCWrapper = (props) => {
75
+ var _a, _b, _c;
76
+ const styles = (_b = (_a = props.params) === null || _a === void 0 ? void 0 : _a.styles) === null || _b === void 0 ? void 0 : _b.trimEnd();
77
+ const id = (_c = props.params) === null || _c === void 0 ? void 0 : _c.RenderingIdentifier;
78
+ return (React.createElement("div", { className: styles ? styles : undefined, id: id ? id : undefined },
79
+ React.createElement("div", { className: "component-content" },
80
+ React.createElement(BYOCComponent, Object.assign({}, props)))));
81
+ };
@@ -0,0 +1,27 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import React from 'react';
11
+ import { fetchFEaaSComponentServerProps } from './feaas-utils';
12
+ import { FEaaSWrapper } from './FEaaSWrapper';
13
+ import { nonSerializedPlaceholderProps } from '../Placeholder/models';
14
+ /**
15
+ * Server component for FEaaS. Retrieves server props and renders client FEaaSWrapper.
16
+ * @param {FEaaSComponentProps} props incoming props
17
+ * @returns {Promise<JSX.Element>} rendered FEaaSWrapper component
18
+ */
19
+ export const FEaaSServerWrapper = (props) => __awaiter(void 0, void 0, void 0, function* () {
20
+ var _a, _b;
21
+ const params = ((_a = props.rendering) === null || _a === void 0 ? void 0 : _a.params) || {};
22
+ const isPageStateNormal = (_b = props.page) === null || _b === void 0 ? void 0 : _b.mode.isNormal;
23
+ // only pass serializable props to the client FEaaS component
24
+ const serializableProps = Object.fromEntries(Object.entries(props).filter(([key]) => !nonSerializedPlaceholderProps.includes(key)));
25
+ const finalProps = Object.assign(Object.assign({}, (yield fetchFEaaSComponentServerProps(params, isPageStateNormal))), serializableProps);
26
+ return React.createElement(FEaaSWrapper, Object.assign({}, finalProps));
27
+ });
@@ -0,0 +1,37 @@
1
+ 'use client';
2
+ import React from 'react';
3
+ import * as FEAAS from '@sitecore-feaas/clientside/react';
4
+ import { getDataFromFields } from '../../utils';
5
+ // FEaaSComponent remains for backward compatibility and testing purposes
6
+ /**
7
+ * @param {FEaaSComponentProps} props component props
8
+ */
9
+ export const FEaaSComponent = (props) => {
10
+ var _a, _b, _c, _d, _e, _f, _g;
11
+ const computedRevision = ((_a = props.params) === null || _a === void 0 ? void 0 : _a.ComponentRevision) || props.revisionFallback;
12
+ if (!props.template &&
13
+ (!props.params ||
14
+ !props.params.LibraryId ||
15
+ !props.params.ComponentId ||
16
+ !props.params.ComponentVersion ||
17
+ !props.params.ComponentHostName ||
18
+ !computedRevision)) {
19
+ // Missing FEaaS component required props
20
+ return null;
21
+ }
22
+ // combine fetchedData from server with datasource data (if present)
23
+ const data = Object.assign(Object.assign({}, props.fetchedData), { _: getDataFromFields((_b = props.fields) !== null && _b !== void 0 ? _b : {}) });
24
+ // FEaaS control would still be hydrated by client
25
+ // we pass all the props as a workaround to avoid hydration error, until we convert all Content SDK components to server side
26
+ // this also allows component to fall back to full client-side rendering when template or src is empty
27
+ // FEAAS should not fetch anything, since Content SDK does the fetching - so we pass empty array into fetch param
28
+ return (React.createElement(FEAAS.Component, { data: data, template: props.template, cdn: (_c = props.params) === null || _c === void 0 ? void 0 : _c.ComponentHostName, library: (_d = props.params) === null || _d === void 0 ? void 0 : _d.LibraryId, version: (_e = props.params) === null || _e === void 0 ? void 0 : _e.ComponentVersion, component: (_f = props.params) === null || _f === void 0 ? void 0 : _f.ComponentId, instance: (_g = props.params) === null || _g === void 0 ? void 0 : _g.ComponentInstanceId, revision: computedRevision, fetch: [] }));
29
+ };
30
+ export const FEaaSWrapper = (props) => {
31
+ var _a, _b;
32
+ const styles = `component feaas ${(_a = props.params) === null || _a === void 0 ? void 0 : _a.styles}`.trimEnd();
33
+ const id = (_b = props.params) === null || _b === void 0 ? void 0 : _b.RenderingIdentifier;
34
+ return (React.createElement("div", { className: styles, id: id ? id : undefined },
35
+ React.createElement("div", { className: "component-content" },
36
+ React.createElement(FEaaSComponent, Object.assign({}, props)))));
37
+ };
@@ -1,4 +1,3 @@
1
- 'use client';
2
1
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
2
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
3
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -8,45 +7,32 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
8
  });
10
9
  };
11
- import React from 'react';
12
10
  import * as FEAAS from '@sitecore-feaas/clientside/react';
13
- import { LayoutServicePageState } from '@sitecore-content-sdk/core/layout';
14
- import { getDataFromFields } from '../utils';
15
- export const FEAAS_COMPONENT_RENDERING_NAME = 'FEaaSComponent';
16
11
  /**
17
- * @param {FEaaSComponentProps} props component props
12
+ * Fetches server component props required for server rendering, based on rendering params.
13
+ * @param {BYOCComponentParams} params component params
18
14
  */
19
- export const FEaaSComponent = (props) => {
20
- var _a, _b, _c, _d, _e, _f, _g;
21
- const computedRevision = ((_a = props.params) === null || _a === void 0 ? void 0 : _a.ComponentRevision) || props.revisionFallback;
22
- if (!props.template &&
23
- (!props.params ||
24
- !props.params.LibraryId ||
25
- !props.params.ComponentId ||
26
- !props.params.ComponentVersion ||
27
- !props.params.ComponentHostName ||
28
- !computedRevision)) {
29
- // Missing FEaaS component required props
30
- return null;
31
- }
32
- // combine fetchedData from server with datasource data (if present)
33
- const data = Object.assign(Object.assign({}, props.fetchedData), { _: getDataFromFields((_b = props.fields) !== null && _b !== void 0 ? _b : {}) });
34
- // FEaaS control would still be hydrated by client
35
- // we pass all the props as a workaround to avoid hydration error, until we convert all Content SDK components to server side
36
- // this also allows component to fall back to full client-side rendering when template or src is empty
37
- // FEAAS should not fetch anything, since Content SDK does the fetching - so we pass empty array into fetch param
38
- return (React.createElement(FEAAS.Component, { data: data, template: props.template, cdn: (_c = props.params) === null || _c === void 0 ? void 0 : _c.ComponentHostName, library: (_d = props.params) === null || _d === void 0 ? void 0 : _d.LibraryId, version: (_e = props.params) === null || _e === void 0 ? void 0 : _e.ComponentVersion, component: (_f = props.params) === null || _f === void 0 ? void 0 : _f.ComponentId, instance: (_g = props.params) === null || _g === void 0 ? void 0 : _g.ComponentInstanceId, revision: computedRevision, fetch: [] }));
39
- };
15
+ export function fetchBYOCComponentServerProps(params) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const fetchDataOptions = params.ComponentDataOverride
18
+ ? JSON.parse(params.ComponentDataOverride)
19
+ : {};
20
+ const fetchedData = yield FEAAS.DataSettings.fetch(fetchDataOptions || {});
21
+ return {
22
+ fetchedData,
23
+ };
24
+ });
25
+ }
40
26
  /**
41
27
  * Fetches server component props required for server rendering, based on rendering params.
42
28
  * Component endpoint will either be retrieved from params or from endpointOverride
43
29
  * @param {FEaaSComponentParams} params component params
44
- * @param {LayoutServicePageState} [pageState] page state to determine which component variant to use
30
+ * @param {boolean} [isPageStateNormal] whether page is in normal mode
45
31
  * @param {string} [endpointOverride] optional override for component endpoint
46
32
  */
47
- export function fetchFEaaSComponentServerProps(params, pageState, endpointOverride) {
33
+ export function fetchFEaaSComponentServerProps(params, isPageStateNormal, endpointOverride) {
48
34
  return __awaiter(this, void 0, void 0, function* () {
49
- const revisionFallback = pageState && pageState !== LayoutServicePageState.Normal ? 'staged' : 'published';
35
+ const revisionFallback = isPageStateNormal ? 'published' : 'staged';
50
36
  const src = endpointOverride || composeComponentEndpoint(params, revisionFallback);
51
37
  let template = '';
52
38
  let fetchedData = {};
@@ -0,0 +1,6 @@
1
+ export { FEaaSWrapper, FEaaSComponent } from './FEaaSWrapper';
2
+ export { BYOCWrapper, BYOCComponent } from './BYOCWrapper';
3
+ export { FEAAS_COMPONENT_RENDERING_NAME, BYOC_COMPONENT_RENDERING_NAME, FEAAS_WRAPPER_RENDERING_NAME, BYOC_WRAPPER_RENDERING_NAME, } from './models';
4
+ export { FEaaSServerWrapper } from './FEaaSSeverWrapper';
5
+ export { BYOCServerWrapper } from './BYOCServerWrapper';
6
+ export { fetchFEaaSComponentServerProps, fetchBYOCComponentServerProps } from './feaas-utils';
@@ -0,0 +1,4 @@
1
+ export const FEAAS_WRAPPER_RENDERING_NAME = 'FEaaSWrapper';
2
+ export const FEAAS_COMPONENT_RENDERING_NAME = 'FEaaSComponent';
3
+ export const BYOC_WRAPPER_RENDERING_NAME = 'BYOCWrapper';
4
+ export const BYOC_COMPONENT_RENDERING_NAME = 'BYOCComponent';
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  var __rest = (this && this.__rest) || function (s, e) {
2
3
  var t = {};
3
4
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -9,7 +10,6 @@ var __rest = (this && this.__rest) || function (s, e) {
9
10
  }
10
11
  return t;
11
12
  };
12
- /* eslint-disable no-unused-expressions, @typescript-eslint/no-unused-expressions */
13
13
  import React, { forwardRef } from 'react';
14
14
  import { isFieldValueEmpty } from '@sitecore-content-sdk/core/layout';
15
15
  import { withFieldMetadata } from '../enhancers/withFieldMetadata';
@@ -0,0 +1,69 @@
1
+ import { getAppComponentProps, getComponentForRendering, getPlaceholderRenderings, renderEmptyPlaceholder, } from './placeholder-utils';
2
+ import React from 'react';
3
+ import { PlaceholderMetadata } from './PlaceholderMetadata';
4
+ import ErrorBoundary from '../ErrorBoundary';
5
+ import { ClientComponentWrapper } from './ClientComponentWrapper';
6
+ import { rsc } from '#rsc-env';
7
+ /**
8
+ * The implemention of placeholder compatible with React Server Components.
9
+ * Renders components from the layout data for the given placeholder name, with consideration for page edit mode.
10
+ * Pulls components from the provided component map.
11
+ * @param {AppPlaceholderProps} props Placeholder props
12
+ * @returns {React.ReactNode | React.ReactElement[]} rendered component(s)
13
+ */
14
+ export const AppPlaceholder = (props) => {
15
+ const { rendering: parentRendering, componentMap, page } = props;
16
+ const placeholderRenderings = getPlaceholderRenderings(parentRendering, props.name, page.mode.isEditing);
17
+ const components = placeholderRenderings
18
+ .map((rendering, index) => {
19
+ const { component: Component, isEmpty, componentType, dynamic, } = getComponentForRendering(rendering, props.name, componentMap, props.hiddenRenderingComponent, props.missingComponentComponent);
20
+ const isClient = componentType === 'client';
21
+ const key = rendering.uid || `component-${index}`;
22
+ const renderedProps = getAppComponentProps(props, rendering);
23
+ const finalRenderedProps = props.modifyComponentProps
24
+ ? props.modifyComponentProps(renderedProps)
25
+ : renderedProps;
26
+ // Client wrapper is required only when component crosses boundary from server to client.
27
+ // It happens when component is marker as client and rendered in RSC context.
28
+ // Also, it is not required when component is hidden or empty, as it will be rendered whthout boundary crossing.
29
+ const useClientWrapper = isClient && rsc && !isEmpty;
30
+ let rendered = useClientWrapper ? (React.createElement(ClientComponentWrapper, { rendering: rendering, componentProps: finalRenderedProps, placeholderName: props.name, key: key })) : (React.createElement(Component, Object.assign({ key: key }, finalRenderedProps, { rendering: rendering, page: page, componentMap: componentMap })));
31
+ if (!isEmpty) {
32
+ const errorBoundaryKey = rendered.type + '-' + index;
33
+ const disableSuspense = props.disableSuspense || false;
34
+ rendered = (React.createElement(ErrorBoundary, { "data-testid": "error-boundary", key: errorBoundaryKey, errorComponent: props.errorComponent, componentLoadingMessage: props.componentLoadingMessage, isDynamic: dynamic, disableSuspense: disableSuspense, rendering: rendered.props.rendering }, rendered));
35
+ }
36
+ // if in edit mode then emit shallow chromes for hydration in Pages
37
+ if (page.mode.isEditing) {
38
+ const key = rendering.uid || `component-${index}`;
39
+ return (React.createElement(PlaceholderMetadata, { key: key, rendering: rendering }, rendered));
40
+ }
41
+ return rendered;
42
+ })
43
+ .filter((element) => element);
44
+ const finalRendering = page.mode.isEditing
45
+ ? [
46
+ React.createElement(PlaceholderMetadata, { key: parentRendering.uid, placeholderName: props.name, rendering: parentRendering }, components),
47
+ ]
48
+ : components;
49
+ const placeholderEmpty = !placeholderRenderings.length;
50
+ if (placeholderEmpty) {
51
+ const rendered = props.renderEmpty ? props.renderEmpty(finalRendering) : finalRendering;
52
+ return page.mode.isEditing ? renderEmptyPlaceholder(rendered) : rendered;
53
+ }
54
+ if (props.render) {
55
+ return props.render(components, placeholderRenderings, props);
56
+ }
57
+ else if (props.renderEach) {
58
+ const renderEach = props.renderEach;
59
+ return finalRendering.map((component, index) => {
60
+ if (component && component.props && component.props.type === 'text/sitecore') {
61
+ return component;
62
+ }
63
+ return renderEach(component, index);
64
+ });
65
+ }
66
+ else {
67
+ return finalRendering;
68
+ }
69
+ };