@sitecore-content-sdk/react 2.0.0-canary.2 → 2.0.0-canary.4
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/dist/cjs/components/Date.js +13 -11
- package/dist/cjs/components/DefaultEmptyFieldEditingComponents.js +2 -1
- package/dist/cjs/components/DesignLibrary/DesignLibrary.js +3 -7
- package/dist/cjs/components/DesignLibrary/DesignLibraryClientEvents.js +13 -5
- package/dist/cjs/components/EditingScripts.js +2 -2
- package/dist/cjs/components/ErrorBoundary.js +8 -3
- package/dist/cjs/components/File.js +3 -1
- package/dist/cjs/components/Form.js +12 -5
- package/dist/cjs/components/Image.js +12 -9
- package/dist/cjs/components/Link.js +19 -46
- package/dist/cjs/components/Placeholder/AppPlaceholder.js +57 -58
- package/dist/cjs/components/Placeholder/ClientComponentWrapper.js +5 -9
- package/dist/cjs/components/Placeholder/Placeholder.js +21 -93
- package/dist/cjs/components/Placeholder/index.js +1 -2
- package/dist/cjs/components/Placeholder/placeholder-utils.js +7 -35
- package/dist/cjs/components/RichText.js +18 -49
- package/dist/cjs/components/SitecoreProvider.js +81 -33
- package/dist/cjs/components/Text.js +12 -8
- package/dist/cjs/enhancers/withAppPlaceholder.js +6 -0
- package/dist/cjs/enhancers/withDatasourceCheck.js +4 -3
- package/dist/cjs/enhancers/withEditorChromes.js +50 -15
- package/dist/cjs/enhancers/withEmptyFieldEditingComponent.js +8 -38
- package/dist/cjs/enhancers/withFieldMetadata.js +9 -39
- package/dist/cjs/enhancers/withPlaceholder.js +16 -52
- package/dist/cjs/enhancers/withSitecore.js +5 -29
- package/dist/cjs/index.js +9 -7
- package/dist/cjs/search/utils.js +2 -2
- package/dist/esm/components/Date.js +13 -11
- package/dist/esm/components/DefaultEmptyFieldEditingComponents.js +2 -1
- package/dist/esm/components/DesignLibrary/DesignLibrary.js +3 -7
- package/dist/esm/components/DesignLibrary/DesignLibraryClientEvents.js +12 -4
- package/dist/esm/components/EditingScripts.js +2 -2
- package/dist/esm/components/ErrorBoundary.js +8 -3
- package/dist/esm/components/File.js +3 -1
- package/dist/esm/components/Form.js +11 -4
- package/dist/esm/components/Image.js +12 -9
- package/dist/esm/components/Link.js +16 -13
- package/dist/esm/components/Placeholder/AppPlaceholder.js +58 -59
- package/dist/esm/components/Placeholder/ClientComponentWrapper.js +4 -8
- package/dist/esm/components/Placeholder/Placeholder.js +20 -89
- package/dist/esm/components/Placeholder/index.js +1 -1
- package/dist/esm/components/Placeholder/placeholder-utils.js +5 -32
- package/dist/esm/components/RichText.js +15 -16
- package/dist/esm/components/SitecoreProvider.js +46 -32
- package/dist/esm/components/Text.js +12 -8
- package/dist/esm/enhancers/withAppPlaceholder.js +6 -0
- package/dist/esm/enhancers/withDatasourceCheck.js +3 -2
- package/dist/esm/enhancers/withEditorChromes.js +17 -12
- package/dist/esm/enhancers/withEmptyFieldEditingComponent.js +5 -5
- package/dist/esm/enhancers/withFieldMetadata.js +6 -6
- package/dist/esm/enhancers/withPlaceholder.js +15 -52
- package/dist/esm/enhancers/withSitecore.js +6 -29
- package/dist/esm/index.js +4 -3
- package/dist/esm/search/utils.js +1 -1
- package/package.json +5 -5
- package/types/components/Date.d.ts.map +1 -1
- package/types/components/DefaultEmptyFieldEditingComponents.d.ts.map +1 -1
- package/types/components/DesignLibrary/DesignLibrary.d.ts +0 -2
- package/types/components/DesignLibrary/DesignLibrary.d.ts.map +1 -1
- package/types/components/DesignLibrary/DesignLibraryClientEvents.d.ts.map +1 -1
- package/types/components/EditingScripts.d.ts +2 -2
- package/types/components/EditingScripts.d.ts.map +1 -1
- package/types/components/ErrorBoundary.d.ts +2 -2
- package/types/components/ErrorBoundary.d.ts.map +1 -1
- package/types/components/File.d.ts.map +1 -1
- package/types/components/Form.d.ts.map +1 -1
- package/types/components/Image.d.ts.map +1 -1
- package/types/components/Link.d.ts.map +1 -1
- package/types/components/Placeholder/AppPlaceholder.d.ts +1 -1
- package/types/components/Placeholder/AppPlaceholder.d.ts.map +1 -1
- package/types/components/Placeholder/ClientComponentWrapper.d.ts +2 -2
- package/types/components/Placeholder/ClientComponentWrapper.d.ts.map +1 -1
- package/types/components/Placeholder/Placeholder.d.ts +4 -19
- package/types/components/Placeholder/Placeholder.d.ts.map +1 -1
- package/types/components/Placeholder/index.d.ts +1 -1
- package/types/components/Placeholder/index.d.ts.map +1 -1
- package/types/components/Placeholder/models.d.ts +30 -56
- package/types/components/Placeholder/models.d.ts.map +1 -1
- package/types/components/Placeholder/placeholder-utils.d.ts +5 -13
- package/types/components/Placeholder/placeholder-utils.d.ts.map +1 -1
- package/types/components/RichText.d.ts +2 -0
- package/types/components/RichText.d.ts.map +1 -1
- package/types/components/SitecoreProvider.d.ts +43 -13
- package/types/components/SitecoreProvider.d.ts.map +1 -1
- package/types/components/Text.d.ts.map +1 -1
- package/types/enhancers/withAppPlaceholder.d.ts +6 -0
- package/types/enhancers/withAppPlaceholder.d.ts.map +1 -1
- package/types/enhancers/withDatasourceCheck.d.ts.map +1 -1
- package/types/enhancers/withEditorChromes.d.ts +4 -1
- package/types/enhancers/withEditorChromes.d.ts.map +1 -1
- package/types/enhancers/withEmptyFieldEditingComponent.d.ts +5 -3
- package/types/enhancers/withEmptyFieldEditingComponent.d.ts.map +1 -1
- package/types/enhancers/withFieldMetadata.d.ts +4 -2
- package/types/enhancers/withFieldMetadata.d.ts.map +1 -1
- package/types/enhancers/withPlaceholder.d.ts +14 -32
- package/types/enhancers/withPlaceholder.d.ts.map +1 -1
- package/types/enhancers/withSitecore.d.ts +8 -50
- package/types/enhancers/withSitecore.d.ts.map +1 -1
- package/types/index.d.ts +4 -3
- package/types/index.d.ts.map +1 -1
- package/dist/cjs/enhancers/withComponentMap.js +0 -24
- package/dist/cjs/enhancers/withLoadImportMap.js +0 -62
- package/dist/esm/enhancers/withComponentMap.js +0 -18
- package/dist/esm/enhancers/withLoadImportMap.js +0 -25
- package/types/enhancers/withComponentMap.d.ts +0 -13
- package/types/enhancers/withComponentMap.d.ts.map +0 -1
- package/types/enhancers/withLoadImportMap.d.ts +0 -28
- package/types/enhancers/withLoadImportMap.d.ts.map +0 -1
|
@@ -10,22 +10,16 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
}
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
|
-
import React
|
|
13
|
+
import React from 'react';
|
|
14
14
|
import { isFieldValueEmpty } from '@sitecore-content-sdk/content/layout';
|
|
15
15
|
import { withFieldMetadata } from '../enhancers/withFieldMetadata';
|
|
16
16
|
import { withEmptyFieldEditingComponent } from '../enhancers/withEmptyFieldEditingComponent';
|
|
17
17
|
import { DefaultEmptyFieldEditingComponentText } from './DefaultEmptyFieldEditingComponents';
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* @param {LinkProps} props component props
|
|
21
|
-
* @public
|
|
22
|
-
*/
|
|
23
|
-
export const Link = withFieldMetadata(withEmptyFieldEditingComponent(forwardRef(
|
|
24
|
-
// eslint-disable-next-line no-unused-vars
|
|
25
|
-
(_a, ref) => {
|
|
26
|
-
var { field, editable = true, showLinkTextWithChildrenPresent } = _a, otherProps = __rest(_a, ["field", "editable", "showLinkTextWithChildrenPresent"]);
|
|
18
|
+
const LinkComponent = (_a) => {
|
|
19
|
+
var { field, showLinkTextWithChildrenPresent, ref } = _a, otherProps = __rest(_a, ["field", "showLinkTextWithChildrenPresent", "ref"]);
|
|
27
20
|
const children = otherProps.children;
|
|
28
21
|
const dynamicField = field;
|
|
22
|
+
delete otherProps.editable; // prevent editable from being passed to the DOM
|
|
29
23
|
if (isFieldValueEmpty(dynamicField)) {
|
|
30
24
|
return null;
|
|
31
25
|
}
|
|
@@ -49,7 +43,16 @@ export const Link = withFieldMetadata(withEmptyFieldEditingComponent(forwardRef(
|
|
|
49
43
|
anchorAttrs.rel = 'noopener noreferrer';
|
|
50
44
|
}
|
|
51
45
|
const linkText = showLinkTextWithChildrenPresent || !children ? link.text || link.href : null;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
return (React.createElement("a", Object.assign({}, anchorAttrs, otherProps, { key: "link", ref: ref }),
|
|
47
|
+
linkText,
|
|
48
|
+
children));
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* The Link component.
|
|
52
|
+
* @param {LinkProps} props component props
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
export const Link = withFieldMetadata(withEmptyFieldEditingComponent(LinkComponent, {
|
|
56
|
+
defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentText,
|
|
57
|
+
}));
|
|
55
58
|
Link.displayName = 'Link';
|
|
@@ -1,72 +1,71 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getChildComponentProps, getComponentForRendering, getPlaceholderRenderings, renderEmptyPlaceholder, } from './placeholder-utils';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { PlaceholderMetadata } from './PlaceholderMetadata';
|
|
4
3
|
import ErrorBoundary from '../ErrorBoundary';
|
|
5
4
|
import { ClientComponentWrapper } from './ClientComponentWrapper';
|
|
6
5
|
import { rsc } from '#rsc-env';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
6
|
+
import { PlaceholderMetadata } from './PlaceholderMetadata';
|
|
7
|
+
const AppPlaceholderComponent = (props) => {
|
|
8
|
+
const renderingData = props.rendering;
|
|
9
|
+
const isEditing = props.page.mode.isEditing;
|
|
10
|
+
const placeholderRenderings = getPlaceholderRenderings(renderingData, props.name, isEditing);
|
|
11
|
+
const isEmpty = !placeholderRenderings.length;
|
|
12
|
+
const components = getPlaceholderComponents(props, placeholderRenderings);
|
|
13
|
+
if (isEmpty) {
|
|
14
|
+
let renderedOutput = components;
|
|
15
|
+
if (props.renderEmpty) {
|
|
16
|
+
renderedOutput = props.renderEmpty(components);
|
|
17
|
+
}
|
|
18
|
+
return isEditing ? renderEmptyPlaceholder(renderedOutput) : renderedOutput;
|
|
19
|
+
}
|
|
20
|
+
else if (props.render) {
|
|
21
|
+
return props.render(components, placeholderRenderings, props);
|
|
22
|
+
}
|
|
23
|
+
return components;
|
|
24
|
+
};
|
|
25
|
+
const getPlaceholderComponents = (placeholderProps, placeholderRenderings) => {
|
|
26
|
+
const { name, rendering, passThroughComponentProps, missingComponentComponent, hiddenRenderingComponent, errorComponent, componentLoadingMessage, renderEach, modifyComponentProps, componentMap, page, } = placeholderProps;
|
|
27
|
+
const isEditing = page.mode.isEditing;
|
|
28
|
+
const componentRuntime = rsc ? 'server' : 'client';
|
|
29
|
+
const transformedComponents = placeholderRenderings
|
|
30
|
+
.map((componentRendering, index) => {
|
|
31
|
+
const { component: ChildComponent, isEmpty: componentEmpty, componentType, dynamic, } = getComponentForRendering(componentRendering, name, componentMap, hiddenRenderingComponent, missingComponentComponent);
|
|
32
|
+
const key = componentRendering.uid || `component-${index}`;
|
|
33
|
+
const renderedProps = modifyComponentProps
|
|
34
|
+
? modifyComponentProps(getChildComponentProps(placeholderProps, componentRendering))
|
|
35
|
+
: getChildComponentProps(placeholderProps, componentRendering);
|
|
29
36
|
// Client wrapper is required only when component crosses boundary from server to client.
|
|
30
37
|
// It happens when component is marker as client and rendered in RSC context.
|
|
31
38
|
// Also, it is not required when component is hidden or empty, as it will be rendered whthout boundary crossing.
|
|
32
|
-
const useClientWrapper =
|
|
33
|
-
let rendered = useClientWrapper ? (React.createElement(ClientComponentWrapper, { rendering: rendering, componentProps:
|
|
34
|
-
if (
|
|
39
|
+
const useClientWrapper = componentType === 'client' && rsc && !componentEmpty;
|
|
40
|
+
let rendered = useClientWrapper ? (React.createElement(ClientComponentWrapper, { rendering: renderedProps.rendering, componentProps: Object.assign(Object.assign({}, renderedProps), passThroughComponentProps), placeholderName: name, key: key })) : (React.createElement(ChildComponent, Object.assign({ key: key }, renderedProps, passThroughComponentProps, { page: page, componentMap: componentMap })));
|
|
41
|
+
if (renderEach) {
|
|
42
|
+
rendered = renderEach(rendered, index);
|
|
43
|
+
}
|
|
44
|
+
if (!componentEmpty) {
|
|
35
45
|
const errorBoundaryKey = rendered.type + '-' + index;
|
|
36
|
-
const disableSuspense =
|
|
37
|
-
rendered = (React.createElement(ErrorBoundary, { "data-testid": "error-boundary", key: errorBoundaryKey, errorComponent:
|
|
46
|
+
const disableSuspense = placeholderProps.disableSuspense || false;
|
|
47
|
+
rendered = (React.createElement(ErrorBoundary, { "data-testid": "error-boundary", key: errorBoundaryKey, errorComponent: errorComponent, componentLoadingMessage: componentLoadingMessage, isDynamic: dynamic, disableSuspense: disableSuspense, rendering: rendered.props.rendering }, rendered));
|
|
38
48
|
}
|
|
39
49
|
// if in edit mode then emit shallow chromes for hydration in Pages
|
|
40
|
-
|
|
41
|
-
const key = rendering.uid || `component-${index}`;
|
|
42
|
-
return (React.createElement(PlaceholderMetadata, { key: key, rendering: rendering, componentRuntime: componentRuntime }, rendered));
|
|
43
|
-
}
|
|
44
|
-
return rendered;
|
|
50
|
+
return isEditing ? (React.createElement(PlaceholderMetadata, { key: key, rendering: componentRendering, componentRuntime: componentRuntime }, rendered)) : (rendered);
|
|
45
51
|
})
|
|
46
|
-
.filter((element) => element);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
React.createElement(PlaceholderMetadata, { key: parentRendering.uid || 'placeholder-metadata-root', placeholderName: props.name, rendering: parentRendering }, components),
|
|
50
|
-
]
|
|
51
|
-
: components;
|
|
52
|
-
const placeholderEmpty = !placeholderRenderings.length;
|
|
53
|
-
if (placeholderEmpty) {
|
|
54
|
-
const rendered = props.renderEmpty ? props.renderEmpty(finalRendering) : finalRendering;
|
|
55
|
-
return page.mode.isEditing ? renderEmptyPlaceholder(rendered) : rendered;
|
|
56
|
-
}
|
|
57
|
-
if (props.render) {
|
|
58
|
-
return props.render(components, placeholderRenderings, props);
|
|
59
|
-
}
|
|
60
|
-
else if (props.renderEach) {
|
|
61
|
-
const renderEach = props.renderEach;
|
|
62
|
-
return finalRendering.map((component, index) => {
|
|
63
|
-
if (component && component.props && component.props.type === 'text/sitecore') {
|
|
64
|
-
return component;
|
|
65
|
-
}
|
|
66
|
-
return renderEach(component, index);
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
return finalRendering;
|
|
52
|
+
.filter((element) => element); // remove nulls
|
|
53
|
+
if (!isEditing) {
|
|
54
|
+
return transformedComponents;
|
|
71
55
|
}
|
|
56
|
+
return [
|
|
57
|
+
React.createElement(PlaceholderMetadata, { key: rendering.uid, placeholderName: name, rendering: rendering }, transformedComponents),
|
|
58
|
+
];
|
|
72
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* The implemention of placeholder compatible with React Server Components.
|
|
62
|
+
* Renders components from the layout data for the given placeholder name, with consideration for page edit mode.
|
|
63
|
+
* Pulls components from the provided component map.
|
|
64
|
+
* @param {AppPlaceholderProps} props Placeholder props
|
|
65
|
+
* @returns {React.ReactNode | React.ReactElement[]} rendered component(s)
|
|
66
|
+
* @public
|
|
67
|
+
*/
|
|
68
|
+
export const AppPlaceholder = (props) => (
|
|
69
|
+
// Using error boundary for errors that may happen within Placeholder itself
|
|
70
|
+
React.createElement(ErrorBoundary, { errorComponent: props.errorComponent },
|
|
71
|
+
React.createElement(AppPlaceholderComponent, Object.assign({}, props))));
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import { useContext } from 'react';
|
|
2
|
+
import { useSitecore } from '../SitecoreProvider';
|
|
4
3
|
import React from 'react';
|
|
5
|
-
import { useSitecore } from '../../enhancers/withSitecore';
|
|
6
4
|
import { getComponentForRendering } from './placeholder-utils';
|
|
7
5
|
export const ClientComponentWrapper = (props) => {
|
|
8
|
-
const { page } = useSitecore();
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
page });
|
|
12
|
-
const { component: Component } = getComponentForRendering(props.rendering, props.placeholderName, componentMap);
|
|
6
|
+
const { page, componentMap: clientComponentMap } = useSitecore();
|
|
7
|
+
const componentPropsWithContext = Object.assign(Object.assign({}, props.componentProps), { rendering: props.rendering, componentMap: clientComponentMap, page });
|
|
8
|
+
const { component: Component } = getComponentForRendering(props.rendering, props.placeholderName, clientComponentMap);
|
|
13
9
|
return React.createElement(Component, Object.assign({}, componentPropsWithContext));
|
|
14
10
|
};
|
|
@@ -1,95 +1,26 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { withComponentMap } from '../../enhancers/withComponentMap';
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
4
3
|
import { PagesEditor } from '@sitecore-content-sdk/content/editing';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import ErrorBoundary, { ErrorComponent } 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
|
-
render() {
|
|
24
|
-
const childProps = Object.assign({}, this.props);
|
|
25
|
-
delete childProps.componentMap;
|
|
26
|
-
if (this.state.error) {
|
|
27
|
-
if (childProps.errorComponent) {
|
|
28
|
-
return React.createElement(childProps.errorComponent, { error: this.state.error });
|
|
29
|
-
}
|
|
30
|
-
return (React.createElement(ErrorComponent, { message: `A rendering error occurred: ${this.state.error.message}.` }));
|
|
31
|
-
}
|
|
32
|
-
const renderingData = childProps.rendering;
|
|
33
|
-
const placeholderRenderings = getPlaceholderRenderings(renderingData, this.props.name, this.props.page.mode.isEditing);
|
|
34
|
-
this.isEmpty = !placeholderRenderings.length;
|
|
35
|
-
const components = PlaceholderComponent.getRenderedComponents(this.props, placeholderRenderings);
|
|
36
|
-
if (this.isEmpty) {
|
|
37
|
-
const rendered = this.props.renderEmpty ? this.props.renderEmpty(components) : components;
|
|
38
|
-
return this.props.page.mode.isEditing ? renderEmptyPlaceholder(rendered) : rendered;
|
|
39
|
-
}
|
|
40
|
-
else if (this.props.render) {
|
|
41
|
-
return this.props.render(components, placeholderRenderings, childProps);
|
|
42
|
-
}
|
|
43
|
-
else if (this.props.renderEach) {
|
|
44
|
-
const renderEach = this.props.renderEach;
|
|
45
|
-
return components.map((component, index) => {
|
|
46
|
-
if (component && component.props && component.props.type === 'text/sitecore') {
|
|
47
|
-
return component;
|
|
48
|
-
}
|
|
49
|
-
return renderEach(component, index);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
return components;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Renders the components for the placeholder based on the provided rendering data.
|
|
59
|
-
* @param {PlaceholderProps} props placeholder component props
|
|
60
|
-
* @param {ComponentRendering[]} placeholderRenderings renderings within placeholder
|
|
61
|
-
* @returns {React.ReactNode | React.ReactElement[]} rendered components
|
|
62
|
-
*/
|
|
63
|
-
PlaceholderComponent.getRenderedComponents = (props, placeholderRenderings) => {
|
|
64
|
-
const { name, missingComponentComponent, hiddenRenderingComponent } = props;
|
|
65
|
-
const transformedComponents = placeholderRenderings
|
|
66
|
-
.map((componentRendering, index) => {
|
|
67
|
-
const key = componentRendering.uid || `component-${index}`;
|
|
68
|
-
const renderedProps = getRenderedComponentProps(props, componentRendering, key);
|
|
69
|
-
const component = getComponentForRendering(componentRendering, name, props.componentMap, hiddenRenderingComponent, missingComponentComponent);
|
|
70
|
-
let rendered = React.createElement(component.component, props.modifyComponentProps ? props.modifyComponentProps(renderedProps) : renderedProps);
|
|
71
|
-
if (!component.isEmpty) {
|
|
72
|
-
const errorBoundaryKey = rendered.type + '-' + index;
|
|
73
|
-
const disableSuspense = props.disableSuspense || false;
|
|
74
|
-
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));
|
|
75
|
-
}
|
|
76
|
-
// if in edit mode then emit shallow chromes for hydration in Pages
|
|
77
|
-
if (props.page.mode.isEditing) {
|
|
78
|
-
return (React.createElement(PlaceholderMetadata, { key: key, rendering: componentRendering }, rendered));
|
|
79
|
-
}
|
|
80
|
-
return rendered;
|
|
81
|
-
})
|
|
82
|
-
.filter((element) => element); // remove nulls
|
|
83
|
-
if (props.page.mode.isEditing) {
|
|
84
|
-
return [
|
|
85
|
-
React.createElement(PlaceholderMetadata, { key: props.rendering.uid, placeholderName: name, rendering: props.rendering }, transformedComponents),
|
|
86
|
-
];
|
|
87
|
-
}
|
|
88
|
-
return transformedComponents;
|
|
89
|
-
};
|
|
90
|
-
const PlaceholderWithComponentMap = withComponentMap(PlaceholderComponent);
|
|
4
|
+
import { getPlaceholderRenderings } from './placeholder-utils';
|
|
5
|
+
import { useSitecore } from '../SitecoreProvider';
|
|
6
|
+
import { AppPlaceholder } from './AppPlaceholder';
|
|
91
7
|
/**
|
|
92
8
|
* The Placeholder component.
|
|
9
|
+
* Renders the components assigned to a placeholder in Sitecore. It also supports custom rendering and empty state.
|
|
10
|
+
* @param {PlaceholderProps} props - The props for the Placeholder component.
|
|
11
|
+
* @returns The rendered Placeholder component.
|
|
93
12
|
* @public
|
|
94
13
|
*/
|
|
95
|
-
export const Placeholder =
|
|
14
|
+
export const Placeholder = (props) => {
|
|
15
|
+
const { page, componentMap } = useSitecore();
|
|
16
|
+
const placeholderRenderings = getPlaceholderRenderings(props.rendering, props.name, page.mode.isEditing);
|
|
17
|
+
const isEmpty = !placeholderRenderings.length;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (isEmpty && PagesEditor.isActive()) {
|
|
20
|
+
PagesEditor.resetChromes();
|
|
21
|
+
}
|
|
22
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
23
|
+
}, []); // Empty array so it runs only once on mount
|
|
24
|
+
const appProps = Object.assign(Object.assign({}, props), { page, componentMap });
|
|
25
|
+
return React.createElement(AppPlaceholder, Object.assign({}, appProps));
|
|
26
|
+
};
|
|
@@ -1,14 +1,3 @@
|
|
|
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
1
|
import React from 'react';
|
|
13
2
|
import { MissingComponent } from '../MissingComponent';
|
|
14
3
|
import { DEFAULT_EXPORT_NAME } from '../sharedTypes';
|
|
@@ -17,7 +6,7 @@ import { HIDDEN_RENDERING_NAME } from '@sitecore-content-sdk/content';
|
|
|
17
6
|
import { HiddenRendering } from '../HiddenRendering';
|
|
18
7
|
import { FEaaSComponent, FEaaSWrapper, BYOCComponent, BYOCWrapper, BYOC_COMPONENT_RENDERING_NAME, BYOC_WRAPPER_RENDERING_NAME, FEAAS_COMPONENT_RENDERING_NAME, FEAAS_WRAPPER_RENDERING_NAME, } from '../FEaaS';
|
|
19
8
|
/**
|
|
20
|
-
* Get the renderings for the specified placeholder from the rendering data.
|
|
9
|
+
* Get the renderings for the specified placeholder from the rendering layout data.
|
|
21
10
|
* @param {ComponentRendering | RouteData } rendering rendering data
|
|
22
11
|
* @param {string} name placeholder name
|
|
23
12
|
* @param {boolean} isEditing whether components should be rendered in editing mode
|
|
@@ -82,28 +71,12 @@ export const renderEmptyPlaceholder = (node) => {
|
|
|
82
71
|
return React.createElement("div", { className: "sc-jss-empty-placeholder" }, node);
|
|
83
72
|
};
|
|
84
73
|
/**
|
|
85
|
-
*
|
|
86
|
-
* @param {PlaceholderProps} placeholderProps
|
|
87
|
-
* @param {ComponentRendering} componentRendering rendering to be rendered
|
|
88
|
-
* @param {string} renderingKey unique key to pass over to rendering props
|
|
89
|
-
* @returns {RenderedProps} props to be passed to the rendered component
|
|
90
|
-
*/
|
|
91
|
-
export const getRenderedComponentProps = (placeholderProps, componentRendering, renderingKey) => {
|
|
92
|
-
// eslint-disable-next-line no-unused-vars
|
|
93
|
-
const { fields, params: placeholderParams } = placeholderProps, passThroughProps = __rest(placeholderProps, ["fields", "params"]);
|
|
94
|
-
delete passThroughProps.missingComponentComponent;
|
|
95
|
-
delete passThroughProps.hiddenRenderingComponent;
|
|
96
|
-
delete passThroughProps.name;
|
|
97
|
-
const mergedContentProps = getAppComponentProps(placeholderProps, componentRendering);
|
|
98
|
-
return Object.assign(Object.assign(Object.assign({ key: renderingKey }, passThroughProps), mergedContentProps), { rendering: componentRendering });
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Merge placeholder and component field and params content props.
|
|
102
|
-
* @param {BasePlaceholderProps} placeholderProps placeholder props
|
|
74
|
+
* Merge specific placeholder props with component field and params content props.
|
|
75
|
+
* @param {PlaceholderProps} placeholderProps placeholder props
|
|
103
76
|
* @param {ComponentRendering} componentRendering component rendering
|
|
104
77
|
* @returns {ComponentProps} merged props
|
|
105
78
|
*/
|
|
106
|
-
export function
|
|
79
|
+
export function getChildComponentProps(placeholderProps, componentRendering) {
|
|
107
80
|
const fields = Object.assign(Object.assign({}, (placeholderProps.fields || {})), (componentRendering.fields || {}));
|
|
108
81
|
const params = Object.assign(Object.assign({}, (placeholderProps.params || {})), (componentRendering.params || {}));
|
|
109
82
|
return {
|
|
@@ -171,7 +144,7 @@ export const getComponentForRendering = (renderingDefinition, placeholderName, c
|
|
|
171
144
|
};
|
|
172
145
|
}
|
|
173
146
|
else if (renderingDefinition.componentName === BYOC_WRAPPER_RENDERING_NAME) {
|
|
174
|
-
// wrapping with error boundary could cause problems in case where parent component uses withPlaceholder
|
|
147
|
+
// wrapping with error boundary could cause problems in case where parent component uses withPlaceholder HOCs and tries to access its children props
|
|
175
148
|
// that's why we need to mark BYOC wrapper dynamic
|
|
176
149
|
return {
|
|
177
150
|
component: BYOCWrapper,
|
|
@@ -10,30 +10,29 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
}
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
|
-
import React
|
|
13
|
+
import React from 'react';
|
|
14
14
|
import { isFieldValueEmpty } from '@sitecore-content-sdk/content/layout';
|
|
15
15
|
import { withFieldMetadata } from '../enhancers/withFieldMetadata';
|
|
16
16
|
import { withEmptyFieldEditingComponent } from '../enhancers/withEmptyFieldEditingComponent';
|
|
17
17
|
import { DefaultEmptyFieldEditingComponentText } from './DefaultEmptyFieldEditingComponents';
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* @param {RichTextProps} props component props
|
|
21
|
-
* @public
|
|
22
|
-
*/
|
|
23
|
-
export const RichText = withFieldMetadata(withEmptyFieldEditingComponent(forwardRef((
|
|
24
|
-
// eslint-disable-next-line no-unused-vars
|
|
25
|
-
_a, ref) => {
|
|
26
|
-
var
|
|
27
|
-
// eslint-disable-next-line no-unused-vars
|
|
28
|
-
{ field, tag = 'div', editable = true } = _a, otherProps = __rest(_a,
|
|
29
|
-
// eslint-disable-next-line no-unused-vars
|
|
30
|
-
["field", "tag", "editable"]);
|
|
18
|
+
const RichTextComponent = (_a) => {
|
|
19
|
+
var { field, tag = 'div', ref } = _a, otherProps = __rest(_a, ["field", "tag", "ref"]);
|
|
31
20
|
if (isFieldValueEmpty(field)) {
|
|
32
21
|
return null;
|
|
33
22
|
}
|
|
23
|
+
delete otherProps.editable; // prevent editable from being passed to the DOM
|
|
34
24
|
const htmlProps = Object.assign({ dangerouslySetInnerHTML: {
|
|
35
25
|
__html: field.value,
|
|
36
26
|
}, ref, suppressHydrationWarning: field.metadata ? true : undefined }, otherProps);
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
const Tag = (tag || 'div');
|
|
28
|
+
return React.createElement(Tag, Object.assign({}, htmlProps));
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The RichText component.
|
|
32
|
+
* @param {RichTextProps} props component props
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export const RichText = withFieldMetadata(withEmptyFieldEditingComponent(RichTextComponent, {
|
|
36
|
+
defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentText,
|
|
37
|
+
}));
|
|
39
38
|
RichText.displayName = 'RichText';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useState, useEffect, useCallback, useMemo, useContext } from 'react';
|
|
3
3
|
import fastDeepEqual from 'fast-deep-equal/es6/react';
|
|
4
4
|
/**
|
|
5
5
|
* The context for the SitecoreProvider component.
|
|
@@ -10,38 +10,52 @@ export const ComponentMapReactContext = React.createContext(new Map());
|
|
|
10
10
|
export const ImportMapReactContext = React.createContext(undefined);
|
|
11
11
|
/**
|
|
12
12
|
* The SitecoreProvider component.
|
|
13
|
+
* @param {SitecoreProviderProps} props - The props for the SitecoreProvider component.
|
|
14
|
+
* @param {SitecoreProviderProps['api']} props.api - The API configuration.
|
|
15
|
+
* @param {SitecoreProviderProps['page']} props.page - The page data.
|
|
16
|
+
* @param {SitecoreProviderProps['componentMap']} props.componentMap - The component map.
|
|
17
|
+
* @param {SitecoreProviderProps['loadImportMap']} props.loadImportMap - The function to load the import map.
|
|
18
|
+
* @param {React.ReactNode} props.children - The children to render.
|
|
19
|
+
* @returns {React.ReactNode} The SitecoreProvider component.
|
|
13
20
|
* @public
|
|
14
21
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
27
|
-
this.state = {
|
|
28
|
-
page: props.page,
|
|
29
|
-
setPage: this.setPage,
|
|
30
|
-
api: props.api,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
componentDidUpdate(prevProps) {
|
|
34
|
-
// In case if somebody will manage SitecoreProvider state by passing fresh `page` prop
|
|
35
|
-
// instead of using `updateContext`
|
|
36
|
-
if (!fastDeepEqual(prevProps.page, this.props.page)) {
|
|
37
|
-
this.setPage(this.props.page);
|
|
38
|
-
return;
|
|
22
|
+
export const SitecoreProvider = (props) => {
|
|
23
|
+
const { api, page: propsPage, componentMap, loadImportMap, children } = props;
|
|
24
|
+
const [page, setPageInternal] = useState(propsPage);
|
|
25
|
+
// Memoize setPage callback
|
|
26
|
+
const setPage = useCallback((value) => {
|
|
27
|
+
setPageInternal(value);
|
|
28
|
+
}, []);
|
|
29
|
+
// Handle page prop changes using useEffect instead of componentDidUpdate
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!fastDeepEqual(propsPage, page)) {
|
|
32
|
+
setPage(propsPage);
|
|
39
33
|
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
}, [propsPage, page, setPage]);
|
|
35
|
+
// Memoize the context value to prevent unnecessary re-renders
|
|
36
|
+
const contextValue = useMemo(() => ({
|
|
37
|
+
page,
|
|
38
|
+
setPage,
|
|
39
|
+
api,
|
|
40
|
+
componentMap,
|
|
41
|
+
loadImportMap,
|
|
42
|
+
}), [page, setPage, api, componentMap, loadImportMap]);
|
|
43
|
+
return (React.createElement(SitecoreProviderReactContext.Provider, { value: contextValue }, children));
|
|
44
|
+
};
|
|
47
45
|
SitecoreProvider.displayName = 'SitecoreProvider';
|
|
46
|
+
/**
|
|
47
|
+
* This hook grants acсess to the current Sitecore page and api.
|
|
48
|
+
* @param {UseSitecoreOptions} [options] hook options
|
|
49
|
+
* @example
|
|
50
|
+
* const EditMode = () => {
|
|
51
|
+
* const { page } = useSitecore();
|
|
52
|
+
* return <span>Edit Mode is {page.mode.isEditing ? 'active' : 'inactive'}</span>
|
|
53
|
+
* }
|
|
54
|
+
* @returns {SitecoreProviderState} The current Sitecore context, including the page and api.
|
|
55
|
+
* @public
|
|
56
|
+
*/
|
|
57
|
+
export function useSitecore(options) {
|
|
58
|
+
const scContext = useContext(SitecoreProviderReactContext);
|
|
59
|
+
const updatable = options === null || options === void 0 ? void 0 : options.updatable;
|
|
60
|
+
return Object.assign(Object.assign({}, scContext), { setPage: updatable ? scContext.setPage : undefined });
|
|
61
|
+
}
|
|
@@ -15,11 +15,7 @@ import { isFieldValueEmpty } from '@sitecore-content-sdk/content/layout';
|
|
|
15
15
|
import { withFieldMetadata } from '../enhancers/withFieldMetadata';
|
|
16
16
|
import { withEmptyFieldEditingComponent } from '../enhancers/withEmptyFieldEditingComponent';
|
|
17
17
|
import { DefaultEmptyFieldEditingComponentText } from './DefaultEmptyFieldEditingComponents';
|
|
18
|
-
|
|
19
|
-
* The Text component.
|
|
20
|
-
* @public
|
|
21
|
-
*/
|
|
22
|
-
export const Text = withFieldMetadata(withEmptyFieldEditingComponent((_a) => {
|
|
18
|
+
const TextComponent = (_a) => {
|
|
23
19
|
var { field, tag, editable = true, encode = true } = _a, otherProps = __rest(_a, ["field", "tag", "editable", "encode"]);
|
|
24
20
|
if (isFieldValueEmpty(field)) {
|
|
25
21
|
return null;
|
|
@@ -53,14 +49,22 @@ export const Text = withFieldMetadata(withEmptyFieldEditingComponent((_a) => {
|
|
|
53
49
|
else {
|
|
54
50
|
children = output;
|
|
55
51
|
}
|
|
52
|
+
const Tag = (tag || 'span');
|
|
56
53
|
if (field.metadata) {
|
|
57
|
-
return React.createElement(
|
|
54
|
+
return (React.createElement(Tag, Object.assign({}, htmlProps, { suppressHydrationWarning: true }), children));
|
|
58
55
|
}
|
|
59
56
|
else if (tag || !encode) {
|
|
60
|
-
return React.createElement(
|
|
57
|
+
return React.createElement(Tag, Object.assign({}, htmlProps), children);
|
|
61
58
|
}
|
|
62
59
|
else {
|
|
63
60
|
return React.createElement(React.Fragment, null, children);
|
|
64
61
|
}
|
|
65
|
-
}
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* The Text component.
|
|
65
|
+
* @public
|
|
66
|
+
*/
|
|
67
|
+
export const Text = withFieldMetadata(withEmptyFieldEditingComponent(TextComponent, {
|
|
68
|
+
defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentText,
|
|
69
|
+
}));
|
|
66
70
|
Text.displayName = 'Text';
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AppPlaceholder } from '../components/Placeholder/AppPlaceholder';
|
|
3
|
+
/**
|
|
4
|
+
* Provides a slot-like functionality by wrapping a component and rendering placeholders defined in the layout data.
|
|
5
|
+
* @param {ComponentType<T>} Component - The component to be wrapped around placeholders.
|
|
6
|
+
* @returns {React.ReactNode} A new component that renders the original component with placeholders.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
3
9
|
export const withAppPlaceholder = (Component) => {
|
|
4
10
|
return (props) => {
|
|
5
11
|
const placeholders = props.rendering.placeholders || {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import React from 'react';
|
|
2
|
-
import { useSitecore } from '
|
|
3
|
+
import { useSitecore } from './../components/SitecoreProvider';
|
|
3
4
|
export const DefaultEditingError = () => (React.createElement("div", { className: "sc-jss-editing-error", role: "alert" }, "Datasource is required. Please choose a content item for this component."));
|
|
4
5
|
/**
|
|
5
6
|
* Checks whether a Sitecore datasource is present and renders appropriately depending on page mode (normal vs editing).
|
|
@@ -11,7 +12,7 @@ export const DefaultEditingError = () => (React.createElement("div", { className
|
|
|
11
12
|
*/
|
|
12
13
|
export function withDatasourceCheck(options) {
|
|
13
14
|
return function withDatasourceCheckHoc(Component) {
|
|
14
|
-
return
|
|
15
|
+
return (props) => {
|
|
15
16
|
var _a, _b;
|
|
16
17
|
const { page } = useSitecore();
|
|
17
18
|
const EditingError = (_a = options === null || options === void 0 ? void 0 : options.editingErrorComponent) !== null && _a !== void 0 ? _a : DefaultEditingError;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
3
|
import { resetEditorChromes } from '..';
|
|
3
4
|
/**
|
|
4
5
|
* HOC to inject editor chromes reset on component update.
|
|
@@ -6,17 +7,21 @@ import { resetEditorChromes } from '..';
|
|
|
6
7
|
* @public
|
|
7
8
|
*/
|
|
8
9
|
export const withEditorChromes = (WrappedComponent) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
const Enhancer = (props) => {
|
|
11
|
+
const isFirstRender = useRef(true);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (isFirstRender.current) {
|
|
14
|
+
isFirstRender.current = false;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// only reset chromes on subsequent re-renders
|
|
15
18
|
resetEditorChromes();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
});
|
|
20
|
+
return React.createElement(WrappedComponent, Object.assign({}, props));
|
|
21
|
+
};
|
|
22
|
+
Enhancer.displayName =
|
|
23
|
+
WrappedComponent.displayName ||
|
|
24
|
+
WrappedComponent.name ||
|
|
25
|
+
'Component';
|
|
21
26
|
return Enhancer;
|
|
22
27
|
};
|