@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.
- package/LICENSE.txt +202 -202
- package/README.md +11 -11
- package/dist/cjs/components/ClientEditingChromesUpdate.js +52 -0
- package/dist/cjs/components/DefaultEmptyFieldEditingComponents.js +4 -4
- package/dist/cjs/components/DesignLibrary.js +85 -103
- package/dist/cjs/components/EditingScripts.js +1 -0
- package/dist/cjs/components/ErrorBoundary.js +1 -0
- package/dist/cjs/components/FEaaS/BYOCServerWrapper.js +28 -0
- package/dist/cjs/components/{BYOCComponent.js → FEaaS/BYOCWrapper.js} +17 -28
- package/dist/cjs/components/FEaaS/FEaaSSeverWrapper.js +34 -0
- package/dist/cjs/components/FEaaS/FEaaSWrapper.js +78 -0
- package/dist/cjs/components/{FEaaSComponent.js → FEaaS/feaas-utils.js} +18 -35
- package/dist/cjs/components/FEaaS/index.js +21 -0
- package/dist/cjs/components/FEaaS/models.js +7 -0
- package/dist/cjs/components/Link.js +1 -1
- package/dist/cjs/components/Placeholder/AppPlaceholder.js +76 -0
- package/dist/cjs/components/Placeholder/ClientComponentWrapper.js +21 -0
- package/dist/cjs/components/Placeholder/Placeholder.js +110 -0
- package/dist/cjs/components/Placeholder/index.js +25 -0
- package/dist/cjs/components/Placeholder/models.js +18 -0
- package/dist/cjs/components/Placeholder/placeholder-utils.js +215 -0
- package/dist/cjs/components/RichText.js +1 -0
- package/dist/cjs/components/Text.js +1 -0
- package/dist/cjs/enhancers/withAppPlaceholder.js +21 -0
- package/dist/cjs/enhancers/withEmptyFieldEditingComponent.js +12 -5
- package/dist/cjs/enhancers/withPlaceholder.js +8 -6
- package/dist/cjs/index.js +17 -11
- package/dist/cjs/rsc-utils/no-rsc.js +5 -0
- package/dist/cjs/rsc-utils/rsc.js +5 -0
- package/dist/esm/components/ClientEditingChromesUpdate.js +15 -0
- package/dist/esm/components/DefaultEmptyFieldEditingComponents.js +4 -4
- package/dist/esm/components/DesignLibrary.js +85 -102
- package/dist/esm/components/EditingScripts.js +1 -0
- package/dist/esm/components/ErrorBoundary.js +1 -0
- package/dist/esm/components/FEaaS/BYOCServerWrapper.js +21 -0
- package/dist/esm/components/{BYOCComponent.js → FEaaS/BYOCWrapper.js} +15 -26
- package/dist/esm/components/FEaaS/FEaaSSeverWrapper.js +27 -0
- package/dist/esm/components/FEaaS/FEaaSWrapper.js +37 -0
- package/dist/esm/components/{FEaaSComponent.js → FEaaS/feaas-utils.js} +16 -30
- package/dist/esm/components/FEaaS/index.js +6 -0
- package/dist/esm/components/FEaaS/models.js +4 -0
- package/dist/esm/components/Link.js +1 -1
- package/dist/esm/components/Placeholder/AppPlaceholder.js +69 -0
- package/dist/esm/components/Placeholder/ClientComponentWrapper.js +14 -0
- package/dist/esm/components/Placeholder/Placeholder.js +103 -0
- package/dist/esm/components/Placeholder/index.js +4 -0
- package/dist/esm/components/Placeholder/models.js +15 -0
- package/dist/esm/components/Placeholder/placeholder-utils.js +203 -0
- package/dist/esm/components/RichText.js +1 -0
- package/dist/esm/components/Text.js +1 -0
- package/dist/esm/enhancers/withAppPlaceholder.js +14 -0
- package/dist/esm/enhancers/withEmptyFieldEditingComponent.js +12 -5
- package/dist/esm/enhancers/withPlaceholder.js +8 -6
- package/dist/esm/index.js +5 -5
- package/dist/esm/rsc-utils/no-rsc.js +2 -0
- package/dist/esm/rsc-utils/rsc.js +2 -0
- package/package.json +16 -4
- package/types/components/ClientEditingChromesUpdate.d.ts +6 -0
- package/types/components/Date.d.ts +1 -1
- package/types/components/DefaultEmptyFieldEditingComponents.d.ts +8 -2
- package/types/components/DesignLibrary.d.ts +13 -13
- package/types/components/ErrorBoundary.d.ts +0 -1
- package/types/components/FEaaS/BYOCServerWrapper.d.ts +3 -0
- package/types/components/FEaaS/BYOCWrapper.d.ts +25 -0
- package/types/components/FEaaS/FEaaSSeverWrapper.d.ts +8 -0
- package/types/components/FEaaS/FEaaSWrapper.d.ts +7 -0
- package/types/components/FEaaS/feaas-utils.d.ts +21 -0
- package/types/components/FEaaS/index.d.ts +6 -0
- package/types/components/FEaaS/models.d.ts +125 -0
- package/types/components/Image.d.ts +1 -1
- package/types/components/Link.d.ts +1 -1
- package/types/components/Placeholder/AppPlaceholder.d.ts +10 -0
- package/types/components/Placeholder/ClientComponentWrapper.d.ts +9 -0
- package/types/components/Placeholder/Placeholder.d.ts +28 -0
- package/types/components/Placeholder/index.d.ts +5 -0
- package/types/components/Placeholder/models.d.ts +140 -0
- package/types/components/Placeholder/placeholder-utils.d.ts +53 -0
- package/types/components/RichText.d.ts +1 -1
- package/types/components/Text.d.ts +1 -1
- package/types/components/sharedTypes/components.d.ts +6 -0
- package/types/components/sharedTypes/props.d.ts +2 -2
- package/types/enhancers/withAppPlaceholder.d.ts +15 -0
- package/types/enhancers/withEmptyFieldEditingComponent.d.ts +3 -3
- package/types/enhancers/withPlaceholder.d.ts +2 -1
- package/types/index.d.ts +4 -5
- package/types/rsc-utils/no-rsc.d.ts +1 -0
- package/types/rsc-utils/rsc.d.ts +1 -0
- package/dist/cjs/components/BYOCWrapper.js +0 -22
- package/dist/cjs/components/FEaaSWrapper.js +0 -19
- package/dist/cjs/components/Placeholder.js +0 -68
- package/dist/cjs/components/PlaceholderCommon.js +0 -176
- package/dist/esm/components/BYOCWrapper.js +0 -15
- package/dist/esm/components/FEaaSWrapper.js +0 -12
- package/dist/esm/components/Placeholder.js +0 -62
- package/dist/esm/components/PlaceholderCommon.js +0 -169
- package/types/components/BYOCComponent.d.ts +0 -93
- package/types/components/BYOCWrapper.d.ts +0 -7
- package/types/components/FEaaSComponent.d.ts +0 -72
- package/types/components/FEaaSWrapper.d.ts +0 -4
- package/types/components/Placeholder.d.ts +0 -20
- package/types/components/PlaceholderCommon.d.ts +0 -89
- /package/dist/cjs/components/{PlaceholderMetadata.js → Placeholder/PlaceholderMetadata.js} +0 -0
- /package/dist/esm/components/{PlaceholderMetadata.js → Placeholder/PlaceholderMetadata.js} +0 -0
- /package/types/components/{PlaceholderMetadata.d.ts → Placeholder/PlaceholderMetadata.d.ts} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { ComponentMapReactContext } from '../SitecoreProvider';
|
|
3
|
+
import { useContext } from 'react';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { useSitecore } from '../../enhancers/withSitecore';
|
|
6
|
+
import { getComponentForRendering } from './placeholder-utils';
|
|
7
|
+
export const ClientComponentWrapper = (props) => {
|
|
8
|
+
const { page } = useSitecore();
|
|
9
|
+
const componentMap = useContext(ComponentMapReactContext);
|
|
10
|
+
const componentPropsWithContext = Object.assign(Object.assign({}, props.componentProps), { rendering: props.rendering, componentMap,
|
|
11
|
+
page });
|
|
12
|
+
const { component: Component } = getComponentForRendering(props.rendering, props.placeholderName, componentMap);
|
|
13
|
+
return React.createElement(Component, Object.assign({}, componentPropsWithContext));
|
|
14
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { withComponentMap } from '../../enhancers/withComponentMap';
|
|
4
|
+
import { PagesEditor } from '@sitecore-content-sdk/core/editing';
|
|
5
|
+
import { withSitecore } from '../../enhancers/withSitecore';
|
|
6
|
+
import { getComponentForRendering, getPlaceholderRenderings, getRenderedComponentProps, renderEmptyPlaceholder, } from './placeholder-utils';
|
|
7
|
+
import { PlaceholderMetadata } from './PlaceholderMetadata';
|
|
8
|
+
import ErrorBoundary from '../ErrorBoundary';
|
|
9
|
+
export class PlaceholderComponent extends React.Component {
|
|
10
|
+
constructor(props) {
|
|
11
|
+
super(props);
|
|
12
|
+
this.isEmpty = false;
|
|
13
|
+
this.state = {};
|
|
14
|
+
}
|
|
15
|
+
componentDidMount() {
|
|
16
|
+
if (this.isEmpty && PagesEditor.isActive()) {
|
|
17
|
+
PagesEditor.resetChromes();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
componentDidCatch(error) {
|
|
21
|
+
this.setState({ error });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Renders the placeholder when it is empty. The required CSS styles are applied to the placeholder in edit mode.
|
|
25
|
+
* @param {React.ReactNode | React.ReactElement[]} node react node
|
|
26
|
+
* @returns react node
|
|
27
|
+
* @deprecated use renderEmptyPlaceholder from react/nextjs import instead
|
|
28
|
+
*/
|
|
29
|
+
renderEmptyPlaceholder(node) {
|
|
30
|
+
return renderEmptyPlaceholder(node);
|
|
31
|
+
}
|
|
32
|
+
render() {
|
|
33
|
+
const childProps = Object.assign({}, this.props);
|
|
34
|
+
delete childProps.componentMap;
|
|
35
|
+
if (this.state.error) {
|
|
36
|
+
if (childProps.errorComponent) {
|
|
37
|
+
return React.createElement(childProps.errorComponent, { error: this.state.error });
|
|
38
|
+
}
|
|
39
|
+
return (React.createElement("div", { className: "sc-content-sdk-placeholder-error" },
|
|
40
|
+
"A rendering error occurred: ",
|
|
41
|
+
this.state.error.message,
|
|
42
|
+
"."));
|
|
43
|
+
}
|
|
44
|
+
const renderingData = childProps.rendering;
|
|
45
|
+
const placeholderRenderings = getPlaceholderRenderings(renderingData, this.props.name, this.props.page.mode.isEditing);
|
|
46
|
+
this.isEmpty = !placeholderRenderings.length;
|
|
47
|
+
const components = PlaceholderComponent.getRenderedComponents(this.props, placeholderRenderings);
|
|
48
|
+
if (this.isEmpty) {
|
|
49
|
+
const rendered = this.props.renderEmpty ? this.props.renderEmpty(components) : components;
|
|
50
|
+
return this.props.page.mode.isEditing ? renderEmptyPlaceholder(rendered) : rendered;
|
|
51
|
+
}
|
|
52
|
+
else if (this.props.render) {
|
|
53
|
+
return this.props.render(components, placeholderRenderings, childProps);
|
|
54
|
+
}
|
|
55
|
+
else if (this.props.renderEach) {
|
|
56
|
+
const renderEach = this.props.renderEach;
|
|
57
|
+
return components.map((component, index) => {
|
|
58
|
+
if (component && component.props && component.props.type === 'text/sitecore') {
|
|
59
|
+
return component;
|
|
60
|
+
}
|
|
61
|
+
return renderEach(component, index);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
return components;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Renders the components for the placeholder based on the provided rendering data.
|
|
71
|
+
* @param {PlaceholderProps} props placeholder component props
|
|
72
|
+
* @param {ComponentRendering[]} placeholderRenderings renderings within placeholder
|
|
73
|
+
* @returns {React.ReactNode | React.ReactElement[]} rendered components
|
|
74
|
+
*/
|
|
75
|
+
PlaceholderComponent.getRenderedComponents = (props, placeholderRenderings) => {
|
|
76
|
+
const { name, missingComponentComponent, hiddenRenderingComponent } = props;
|
|
77
|
+
const transformedComponents = placeholderRenderings
|
|
78
|
+
.map((componentRendering, index) => {
|
|
79
|
+
const key = componentRendering.uid || `component-${index}`;
|
|
80
|
+
const renderedProps = getRenderedComponentProps(props, componentRendering, key);
|
|
81
|
+
const component = getComponentForRendering(componentRendering, name, props.componentMap, hiddenRenderingComponent, missingComponentComponent);
|
|
82
|
+
let rendered = React.createElement(component.component, props.modifyComponentProps ? props.modifyComponentProps(renderedProps) : renderedProps);
|
|
83
|
+
if (!component.isEmpty) {
|
|
84
|
+
const errorBoundaryKey = rendered.type + '-' + index;
|
|
85
|
+
const disableSuspense = props.disableSuspense || false;
|
|
86
|
+
rendered = (React.createElement(ErrorBoundary, { "data-testid": "error-boundary", key: errorBoundaryKey, errorComponent: props.errorComponent, componentLoadingMessage: props.componentLoadingMessage, isDynamic: component.dynamic, disableSuspense: disableSuspense, rendering: rendered.props.rendering }, rendered));
|
|
87
|
+
}
|
|
88
|
+
// if in edit mode then emit shallow chromes for hydration in Pages
|
|
89
|
+
if (props.page.mode.isEditing) {
|
|
90
|
+
return (React.createElement(PlaceholderMetadata, { key: key, rendering: componentRendering }, rendered));
|
|
91
|
+
}
|
|
92
|
+
return rendered;
|
|
93
|
+
})
|
|
94
|
+
.filter((element) => element); // remove nulls
|
|
95
|
+
if (props.page.mode.isEditing) {
|
|
96
|
+
return [
|
|
97
|
+
React.createElement(PlaceholderMetadata, { key: props.rendering.uid, placeholderName: name, rendering: props.rendering }, transformedComponents),
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
return transformedComponents;
|
|
101
|
+
};
|
|
102
|
+
const PlaceholderWithComponentMap = withComponentMap(PlaceholderComponent);
|
|
103
|
+
export const Placeholder = withSitecore()(PlaceholderWithComponentMap);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prop names from placeholder that cannot be serialized and passed from server to client side components
|
|
3
|
+
*/
|
|
4
|
+
export const nonSerializedPlaceholderProps = [
|
|
5
|
+
'renderEmpty',
|
|
6
|
+
'render',
|
|
7
|
+
'renderEach',
|
|
8
|
+
'errorComponent',
|
|
9
|
+
'componentLoadingMessage',
|
|
10
|
+
'modifyComponentProps',
|
|
11
|
+
'componentMap',
|
|
12
|
+
'page',
|
|
13
|
+
'missingComponentComponent',
|
|
14
|
+
'hiddenRenderingComponent',
|
|
15
|
+
];
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { MissingComponent } from '../MissingComponent';
|
|
14
|
+
import { DEFAULT_EXPORT_NAME } from '../sharedTypes';
|
|
15
|
+
import { isDynamicPlaceholder, getDynamicPlaceholderPattern, } from '@sitecore-content-sdk/core/layout';
|
|
16
|
+
import { constants } from '@sitecore-content-sdk/core';
|
|
17
|
+
import { HiddenRendering } from '../HiddenRendering';
|
|
18
|
+
import { FEaaSComponent, FEaaSWrapper, BYOCComponent, BYOCWrapper, BYOC_COMPONENT_RENDERING_NAME, BYOC_WRAPPER_RENDERING_NAME, FEAAS_COMPONENT_RENDERING_NAME, FEAAS_WRAPPER_RENDERING_NAME, } from '../FEaaS';
|
|
19
|
+
/**
|
|
20
|
+
* Get the renderings for the specified placeholder from the rendering data.
|
|
21
|
+
* @param {ComponentRendering | RouteData } rendering rendering data
|
|
22
|
+
* @param {string} name placeholder name
|
|
23
|
+
* @param {boolean} isEditing whether components should be rendered in editing mode
|
|
24
|
+
* @returns {ComponentRendering[]} array of component renderings
|
|
25
|
+
*/
|
|
26
|
+
export const getPlaceholderRenderings = (rendering, name, isEditing) => {
|
|
27
|
+
let result;
|
|
28
|
+
let phName = name.slice();
|
|
29
|
+
/**
|
|
30
|
+
* Process (SXA) dynamic placeholders
|
|
31
|
+
* Find and replace the matching dynamic placeholder e.g 'nameOfContainer-{*}' with the requested e.g. 'nameOfContainer-1'.
|
|
32
|
+
* For Metadata EditMode, we need to keep the raw placeholder name in place.
|
|
33
|
+
*/
|
|
34
|
+
if (rendering === null || rendering === void 0 ? void 0 : rendering.placeholders) {
|
|
35
|
+
Object.keys(rendering.placeholders).forEach((placeholder) => {
|
|
36
|
+
const patternPlaceholder = isDynamicPlaceholder(placeholder)
|
|
37
|
+
? getDynamicPlaceholderPattern(placeholder)
|
|
38
|
+
: null;
|
|
39
|
+
if (patternPlaceholder && patternPlaceholder.test(phName)) {
|
|
40
|
+
if (isEditing) {
|
|
41
|
+
phName = placeholder;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
rendering.placeholders[phName] = rendering.placeholders[placeholder];
|
|
45
|
+
delete rendering.placeholders[placeholder];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (rendering && rendering.placeholders && Object.keys(rendering.placeholders).length > 0) {
|
|
51
|
+
result = rendering.placeholders[phName];
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
result = null;
|
|
55
|
+
}
|
|
56
|
+
if (!result) {
|
|
57
|
+
console.warn(`Placeholder '${phName}' was not found in the current rendering data`, JSON.stringify(rendering, null, 2));
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Get SXA specific params from Sitecore rendering params
|
|
64
|
+
* @param {ComponentRendering} rendering rendering object
|
|
65
|
+
* @returns {object} converted SXA params
|
|
66
|
+
*/
|
|
67
|
+
export const getSXAParams = (rendering) => {
|
|
68
|
+
if (!rendering.params)
|
|
69
|
+
return {};
|
|
70
|
+
const { GridParameters, Styles } = rendering.params;
|
|
71
|
+
return ((GridParameters || Styles) && {
|
|
72
|
+
styles: `${GridParameters || ''} ${Styles || ''}`,
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Renders the placeholder when it is empty. The required CSS styles are applied to the placeholder in edit mode.
|
|
77
|
+
* @param {React.ReactNode | React.ReactElement[]} node react node
|
|
78
|
+
* @returns react node
|
|
79
|
+
*/
|
|
80
|
+
export const renderEmptyPlaceholder = (node) => {
|
|
81
|
+
return React.createElement("div", { className: "sc-jss-empty-placeholder" }, node);
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Get component props to be passed to the rendered component.
|
|
85
|
+
* @param {PlaceholderProps} placeholderProps current placeholder props
|
|
86
|
+
* @param {ComponentRendering} componentRendering rendering to be rendered
|
|
87
|
+
* @param {string} renderingKey unique key to pass over to rendering props
|
|
88
|
+
* @returns {RenderedProps} props to be passed to the rendered component
|
|
89
|
+
*/
|
|
90
|
+
export const getRenderedComponentProps = (placeholderProps, componentRendering, renderingKey) => {
|
|
91
|
+
// eslint-disable-next-line no-unused-vars
|
|
92
|
+
const { fields, params: placeholderParams } = placeholderProps, passThroughProps = __rest(placeholderProps, ["fields", "params"]);
|
|
93
|
+
delete passThroughProps.missingComponentComponent;
|
|
94
|
+
delete passThroughProps.hiddenRenderingComponent;
|
|
95
|
+
delete passThroughProps.name;
|
|
96
|
+
const mergedContentProps = getAppComponentProps(placeholderProps, componentRendering);
|
|
97
|
+
return Object.assign(Object.assign(Object.assign({ key: renderingKey }, passThroughProps), mergedContentProps), { rendering: componentRendering });
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Merge placeholder and component field and params content props.
|
|
101
|
+
* @param {BasePlaceholderProps} placeholderProps placeholder props
|
|
102
|
+
* @param {ComponentRendering} componentRendering component rendering
|
|
103
|
+
* @returns {ComponentProps} merged props
|
|
104
|
+
*/
|
|
105
|
+
export function getAppComponentProps(placeholderProps, componentRendering) {
|
|
106
|
+
const fields = Object.assign(Object.assign({}, (placeholderProps.fields || {})), (componentRendering.fields || {}));
|
|
107
|
+
const params = Object.assign(Object.assign({}, (placeholderProps.params || {})), (componentRendering.params || {}));
|
|
108
|
+
return {
|
|
109
|
+
fields,
|
|
110
|
+
params: Object.assign(Object.assign({}, params), getSXAParams(componentRendering)),
|
|
111
|
+
rendering: componentRendering,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get component implemenation from the component map based on the rendering definition.
|
|
116
|
+
* @param {ComponentRendering} renderingDefinition rendering data
|
|
117
|
+
* @param {string} placeholderName name of current placeholder
|
|
118
|
+
* @param {ComponentMap} componentMap component map for the current app
|
|
119
|
+
* @param {React.ComponentClass} [hiddenRenderingComponent] fallback implementation in to be rendered if the rendering is hidden
|
|
120
|
+
* @param {React.ComponentClass} [missingComponentComponent] fallback implementation in case no component is found in the component map
|
|
121
|
+
* @returns {ContentSDKComponet | null} component implementation or null if no component map is provided
|
|
122
|
+
*/
|
|
123
|
+
export const getComponentForRendering = (renderingDefinition, placeholderName, componentMap, hiddenRenderingComponent, missingComponentComponent) => {
|
|
124
|
+
var _a, _b;
|
|
125
|
+
if (renderingDefinition.componentName === constants.HIDDEN_RENDERING_NAME) {
|
|
126
|
+
return {
|
|
127
|
+
component: hiddenRenderingComponent !== null && hiddenRenderingComponent !== void 0 ? hiddenRenderingComponent : HiddenRendering,
|
|
128
|
+
isEmpty: true,
|
|
129
|
+
componentType: 'universal',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
else if (!renderingDefinition.componentName) {
|
|
133
|
+
console.error(`Placeholder ${placeholderName} contains unknown component ${renderingDefinition.componentName}. Ensure that a React component exists for it, and that it is registered in your component-map file.`);
|
|
134
|
+
return {
|
|
135
|
+
component: () => React.createElement(React.Fragment, null),
|
|
136
|
+
isEmpty: true,
|
|
137
|
+
componentType: 'universal',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
let component = null;
|
|
141
|
+
if (!componentMap || componentMap.size === 0) {
|
|
142
|
+
console.warn(`No components were available in component map to service request for component ${renderingDefinition}`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
component = componentMap.get(renderingDefinition.componentName);
|
|
146
|
+
}
|
|
147
|
+
if (!component) {
|
|
148
|
+
// Fallback/defaults for Sitecore Component renderings (in case not defined in component map)
|
|
149
|
+
if (renderingDefinition.componentName === FEAAS_COMPONENT_RENDERING_NAME) {
|
|
150
|
+
return {
|
|
151
|
+
component: FEaaSComponent,
|
|
152
|
+
isEmpty: false,
|
|
153
|
+
componentType: 'universal',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
else if (renderingDefinition.componentName === FEAAS_WRAPPER_RENDERING_NAME) {
|
|
157
|
+
return {
|
|
158
|
+
component: FEaaSWrapper,
|
|
159
|
+
isEmpty: false,
|
|
160
|
+
componentType: 'universal',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
else if (renderingDefinition.componentName === BYOC_COMPONENT_RENDERING_NAME) {
|
|
164
|
+
return {
|
|
165
|
+
component: BYOCComponent,
|
|
166
|
+
isEmpty: false,
|
|
167
|
+
componentType: 'universal',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
else if (renderingDefinition.componentName === BYOC_WRAPPER_RENDERING_NAME) {
|
|
171
|
+
// wrapping with error boundary could cause problems in case where parent component uses withPlaceholder HOC and tries to access its children props
|
|
172
|
+
// that's why we need to mark BYOC wrapper dynamic
|
|
173
|
+
return {
|
|
174
|
+
component: BYOCWrapper,
|
|
175
|
+
dynamic: true,
|
|
176
|
+
componentType: 'universal',
|
|
177
|
+
isEmpty: false,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
component: missingComponentComponent !== null && missingComponentComponent !== void 0 ? missingComponentComponent : MissingComponent,
|
|
182
|
+
isEmpty: true,
|
|
183
|
+
componentType: 'universal',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// Render SXA Rendering Variant if available
|
|
187
|
+
const exportName = (_a = renderingDefinition.params) === null || _a === void 0 ? void 0 : _a.FieldNames;
|
|
188
|
+
const renderedComponent = exportName && exportName !== DEFAULT_EXPORT_NAME
|
|
189
|
+
? component[exportName]
|
|
190
|
+
: component.default ||
|
|
191
|
+
component.Default ||
|
|
192
|
+
component;
|
|
193
|
+
const dynamic = !!((_b = renderedComponent.render) === null || _b === void 0 ? void 0 : _b.preload) ||
|
|
194
|
+
renderingDefinition.componentName === BYOC_WRAPPER_RENDERING_NAME;
|
|
195
|
+
// all dynamic elements will have a separate render prop
|
|
196
|
+
return {
|
|
197
|
+
component: renderedComponent,
|
|
198
|
+
dynamic,
|
|
199
|
+
componentType: component
|
|
200
|
+
.componentType,
|
|
201
|
+
isEmpty: false,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AppPlaceholder } from '../components/Placeholder/AppPlaceholder';
|
|
3
|
+
export const withAppPlaceholder = (Component) => {
|
|
4
|
+
return (props) => {
|
|
5
|
+
const placeholders = props.rendering.placeholders;
|
|
6
|
+
const phProps = {};
|
|
7
|
+
for (const placeholder of Object.keys(placeholders)) {
|
|
8
|
+
phProps[placeholder] = (React.createElement(AppPlaceholder, { name: placeholder, rendering: props.rendering, componentMap: props.componentMap, page: props.page }));
|
|
9
|
+
}
|
|
10
|
+
const displayName = Component.displayName || Component.name || 'Component';
|
|
11
|
+
const propsCopy = Object.assign(Object.assign({}, props), { displayName });
|
|
12
|
+
return React.createElement(Component, Object.assign({}, propsCopy, { placeholders: phProps }));
|
|
13
|
+
};
|
|
14
|
+
};
|
|
@@ -10,18 +10,25 @@ export function withEmptyFieldEditingComponent(FieldComponent, options) {
|
|
|
10
10
|
var _a;
|
|
11
11
|
const { editable = true } = props;
|
|
12
12
|
if (((_a = props.field) === null || _a === void 0 ? void 0 : _a.metadata) && editable && isFieldValueEmpty(props.field)) {
|
|
13
|
-
|
|
13
|
+
const Component = props.emptyFieldEditingComponent || options.defaultEmptyFieldEditingComponent;
|
|
14
|
+
let resolvedProps = props;
|
|
15
|
+
// If no custom empty field editing component is provided, we can omit unnecessary props
|
|
16
|
+
// to do not insert them to html
|
|
17
|
+
if (!props.emptyFieldEditingComponent) {
|
|
18
|
+
resolvedProps = Object.assign(Object.assign({}, props), { editable: undefined, field: undefined });
|
|
19
|
+
}
|
|
20
|
+
return React.createElement(Component, Object.assign({}, resolvedProps));
|
|
14
21
|
}
|
|
15
22
|
return null;
|
|
16
23
|
};
|
|
17
24
|
if (options.isForwardRef) {
|
|
18
25
|
return forwardRef((props, ref) => {
|
|
19
|
-
const
|
|
20
|
-
return (
|
|
26
|
+
const emptyFieldEditingComponent = getEmptyFieldEditingComponent(props);
|
|
27
|
+
return (emptyFieldEditingComponent || (React.createElement(FieldComponent, Object.assign({}, props, { ref: ref }))));
|
|
21
28
|
});
|
|
22
29
|
}
|
|
23
30
|
return (props) => {
|
|
24
|
-
const
|
|
25
|
-
return
|
|
31
|
+
const emptyFieldEditingComponent = getEmptyFieldEditingComponent(props);
|
|
32
|
+
return emptyFieldEditingComponent || React.createElement(FieldComponent, Object.assign({}, props));
|
|
26
33
|
};
|
|
27
34
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { PlaceholderCommon } from '../components/PlaceholderCommon';
|
|
3
2
|
import { withComponentMap } from './withComponentMap';
|
|
4
3
|
import { withSitecore } from './withSitecore';
|
|
4
|
+
import { PlaceholderComponent, getPlaceholderRenderings, } from '../components/Placeholder';
|
|
5
5
|
/**
|
|
6
|
+
* HOC to provide client-side placeholder functionality to a component.
|
|
6
7
|
* @param {WithPlaceholderSpec} placeholders
|
|
7
8
|
* @param {WithPlaceholderOptions} [options]
|
|
8
9
|
*/
|
|
9
10
|
export function withPlaceholder(placeholders, options) {
|
|
10
11
|
return (WrappedComponent) => {
|
|
11
|
-
class WithPlaceholder extends
|
|
12
|
+
class WithPlaceholder extends PlaceholderComponent {
|
|
12
13
|
constructor(props) {
|
|
13
14
|
super(props);
|
|
14
15
|
}
|
|
@@ -36,16 +37,17 @@ export function withPlaceholder(placeholders, options) {
|
|
|
36
37
|
definitelyArrayPlacholders.forEach((placeholder) => {
|
|
37
38
|
let placeholderData;
|
|
38
39
|
if (typeof placeholder !== 'string' && placeholder.placeholder && placeholder.prop) {
|
|
39
|
-
placeholderData =
|
|
40
|
+
placeholderData = getPlaceholderRenderings(renderingData, placeholder.placeholder, childProps.page.mode.isEditing);
|
|
40
41
|
if (placeholderData) {
|
|
41
|
-
childProps[placeholder.prop] =
|
|
42
|
+
childProps[placeholder.prop] =
|
|
43
|
+
PlaceholderComponent.getRenderedComponents(this.props, placeholderData);
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
else {
|
|
45
|
-
placeholderData =
|
|
47
|
+
placeholderData = getPlaceholderRenderings(renderingData, placeholder, childProps.page.mode.isEditing);
|
|
46
48
|
if (placeholderData) {
|
|
47
49
|
childProps[placeholder] =
|
|
48
|
-
this.
|
|
50
|
+
PlaceholderComponent.getRenderedComponents(this.props, placeholderData);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
});
|
package/dist/esm/index.js
CHANGED
|
@@ -5,16 +5,15 @@ export { DictionaryService } from '@sitecore-content-sdk/core/i18n';
|
|
|
5
5
|
export { DefaultRetryStrategy, GraphQLRequestClient, ErrorPage, } from '@sitecore-content-sdk/core/client';
|
|
6
6
|
export { mediaApi } from '@sitecore-content-sdk/core/media';
|
|
7
7
|
export { Form } from './components/Form';
|
|
8
|
-
export { Placeholder } from './components/Placeholder';
|
|
8
|
+
export { Placeholder, AppPlaceholder, } from './components/Placeholder';
|
|
9
9
|
export { Image, } from './components/Image';
|
|
10
10
|
export { RichText } from './components/RichText';
|
|
11
11
|
export { Text } from './components/Text';
|
|
12
12
|
export { DateField } from './components/Date';
|
|
13
|
-
export { FEaaSComponent, fetchFEaaSComponentServerProps,
|
|
14
|
-
|
|
13
|
+
export { FEaaSComponent, fetchFEaaSComponentServerProps, BYOCComponent, fetchBYOCComponentServerProps,
|
|
14
|
+
// leaving original names for backward compatibility
|
|
15
|
+
BYOCWrapper, BYOCWrapper as BYOCClientWrapper, FEaaSWrapper, FEaaSWrapper as FEaaSClientWrapper, FEaaSServerWrapper, BYOCServerWrapper, } from './components/FEaaS';
|
|
15
16
|
export { DesignLibrary } from './components/DesignLibrary';
|
|
16
|
-
export { BYOCComponent, fetchBYOCComponentServerProps, } from './components/BYOCComponent';
|
|
17
|
-
export { BYOCWrapper } from './components/BYOCWrapper';
|
|
18
17
|
export { Link } from './components/Link';
|
|
19
18
|
export { File } from './components/File';
|
|
20
19
|
export { SitecoreProvider, SitecoreProviderReactContext, } from './components/SitecoreProvider';
|
|
@@ -26,4 +25,5 @@ export { withFieldMetadata } from './enhancers/withFieldMetadata';
|
|
|
26
25
|
export { withEmptyFieldEditingComponent } from './enhancers/withEmptyFieldEditingComponent';
|
|
27
26
|
export { EditingScripts } from './components/EditingScripts';
|
|
28
27
|
export { DefaultEmptyFieldEditingComponentText, DefaultEmptyFieldEditingComponentImage, } from './components/DefaultEmptyFieldEditingComponents';
|
|
28
|
+
export { ClientEditingChromesUpdate } from './components/ClientEditingChromesUpdate';
|
|
29
29
|
export { SitePathService } from '@sitecore-content-sdk/core/site';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sitecore-content-sdk/react",
|
|
3
|
-
"version": "1.2.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"module": "dist/esm/index.js",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@types/chai-string": "^1.4.5",
|
|
39
39
|
"@types/mocha": "^10.0.10",
|
|
40
40
|
"@types/node": "22.15.14",
|
|
41
|
+
"@types/proxyquire": "^1.3.31",
|
|
41
42
|
"@types/react": "^19.1.3",
|
|
42
43
|
"@types/react-dom": "^19.1.3",
|
|
43
44
|
"@types/sinon": "^17.0.4",
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
"mocha": "^11.2.2",
|
|
59
60
|
"nyc": "^17.1.0",
|
|
60
61
|
"prettier": "^2.8.0",
|
|
62
|
+
"proxyquire": "^2.1.3",
|
|
61
63
|
"react": "^19.1.0",
|
|
62
64
|
"react-dom": "^19.1.0",
|
|
63
65
|
"sinon": "^20.0.0",
|
|
@@ -72,14 +74,24 @@
|
|
|
72
74
|
"react-dom": "^19.1.0"
|
|
73
75
|
},
|
|
74
76
|
"dependencies": {
|
|
75
|
-
"@sitecore-content-sdk/core": "1.2.0
|
|
77
|
+
"@sitecore-content-sdk/core": "1.2.0",
|
|
76
78
|
"fast-deep-equal": "^3.1.3"
|
|
77
79
|
},
|
|
78
80
|
"description": "",
|
|
79
81
|
"types": "types/index.d.ts",
|
|
80
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "7c079f6f1d968ad39ce5b927559734c96d6adc20",
|
|
81
83
|
"files": [
|
|
82
84
|
"dist",
|
|
83
85
|
"types"
|
|
84
|
-
]
|
|
86
|
+
],
|
|
87
|
+
"imports": {
|
|
88
|
+
"#rsc-env": {
|
|
89
|
+
"react-server": {
|
|
90
|
+
"import": "./dist/esm/rsc-utils/rsc.js",
|
|
91
|
+
"default": "./dist/cjs/rsc-utils/rsc.js"
|
|
92
|
+
},
|
|
93
|
+
"import": "./dist/esm/rsc-utils/no-rsc.js",
|
|
94
|
+
"default": "./dist/cjs/rsc-utils/no-rsc.js"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
85
97
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { JSX } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Updates editing chromes in app router / RSC context.
|
|
4
|
+
* This ensures all the relevant Pages editing markup is applied once all client components are loaded.
|
|
5
|
+
*/
|
|
6
|
+
export declare const ClientEditingChromesUpdate: () => JSX.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { EditableFieldProps } from './sharedTypes';
|
|
3
3
|
import { FieldMetadata } from '@sitecore-content-sdk/core/layout';
|
|
4
|
-
export interface DateFieldProps extends EditableFieldProps {
|
|
4
|
+
export interface DateFieldProps extends EditableFieldProps<DateFieldProps> {
|
|
5
5
|
/** The date field data. */
|
|
6
6
|
[htmlAttributes: string]: unknown;
|
|
7
7
|
field: FieldMetadata & {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
export declare const DefaultEmptyFieldEditingComponentText: React.FC
|
|
3
|
-
|
|
2
|
+
export declare const DefaultEmptyFieldEditingComponentText: React.FC<{
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
tag?: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare const DefaultEmptyFieldEditingComponentImage: React.FC<{
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
className?: string;
|
|
9
|
+
}>;
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import * as codegen from '@sitecore-content-sdk/core/codegen';
|
|
3
3
|
export declare const __mockDependencies: (mocks: any) => void;
|
|
4
4
|
export type ImportMapImport = {
|
|
5
5
|
default: codegen.ImportEntry[];
|
|
6
6
|
};
|
|
7
|
-
type VariantGenerationProps = {
|
|
8
|
-
/**
|
|
9
|
-
* The import map to be used in variant generation mode.
|
|
10
|
-
*/
|
|
11
|
-
loadImportMap?: () => Promise<ImportMapImport>;
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* This component is used to render the component in variant generation mode.
|
|
15
|
-
* It is used to send the import-map and component-props events to the parent window and render the dynamic component.
|
|
16
|
-
*/
|
|
17
|
-
export declare const VariantGeneration: (props: VariantGenerationProps) => JSX.Element;
|
|
18
7
|
type DesignLibraryProps = {
|
|
19
8
|
/**
|
|
20
9
|
* The dynamic import for import map to be used in variant generation mode.
|
|
@@ -22,5 +11,16 @@ type DesignLibraryProps = {
|
|
|
22
11
|
*/
|
|
23
12
|
loadImportMap?: () => Promise<ImportMapImport>;
|
|
24
13
|
};
|
|
25
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Design Library component.
|
|
16
|
+
*
|
|
17
|
+
* Renders the **real** Sitecore component for `library` / `library-metadata` modes and,
|
|
18
|
+
* when generation is enabled (`page.mode.designLibrary.isVariantGeneration === true`),
|
|
19
|
+
* wires the **variant generation** handshake so the parent (DL Studio) can send
|
|
20
|
+
* generated code to preview and iterate on.
|
|
21
|
+
* @param {DesignLibraryProps} props
|
|
22
|
+
* @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.
|
|
23
|
+
* @returns {JSX.Element} The preview surface, or `null` when not in Design Library mode.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DesignLibrary: ({ loadImportMap }: DesignLibraryProps) => React.JSX.Element;
|
|
26
26
|
export {};
|
|
@@ -7,7 +7,6 @@ type ErrorComponentProps = {
|
|
|
7
7
|
export type ErrorBoundaryProps = {
|
|
8
8
|
children: ReactNode;
|
|
9
9
|
page: Page;
|
|
10
|
-
type: string;
|
|
11
10
|
isDynamic?: boolean;
|
|
12
11
|
errorComponent?: React.ComponentClass<ErrorComponentProps> | React.FC<ErrorComponentProps>;
|
|
13
12
|
rendering?: ComponentRendering;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { JSX } from 'react';
|
|
2
|
+
import { BYOCComponentProps } from './models';
|
|
3
|
+
/**
|
|
4
|
+
* BYOCComponent facilitate the rendering of external components. It manages potential errors,
|
|
5
|
+
* missing components, and customization of error messages or alternative rendering components.
|
|
6
|
+
* @param {ByocComponentProps} props component props
|
|
7
|
+
* @returns dynamically rendered component or Missing Component error frame
|
|
8
|
+
*/
|
|
9
|
+
export declare class BYOCComponent extends React.Component<BYOCComponentProps> {
|
|
10
|
+
state: Readonly<{
|
|
11
|
+
error?: Error;
|
|
12
|
+
}>;
|
|
13
|
+
constructor(props: BYOCComponentProps);
|
|
14
|
+
static getDerivedStateFromError(error: Error): {
|
|
15
|
+
error: Error;
|
|
16
|
+
};
|
|
17
|
+
componentDidCatch(error: Error): void;
|
|
18
|
+
render(): JSX.Element;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* SXA wrapper for BYOC components
|
|
22
|
+
* @param {BYOCComponentProps} props component props
|
|
23
|
+
* @returns wrapped BYOC component
|
|
24
|
+
*/
|
|
25
|
+
export declare const BYOCWrapper: (props: BYOCComponentProps) => JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FEaaSServerWrapperProps } from './models';
|
|
3
|
+
/**
|
|
4
|
+
* Server component for FEaaS. Retrieves server props and renders client FEaaSWrapper.
|
|
5
|
+
* @param {FEaaSComponentProps} props incoming props
|
|
6
|
+
* @returns {Promise<JSX.Element>} rendered FEaaSWrapper component
|
|
7
|
+
*/
|
|
8
|
+
export declare const FEaaSServerWrapper: (props: FEaaSServerWrapperProps) => Promise<React.JSX.Element>;
|