@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.
Files changed (78) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +8 -0
  3. package/dist/cjs/ComponentBuilder.js +25 -0
  4. package/dist/cjs/components/BYOCComponent.js +122 -0
  5. package/dist/cjs/components/BYOCWrapper.js +18 -0
  6. package/dist/cjs/components/Date.js +58 -0
  7. package/dist/cjs/components/EditFrame.js +39 -0
  8. package/dist/cjs/components/FEaaSComponent.js +152 -0
  9. package/dist/cjs/components/FEaaSWrapper.js +18 -0
  10. package/dist/cjs/components/File.js +53 -0
  11. package/dist/cjs/components/HiddenRendering.js +15 -0
  12. package/dist/cjs/components/Image.js +120 -0
  13. package/dist/cjs/components/Link.js +115 -0
  14. package/dist/cjs/components/MissingComponent.js +34 -0
  15. package/dist/cjs/components/Placeholder.js +80 -0
  16. package/dist/cjs/components/PlaceholderCommon.js +212 -0
  17. package/dist/cjs/components/RichText.js +66 -0
  18. package/dist/cjs/components/SitecoreContext.js +67 -0
  19. package/dist/cjs/components/Text.js +83 -0
  20. package/dist/cjs/components/sharedTypes.js +2 -0
  21. package/dist/cjs/enhancers/withComponentFactory.js +27 -0
  22. package/dist/cjs/enhancers/withDatasourceCheck.js +28 -0
  23. package/dist/cjs/enhancers/withEditorChromes.js +24 -0
  24. package/dist/cjs/enhancers/withPlaceholder.js +63 -0
  25. package/dist/cjs/enhancers/withSitecoreContext.js +53 -0
  26. package/dist/cjs/index.js +66 -0
  27. package/dist/cjs/utils.js +118 -0
  28. package/dist/esm/ComponentBuilder.js +21 -0
  29. package/dist/esm/components/BYOCComponent.js +91 -0
  30. package/dist/esm/components/BYOCWrapper.js +11 -0
  31. package/dist/esm/components/Date.js +51 -0
  32. package/dist/esm/components/EditFrame.js +32 -0
  33. package/dist/esm/components/FEaaSComponent.js +120 -0
  34. package/dist/esm/components/FEaaSWrapper.js +11 -0
  35. package/dist/esm/components/File.js +46 -0
  36. package/dist/esm/components/HiddenRendering.js +8 -0
  37. package/dist/esm/components/Image.js +112 -0
  38. package/dist/esm/components/Link.js +86 -0
  39. package/dist/esm/components/MissingComponent.js +27 -0
  40. package/dist/esm/components/Placeholder.js +74 -0
  41. package/dist/esm/components/PlaceholderCommon.js +205 -0
  42. package/dist/esm/components/RichText.js +37 -0
  43. package/dist/esm/components/SitecoreContext.js +60 -0
  44. package/dist/esm/components/Text.js +76 -0
  45. package/dist/esm/components/sharedTypes.js +1 -0
  46. package/dist/esm/enhancers/withComponentFactory.js +20 -0
  47. package/dist/esm/enhancers/withDatasourceCheck.js +20 -0
  48. package/dist/esm/enhancers/withEditorChromes.js +17 -0
  49. package/dist/esm/enhancers/withPlaceholder.js +56 -0
  50. package/dist/esm/enhancers/withSitecoreContext.js +45 -0
  51. package/dist/esm/index.js +23 -0
  52. package/dist/esm/utils.js +109 -0
  53. package/package.json +76 -0
  54. package/types/ComponentBuilder.d.ts +28 -0
  55. package/types/components/BYOCComponent.d.ts +87 -0
  56. package/types/components/BYOCWrapper.d.ts +3 -0
  57. package/types/components/Date.d.ts +22 -0
  58. package/types/components/EditFrame.d.ts +12 -0
  59. package/types/components/FEaaSComponent.d.ts +71 -0
  60. package/types/components/FEaaSWrapper.d.ts +3 -0
  61. package/types/components/File.d.ts +19 -0
  62. package/types/components/HiddenRendering.d.ts +4 -0
  63. package/types/components/Image.d.ts +62 -0
  64. package/types/components/Link.d.ts +47 -0
  65. package/types/components/MissingComponent.d.ts +9 -0
  66. package/types/components/Placeholder.d.ts +25 -0
  67. package/types/components/PlaceholderCommon.d.ts +105 -0
  68. package/types/components/RichText.d.ts +32 -0
  69. package/types/components/SitecoreContext.d.ts +43 -0
  70. package/types/components/Text.d.ts +26 -0
  71. package/types/components/sharedTypes.d.ts +7 -0
  72. package/types/enhancers/withComponentFactory.d.ts +13 -0
  73. package/types/enhancers/withDatasourceCheck.d.ts +22 -0
  74. package/types/enhancers/withEditorChromes.d.ts +3 -0
  75. package/types/enhancers/withPlaceholder.d.ts +37 -0
  76. package/types/enhancers/withSitecoreContext.d.ts +47 -0
  77. package/types/index.d.ts +24 -0
  78. package/types/utils.d.ts +42 -0
@@ -0,0 +1,91 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import React from 'react';
11
+ import { getDataFromFields } from '../utils';
12
+ import { MissingComponent } from './MissingComponent';
13
+ import * as FEAAS from '@sitecore-feaas/clientside/react';
14
+ export const BYOC_COMPONENT_RENDERING_NAME = 'BYOCComponent';
15
+ const DefaultErrorComponent = (props) => {
16
+ var _a;
17
+ return (React.createElement("div", null,
18
+ "A rendering error occurred: ", (_a = props.error) === null || _a === void 0 ? void 0 :
19
+ _a.message,
20
+ "."));
21
+ };
22
+ /**
23
+ * BYOCComponent facilitate the rendering of external components. It manages potential errors,
24
+ * missing components, and customization of error messages or alternative rendering components.
25
+ * @param {ByocComponentProps} props component props
26
+ * @returns dynamicly rendered component or Missing Component error frame
27
+ */
28
+ export class BYOCComponent extends React.Component {
29
+ constructor(props) {
30
+ super(props);
31
+ this.state = {};
32
+ }
33
+ static getDerivedStateFromError(error) {
34
+ // Update state so the next render will show the fallback UI.
35
+ return { error: error };
36
+ }
37
+ componentDidCatch(error) {
38
+ this.setState({ error });
39
+ }
40
+ render() {
41
+ var _a, _b, _c;
42
+ const props = this.props;
43
+ if (this.state.error) {
44
+ return this.props.errorComponent ? (React.createElement(this.props.errorComponent, { error: this.state.error })) : (React.createElement(DefaultErrorComponent, { error: this.state.error }));
45
+ }
46
+ const { ComponentName: componentName } = props.params || {};
47
+ if (!componentName) {
48
+ const noNameProps = {
49
+ errorOverride: 'BYOC: The ComponentName for this rendering is missing',
50
+ };
51
+ return props.missingComponentComponent ? (React.createElement(this.props.missingComponentComponent, Object.assign({}, noNameProps))) : (React.createElement(MissingComponent, Object.assign({}, noNameProps)));
52
+ }
53
+ const unRegisteredComponentProps = {
54
+ rendering: {
55
+ componentName: componentName,
56
+ },
57
+ errorOverride: 'BYOC: This component was not registered.',
58
+ };
59
+ const fallbackComponent = this.props.missingComponentComponent ? (React.createElement(this.props.missingComponentComponent, Object.assign({}, unRegisteredComponentProps))) : (React.createElement(MissingComponent, Object.assign({}, unRegisteredComponentProps)));
60
+ const ErrorComponent = this.props.errorComponent;
61
+ let componentProps = {};
62
+ if ((_a = props.params) === null || _a === void 0 ? void 0 : _a.ComponentProps) {
63
+ try {
64
+ componentProps = (_b = JSON.parse(props.params.ComponentProps)) !== null && _b !== void 0 ? _b : {};
65
+ }
66
+ catch (e) {
67
+ console.error(`Parsing props for ${componentName} component from rendering params failed. Error: ${e}`);
68
+ return ErrorComponent ? (React.createElement(ErrorComponent, { error: e })) : (React.createElement(DefaultErrorComponent, { error: e }));
69
+ }
70
+ }
71
+ // apply props from item datasource
72
+ const dataSourcesData = Object.assign(Object.assign({}, props.fetchedData), { _: getDataFromFields((_c = props.fields) !== null && _c !== void 0 ? _c : {}) });
73
+ // we render fallback on client to avoid problems with client-only components
74
+ return (React.createElement(FEAAS.ExternalComponent, Object.assign({ componentName: componentName, clientFallback: fallbackComponent, datasources: dataSourcesData }, componentProps)));
75
+ }
76
+ }
77
+ /**
78
+ * Fetches server component props required for server rendering, based on rendering params.
79
+ * @param {BYOCComponentParams} params component params
80
+ */
81
+ export function fetchBYOCComponentServerProps(params) {
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const fetchDataOptions = params.ComponentDataOverride
84
+ ? JSON.parse(params.ComponentDataOverride)
85
+ : {};
86
+ const fetchedData = yield FEAAS.DataSettings.fetch(fetchDataOptions || {});
87
+ return {
88
+ fetchedData,
89
+ };
90
+ });
91
+ }
@@ -0,0 +1,11 @@
1
+ import { BYOCComponent } from './BYOCComponent';
2
+ import React from 'react';
3
+ export const BYOC_WRAPPER_RENDERING_NAME = 'BYOCWrapper';
4
+ export const BYOCWrapper = (props) => {
5
+ var _a, _b, _c;
6
+ const styles = (_b = (_a = props.params) === null || _a === void 0 ? void 0 : _a.styles) === null || _b === void 0 ? void 0 : _b.trimEnd();
7
+ const id = (_c = props.params) === null || _c === void 0 ? void 0 : _c.RenderingIdentifier;
8
+ return (React.createElement("div", { className: styles ? styles : undefined, id: id ? id : undefined },
9
+ React.createElement("div", { className: "component-content" },
10
+ React.createElement(BYOCComponent, Object.assign({}, props)))));
11
+ };
@@ -0,0 +1,51 @@
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 DateField = (_a) => {
15
+ var { field, tag, editable, render } = _a, otherProps = __rest(_a, ["field", "tag", "editable", "render"]);
16
+ if (!field || (!field.editable && !field.value)) {
17
+ return null;
18
+ }
19
+ let children;
20
+ const htmlProps = Object.assign({}, otherProps);
21
+ if (field.editable && editable) {
22
+ htmlProps.dangerouslySetInnerHTML = {
23
+ __html: field.editable,
24
+ };
25
+ }
26
+ else if (render) {
27
+ children = render(field.value ? new Date(field.value) : null);
28
+ }
29
+ else {
30
+ children = field.value;
31
+ }
32
+ if (tag || (field.editable && editable)) {
33
+ return React.createElement(tag || 'span', htmlProps, children);
34
+ }
35
+ else {
36
+ return React.createElement(React.Fragment, null, children);
37
+ }
38
+ };
39
+ DateField.propTypes = {
40
+ field: PropTypes.shape({
41
+ value: PropTypes.string,
42
+ editable: PropTypes.string,
43
+ }).isRequired,
44
+ tag: PropTypes.string,
45
+ editable: PropTypes.bool,
46
+ render: PropTypes.func,
47
+ };
48
+ DateField.defaultProps = {
49
+ editable: true,
50
+ };
51
+ DateField.displayName = 'Date';
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { useSitecoreContext } from '../enhancers/withSitecoreContext';
3
+ import { mapButtonToCommand, } from '@sitecore-jss/sitecore-jss/utils';
4
+ export const EditFrame = ({ children, dataSource, buttons, title, tooltip, cssClass, parameters, }) => {
5
+ var _a;
6
+ const { sitecoreContext } = useSitecoreContext();
7
+ if (!sitecoreContext.pageEditing) {
8
+ return React.createElement(React.Fragment, null, children);
9
+ }
10
+ const chromeData = {
11
+ displayName: title,
12
+ expandedDisplayName: tooltip,
13
+ };
14
+ const frameProps = {};
15
+ frameProps.className = 'scLooseFrameZone';
16
+ if (cssClass) {
17
+ frameProps.className = `${frameProps.className} ${cssClass}`;
18
+ }
19
+ // item uri for edit frame target
20
+ if (dataSource) {
21
+ const databaseName = dataSource.databaseName || ((_a = sitecoreContext.route) === null || _a === void 0 ? void 0 : _a.databaseName);
22
+ const language = dataSource.language || sitecoreContext.language;
23
+ frameProps.sc_item = `sitecore://${databaseName}/${dataSource.itemId}?lang=${language}`;
24
+ chromeData.contextItemUri = frameProps.sc_item;
25
+ }
26
+ chromeData.commands = buttons === null || buttons === void 0 ? void 0 : buttons.map((value) => {
27
+ return mapButtonToCommand(value, dataSource === null || dataSource === void 0 ? void 0 : dataSource.itemId, parameters);
28
+ });
29
+ return (React.createElement("div", Object.assign({ className: "scLooseFrameZone" }, frameProps),
30
+ React.createElement("span", { className: "scChromeData" }, JSON.stringify(chromeData)),
31
+ children));
32
+ };
@@ -0,0 +1,120 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import React from 'react';
11
+ import * as FEAAS from '@sitecore-feaas/clientside/react';
12
+ import { LayoutServicePageState } from '@sitecore-jss/sitecore-jss/layout';
13
+ import { getDataFromFields } from '../utils';
14
+ export const FEAAS_COMPONENT_RENDERING_NAME = 'FEaaSComponent';
15
+ /**
16
+ * @param {FEaaSComponentProps} props component props
17
+ */
18
+ export const FEaaSComponent = (props) => {
19
+ var _a, _b, _c, _d, _e, _f, _g;
20
+ const computedRevision = ((_a = props.params) === null || _a === void 0 ? void 0 : _a.ComponentRevision) || props.revisionFallback;
21
+ if (!props.template &&
22
+ (!props.params ||
23
+ !props.params.LibraryId ||
24
+ !props.params.ComponentId ||
25
+ !props.params.ComponentVersion ||
26
+ !props.params.ComponentHostName ||
27
+ !computedRevision)) {
28
+ // Missing FEaaS component required props
29
+ return null;
30
+ }
31
+ // combine fetchedData from server with datasource data (if present)
32
+ const data = Object.assign(Object.assign({}, props.fetchedData), { _: getDataFromFields((_b = props.fields) !== null && _b !== void 0 ? _b : {}) });
33
+ // FEaaS control would still be hydrated by client
34
+ // we pass all the props as a workaround to avoid hydration error, until we convert all JSS components to server side
35
+ // this also allows component to fall back to full client-side rendering when template or src is empty
36
+ // FEAAS should not fetch anything, since JSS does the fetching - so we pass empty array into fetch param
37
+ return (React.createElement(FEAAS.Component, { data: data, template: props.template, cdn: (_c = props.params) === null || _c === void 0 ? void 0 : _c.ComponentHostName, library: (_d = props.params) === null || _d === void 0 ? void 0 : _d.LibraryId, version: (_e = props.params) === null || _e === void 0 ? void 0 : _e.ComponentVersion, component: (_f = props.params) === null || _f === void 0 ? void 0 : _f.ComponentId, instance: (_g = props.params) === null || _g === void 0 ? void 0 : _g.ComponentInstanceId, revision: computedRevision, fetch: [] }));
38
+ };
39
+ /**
40
+ * Fetches server component props required for server rendering, based on rendering params.
41
+ * Component endpoint will either be retrieved from params or from endpointOverride
42
+ * @param {FEaaSComponentParams} params component params
43
+ * @param {LayoutServicePageState} [pageState] page state to determine which component variant to use
44
+ * @param {string} [endpointOverride] optional override for component endpoint
45
+ */
46
+ export function fetchFEaaSComponentServerProps(params, pageState, endpointOverride) {
47
+ return __awaiter(this, void 0, void 0, function* () {
48
+ const revisionFallback = pageState && pageState !== LayoutServicePageState.Normal ? 'staged' : 'published';
49
+ const src = endpointOverride || composeComponentEndpoint(params, revisionFallback);
50
+ let template = '';
51
+ let fetchedData = {};
52
+ const fetchDataOptions = params.ComponentDataOverride
53
+ ? JSON.parse(params.ComponentDataOverride)
54
+ : {};
55
+ try {
56
+ template = yield fetchComponentTemplate(src, params, revisionFallback);
57
+ fetchedData = yield fetchData(fetchDataOptions);
58
+ }
59
+ catch (e) {
60
+ console.error(e);
61
+ }
62
+ return {
63
+ fetchedData,
64
+ revisionFallback,
65
+ template,
66
+ };
67
+ });
68
+ }
69
+ /**
70
+ * @param {string} src component endpoint
71
+ * @param {FEaaSComponentParams} params rendering parameters for FEAAS component
72
+ * @param {RevisionType} revisionFallback fallback revision to fetch if revision is absent in params
73
+ */
74
+ function fetchComponentTemplate(src, params, revisionFallback) {
75
+ return __awaiter(this, void 0, void 0, function* () {
76
+ try {
77
+ const { template } = yield FEAAS.fetchComponent(src);
78
+ return template;
79
+ }
80
+ catch (error) {
81
+ console.error(`Fetch FEAAS component from ${src} failed. Ensure the component revision "${params.ComponentRevision ||
82
+ revisionFallback}" is present`);
83
+ throw error;
84
+ }
85
+ });
86
+ }
87
+ /**
88
+ * Fetches component data based on the provided data options.
89
+ * This function asynchronously fetches data using the FEAAS.DataSettings.fetch method.
90
+ *
91
+ * @param {FEAAS.DataOptions} dataOptions - Options to customize data fetching.
92
+ * @returns {Promise<FEAAS.DataScopes>} A promise that resolves with the fetched data,
93
+ * or rejects with an error if data fetching encounters an issue.
94
+ * @throws {Error} If an error occurs during data fetching, it is propagated as an error.
95
+ */
96
+ function fetchData(dataOptions) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ try {
99
+ const fetchedData = yield FEAAS.DataSettings.fetch(dataOptions || {});
100
+ return fetchedData;
101
+ }
102
+ catch (error) {
103
+ console.error('Fetch FEAAS component data settings failed');
104
+ throw error;
105
+ }
106
+ });
107
+ }
108
+ /**
109
+ * Build component endpoint URL from component's params
110
+ * @param {FEaaSComponentParams} params rendering parameters for FEAAS component
111
+ * @param {RevisionType} revisionFallback fallback revision to fetch if revision is absent in params
112
+ * @returns component endpoint URL
113
+ */
114
+ export const composeComponentEndpoint = (params, revisionFallback) => {
115
+ const revision = params.ComponentRevision || revisionFallback;
116
+ const hostname = params.ComponentHostName.startsWith('https://')
117
+ ? params.ComponentHostName
118
+ : `https://${params.ComponentHostName}`;
119
+ return `${hostname}/components/${params.LibraryId}/${params.ComponentId}/${params.ComponentVersion}/${revision}`;
120
+ };
@@ -0,0 +1,11 @@
1
+ import { FEaaSComponent } from './FEaaSComponent';
2
+ import React from 'react';
3
+ export const FEAAS_WRAPPER_RENDERING_NAME = 'FEaaSWrapper';
4
+ export const FEaaSWrapper = (props) => {
5
+ var _a, _b;
6
+ const styles = `component feaas ${(_a = props.params) === null || _a === void 0 ? void 0 : _a.styles}`.trimEnd();
7
+ const id = (_b = props.params) === null || _b === void 0 ? void 0 : _b.RenderingIdentifier;
8
+ return (React.createElement("div", { className: styles, id: id ? id : undefined },
9
+ React.createElement("div", { className: "component-content" },
10
+ React.createElement(FEaaSComponent, Object.assign({}, props)))));
11
+ };
@@ -0,0 +1,46 @@
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 PropTypes from 'prop-types';
13
+ import React from 'react';
14
+ export const File = (_a) => {
15
+ /*
16
+ File fields cannot be managed via the EE. We never output "editable."
17
+ */
18
+ var { field, children } = _a, otherProps = __rest(_a, ["field", "children"]);
19
+ const dynamicField = field;
20
+ if (!field || (!dynamicField.value && !dynamicField.src)) {
21
+ return null;
22
+ }
23
+ // handle link directly on field for forgetful devs
24
+ const file = (dynamicField.src
25
+ ? field
26
+ : dynamicField.value);
27
+ if (!file) {
28
+ return null;
29
+ }
30
+ const linkText = !children ? file.title || file.displayName : null;
31
+ const anchorAttrs = {
32
+ href: file.src,
33
+ };
34
+ return React.createElement('a', Object.assign(Object.assign({}, anchorAttrs), otherProps), linkText, children);
35
+ };
36
+ File.propTypes = {
37
+ field: PropTypes.oneOfType([
38
+ PropTypes.shape({
39
+ src: PropTypes.string,
40
+ }),
41
+ PropTypes.shape({
42
+ value: PropTypes.object,
43
+ }),
44
+ ]).isRequired,
45
+ };
46
+ File.displayName = 'File';
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ const styles = {
3
+ height: '100px',
4
+ backgroundImage: 'linear-gradient(45deg, #ffffff 25%, #dcdcdc 25%, #dcdcdc 50%, #ffffff 50%, #ffffff 75%, #dcdcdc 75%, #dcdcdc 100%)',
5
+ backgroundSize: '3px 3px',
6
+ };
7
+ export const HiddenRendering = () => React.createElement("div", { style: styles });
8
+ export const HIDDEN_RENDERING_NAME = 'Hidden Rendering';
@@ -0,0 +1,112 @@
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 { mediaApi } from '@sitecore-jss/sitecore-jss/media';
13
+ import PropTypes from 'prop-types';
14
+ import React from 'react';
15
+ import { addClassName, convertAttributesToReactProps } from '../utils';
16
+ import { getAttributesString } from '../utils';
17
+ const getEditableWrapper = (editableMarkup, ...otherProps) => (
18
+ // create an inline wrapper and use dangerouslySetInnerHTML.
19
+ // if we try to parse the EE value, the parser will strip invalid or disallowed attributes from html elements - and EE uses several
20
+ React.createElement("span", Object.assign({ className: "sc-image-wrapper" }, otherProps, { dangerouslySetInnerHTML: { __html: editableMarkup } })));
21
+ const getImageAttrs = (_a, imageParams, mediaUrlPrefix) => {
22
+ var { src, srcSet } = _a, otherAttrs = __rest(_a, ["src", "srcSet"]);
23
+ if (!src) {
24
+ return null;
25
+ }
26
+ addClassName(otherAttrs);
27
+ const newAttrs = Object.assign({}, otherAttrs);
28
+ // update image URL for jss handler and image rendering params
29
+ const resolvedSrc = mediaApi.updateImageUrl(src, imageParams, mediaUrlPrefix);
30
+ if (srcSet) {
31
+ // replace with HTML-formatted srcset, including updated image URLs
32
+ newAttrs.srcSet = mediaApi.getSrcSet(resolvedSrc, srcSet, imageParams, mediaUrlPrefix);
33
+ }
34
+ // always output original src as fallback for older browsers
35
+ newAttrs.src = resolvedSrc;
36
+ return newAttrs;
37
+ };
38
+ /**
39
+ * @param {ImageField} imageField {ImageField} provides the dynamicMedia which is used to render the image
40
+ * @param {ImageProps.imageParams} imageParams {ImageProp['imageParams']}} provides the image parameters that will be attached to the image URL
41
+ * @param {RegExp} mediaUrlPrefix {RegExp} the url prefix regex used in the mediaApi
42
+ * @param {ImageProps} otherProps {ImageProps} all other props included on the image component
43
+ * @returns Experience Editor Markup
44
+ */
45
+ export const getEEMarkup = (imageField, imageParams, mediaUrlPrefix, otherProps) => {
46
+ // we likely have an experience editor value, should be a string
47
+ const foundImg = mediaApi.findEditorImageTag(imageField.editable);
48
+ if (!foundImg) {
49
+ return getEditableWrapper(imageField.editable);
50
+ }
51
+ const foundImgProps = convertAttributesToReactProps(foundImg.attrs);
52
+ // Note: otherProps may override values from foundImgProps, e.g. `style`, `className` prop
53
+ // We do not attempt to merge.
54
+ const imgAttrs = getImageAttrs(Object.assign(Object.assign({}, foundImgProps), otherProps), imageParams, mediaUrlPrefix);
55
+ if (!imgAttrs) {
56
+ return getEditableWrapper(imageField.editable);
57
+ }
58
+ const imgHtml = `<img ${getAttributesString(imgAttrs)} />`;
59
+ const editableMarkup = imageField.editable.replace(foundImg.imgTag, imgHtml);
60
+ return getEditableWrapper(editableMarkup);
61
+ };
62
+ export const Image = (_a) => {
63
+ var { editable, imageParams, field, mediaUrlPrefix } = _a, otherProps = __rest(_a, ["editable", "imageParams", "field", "mediaUrlPrefix"]);
64
+ const dynamicMedia = field;
65
+ if (!field ||
66
+ (!dynamicMedia.editable && !dynamicMedia.value && !dynamicMedia.src)) {
67
+ return null;
68
+ }
69
+ const imageField = dynamicMedia;
70
+ if (editable && imageField.editable) {
71
+ return getEEMarkup(imageField, imageParams, mediaUrlPrefix, otherProps);
72
+ }
73
+ // some wise-guy/gal is passing in a 'raw' image object value
74
+ const img = dynamicMedia.src
75
+ ? field
76
+ : dynamicMedia.value;
77
+ if (!img) {
78
+ return null;
79
+ }
80
+ const attrs = getImageAttrs(Object.assign(Object.assign({}, img), otherProps), imageParams, mediaUrlPrefix);
81
+ if (attrs) {
82
+ return React.createElement("img", Object.assign({}, attrs));
83
+ }
84
+ return null; // we can't handle the truth
85
+ };
86
+ Image.propTypes = {
87
+ media: PropTypes.oneOfType([
88
+ PropTypes.shape({
89
+ src: PropTypes.string,
90
+ }),
91
+ PropTypes.shape({
92
+ value: PropTypes.object,
93
+ editable: PropTypes.string,
94
+ }),
95
+ ]),
96
+ field: PropTypes.oneOfType([
97
+ PropTypes.shape({
98
+ src: PropTypes.string,
99
+ }),
100
+ PropTypes.shape({
101
+ value: PropTypes.object,
102
+ editable: PropTypes.string,
103
+ }),
104
+ ]),
105
+ editable: PropTypes.bool,
106
+ mediaUrlPrefix: PropTypes.instanceOf(RegExp),
107
+ imageParams: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.number.isRequired, PropTypes.string.isRequired]).isRequired),
108
+ };
109
+ Image.defaultProps = {
110
+ editable: true,
111
+ };
112
+ Image.displayName = 'Image';
@@ -0,0 +1,86 @@
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 Link = forwardRef((_a, ref) => {
15
+ var { field, editable, showLinkTextWithChildrenPresent } = _a, otherProps = __rest(_a, ["field", "editable", "showLinkTextWithChildrenPresent"]);
16
+ const children = otherProps.children;
17
+ const dynamicField = field;
18
+ if (!field ||
19
+ (!dynamicField.editableFirstPart &&
20
+ !dynamicField.value &&
21
+ !dynamicField.href)) {
22
+ return null;
23
+ }
24
+ const resultTags = [];
25
+ // EXPERIENCE EDITOR RENDERING
26
+ if (editable && dynamicField.editableFirstPart) {
27
+ const markup = dynamicField.editableFirstPart + dynamicField.editableLastPart;
28
+ // in an ideal world, we'd pre-render React children here and inject them between editableFirstPart and editableLastPart.
29
+ // However, we cannot combine arbitrary unparsed HTML (innerHTML) based components with actual vDOM components (the children)
30
+ // because the innerHTML is not parsed - it'd make a discontinuous vDOM. So, we'll go for the next best compromise of rendering the link field and children separately
31
+ // as siblings. Should be "good enough" for most cases - and write your own helper if it isn't. Or bring xEditor out of 2006.
32
+ const htmlProps = Object.assign(Object.assign({ className: 'sc-link-wrapper', dangerouslySetInnerHTML: {
33
+ __html: markup,
34
+ } }, otherProps), { key: 'editable' });
35
+ // Exclude children, since 'dangerouslySetInnerHTML' and 'children' can't be set together
36
+ // and children will be added as a sibling
37
+ delete htmlProps.children;
38
+ resultTags.push(React.createElement("span", Object.assign({}, htmlProps)));
39
+ // don't render normal link tag when editing, if no children exist
40
+ // this preserves normal-ish behavior if not using a link body (no hacks required)
41
+ if (!children) {
42
+ return resultTags[0];
43
+ }
44
+ }
45
+ // handle link directly on field for forgetful devs
46
+ const link = dynamicField.href
47
+ ? field
48
+ : dynamicField.value;
49
+ if (!link) {
50
+ return null;
51
+ }
52
+ const anchor = link.linktype !== 'anchor' && link.anchor ? `#${link.anchor}` : '';
53
+ const querystring = link.querystring ? `?${link.querystring}` : '';
54
+ const anchorAttrs = {
55
+ href: `${link.href}${querystring}${anchor}`,
56
+ className: link.class,
57
+ title: link.title,
58
+ target: link.target,
59
+ };
60
+ if (anchorAttrs.target === '_blank' && !anchorAttrs.rel) {
61
+ // information disclosure attack prevention keeps target blank site from getting ref to window.opener
62
+ anchorAttrs.rel = 'noopener noreferrer';
63
+ }
64
+ const linkText = showLinkTextWithChildrenPresent || !children ? link.text || link.href : null;
65
+ resultTags.push(React.createElement('a', Object.assign(Object.assign(Object.assign({}, anchorAttrs), otherProps), { key: 'link', ref }), linkText, children));
66
+ return React.createElement(React.Fragment, null, resultTags);
67
+ });
68
+ export const LinkPropTypes = {
69
+ field: PropTypes.oneOfType([
70
+ PropTypes.shape({
71
+ href: PropTypes.oneOfType([PropTypes.string.isRequired, PropTypes.oneOf([null]).isRequired]),
72
+ }),
73
+ PropTypes.shape({
74
+ value: PropTypes.object,
75
+ editableFirstPart: PropTypes.string,
76
+ editableLastPart: PropTypes.string,
77
+ }),
78
+ ]).isRequired,
79
+ editable: PropTypes.bool,
80
+ showLinkTextWithChildrenPresent: PropTypes.bool,
81
+ };
82
+ Link.propTypes = LinkPropTypes;
83
+ Link.defaultProps = {
84
+ editable: true,
85
+ };
86
+ Link.displayName = 'Link';
@@ -0,0 +1,27 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+ export const MissingComponent = (props) => {
4
+ const componentName = props.rendering && props.rendering.componentName
5
+ ? props.rendering.componentName
6
+ : 'Unnamed Component';
7
+ // error override would mean component is not unimplemented
8
+ !props.errorOverride &&
9
+ console.log(`Component props for unimplemented '${componentName}' component`, props);
10
+ const errorMessage = props.errorOverride ||
11
+ 'JSS component is missing React implementation. See the developer console for more information.';
12
+ return (React.createElement("div", { style: {
13
+ background: 'darkorange',
14
+ outline: '5px solid orange',
15
+ padding: '10px',
16
+ color: 'white',
17
+ maxWidth: '500px',
18
+ } },
19
+ React.createElement("h2", null, componentName),
20
+ React.createElement("p", null, errorMessage)));
21
+ };
22
+ MissingComponent.propTypes = {
23
+ rendering: PropTypes.shape({
24
+ componentName: PropTypes.string,
25
+ }),
26
+ };
27
+ MissingComponent.displayName = 'MissingComponent';