@exdst-sitecore-content-sdk/astro 0.0.1
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 +3 -0
- package/package.json +101 -0
- package/src/client/index.ts +12 -0
- package/src/client/sitecore-astro-client.test.ts +271 -0
- package/src/client/sitecore-astro-client.ts +137 -0
- package/src/components/AstroImage.astro +114 -0
- package/src/components/Date.astro +76 -0
- package/src/components/DefaultEmptyFieldEditingComponentImage.astro +24 -0
- package/src/components/DefaultEmptyFieldEditingComponentText.astro +12 -0
- package/src/components/EditingScripts.astro +49 -0
- package/src/components/EmptyRendering.astro +3 -0
- package/src/components/ErrorBoundary.astro +77 -0
- package/src/components/FieldMetadata.astro +30 -0
- package/src/components/File.astro +46 -0
- package/src/components/HiddenRendering.astro +22 -0
- package/src/components/Image.astro +155 -0
- package/src/components/Link.astro +105 -0
- package/src/components/MissingComponent.astro +39 -0
- package/src/components/Placeholder/EmptyPlaceholder.astro +9 -0
- package/src/components/Placeholder/Placeholder.astro +100 -0
- package/src/components/Placeholder/PlaceholderMetadata.astro +102 -0
- package/src/components/Placeholder/PlaceholderUtils.astro +153 -0
- package/src/components/Placeholder/index.ts +5 -0
- package/src/components/Placeholder/models.ts +82 -0
- package/src/components/Placeholder/placeholder-utils.test.ts +162 -0
- package/src/components/Placeholder/placeholder-utils.ts +80 -0
- package/src/components/RenderWrapper.astro +31 -0
- package/src/components/RichText.astro +59 -0
- package/src/components/Text.astro +97 -0
- package/src/components/sharedTypes/index.ts +1 -0
- package/src/components/sharedTypes/props.ts +17 -0
- package/src/config/define-config.test.ts +526 -0
- package/src/config/define-config.ts +99 -0
- package/src/config/index.ts +1 -0
- package/src/config-cli/define-cli-config.test.ts +95 -0
- package/src/config-cli/define-cli-config.ts +50 -0
- package/src/config-cli/index.ts +1 -0
- package/src/context.ts +68 -0
- package/src/editing/constants.ts +8 -0
- package/src/editing/editing-config-middleware.test.ts +166 -0
- package/src/editing/editing-config-middleware.ts +111 -0
- package/src/editing/editing-render-middleware.test.ts +801 -0
- package/src/editing/editing-render-middleware.ts +288 -0
- package/src/editing/index.ts +16 -0
- package/src/editing/render-middleware.test.ts +57 -0
- package/src/editing/render-middleware.ts +51 -0
- package/src/editing/utils.test.ts +852 -0
- package/src/editing/utils.ts +308 -0
- package/src/enhancers/WithEmptyFieldEditingComponent.astro +56 -0
- package/src/enhancers/WithFieldMetadata.astro +31 -0
- package/src/env.d.ts +12 -0
- package/src/index.ts +16 -0
- package/src/middleware/index.ts +24 -0
- package/src/middleware/middleware.test.ts +507 -0
- package/src/middleware/middleware.ts +167 -0
- package/src/middleware/multisite-middleware.test.ts +672 -0
- package/src/middleware/multisite-middleware.ts +147 -0
- package/src/middleware/robots-middleware.test.ts +113 -0
- package/src/middleware/robots-middleware.ts +47 -0
- package/src/middleware/sitemap-middleware.test.ts +152 -0
- package/src/middleware/sitemap-middleware.ts +65 -0
- package/src/services/component-props-service.ts +182 -0
- package/src/sharedTypes/component-props.ts +17 -0
- package/src/site/index.ts +1 -0
- package/src/test-data/components/Bar.astro +0 -0
- package/src/test-data/components/Baz.astro +0 -0
- package/src/test-data/components/Foo.astro +0 -0
- package/src/test-data/components/Hero.variant.astro +0 -0
- package/src/test-data/components/NotComponent.bsx +0 -0
- package/src/test-data/components/Qux.astro +0 -0
- package/src/test-data/components/folded/Folded.astro +0 -0
- package/src/test-data/components/folded/random-file-2.docx +0 -0
- package/src/test-data/components/random-file.txt +0 -0
- package/src/test-data/helpers.ts +46 -0
- package/src/test-data/personalizeData.ts +63 -0
- package/src/tools/generate-map.ts +83 -0
- package/src/tools/index.ts +8 -0
- package/src/tools/templating/components.test.ts +305 -0
- package/src/tools/templating/components.ts +49 -0
- package/src/tools/templating/constants.ts +4 -0
- package/src/tools/templating/default-component.test.ts +31 -0
- package/src/tools/templating/default-component.ts +63 -0
- package/src/tools/templating/index.ts +2 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/utils.test.ts +48 -0
- package/src/utils/utils.ts +52 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Page } from '@sitecore-content-sdk/core/client';
|
|
2
|
+
import { AstroContentSdkComponent } from '../../sharedTypes/component-props';
|
|
3
|
+
import { ComponentRendering, Field, Item, RouteData } from '@sitecore-content-sdk/core/layout';
|
|
4
|
+
|
|
5
|
+
/** Provided for the component which represents rendering data */
|
|
6
|
+
export type ComponentProps = {
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
rendering: ComponentRendering;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export interface PlaceholderProps {
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
/** Name of the placeholder to render. */
|
|
14
|
+
name: string;
|
|
15
|
+
/** Rendering data to be used when rendering the placeholder. */
|
|
16
|
+
rendering: ComponentRendering | RouteData;
|
|
17
|
+
/**
|
|
18
|
+
* An object of field names/values that are aggregated and propagated through the component tree created by a placeholder.
|
|
19
|
+
* Any component or placeholder rendered by a placeholder will have access to this data via `props.fields`.
|
|
20
|
+
*/
|
|
21
|
+
fields?: {
|
|
22
|
+
[name: string]: Field | Item | Item[];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* An object of rendering parameter names/values that are aggregated and propagated through the component tree created by a placeholder.
|
|
26
|
+
* Any component or placeholder rendered by a placeholder will have access to this data via `props.params`.
|
|
27
|
+
*/
|
|
28
|
+
params?: {
|
|
29
|
+
[name: string]: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Modify final props of component (before render) provided by rendering data.
|
|
33
|
+
* Can be used in case when you need to insert additional data into the component.
|
|
34
|
+
* @param {ComponentProps} componentProps component props to be modified
|
|
35
|
+
* @returns {ComponentProps} modified or initial props
|
|
36
|
+
*/
|
|
37
|
+
modifyComponentProps?: (componentProps: ComponentProps) => ComponentProps;
|
|
38
|
+
/**
|
|
39
|
+
* A component that is rendered in place of any components that are in this placeholder,
|
|
40
|
+
* but do not have a definition in the componentMap (i.e. don't have an implementation)
|
|
41
|
+
*/
|
|
42
|
+
missingComponentComponent?: AstroContentSdkComponent;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A component that is rendered in place of any components that are hidden
|
|
46
|
+
*/
|
|
47
|
+
hiddenRenderingComponent?: AstroContentSdkComponent;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A component that is rendered in place of the placeholder when an error occurs rendering
|
|
51
|
+
* the placeholder
|
|
52
|
+
*/
|
|
53
|
+
errorComponent?: AstroContentSdkComponent;
|
|
54
|
+
/**
|
|
55
|
+
* Page data.
|
|
56
|
+
* This data is passed by the SitecoreProvider.
|
|
57
|
+
*/
|
|
58
|
+
page: Page;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Render HTML or an Astro component when the placeholder contains no content components.
|
|
62
|
+
*/
|
|
63
|
+
renderEmpty?: string | AstroContentSdkComponent;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Render HTML or an Astro component wrapped around the placeholder and components.
|
|
67
|
+
* For HTML wrapper use ${component} string placeholder to set where the placeholder and components should be rendered.
|
|
68
|
+
*/
|
|
69
|
+
render?: string | AstroContentSdkComponent;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Render HTML or an Astro component wrapped around each non-system component added to the placeholder.
|
|
73
|
+
* For HTML wrapper use ${component} string placeholder to set where the component should be rendered.
|
|
74
|
+
* Mutually exclusive with `render`.
|
|
75
|
+
*/
|
|
76
|
+
renderEach?: string | AstroContentSdkComponent;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ComponentForRendering {
|
|
80
|
+
component: AstroContentSdkComponent;
|
|
81
|
+
isEmpty: boolean;
|
|
82
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/* eslint-disable no-unused-expressions */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
import { expect } from 'chai';
|
|
5
|
+
import { createSandbox } from 'sinon';
|
|
6
|
+
import { getPlaceholderRenderings, getSXAParams } from './placeholder-utils';
|
|
7
|
+
import { ComponentRendering } from '@sitecore-content-sdk/core/layout';
|
|
8
|
+
|
|
9
|
+
describe('placeholder-utils', () => {
|
|
10
|
+
const sandbox = createSandbox();
|
|
11
|
+
let consoleWarnStub: any;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
consoleWarnStub = sandbox.stub(console, 'warn');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
sandbox.restore();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('getPlaceholderRenderings', () => {
|
|
22
|
+
it('should return null if rendering does not have placeholders', () => {
|
|
23
|
+
const rendering: ComponentRendering = {
|
|
24
|
+
componentName: 'TestComponent',
|
|
25
|
+
uid: 'test-uid',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const result = getPlaceholderRenderings(rendering, 'test-placeholder', false);
|
|
29
|
+
|
|
30
|
+
expect(result).to.deep.equal([]);
|
|
31
|
+
expect(consoleWarnStub.calledOnce).to.be.true;
|
|
32
|
+
expect(consoleWarnStub.firstCall.args[0]).to.include('test-placeholder');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should return renderings from placeholder by name', () => {
|
|
36
|
+
const expectedRenderings = [
|
|
37
|
+
{
|
|
38
|
+
componentName: 'Component1',
|
|
39
|
+
uid: 'comp1-uid',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
componentName: 'Component2',
|
|
43
|
+
uid: 'comp2-uid',
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const rendering: ComponentRendering = {
|
|
48
|
+
componentName: 'TestComponent',
|
|
49
|
+
uid: 'test-uid',
|
|
50
|
+
placeholders: {
|
|
51
|
+
'test-placeholder': expectedRenderings,
|
|
52
|
+
'other-placeholder': [{ componentName: 'OtherComponent', uid: 'other-uid' }],
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const result = getPlaceholderRenderings(rendering, 'test-placeholder', false);
|
|
57
|
+
|
|
58
|
+
expect(result).to.deep.equal(expectedRenderings);
|
|
59
|
+
expect(consoleWarnStub.called).to.be.false;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should parse dynamic SXA placeholder names correctly', () => {
|
|
63
|
+
const expectedRenderings = [
|
|
64
|
+
{
|
|
65
|
+
componentName: 'DynamicComponent',
|
|
66
|
+
uid: 'dynamic-uid',
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const rendering: ComponentRendering = {
|
|
71
|
+
componentName: 'TestComponent',
|
|
72
|
+
uid: 'test-uid',
|
|
73
|
+
placeholders: {
|
|
74
|
+
'container-{*}': expectedRenderings,
|
|
75
|
+
'other-placeholder': [{ componentName: 'OtherComponent', uid: 'other-uid' }],
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Test non-editing mode - should replace dynamic placeholder
|
|
80
|
+
const result = getPlaceholderRenderings(rendering, 'container-1', false);
|
|
81
|
+
expect(result).to.deep.equal(expectedRenderings);
|
|
82
|
+
expect(rendering.placeholders['container-1']).to.deep.equal(expectedRenderings);
|
|
83
|
+
expect(rendering.placeholders['container-{*}']).to.be.undefined;
|
|
84
|
+
|
|
85
|
+
// Reset rendering for editing mode test
|
|
86
|
+
rendering.placeholders = {
|
|
87
|
+
'container-{*}': expectedRenderings,
|
|
88
|
+
'other-placeholder': [{ componentName: 'OtherComponent', uid: 'other-uid' }],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Test editing mode - should keep original placeholder name
|
|
92
|
+
const editResult = getPlaceholderRenderings(rendering, 'container-1', true);
|
|
93
|
+
expect(editResult).to.deep.equal(expectedRenderings);
|
|
94
|
+
expect(rendering.placeholders['container-{*}']).to.deep.equal(expectedRenderings);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('getSXAParams', () => {
|
|
99
|
+
it('should return GridParameters and Styles when present', () => {
|
|
100
|
+
const rendering: ComponentRendering = {
|
|
101
|
+
componentName: 'TestComponent',
|
|
102
|
+
uid: 'test-uid',
|
|
103
|
+
params: {
|
|
104
|
+
GridParameters: 'col-lg-6',
|
|
105
|
+
Styles: 'custom-class',
|
|
106
|
+
OtherParam: 'other-value',
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const result = getSXAParams(rendering);
|
|
111
|
+
|
|
112
|
+
expect(result).to.deep.equal({
|
|
113
|
+
styles: 'col-lg-6 custom-class',
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should return only GridParameters when Styles not present', () => {
|
|
118
|
+
const rendering: ComponentRendering = {
|
|
119
|
+
componentName: 'TestComponent',
|
|
120
|
+
uid: 'test-uid',
|
|
121
|
+
params: {
|
|
122
|
+
GridParameters: 'col-lg-8',
|
|
123
|
+
OtherParam: 'other-value',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const result = getSXAParams(rendering);
|
|
128
|
+
|
|
129
|
+
expect(result).to.deep.equal({
|
|
130
|
+
styles: 'col-lg-8 ',
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should return only Styles when GridParameters not present', () => {
|
|
135
|
+
const rendering: ComponentRendering = {
|
|
136
|
+
componentName: 'TestComponent',
|
|
137
|
+
uid: 'test-uid',
|
|
138
|
+
params: {
|
|
139
|
+
Styles: 'custom-styles',
|
|
140
|
+
OtherParam: 'other-value',
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const result = getSXAParams(rendering);
|
|
145
|
+
|
|
146
|
+
expect(result).to.deep.equal({
|
|
147
|
+
styles: ' custom-styles',
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should return empty object when no params', () => {
|
|
152
|
+
const rendering: ComponentRendering = {
|
|
153
|
+
componentName: 'TestComponent',
|
|
154
|
+
uid: 'test-uid',
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const result = getSXAParams(rendering);
|
|
158
|
+
|
|
159
|
+
expect(result).to.deep.equal({});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComponentRendering,
|
|
3
|
+
RouteData,
|
|
4
|
+
isDynamicPlaceholder,
|
|
5
|
+
getDynamicPlaceholderPattern,
|
|
6
|
+
} from '@sitecore-content-sdk/core/layout';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the renderings for the specified placeholder from the rendering data.
|
|
10
|
+
* @param {ComponentRendering | RouteData } rendering rendering data
|
|
11
|
+
* @param {string} name placeholder name
|
|
12
|
+
* @param {boolean} isEditing whether components should be rendered in editing mode
|
|
13
|
+
* @returns {ComponentRendering[]} array of component renderings
|
|
14
|
+
*/
|
|
15
|
+
export const getPlaceholderRenderings = (
|
|
16
|
+
rendering: ComponentRendering | RouteData,
|
|
17
|
+
name: string,
|
|
18
|
+
isEditing: boolean
|
|
19
|
+
) => {
|
|
20
|
+
let result;
|
|
21
|
+
let phName = name.slice();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Process (SXA) dynamic placeholders
|
|
25
|
+
* Find and replace the matching dynamic placeholder e.g 'nameOfContainer-{*}' with the requested e.g. 'nameOfContainer-1'.
|
|
26
|
+
* For Metadata EditMode, we need to keep the raw placeholder name in place.
|
|
27
|
+
*/
|
|
28
|
+
if (rendering?.placeholders) {
|
|
29
|
+
Object.keys(rendering.placeholders).forEach((placeholder) => {
|
|
30
|
+
const patternPlaceholder = isDynamicPlaceholder(placeholder)
|
|
31
|
+
? getDynamicPlaceholderPattern(placeholder)
|
|
32
|
+
: null;
|
|
33
|
+
|
|
34
|
+
if (patternPlaceholder && patternPlaceholder.test(phName)) {
|
|
35
|
+
if (isEditing) {
|
|
36
|
+
phName = placeholder;
|
|
37
|
+
} else {
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
rendering.placeholders[phName] = rendering.placeholders[placeholder];
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
delete rendering.placeholders[placeholder];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (rendering && rendering.placeholders && Object.keys(rendering.placeholders).length > 0) {
|
|
48
|
+
result = rendering.placeholders[phName];
|
|
49
|
+
} else {
|
|
50
|
+
result = null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!result) {
|
|
54
|
+
console.warn(
|
|
55
|
+
`Placeholder '${phName}' was not found in the current rendering data`,
|
|
56
|
+
JSON.stringify(rendering, null, 2)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return result;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get SXA specific params from Sitecore rendering params
|
|
67
|
+
* @param {ComponentRendering} rendering rendering object
|
|
68
|
+
* @returns {object} converted SXA params
|
|
69
|
+
*/
|
|
70
|
+
export const getSXAParams = (rendering: ComponentRendering) => {
|
|
71
|
+
if (!rendering.params) return {};
|
|
72
|
+
|
|
73
|
+
const { GridParameters, Styles } = rendering.params;
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
(GridParameters || Styles) && {
|
|
77
|
+
styles: `${GridParameters || ''} ${Styles || ''}`,
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { AstroContentSdkComponent } from '../sharedTypes/component-props';
|
|
3
|
+
|
|
4
|
+
interface RenderWrapperProps {
|
|
5
|
+
wrapper?: AstroContentSdkComponent | string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { wrapper } = Astro.props as RenderWrapperProps;
|
|
9
|
+
|
|
10
|
+
let html;
|
|
11
|
+
let WrapperComponent = wrapper as AstroContentSdkComponent;
|
|
12
|
+
|
|
13
|
+
const isHtmlWrapper = wrapper && typeof wrapper === 'string';
|
|
14
|
+
|
|
15
|
+
if (isHtmlWrapper) {
|
|
16
|
+
const componentHtml = await Astro.slots.render('default');
|
|
17
|
+
html = wrapper.replace('${component}', componentHtml);
|
|
18
|
+
}
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<>
|
|
22
|
+
{!wrapper && <slot />}
|
|
23
|
+
{
|
|
24
|
+
wrapper && !isHtmlWrapper && (
|
|
25
|
+
<WrapperComponent>
|
|
26
|
+
<slot />
|
|
27
|
+
</WrapperComponent>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
{isHtmlWrapper && <Fragment set:html={html} />}
|
|
31
|
+
</>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { EditableFieldProps } from './sharedTypes';
|
|
3
|
+
import {
|
|
4
|
+
FieldMetadata,
|
|
5
|
+
isFieldValueEmpty,
|
|
6
|
+
} from '@sitecore-content-sdk/core/layout';
|
|
7
|
+
import WithEmptyFieldEditingComponent from '../enhancers/WithEmptyFieldEditingComponent.astro';
|
|
8
|
+
import WithFieldMetadata from '../enhancers/WithFieldMetadata.astro';
|
|
9
|
+
import DefaultEmptyFieldEditingComponentText from './DefaultEmptyFieldEditingComponentText.astro';
|
|
10
|
+
|
|
11
|
+
export interface RichTextField extends FieldMetadata {
|
|
12
|
+
value?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RichTextProps extends EditableFieldProps {
|
|
16
|
+
[htmlAttributes: string]: unknown;
|
|
17
|
+
/** The text field data. */
|
|
18
|
+
field: RichTextField;
|
|
19
|
+
/**
|
|
20
|
+
* The HTML element that will wrap the contents of the field.
|
|
21
|
+
*/
|
|
22
|
+
tag?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
field,
|
|
27
|
+
tag = 'div',
|
|
28
|
+
editable = true,
|
|
29
|
+
emptyFieldEditingComponent,
|
|
30
|
+
} = Astro.props as RichTextProps;
|
|
31
|
+
|
|
32
|
+
const isEmptyField = isFieldValueEmpty(field);
|
|
33
|
+
|
|
34
|
+
const Tag = tag;
|
|
35
|
+
|
|
36
|
+
const attrs = (function () {
|
|
37
|
+
const { field, ...attrs } = Astro.props;
|
|
38
|
+
const { tag, ...finalAttrs } = attrs;
|
|
39
|
+
return finalAttrs;
|
|
40
|
+
})();
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
{
|
|
44
|
+
(
|
|
45
|
+
<WithFieldMetadata field={field} editable={editable}>
|
|
46
|
+
<WithEmptyFieldEditingComponent
|
|
47
|
+
field={field}
|
|
48
|
+
editable={editable}
|
|
49
|
+
defaultEmptyFieldEditingComponent={
|
|
50
|
+
DefaultEmptyFieldEditingComponentText
|
|
51
|
+
}
|
|
52
|
+
emptyFieldEditingComponent={emptyFieldEditingComponent}
|
|
53
|
+
{...attrs}
|
|
54
|
+
>
|
|
55
|
+
{!isEmptyField && <Tag {...attrs} set:html={field.value} />}
|
|
56
|
+
</WithEmptyFieldEditingComponent>
|
|
57
|
+
</WithFieldMetadata>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
FieldMetadata,
|
|
4
|
+
isFieldValueEmpty,
|
|
5
|
+
} from '@sitecore-content-sdk/core/layout';
|
|
6
|
+
import { EditableFieldProps } from './sharedTypes';
|
|
7
|
+
import WithFieldMetadata from '../enhancers/WithFieldMetadata.astro';
|
|
8
|
+
import WithEmptyFieldEditingComponent from '../enhancers/WithEmptyFieldEditingComponent.astro';
|
|
9
|
+
import DefaultEmptyFieldEditingComponentText from './DefaultEmptyFieldEditingComponentText.astro';
|
|
10
|
+
|
|
11
|
+
export interface TextField extends FieldMetadata {
|
|
12
|
+
value?: string | number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TextProps extends EditableFieldProps {
|
|
16
|
+
[htmlAttributes: string]: unknown;
|
|
17
|
+
/** The text field data. */
|
|
18
|
+
field: TextField;
|
|
19
|
+
/**
|
|
20
|
+
* The HTML element that will wrap the contents of the field.
|
|
21
|
+
*/
|
|
22
|
+
tag?: string;
|
|
23
|
+
/**
|
|
24
|
+
* If false, HTML-encoding of the field value is disabled and the value is rendered as-is.
|
|
25
|
+
*/
|
|
26
|
+
encode?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
field,
|
|
31
|
+
tag,
|
|
32
|
+
editable = true,
|
|
33
|
+
encode = true,
|
|
34
|
+
emptyFieldEditingComponent,
|
|
35
|
+
...otherProps
|
|
36
|
+
} = Astro.props as TextProps;
|
|
37
|
+
|
|
38
|
+
const isEmptyField = isFieldValueEmpty(field);
|
|
39
|
+
|
|
40
|
+
// can't use editable value if we want to output unencoded
|
|
41
|
+
const isEditable = !encode ? false : editable;
|
|
42
|
+
|
|
43
|
+
let output: string | number | string[] = '';
|
|
44
|
+
if (!isEmptyField) {
|
|
45
|
+
output = field.value === undefined ? '' : field.value;
|
|
46
|
+
|
|
47
|
+
// when string value isn't formatted, we should format line breaks
|
|
48
|
+
const splitted = String(output).split('\n');
|
|
49
|
+
|
|
50
|
+
if (splitted.length) {
|
|
51
|
+
const formatted: string[] = [];
|
|
52
|
+
|
|
53
|
+
splitted.forEach((str, i) => {
|
|
54
|
+
const isLast = i === splitted.length - 1;
|
|
55
|
+
|
|
56
|
+
formatted.push(str);
|
|
57
|
+
|
|
58
|
+
if (!isLast) {
|
|
59
|
+
formatted.push('<br />');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
output = formatted;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const Tag = tag || 'span';
|
|
68
|
+
|
|
69
|
+
const attrs: {
|
|
70
|
+
[htmlAttributes: string]: unknown;
|
|
71
|
+
} = {
|
|
72
|
+
...otherProps,
|
|
73
|
+
};
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
{
|
|
77
|
+
(
|
|
78
|
+
<WithFieldMetadata field={field} editable={isEditable}>
|
|
79
|
+
<WithEmptyFieldEditingComponent
|
|
80
|
+
field={field}
|
|
81
|
+
editable={isEditable}
|
|
82
|
+
defaultEmptyFieldEditingComponent={
|
|
83
|
+
DefaultEmptyFieldEditingComponentText
|
|
84
|
+
}
|
|
85
|
+
emptyFieldEditingComponent={emptyFieldEditingComponent}
|
|
86
|
+
{...attrs}
|
|
87
|
+
>
|
|
88
|
+
{!isEmptyField && (
|
|
89
|
+
<>
|
|
90
|
+
{(tag || !encode) && <Tag {...attrs} set:html={output} />}
|
|
91
|
+
{(!tag || encode) && <Fragment {...attrs} set:html={output} />}
|
|
92
|
+
</>
|
|
93
|
+
)}
|
|
94
|
+
</WithEmptyFieldEditingComponent>
|
|
95
|
+
</WithFieldMetadata>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './props';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AstroContentSdkComponent } from "../../sharedTypes/component-props";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared editing field props
|
|
5
|
+
*/
|
|
6
|
+
export interface EditableFieldProps {
|
|
7
|
+
/**
|
|
8
|
+
* Can be used to explicitly disable inline editing.
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
editable?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Custom element to render in Pages in edit mode if field value is empty
|
|
14
|
+
*/
|
|
15
|
+
emptyFieldEditingComponent?: AstroContentSdkComponent;
|
|
16
|
+
}
|
|
17
|
+
|