@sitecore-jss/sitecore-jss-react 0.1.0-beta.2
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 -0
- package/README.md +8 -0
- package/dist/cjs/ComponentBuilder.js +25 -0
- package/dist/cjs/components/BYOCComponent.js +122 -0
- package/dist/cjs/components/BYOCWrapper.js +18 -0
- package/dist/cjs/components/Date.js +58 -0
- package/dist/cjs/components/EditFrame.js +39 -0
- package/dist/cjs/components/FEaaSComponent.js +152 -0
- package/dist/cjs/components/FEaaSWrapper.js +18 -0
- package/dist/cjs/components/File.js +53 -0
- package/dist/cjs/components/HiddenRendering.js +15 -0
- package/dist/cjs/components/Image.js +120 -0
- package/dist/cjs/components/Link.js +115 -0
- package/dist/cjs/components/MissingComponent.js +34 -0
- package/dist/cjs/components/Placeholder.js +80 -0
- package/dist/cjs/components/PlaceholderCommon.js +212 -0
- package/dist/cjs/components/RichText.js +66 -0
- package/dist/cjs/components/SitecoreContext.js +67 -0
- package/dist/cjs/components/Text.js +83 -0
- package/dist/cjs/components/sharedTypes.js +2 -0
- package/dist/cjs/enhancers/withComponentFactory.js +27 -0
- package/dist/cjs/enhancers/withDatasourceCheck.js +28 -0
- package/dist/cjs/enhancers/withEditorChromes.js +24 -0
- package/dist/cjs/enhancers/withPlaceholder.js +63 -0
- package/dist/cjs/enhancers/withSitecoreContext.js +53 -0
- package/dist/cjs/index.js +66 -0
- package/dist/cjs/utils.js +118 -0
- package/dist/esm/ComponentBuilder.js +21 -0
- package/dist/esm/components/BYOCComponent.js +91 -0
- package/dist/esm/components/BYOCWrapper.js +11 -0
- package/dist/esm/components/Date.js +51 -0
- package/dist/esm/components/EditFrame.js +32 -0
- package/dist/esm/components/FEaaSComponent.js +120 -0
- package/dist/esm/components/FEaaSWrapper.js +11 -0
- package/dist/esm/components/File.js +46 -0
- package/dist/esm/components/HiddenRendering.js +8 -0
- package/dist/esm/components/Image.js +112 -0
- package/dist/esm/components/Link.js +86 -0
- package/dist/esm/components/MissingComponent.js +27 -0
- package/dist/esm/components/Placeholder.js +74 -0
- package/dist/esm/components/PlaceholderCommon.js +205 -0
- package/dist/esm/components/RichText.js +37 -0
- package/dist/esm/components/SitecoreContext.js +60 -0
- package/dist/esm/components/Text.js +76 -0
- package/dist/esm/components/sharedTypes.js +1 -0
- package/dist/esm/enhancers/withComponentFactory.js +20 -0
- package/dist/esm/enhancers/withDatasourceCheck.js +20 -0
- package/dist/esm/enhancers/withEditorChromes.js +17 -0
- package/dist/esm/enhancers/withPlaceholder.js +56 -0
- package/dist/esm/enhancers/withSitecoreContext.js +45 -0
- package/dist/esm/index.js +23 -0
- package/dist/esm/utils.js +109 -0
- package/package.json +76 -0
- package/types/ComponentBuilder.d.ts +28 -0
- package/types/components/BYOCComponent.d.ts +87 -0
- package/types/components/BYOCWrapper.d.ts +3 -0
- package/types/components/Date.d.ts +22 -0
- package/types/components/EditFrame.d.ts +12 -0
- package/types/components/FEaaSComponent.d.ts +71 -0
- package/types/components/FEaaSWrapper.d.ts +3 -0
- package/types/components/File.d.ts +19 -0
- package/types/components/HiddenRendering.d.ts +4 -0
- package/types/components/Image.d.ts +62 -0
- package/types/components/Link.d.ts +47 -0
- package/types/components/MissingComponent.d.ts +9 -0
- package/types/components/Placeholder.d.ts +25 -0
- package/types/components/PlaceholderCommon.d.ts +105 -0
- package/types/components/RichText.d.ts +32 -0
- package/types/components/SitecoreContext.d.ts +43 -0
- package/types/components/Text.d.ts +26 -0
- package/types/components/sharedTypes.d.ts +7 -0
- package/types/enhancers/withComponentFactory.d.ts +13 -0
- package/types/enhancers/withDatasourceCheck.d.ts +22 -0
- package/types/enhancers/withEditorChromes.d.ts +3 -0
- package/types/enhancers/withPlaceholder.d.ts +37 -0
- package/types/enhancers/withSitecoreContext.d.ts +47 -0
- package/types/index.d.ts +24 -0
- package/types/utils.d.ts +42 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { PlaceholderCommon } from './PlaceholderCommon';
|
|
3
|
+
import { withComponentFactory } from '../enhancers/withComponentFactory';
|
|
4
|
+
import { HorizonEditor } from '@sitecore-jss/sitecore-jss/utils';
|
|
5
|
+
/**
|
|
6
|
+
* @param {HtmlElementRendering | ComponentRendering} rendering
|
|
7
|
+
*/
|
|
8
|
+
function isRawRendering(rendering) {
|
|
9
|
+
return (!rendering.componentName &&
|
|
10
|
+
rendering.name !== undefined);
|
|
11
|
+
}
|
|
12
|
+
class PlaceholderComponent extends PlaceholderCommon {
|
|
13
|
+
constructor(props) {
|
|
14
|
+
super(props);
|
|
15
|
+
this.isEmpty = false;
|
|
16
|
+
}
|
|
17
|
+
componentDidMount() {
|
|
18
|
+
super.componentDidMount();
|
|
19
|
+
if (this.isEmpty && HorizonEditor.isActive()) {
|
|
20
|
+
HorizonEditor.resetChromes();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* In case we need to render an empty placeholder, some part of the markup will be inserted by the EE,
|
|
25
|
+
* so we need to separate the empty placeholder's markup and allow React reconciliation to be executed correctly
|
|
26
|
+
* and retain sibling tags
|
|
27
|
+
* @param {React.ReactNode | React.ReactElement[]} node react node
|
|
28
|
+
* @returns react node
|
|
29
|
+
*/
|
|
30
|
+
renderEmptyPlaceholder(node) {
|
|
31
|
+
return React.createElement("div", { className: "sc-jss-empty-placeholder" }, node);
|
|
32
|
+
}
|
|
33
|
+
render() {
|
|
34
|
+
const childProps = Object.assign({}, this.props);
|
|
35
|
+
delete childProps.componentFactory;
|
|
36
|
+
if (this.state.error) {
|
|
37
|
+
if (childProps.errorComponent) {
|
|
38
|
+
return React.createElement(childProps.errorComponent, { error: this.state.error });
|
|
39
|
+
}
|
|
40
|
+
return (React.createElement("div", { className: "sc-jss-placeholder-error" },
|
|
41
|
+
"A rendering error occurred: ",
|
|
42
|
+
this.state.error.message,
|
|
43
|
+
"."));
|
|
44
|
+
}
|
|
45
|
+
const renderingData = childProps.rendering;
|
|
46
|
+
const placeholderData = PlaceholderCommon.getPlaceholderDataFromRenderingData(renderingData, this.props.name);
|
|
47
|
+
const components = this.getComponentsForRenderingData(placeholderData);
|
|
48
|
+
this.isEmpty = placeholderData.every((rendering) => isRawRendering(rendering));
|
|
49
|
+
if (this.props.renderEmpty && this.isEmpty) {
|
|
50
|
+
const rendered = this.props.renderEmpty(components);
|
|
51
|
+
return components.length ? this.renderEmptyPlaceholder(rendered) : rendered;
|
|
52
|
+
}
|
|
53
|
+
else if (components.length && this.isEmpty) {
|
|
54
|
+
return this.renderEmptyPlaceholder(components);
|
|
55
|
+
}
|
|
56
|
+
else if (this.props.render) {
|
|
57
|
+
return this.props.render(components, placeholderData, childProps);
|
|
58
|
+
}
|
|
59
|
+
else if (this.props.renderEach) {
|
|
60
|
+
const renderEach = this.props.renderEach;
|
|
61
|
+
return components.map((component, index) => {
|
|
62
|
+
if (component && component.props && component.props.type === 'text/sitecore') {
|
|
63
|
+
return component;
|
|
64
|
+
}
|
|
65
|
+
return renderEach(component, index);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return components;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
PlaceholderComponent.propTypes = PlaceholderCommon.propTypes;
|
|
74
|
+
export const Placeholder = withComponentFactory(PlaceholderComponent);
|
|
@@ -0,0 +1,205 @@
|
|
|
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 PropTypes from 'prop-types';
|
|
14
|
+
import { MissingComponent } from './MissingComponent';
|
|
15
|
+
import { convertAttributesToReactProps } from '../utils';
|
|
16
|
+
import { HiddenRendering, HIDDEN_RENDERING_NAME } from './HiddenRendering';
|
|
17
|
+
import { FEaaSComponent, FEAAS_COMPONENT_RENDERING_NAME } from './FEaaSComponent';
|
|
18
|
+
import { FEaaSWrapper, FEAAS_WRAPPER_RENDERING_NAME } from './FEaaSWrapper';
|
|
19
|
+
import { BYOCComponent, BYOC_COMPONENT_RENDERING_NAME } from './BYOCComponent';
|
|
20
|
+
import { BYOCWrapper, BYOC_WRAPPER_RENDERING_NAME } from './BYOCWrapper';
|
|
21
|
+
/**
|
|
22
|
+
* These patterns need for right rendering Dynamic placeholders.
|
|
23
|
+
* Must be distinguished Splitter components and another placeholders(containers)
|
|
24
|
+
*/
|
|
25
|
+
const EXCLUDE_PLACEHOLDERS_RENDER = [
|
|
26
|
+
new RegExp(/column-(\d{1})-\{\*\}/i),
|
|
27
|
+
new RegExp(/row-(\d{1})-\{\*\}/i),
|
|
28
|
+
];
|
|
29
|
+
export class PlaceholderCommon extends React.Component {
|
|
30
|
+
constructor(props) {
|
|
31
|
+
super(props);
|
|
32
|
+
this.nodeRefs = [];
|
|
33
|
+
this.state = {};
|
|
34
|
+
this.addRef = this.addRef.bind(this);
|
|
35
|
+
this.updateKeyAttributes = this.updateKeyAttributes.bind(this);
|
|
36
|
+
this.createRawElement = this.createRawElement.bind(this);
|
|
37
|
+
}
|
|
38
|
+
static getPlaceholderDataFromRenderingData(rendering, name) {
|
|
39
|
+
let result;
|
|
40
|
+
/** [SXA] it needs for deleting dynamics placeholder when we set him number(props.name) of container.
|
|
41
|
+
from backend side we get common name of placeholder is called 'nameOfContainer-{*}' where '{*}' marker for replacing **/
|
|
42
|
+
if (rendering === null || rendering === void 0 ? void 0 : rendering.placeholders) {
|
|
43
|
+
Object.keys(rendering.placeholders).forEach((placeholder) => {
|
|
44
|
+
if (placeholder.indexOf('{*}') !== -1 &&
|
|
45
|
+
!EXCLUDE_PLACEHOLDERS_RENDER.some((pattern) => name.search(pattern) !== -1) &&
|
|
46
|
+
name.replace(/[^a-zA-Z]*/gi, '') === placeholder.replace(/[^a-zA-Z]*/gi, '')) {
|
|
47
|
+
rendering.placeholders[name] = rendering.placeholders[placeholder];
|
|
48
|
+
delete rendering.placeholders[placeholder];
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (rendering && rendering.placeholders && Object.keys(rendering.placeholders).length > 0) {
|
|
53
|
+
result = rendering.placeholders[name];
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
result = null;
|
|
57
|
+
}
|
|
58
|
+
if (!result) {
|
|
59
|
+
console.warn(`Placeholder '${name}' was not found in the current rendering data`, JSON.stringify(rendering, null, 2));
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
componentDidMount() {
|
|
65
|
+
this.updateKeyAttributes();
|
|
66
|
+
}
|
|
67
|
+
componentDidUpdate() {
|
|
68
|
+
this.updateKeyAttributes();
|
|
69
|
+
}
|
|
70
|
+
componentDidCatch(error) {
|
|
71
|
+
this.setState({ error });
|
|
72
|
+
}
|
|
73
|
+
getSXAParams(rendering) {
|
|
74
|
+
if (!rendering.params)
|
|
75
|
+
return {};
|
|
76
|
+
return (rendering.params.FieldNames && {
|
|
77
|
+
styles: `${rendering.params.GridParameters || ''} ${rendering.params.Styles || ''}`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
getComponentsForRenderingData(placeholderData) {
|
|
81
|
+
const _a = this.props, { name, fields: placeholderFields, params: placeholderParams, missingComponentComponent, hiddenRenderingComponent } = _a, placeholderProps = __rest(_a, ["name", "fields", "params", "missingComponentComponent", "hiddenRenderingComponent"]);
|
|
82
|
+
return placeholderData
|
|
83
|
+
.map((rendering, index) => {
|
|
84
|
+
const key = rendering.uid
|
|
85
|
+
? rendering.uid
|
|
86
|
+
: `component-${index}`;
|
|
87
|
+
const commonProps = { key };
|
|
88
|
+
// if the element is not a 'component rendering', render it 'raw'
|
|
89
|
+
if (!rendering.componentName &&
|
|
90
|
+
rendering.name) {
|
|
91
|
+
return this.createRawElement(rendering, commonProps);
|
|
92
|
+
}
|
|
93
|
+
const componentRendering = rendering;
|
|
94
|
+
let component;
|
|
95
|
+
if (componentRendering.componentName === HIDDEN_RENDERING_NAME) {
|
|
96
|
+
component = hiddenRenderingComponent !== null && hiddenRenderingComponent !== void 0 ? hiddenRenderingComponent : HiddenRendering;
|
|
97
|
+
}
|
|
98
|
+
else if (!componentRendering.componentName) {
|
|
99
|
+
component = () => React.createElement(React.Fragment, null);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
component = this.getComponentForRendering(componentRendering);
|
|
103
|
+
}
|
|
104
|
+
// Fallback/defaults for Sitecore Component renderings (in case not defined in component factory)
|
|
105
|
+
if (!component) {
|
|
106
|
+
if (componentRendering.componentName === FEAAS_COMPONENT_RENDERING_NAME) {
|
|
107
|
+
component = FEaaSComponent;
|
|
108
|
+
}
|
|
109
|
+
else if (componentRendering.componentName === FEAAS_WRAPPER_RENDERING_NAME) {
|
|
110
|
+
component = FEaaSWrapper;
|
|
111
|
+
}
|
|
112
|
+
else if (componentRendering.componentName === BYOC_COMPONENT_RENDERING_NAME) {
|
|
113
|
+
component = BYOCComponent;
|
|
114
|
+
}
|
|
115
|
+
else if (componentRendering.componentName === BYOC_WRAPPER_RENDERING_NAME) {
|
|
116
|
+
component = BYOCWrapper;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!component) {
|
|
120
|
+
console.error(`Placeholder ${name} contains unknown component ${componentRendering.componentName}. Ensure that a React component exists for it, and that it is registered in your componentFactory.js.`);
|
|
121
|
+
component = missingComponentComponent !== null && missingComponentComponent !== void 0 ? missingComponentComponent : MissingComponent;
|
|
122
|
+
}
|
|
123
|
+
const finalProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, commonProps), placeholderProps), ((placeholderFields || componentRendering.fields) && {
|
|
124
|
+
fields: Object.assign(Object.assign({}, placeholderFields), componentRendering.fields),
|
|
125
|
+
})), ((placeholderParams || componentRendering.params) && {
|
|
126
|
+
params: Object.assign(Object.assign(Object.assign({}, placeholderParams), componentRendering.params), this.getSXAParams(componentRendering)),
|
|
127
|
+
})), { rendering: componentRendering });
|
|
128
|
+
return React.createElement(component, this.props.modifyComponentProps ? this.props.modifyComponentProps(finalProps) : finalProps);
|
|
129
|
+
})
|
|
130
|
+
.filter((element) => element); // remove nulls
|
|
131
|
+
}
|
|
132
|
+
getComponentForRendering(renderingDefinition) {
|
|
133
|
+
var _a;
|
|
134
|
+
const componentFactory = this.props.componentFactory;
|
|
135
|
+
if (!componentFactory || typeof componentFactory !== 'function') {
|
|
136
|
+
console.warn(`No componentFactory was available to service request for component ${renderingDefinition}`);
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
// Render SXA Rendering Variant
|
|
140
|
+
if ((_a = renderingDefinition.params) === null || _a === void 0 ? void 0 : _a.FieldNames) {
|
|
141
|
+
return componentFactory(renderingDefinition.componentName, renderingDefinition.params.FieldNames);
|
|
142
|
+
}
|
|
143
|
+
return componentFactory(renderingDefinition.componentName);
|
|
144
|
+
}
|
|
145
|
+
addRef(nodeRef) {
|
|
146
|
+
this.nodeRefs.push(nodeRef);
|
|
147
|
+
}
|
|
148
|
+
createRawElement(elem, baseProps) {
|
|
149
|
+
if (!elem.name) {
|
|
150
|
+
console.error('"elem.name" is undefined in "createRawElement". Something is likely wrong with your component data. Ensure that your components have a name.');
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const attributes = convertAttributesToReactProps(elem.attributes);
|
|
154
|
+
const props = Object.assign(Object.assign(Object.assign({}, baseProps), attributes), { dangerouslySetInnerHTML: elem.contents ? { __html: elem.contents } : undefined });
|
|
155
|
+
/* Since we can't set the "key" attribute via React, stash it
|
|
156
|
+
* so we can set in the DOM after render.
|
|
157
|
+
*/
|
|
158
|
+
if (!Array.isArray(attributes) && attributes && attributes.chrometype === 'placeholder') {
|
|
159
|
+
props.phkey = elem.attributes.key; // props that get rendered as dom attribute names need to be lowercase, otherwise React complains.
|
|
160
|
+
props.ref = this.addRef; // only need ref for placeholder containers, trying to add it to other components (e.g. stateless components) may result in a warning.
|
|
161
|
+
}
|
|
162
|
+
return React.createElement(elem.name, props);
|
|
163
|
+
}
|
|
164
|
+
updateKeyAttributes() {
|
|
165
|
+
if (!this.nodeRefs) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.nodeRefs.forEach((ref) => {
|
|
169
|
+
if (ref && ref.getAttribute) {
|
|
170
|
+
// ref might be a wrapped component, so check for existence of getAttribute method
|
|
171
|
+
const key = ref.getAttribute('phkey');
|
|
172
|
+
if (key) {
|
|
173
|
+
// need to manually set the 'key' attribute after component mount because
|
|
174
|
+
// 'key' is a reserved attribute/prop in React. so it will never be rendered
|
|
175
|
+
// as an html attribute.
|
|
176
|
+
ref.setAttribute('key', key);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
PlaceholderCommon.propTypes = {
|
|
183
|
+
rendering: PropTypes.oneOfType([
|
|
184
|
+
PropTypes.object,
|
|
185
|
+
PropTypes.object,
|
|
186
|
+
]).isRequired,
|
|
187
|
+
fields: PropTypes.objectOf(PropTypes.oneOfType([
|
|
188
|
+
PropTypes.object,
|
|
189
|
+
PropTypes.object,
|
|
190
|
+
]).isRequired),
|
|
191
|
+
params: PropTypes.objectOf(PropTypes.string.isRequired),
|
|
192
|
+
missingComponentComponent: PropTypes.oneOfType([
|
|
193
|
+
PropTypes.object,
|
|
194
|
+
PropTypes.func,
|
|
195
|
+
]),
|
|
196
|
+
hiddenRenderingComponent: PropTypes.oneOfType([
|
|
197
|
+
PropTypes.object,
|
|
198
|
+
PropTypes.func,
|
|
199
|
+
]),
|
|
200
|
+
errorComponent: PropTypes.oneOfType([
|
|
201
|
+
PropTypes.object,
|
|
202
|
+
PropTypes.func,
|
|
203
|
+
]),
|
|
204
|
+
modifyComponentProps: PropTypes.func,
|
|
205
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
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, { forwardRef } from 'react';
|
|
13
|
+
import PropTypes from 'prop-types';
|
|
14
|
+
export const RichText = forwardRef((_a, ref) => {
|
|
15
|
+
var { field, tag, editable } = _a, otherProps = __rest(_a, ["field", "tag", "editable"]);
|
|
16
|
+
if (!field || (!field.editable && !field.value)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const htmlProps = Object.assign({ dangerouslySetInnerHTML: {
|
|
20
|
+
__html: field.editable && editable ? field.editable : field.value,
|
|
21
|
+
}, ref }, otherProps);
|
|
22
|
+
return React.createElement(tag || 'div', htmlProps);
|
|
23
|
+
});
|
|
24
|
+
export const RichTextPropTypes = {
|
|
25
|
+
field: PropTypes.shape({
|
|
26
|
+
value: PropTypes.string,
|
|
27
|
+
editable: PropTypes.string,
|
|
28
|
+
}),
|
|
29
|
+
tag: PropTypes.string,
|
|
30
|
+
editable: PropTypes.bool,
|
|
31
|
+
};
|
|
32
|
+
RichText.propTypes = RichTextPropTypes;
|
|
33
|
+
RichText.defaultProps = {
|
|
34
|
+
tag: 'div',
|
|
35
|
+
editable: true,
|
|
36
|
+
};
|
|
37
|
+
RichText.displayName = 'RichText';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import fastDeepEqual from 'fast-deep-equal/es6/react';
|
|
5
|
+
export const SitecoreContextReactContext = React.createContext({});
|
|
6
|
+
export const ComponentFactoryReactContext = React.createContext({});
|
|
7
|
+
export class SitecoreContext extends React.Component {
|
|
8
|
+
constructor(props) {
|
|
9
|
+
super(props);
|
|
10
|
+
/**
|
|
11
|
+
* Update context state. Value can be @type {LayoutServiceData} which will be automatically transformed
|
|
12
|
+
* or you can provide exact @type {SitecoreContextValue}
|
|
13
|
+
* @param {SitecoreContextValue | LayoutServiceData} value New context value
|
|
14
|
+
*/
|
|
15
|
+
this.setContext = (value) => {
|
|
16
|
+
this.setState({
|
|
17
|
+
context: value.sitecore
|
|
18
|
+
? this.constructContext(value)
|
|
19
|
+
: Object.assign({}, value),
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
const context = this.constructContext(props.layoutData);
|
|
23
|
+
this.state = {
|
|
24
|
+
context,
|
|
25
|
+
setContext: this.setContext,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
constructContext(layoutData) {
|
|
29
|
+
var _a;
|
|
30
|
+
if (!layoutData) {
|
|
31
|
+
return {
|
|
32
|
+
pageEditing: false,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return Object.assign({ route: layoutData.sitecore.route, itemId: (_a = layoutData.sitecore.route) === null || _a === void 0 ? void 0 : _a.itemId }, layoutData.sitecore.context);
|
|
36
|
+
}
|
|
37
|
+
componentDidUpdate(prevProps) {
|
|
38
|
+
// In case if somebody will manage SitecoreContext state by passing fresh `layoutData` prop
|
|
39
|
+
// instead of using `updateSitecoreContext`
|
|
40
|
+
if (!fastDeepEqual(prevProps.layoutData, this.props.layoutData)) {
|
|
41
|
+
this.setContext(this.props.layoutData);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
return (React.createElement(ComponentFactoryReactContext.Provider, { value: this.props.componentFactory },
|
|
47
|
+
React.createElement(SitecoreContextReactContext.Provider, { value: this.state }, this.props.children)));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
SitecoreContext.propTypes = {
|
|
51
|
+
children: PropTypes.any.isRequired,
|
|
52
|
+
componentFactory: PropTypes.func,
|
|
53
|
+
layoutData: PropTypes.shape({
|
|
54
|
+
sitecore: PropTypes.shape({
|
|
55
|
+
context: PropTypes.any,
|
|
56
|
+
route: PropTypes.any,
|
|
57
|
+
}),
|
|
58
|
+
}),
|
|
59
|
+
};
|
|
60
|
+
SitecoreContext.displayName = 'SitecoreContext';
|
|
@@ -0,0 +1,76 @@
|
|
|
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 PropTypes from 'prop-types';
|
|
14
|
+
export const Text = (_a) => {
|
|
15
|
+
var { field, tag, editable, encode } = _a, otherProps = __rest(_a, ["field", "tag", "editable", "encode"]);
|
|
16
|
+
if (!field || (!field.editable && (field.value === undefined || field.value === ''))) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
// can't use editable value if we want to output unencoded
|
|
20
|
+
if (!encode) {
|
|
21
|
+
// eslint-disable-next-line no-param-reassign
|
|
22
|
+
editable = false;
|
|
23
|
+
}
|
|
24
|
+
const isEditable = field.editable && editable;
|
|
25
|
+
let output = isEditable
|
|
26
|
+
? field.editable || ''
|
|
27
|
+
: field.value === undefined
|
|
28
|
+
? ''
|
|
29
|
+
: field.value;
|
|
30
|
+
// when string value isn't formatted, we should format line breaks
|
|
31
|
+
if (!field.editable && typeof output === 'string') {
|
|
32
|
+
const splitted = String(output).split('\n');
|
|
33
|
+
if (splitted.length) {
|
|
34
|
+
const formatted = [];
|
|
35
|
+
splitted.forEach((str, i) => {
|
|
36
|
+
const isLast = i === splitted.length - 1;
|
|
37
|
+
formatted.push(str);
|
|
38
|
+
if (!isLast) {
|
|
39
|
+
formatted.push(React.createElement("br", { key: i }));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
output = formatted;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const setDangerously = isEditable || !encode;
|
|
46
|
+
let children = null;
|
|
47
|
+
const htmlProps = Object.assign({}, otherProps);
|
|
48
|
+
if (setDangerously) {
|
|
49
|
+
htmlProps.dangerouslySetInnerHTML = {
|
|
50
|
+
__html: output,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
children = output;
|
|
55
|
+
}
|
|
56
|
+
if (tag || setDangerously) {
|
|
57
|
+
return React.createElement(tag || 'span', htmlProps, children);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
return React.createElement(React.Fragment, null, children);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
Text.propTypes = {
|
|
64
|
+
field: PropTypes.shape({
|
|
65
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
66
|
+
editable: PropTypes.string,
|
|
67
|
+
}),
|
|
68
|
+
tag: PropTypes.string,
|
|
69
|
+
editable: PropTypes.bool,
|
|
70
|
+
encode: PropTypes.bool,
|
|
71
|
+
};
|
|
72
|
+
Text.defaultProps = {
|
|
73
|
+
editable: true,
|
|
74
|
+
encode: true,
|
|
75
|
+
};
|
|
76
|
+
Text.displayName = 'Text';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ComponentFactoryReactContext } from '../components/SitecoreContext';
|
|
3
|
+
import { useContext } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* @param {React.ComponentClass<T> | React.FC<T>} Component
|
|
6
|
+
*/
|
|
7
|
+
export function withComponentFactory(Component) {
|
|
8
|
+
/**
|
|
9
|
+
* @param {T} props - props to pass to the wrapped component
|
|
10
|
+
* @returns {JSX.Element} - the rendered component
|
|
11
|
+
*/
|
|
12
|
+
function WithComponentFactory(props) {
|
|
13
|
+
const context = useContext(ComponentFactoryReactContext);
|
|
14
|
+
return React.createElement(Component, Object.assign({}, props, { componentFactory: props.componentFactory || context }));
|
|
15
|
+
}
|
|
16
|
+
WithComponentFactory.displayName = `withComponentFactory(${Component.displayName ||
|
|
17
|
+
Component.name ||
|
|
18
|
+
'Anonymous'})`;
|
|
19
|
+
return WithComponentFactory;
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useSitecoreContext } from './withSitecoreContext';
|
|
3
|
+
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
|
+
* Checks whether a Sitecore datasource is present and renders appropriately depending on page mode (normal vs editing).
|
|
6
|
+
* @param {WithDatasourceCheckOptions} [options]
|
|
7
|
+
* @returns
|
|
8
|
+
* The wrapped component, if a datasource is present.
|
|
9
|
+
* A null component (in normal mode) or an error component (in editing mode), if a datasource is not present.
|
|
10
|
+
*/
|
|
11
|
+
export function withDatasourceCheck(options) {
|
|
12
|
+
return function withDatasourceCheckHoc(Component) {
|
|
13
|
+
return function WithDatasourceCheck(props) {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
const { sitecoreContext } = useSitecoreContext();
|
|
16
|
+
const EditingError = (_a = options === null || options === void 0 ? void 0 : options.editingErrorComponent) !== null && _a !== void 0 ? _a : DefaultEditingError;
|
|
17
|
+
return ((_b = props.rendering) === null || _b === void 0 ? void 0 : _b.dataSource) ? (React.createElement(Component, Object.assign({}, props))) : sitecoreContext.pageEditing ? (React.createElement(EditingError, null)) : null;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { resetEditorChromes } from '..';
|
|
3
|
+
export const withEditorChromes = (WrappedComponent) => {
|
|
4
|
+
class Enhancer extends React.Component {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
|
|
8
|
+
}
|
|
9
|
+
componentDidUpdate() {
|
|
10
|
+
resetEditorChromes();
|
|
11
|
+
}
|
|
12
|
+
render() {
|
|
13
|
+
return React.createElement(WrappedComponent, Object.assign({}, this.props));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return Enhancer;
|
|
17
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { PlaceholderCommon } from '../components/PlaceholderCommon';
|
|
3
|
+
import { withComponentFactory } from './withComponentFactory';
|
|
4
|
+
/**
|
|
5
|
+
* @param {WithPlaceholderSpec} placeholders
|
|
6
|
+
* @param {WithPlaceholderOptions} [options]
|
|
7
|
+
*/
|
|
8
|
+
export function withPlaceholder(placeholders, options) {
|
|
9
|
+
return (WrappedComponent) => {
|
|
10
|
+
class WithPlaceholder extends PlaceholderCommon {
|
|
11
|
+
constructor(props) {
|
|
12
|
+
super(props);
|
|
13
|
+
}
|
|
14
|
+
render() {
|
|
15
|
+
let childProps = Object.assign({}, this.props);
|
|
16
|
+
delete childProps.componentFactory;
|
|
17
|
+
if (options && options.propsTransformer) {
|
|
18
|
+
childProps = options.propsTransformer(childProps);
|
|
19
|
+
}
|
|
20
|
+
if (this.state.error) {
|
|
21
|
+
if (childProps.errorComponent) {
|
|
22
|
+
return React.createElement(childProps.errorComponent, { error: this.state.error });
|
|
23
|
+
}
|
|
24
|
+
return (React.createElement("div", { className: "sc-jss-placeholder-error" },
|
|
25
|
+
"A rendering error occurred: ",
|
|
26
|
+
this.state.error.message,
|
|
27
|
+
"."));
|
|
28
|
+
}
|
|
29
|
+
const renderingData = options && options.resolvePlaceholderDataFromProps
|
|
30
|
+
? options.resolvePlaceholderDataFromProps(childProps)
|
|
31
|
+
: childProps.rendering;
|
|
32
|
+
const definitelyArrayPlacholders = !Array.isArray(placeholders)
|
|
33
|
+
? [placeholders]
|
|
34
|
+
: placeholders;
|
|
35
|
+
definitelyArrayPlacholders.forEach((placeholder) => {
|
|
36
|
+
let placeholderData;
|
|
37
|
+
if (typeof placeholder !== 'string' && placeholder.placeholder && placeholder.prop) {
|
|
38
|
+
placeholderData = PlaceholderCommon.getPlaceholderDataFromRenderingData(renderingData, placeholder.placeholder);
|
|
39
|
+
if (placeholderData) {
|
|
40
|
+
childProps[placeholder.prop] = this.getComponentsForRenderingData(placeholderData);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
placeholderData = PlaceholderCommon.getPlaceholderDataFromRenderingData(renderingData, placeholder);
|
|
45
|
+
if (placeholderData) {
|
|
46
|
+
childProps[placeholder] = this.getComponentsForRenderingData(placeholderData);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return React.createElement(WrappedComponent, Object.assign({}, childProps));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
WithPlaceholder.propTypes = PlaceholderCommon.propTypes;
|
|
54
|
+
return withComponentFactory(WithPlaceholder);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SitecoreContextReactContext } from '../components/SitecoreContext';
|
|
3
|
+
/**
|
|
4
|
+
* @param {WithSitecoreContextOptions} [options]
|
|
5
|
+
*/
|
|
6
|
+
export function withSitecoreContext(options) {
|
|
7
|
+
return function withSitecoreContextHoc(Component) {
|
|
8
|
+
return function WithSitecoreContext(props) {
|
|
9
|
+
return (React.createElement(SitecoreContextReactContext.Consumer, null, (context) => (React.createElement(Component, Object.assign({}, props, { sitecoreContext: context.context, updateSitecoreContext: options && options.updatable && context.setContext })))));
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* This hook grants acсess to the current Sitecore page context
|
|
15
|
+
* by default JSS includes the following properties in this context:
|
|
16
|
+
* - pageEditing - Provided by Layout Service, a boolean indicating whether the route is being accessed via the Experience Editor.
|
|
17
|
+
* - pageState - Like pageEditing, but a string: normal, preview or edit.
|
|
18
|
+
* - site - Provided by Layout Service, an object containing the name of the current Sitecore site context.
|
|
19
|
+
*
|
|
20
|
+
* @see https://jss.sitecore.com/docs/techniques/extending-layout-service/layoutservice-extending-context
|
|
21
|
+
*
|
|
22
|
+
* @param {WithSitecoreContextOptions} [options] hook options
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const EditMode = () => {
|
|
26
|
+
* const { sitecoreContext } = useSitecoreContext();
|
|
27
|
+
* return <span>Edit Mode is {sitecoreContext.pageEditing ? 'active' : 'inactive'}</span>
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const EditMode = () => {
|
|
32
|
+
* const { sitecoreContext, updateSitecoreContext } = useSitecoreContext({ updatable: true });
|
|
33
|
+
* const onClick = () => updateSitecoreContext({ pageEditing: true });
|
|
34
|
+
* return <span onClick={onClick}>Edit Mode is {sitecoreContext.pageEditing ? 'active' : 'inactive'}</span>
|
|
35
|
+
* }
|
|
36
|
+
* @returns {Object} { sitecoreContext, updateSitecoreContext }
|
|
37
|
+
*/
|
|
38
|
+
export function useSitecoreContext(options) {
|
|
39
|
+
const reactContext = React.useContext(SitecoreContextReactContext);
|
|
40
|
+
const updatable = options === null || options === void 0 ? void 0 : options.updatable;
|
|
41
|
+
return {
|
|
42
|
+
sitecoreContext: reactContext.context,
|
|
43
|
+
updateSitecoreContext: updatable ? reactContext.setContext : undefined,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { constants, NativeDataFetcher, enableDebug, } from '@sitecore-jss/sitecore-jss';
|
|
2
|
+
export { isEditorActive, resetEditorChromes, DefaultEditFrameButton, DefaultEditFrameButtons, } from '@sitecore-jss/sitecore-jss/utils';
|
|
3
|
+
export { getContentStylesheetLink, getComponentLibraryStylesheetLinks, LayoutServicePageState, GraphQLLayoutService, getChildPlaceholder, getFieldValue, } from '@sitecore-jss/sitecore-jss/layout';
|
|
4
|
+
export { GraphQLDictionaryService, } from '@sitecore-jss/sitecore-jss/i18n';
|
|
5
|
+
export { mediaApi } from '@sitecore-jss/sitecore-jss/media';
|
|
6
|
+
export { Placeholder } from './components/Placeholder';
|
|
7
|
+
export { Image, getEEMarkup, } from './components/Image';
|
|
8
|
+
export { RichText, RichTextPropTypes } from './components/RichText';
|
|
9
|
+
export { Text } from './components/Text';
|
|
10
|
+
export { DateField } from './components/Date';
|
|
11
|
+
export { FEaaSComponent, fetchFEaaSComponentServerProps, } from './components/FEaaSComponent';
|
|
12
|
+
export { FEaaSWrapper } from './components/FEaaSWrapper';
|
|
13
|
+
export { BYOCComponent, fetchBYOCComponentServerProps, } from './components/BYOCComponent';
|
|
14
|
+
export { BYOCWrapper } from './components/BYOCWrapper';
|
|
15
|
+
export { Link, LinkPropTypes } from './components/Link';
|
|
16
|
+
export { File } from './components/File';
|
|
17
|
+
export { SitecoreContext, SitecoreContextReactContext, } from './components/SitecoreContext';
|
|
18
|
+
export { withSitecoreContext, useSitecoreContext, } from './enhancers/withSitecoreContext';
|
|
19
|
+
export { withEditorChromes } from './enhancers/withEditorChromes';
|
|
20
|
+
export { withPlaceholder } from './enhancers/withPlaceholder';
|
|
21
|
+
export { withDatasourceCheck } from './enhancers/withDatasourceCheck';
|
|
22
|
+
export { EditFrame } from './components/EditFrame';
|
|
23
|
+
export { ComponentBuilder } from './ComponentBuilder';
|