@exdst-sitecore-content-sdk/astro 0.0.16 → 0.0.19

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 (110) hide show
  1. package/README.md +3 -3
  2. package/package.json +41 -42
  3. package/src/client/index.ts +1 -1
  4. package/src/client/sitecore-astro-client.test.ts +41 -20
  5. package/src/client/sitecore-astro-client.ts +74 -57
  6. package/src/components/AstroImage.astro +2 -2
  7. package/src/components/AstroImage.astro.test.ts +542 -0
  8. package/src/components/Date.astro +5 -1
  9. package/src/components/Date.astro.test.ts +197 -0
  10. package/src/components/DefaultEmptyFieldEditingComponentImage.astro +4 -0
  11. package/src/components/DefaultEmptyFieldEditingComponentText.astro +4 -0
  12. package/src/components/EditingScripts.astro +2 -2
  13. package/src/components/EditingScripts.astro.test.ts +267 -0
  14. package/src/components/ErrorBoundary.astro +8 -9
  15. package/src/components/ErrorBoundary.astro.test.ts +252 -0
  16. package/src/components/ErrorComponent.astro +16 -0
  17. package/src/components/ErrorComponent.astro.test.ts +31 -0
  18. package/src/components/FieldMetadata.astro +1 -1
  19. package/src/components/FieldMetadata.astro.test.ts +40 -0
  20. package/src/components/File.astro +5 -1
  21. package/src/components/File.astro.test.ts +68 -0
  22. package/src/components/HiddenRendering.astro.test.ts +36 -0
  23. package/src/components/Image.astro +18 -4
  24. package/src/components/Image.astro.test.ts +438 -0
  25. package/src/components/Link.astro +13 -1
  26. package/src/components/Link.astro.test.ts +261 -0
  27. package/src/components/MissingComponent.astro.test.ts +21 -0
  28. package/src/components/Placeholder/Placeholder.astro +18 -23
  29. package/src/components/Placeholder/Placeholder.astro.test.ts +1088 -0
  30. package/src/components/Placeholder/PlaceholderMetadata.astro +24 -18
  31. package/src/components/Placeholder/PlaceholderMetadata.astro.test.ts +228 -0
  32. package/src/components/Placeholder/PlaceholderUtils.astro +21 -40
  33. package/src/components/Placeholder/PlaceholderUtils.astro.test.ts +149 -0
  34. package/src/components/Placeholder/models.ts +26 -17
  35. package/src/components/Placeholder/placeholder-utils.test.ts +153 -6
  36. package/src/components/Placeholder/placeholder-utils.ts +33 -11
  37. package/src/components/RichText.astro +9 -1
  38. package/src/components/RichText.astro.test.ts +205 -0
  39. package/src/components/Text.astro +15 -3
  40. package/src/components/Text.astro.test.ts +273 -0
  41. package/src/config/define-config.test.ts +5 -5
  42. package/src/config/define-config.ts +22 -42
  43. package/src/config-cli/define-cli-config.test.ts +5 -12
  44. package/src/config-cli/define-cli-config.ts +4 -8
  45. package/src/context.ts +42 -11
  46. package/src/debug.ts +13 -0
  47. package/src/editing/editing-config-middleware.test.ts +5 -7
  48. package/src/editing/editing-config-middleware.ts +11 -7
  49. package/src/editing/editing-render-middleware.test.ts +366 -24
  50. package/src/editing/editing-render-middleware.ts +34 -12
  51. package/src/editing/index.ts +2 -0
  52. package/src/editing/render-middleware.test.ts +1 -1
  53. package/src/editing/render-middleware.ts +1 -1
  54. package/src/editing/types.ts +39 -0
  55. package/src/editing/utils.test.ts +364 -4
  56. package/src/editing/utils.ts +82 -24
  57. package/src/enhancers/WithEmptyFieldEditingComponent.astro +1 -1
  58. package/src/enhancers/WithEmptyFieldEditingComponent.astro.test.ts +380 -0
  59. package/src/enhancers/WithFieldMetadata.astro.test.ts +113 -0
  60. package/src/index.ts +10 -7
  61. package/src/middleware/index.ts +4 -12
  62. package/src/middleware/middleware.test.ts +13 -0
  63. package/src/middleware/middleware.ts +12 -3
  64. package/src/middleware/multisite-middleware.test.ts +45 -50
  65. package/src/middleware/multisite-middleware.ts +33 -6
  66. package/src/middleware/robots-middleware.test.ts +20 -4
  67. package/src/middleware/robots-middleware.ts +10 -3
  68. package/src/middleware/sitemap-middleware.test.ts +35 -3
  69. package/src/middleware/sitemap-middleware.ts +7 -6
  70. package/src/services/component-props-service.ts +7 -6
  71. package/src/sharedTypes/component-props.ts +15 -4
  72. package/src/site/index.ts +1 -1
  73. package/src/tests/astro-helpers.ts +61 -0
  74. package/src/tests/test-components/CustomErrorComponent.astro +3 -0
  75. package/src/tests/test-components/CustomHiddenRendering.astro +10 -0
  76. package/src/tests/test-components/CustomMissingComponent.astro +9 -0
  77. package/src/tests/test-components/DownloadCallout.astro +12 -0
  78. package/src/tests/test-components/EmptyFieldEditingComponent.astro +5 -0
  79. package/src/tests/test-components/ErrorBoundaryWithError.astro +10 -0
  80. package/src/tests/test-components/Home.astro +12 -0
  81. package/src/tests/test-components/SxaRichText.astro +23 -0
  82. package/src/tests/test-components/SxaRichTextDefault.astro +7 -0
  83. package/src/tests/test-components/SxaRichTextWithTitle.astro +8 -0
  84. package/src/tests/test-components/TestComponent.astro +9 -0
  85. package/src/tests/test-components/TestComponentWithError.astro +4 -0
  86. package/src/tests/test-components/TestComponentWithField.astro +17 -0
  87. package/src/tests/test-components/TestHeader.astro +8 -0
  88. package/src/tests/test-components/TestLogo.astro +5 -0
  89. package/src/tests/test-components/TestParentWrapperComponent.astro +5 -0
  90. package/src/tests/test-components/TestWrapperComponent.astro +5 -0
  91. package/src/tests/test-data/metadata-data.ts +86 -0
  92. package/src/tests/test-data/normal-mode-data.ts +466 -0
  93. package/src/tests/vitest.setup.ts +4 -0
  94. package/src/tools/generate-map.ts +4 -3
  95. package/src/tools/index.ts +2 -4
  96. package/src/tools/templating/components.test.ts +100 -87
  97. package/src/tools/templating/components.ts +2 -1
  98. package/src/tools/templating/default-component.ts +3 -8
  99. package/src/utils/utils.ts +20 -2
  100. /package/src/{test-data → tests}/helpers.ts +0 -0
  101. /package/src/{test-data → tests}/personalizeData.ts +0 -0
  102. /package/src/{test-data/components → tests/test-components/map-components}/Bar.astro +0 -0
  103. /package/src/{test-data/components → tests/test-components/map-components}/Baz.astro +0 -0
  104. /package/src/{test-data/components → tests/test-components/map-components}/Foo.astro +0 -0
  105. /package/src/{test-data/components → tests/test-components/map-components}/Hero.variant.astro +0 -0
  106. /package/src/{test-data/components → tests/test-components/map-components}/NotComponent.bsx +0 -0
  107. /package/src/{test-data/components → tests/test-components/map-components}/Qux.astro +0 -0
  108. /package/src/{test-data/components → tests/test-components/map-components}/folded/Folded.astro +0 -0
  109. /package/src/{test-data/components → tests/test-components/map-components}/folded/random-file-2.docx +0 -0
  110. /package/src/{test-data/components → tests/test-components/map-components}/random-file.txt +0 -0
@@ -3,8 +3,13 @@
3
3
  /* eslint-disable @typescript-eslint/no-explicit-any */
4
4
  import { expect } from 'chai';
5
5
  import { createSandbox } from 'sinon';
6
- import { getPlaceholderRenderings, getSXAParams } from './placeholder-utils';
7
- import { ComponentRendering } from '@sitecore-content-sdk/core/layout';
6
+ import {
7
+ getChildComponentProps,
8
+ getPlaceholderRenderings,
9
+ getSXAParams,
10
+ } from './placeholder-utils';
11
+ import { ComponentRendering } from '@sitecore-content-sdk/content/layout';
12
+ import { PlaceholderProps } from './models';
8
13
 
9
14
  describe('placeholder-utils', () => {
10
15
  const sandbox = createSandbox();
@@ -79,8 +84,8 @@ describe('placeholder-utils', () => {
79
84
  // Test non-editing mode - should replace dynamic placeholder
80
85
  const result = getPlaceholderRenderings(rendering, 'container-1', false);
81
86
  expect(result).to.deep.equal(expectedRenderings);
82
- expect(rendering.placeholders['container-1']).to.deep.equal(expectedRenderings);
83
- expect(rendering.placeholders['container-{*}']).to.be.undefined;
87
+ expect(rendering.placeholders?.['container-1']).to.deep.equal(expectedRenderings);
88
+ expect(rendering.placeholders?.['container-{*}']).to.be.undefined;
84
89
 
85
90
  // Reset rendering for editing mode test
86
91
  rendering.placeholders = {
@@ -148,7 +153,7 @@ describe('placeholder-utils', () => {
148
153
  });
149
154
  });
150
155
 
151
- it('should return empty object when no params', () => {
156
+ it('should return empty styles string when no params', () => {
152
157
  const rendering: ComponentRendering = {
153
158
  componentName: 'TestComponent',
154
159
  uid: 'test-uid',
@@ -156,7 +161,149 @@ describe('placeholder-utils', () => {
156
161
 
157
162
  const result = getSXAParams(rendering);
158
163
 
159
- expect(result).to.deep.equal({});
164
+ expect(result).to.deep.equal({ styles: '' });
165
+ });
166
+ });
167
+
168
+ describe('getChildComponentProps', () => {
169
+ it('should merge placeholder and rendering fields', () => {
170
+ const placeholderProps: PlaceholderProps = {
171
+ name: 'test-placeholder',
172
+ rendering: { componentName: 'Test', uid: 'test-uid' },
173
+ page: {
174
+ layout: {},
175
+ locale: 'en',
176
+ mode: {
177
+ name: 'normal',
178
+ isNormal: true,
179
+ isPreview: false,
180
+ isEditing: false,
181
+ isDesignLibrary: false,
182
+ designLibrary: { isVariantGeneration: false },
183
+ },
184
+ },
185
+ fields: {
186
+ placeholderField: { value: 'placeholder-value' },
187
+ sharedField: { value: 'placeholder-shared-value' },
188
+ },
189
+ };
190
+
191
+ const componentRendering: ComponentRendering = {
192
+ componentName: 'TestComponent',
193
+ uid: 'test-uid',
194
+ fields: {
195
+ renderingField: { value: 'rendering-value' },
196
+ sharedField: { value: 'rendering-shared-value' },
197
+ },
198
+ };
199
+
200
+ const result = getChildComponentProps(placeholderProps, componentRendering);
201
+
202
+ expect(result.fields).to.deep.equal({
203
+ placeholderField: { value: 'placeholder-value' },
204
+ renderingField: { value: 'rendering-value' },
205
+ sharedField: { value: 'rendering-shared-value' }, // rendering should override placeholder
206
+ });
207
+ expect(result.rendering).to.equal(componentRendering);
208
+ });
209
+
210
+ it('should merge placeholder and rendering params', () => {
211
+ const placeholderProps: PlaceholderProps = {
212
+ name: 'test-placeholder',
213
+ rendering: { componentName: 'Test', uid: 'test-uid' },
214
+ page: {
215
+ layout: {},
216
+ locale: 'en',
217
+ mode: {
218
+ name: 'normal',
219
+ isNormal: true,
220
+ isPreview: false,
221
+ isEditing: false,
222
+ isDesignLibrary: false,
223
+ designLibrary: { isVariantGeneration: false },
224
+ },
225
+ },
226
+ params: {
227
+ placeholderParam: 'placeholder-param-value',
228
+ sharedParam: 'placeholder-shared-param',
229
+ },
230
+ };
231
+
232
+ const componentRendering: ComponentRendering = {
233
+ componentName: 'TestComponent',
234
+ uid: 'test-uid',
235
+ params: {
236
+ renderingParam: 'rendering-param-value',
237
+ sharedParam: 'rendering-shared-param',
238
+ GridParameters: 'col-lg-6',
239
+ Styles: 'custom-class',
240
+ },
241
+ };
242
+
243
+ const result = getChildComponentProps(placeholderProps, componentRendering);
244
+
245
+ expect(result.params).to.deep.equal({
246
+ placeholderParam: 'placeholder-param-value',
247
+ renderingParam: 'rendering-param-value',
248
+ sharedParam: 'rendering-shared-param', // rendering should override placeholder
249
+ GridParameters: 'col-lg-6',
250
+ Styles: 'custom-class',
251
+ styles: 'col-lg-6 custom-class', // SXA styles should be added
252
+ });
253
+ expect(result.rendering).to.equal(componentRendering);
254
+ });
255
+
256
+ it('should return minimal child component props object', () => {
257
+ const placeholderProps: PlaceholderProps = {
258
+ name: 'test-placeholder',
259
+ rendering: { componentName: 'Test', uid: 'test-uid' },
260
+ page: {
261
+ layout: {},
262
+ locale: 'en',
263
+ mode: {
264
+ name: 'normal',
265
+ isNormal: true,
266
+ isPreview: false,
267
+ isEditing: false,
268
+ isDesignLibrary: false,
269
+ designLibrary: { isVariantGeneration: false },
270
+ },
271
+ },
272
+ componentMap: new Map(),
273
+ customProp: 'custom-value',
274
+ // missingComponentComponent: MissingComponent,
275
+ // hiddenRenderingComponent: HiddenRendering,
276
+ };
277
+
278
+ const componentRendering: ComponentRendering = {
279
+ componentName: 'TestComponent',
280
+ uid: 'test-uid',
281
+ fields: {
282
+ testField: { value: 'test-value' },
283
+ },
284
+ params: {
285
+ testParam: 'test-param',
286
+ },
287
+ };
288
+
289
+ const result = getChildComponentProps(placeholderProps, componentRendering);
290
+
291
+ // getChildComponentProps returns only fields, params, and rendering
292
+ expect(result.rendering).to.equal(componentRendering);
293
+ expect(result.fields).to.deep.equal({
294
+ testField: { value: 'test-value' },
295
+ });
296
+ expect(result.params).to.deep.equal({
297
+ testParam: 'test-param',
298
+ });
299
+
300
+ // getChildComponentProps does not include these props
301
+ expect((result as any).key).to.be.undefined;
302
+ expect((result as any).customProp).to.be.undefined;
303
+ expect((result as any).componentMap).to.be.undefined;
304
+ expect((result as any).missingComponentComponent).to.be.undefined;
305
+ expect((result as any).hiddenRenderingComponent).to.be.undefined;
306
+ expect((result as any).name).to.be.undefined;
160
307
  });
161
308
  });
162
309
  });
@@ -3,10 +3,11 @@ import {
3
3
  RouteData,
4
4
  isDynamicPlaceholder,
5
5
  getDynamicPlaceholderPattern,
6
- } from '@sitecore-content-sdk/core/layout';
6
+ } from '@sitecore-content-sdk/content/layout';
7
+ import { ChildComponentProps, PlaceholderProps } from './models';
7
8
 
8
9
  /**
9
- * Get the renderings for the specified placeholder from the rendering data.
10
+ * Get the renderings for the specified placeholder from the rendering layout data.
10
11
  * @param {ComponentRendering | RouteData } rendering rendering data
11
12
  * @param {string} name placeholder name
12
13
  * @param {boolean} isEditing whether components should be rendered in editing mode
@@ -26,19 +27,17 @@ export const getPlaceholderRenderings = (
26
27
  * For Metadata EditMode, we need to keep the raw placeholder name in place.
27
28
  */
28
29
  if (rendering?.placeholders) {
29
- Object.keys(rendering.placeholders).forEach((placeholder) => {
30
- const patternPlaceholder = isDynamicPlaceholder(placeholder)
31
- ? getDynamicPlaceholderPattern(placeholder)
30
+ Object.entries(rendering.placeholders).forEach(([key, value]) => {
31
+ const patternPlaceholder = isDynamicPlaceholder(key)
32
+ ? getDynamicPlaceholderPattern(key)
32
33
  : null;
33
34
 
34
35
  if (patternPlaceholder && patternPlaceholder.test(phName)) {
35
36
  if (isEditing) {
36
- phName = placeholder;
37
+ phName = key;
37
38
  } else {
38
- // @ts-ignore
39
- rendering.placeholders[phName] = rendering.placeholders[placeholder];
40
- // @ts-ignore
41
- delete rendering.placeholders[placeholder];
39
+ rendering.placeholders![phName] = value;
40
+ delete rendering.placeholders![key];
42
41
  }
43
42
  }
44
43
  });
@@ -68,7 +67,7 @@ export const getPlaceholderRenderings = (
68
67
  * @returns {object} converted SXA params
69
68
  */
70
69
  export const getSXAParams = (rendering: ComponentRendering) => {
71
- if (!rendering.params) return {};
70
+ if (!rendering.params) return { styles: '' };
72
71
 
73
72
  const { GridParameters, Styles } = rendering.params;
74
73
 
@@ -78,3 +77,26 @@ export const getSXAParams = (rendering: ComponentRendering) => {
78
77
  }
79
78
  );
80
79
  };
80
+
81
+ /**
82
+ * Merge specific placeholder props with component field and params content props.
83
+ * @param {PlaceholderProps} placeholderProps placeholder props
84
+ * @param {ComponentRendering} componentRendering component rendering
85
+ * @returns {ComponentProps} merged props
86
+ */
87
+ export function getChildComponentProps<T extends PlaceholderProps>(
88
+ placeholderProps: T,
89
+ componentRendering: ComponentRendering
90
+ ): ChildComponentProps {
91
+ const fields = { ...(placeholderProps.fields || {}), ...(componentRendering.fields || {}) };
92
+ const params = { ...(placeholderProps.params || {}), ...(componentRendering.params || {}) };
93
+ return {
94
+ fields,
95
+ params: {
96
+ ...params,
97
+ // Provide SXA styles
98
+ ...getSXAParams(componentRendering),
99
+ },
100
+ rendering: componentRendering,
101
+ };
102
+ }
@@ -3,15 +3,23 @@ import { EditableFieldProps } from './sharedTypes';
3
3
  import {
4
4
  FieldMetadata,
5
5
  isFieldValueEmpty,
6
- } from '@sitecore-content-sdk/core/layout';
6
+ } from '@sitecore-content-sdk/content/layout';
7
7
  import WithEmptyFieldEditingComponent from '../enhancers/WithEmptyFieldEditingComponent.astro';
8
8
  import WithFieldMetadata from '../enhancers/WithFieldMetadata.astro';
9
9
  import DefaultEmptyFieldEditingComponentText from './DefaultEmptyFieldEditingComponentText.astro';
10
10
 
11
+ /**
12
+ * The interface for the RichText field.
13
+ * @public
14
+ */
11
15
  export interface RichTextField extends FieldMetadata {
12
16
  value?: string;
13
17
  }
14
18
 
19
+ /**
20
+ * The interface for the RichText component props.
21
+ * @public
22
+ */
15
23
  export interface RichTextProps extends EditableFieldProps {
16
24
  [htmlAttributes: string]: unknown;
17
25
  /** The text field data. */
@@ -0,0 +1,205 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { renderAstroComponent } from '../tests/astro-helpers';
3
+ import RichText from './RichText.astro';
4
+ import EmptyFieldEditingComponent from '../tests/test-components/EmptyFieldEditingComponent.astro';
5
+
6
+ describe('<RichText />', () => {
7
+ test('should render nothing with missing field', async () => {
8
+ const field = null!;
9
+
10
+ const rendered = (
11
+ await renderAstroComponent(RichText, {
12
+ props: { field: field },
13
+ })
14
+ ).querySelectorAll('div');
15
+
16
+ expect(rendered).to.have.length(0);
17
+ });
18
+
19
+ test('should render nothing with empty value', async () => {
20
+ const field = {
21
+ value: '',
22
+ };
23
+
24
+ const rendered = (
25
+ await renderAstroComponent(RichText, {
26
+ props: { field: field },
27
+ })
28
+ ).querySelectorAll('div');
29
+
30
+ expect(rendered).to.have.length(0);
31
+ });
32
+
33
+ test('should render nothing with missing value', async () => {
34
+ const field = {};
35
+ const rendered = (
36
+ await renderAstroComponent(RichText, {
37
+ props: { field: field },
38
+ })
39
+ ).querySelectorAll('div');
40
+ expect(rendered).to.have.length(0);
41
+ });
42
+
43
+ test('should render value with editing explicitly disabled', async () => {
44
+ const field = {
45
+ value: 'value',
46
+ };
47
+ const rendered = (
48
+ await renderAstroComponent(RichText, {
49
+ props: { field: field, editable: false },
50
+ })
51
+ ).querySelectorAll('div');
52
+
53
+ expect(rendered).to.have.length(1);
54
+ expect(rendered[0].innerHTML).to.contain('value');
55
+ });
56
+
57
+ test('should render value with with just a value', async () => {
58
+ const field = {
59
+ value: 'value',
60
+ };
61
+ const rendered = (
62
+ await renderAstroComponent(RichText, {
63
+ props: { field: field },
64
+ })
65
+ ).querySelectorAll('div');
66
+
67
+ expect(rendered).to.have.length(1);
68
+ expect(rendered[0].innerHTML).to.contain('value');
69
+ });
70
+
71
+ test('should render embedded html as-is', async () => {
72
+ const field = {
73
+ value: '<input type="text">some crazy stuff<script code="whaaaat">uh oh</script>',
74
+ };
75
+ const rendered = (
76
+ await renderAstroComponent(RichText, {
77
+ props: { field: field },
78
+ })
79
+ ).querySelectorAll('div');
80
+
81
+ expect(rendered).to.have.length(1);
82
+ expect(rendered[0].innerHTML).to.contain(field.value);
83
+ });
84
+
85
+ test('should render tag with a tag provided', async () => {
86
+ const field = {
87
+ value: 'value',
88
+ };
89
+ const rendered = (
90
+ await renderAstroComponent(RichText, {
91
+ props: { field: field, tag: 'p' },
92
+ })
93
+ ).querySelectorAll('p');
94
+
95
+ expect(rendered).to.have.length(1);
96
+ expect(rendered[0].innerHTML).to.contain('value');
97
+ });
98
+
99
+ test('should render other attributes with other props provided', async () => {
100
+ const field = {
101
+ value: 'value',
102
+ };
103
+ const rendered = (
104
+ await renderAstroComponent(RichText, {
105
+ props: { field: field, tag: 'h1', class: 'cssClass', id: 'lorem' },
106
+ })
107
+ ).querySelectorAll('h1');
108
+ expect(rendered).to.have.length(1);
109
+ expect(rendered[0].outerHTML).to.contain('<h1 class="cssClass" id="lorem">');
110
+ expect(rendered[0].outerHTML).to.contain('value');
111
+ });
112
+
113
+ describe('edit mode', () => {
114
+ const testMetadata = {
115
+ contextItem: {
116
+ id: '{09A07660-6834-476C-B93B-584248D3003B}',
117
+ language: 'en',
118
+ revision: 'a0b36ce0a7db49418edf90eb9621e145',
119
+ version: 1,
120
+ },
121
+ fieldId: '{414061F4-FBB1-4591-BC37-BFFA67F745EB}',
122
+ fieldType: 'single-line',
123
+ rawValue: 'Test1',
124
+ };
125
+
126
+ test('should render field metadata component when metadata property is present', async () => {
127
+ const field = {
128
+ value: 'value',
129
+ metadata: testMetadata,
130
+ };
131
+
132
+ const rendered = await renderAstroComponent(RichText, {
133
+ props: { field: field },
134
+ });
135
+
136
+ expect(rendered.innerHTML).to.equal(
137
+ [
138
+ `<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
139
+ testMetadata
140
+ )}</code>`,
141
+ '<div>value</div>',
142
+ '<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
143
+ ].join('')
144
+ );
145
+ });
146
+
147
+ test('should render default empty field component when field value is empty', async () => {
148
+ const field = {
149
+ value: '',
150
+ metadata: testMetadata,
151
+ };
152
+
153
+ const rendered = await renderAstroComponent(RichText, {
154
+ props: { field: field },
155
+ });
156
+
157
+ expect(rendered.innerHTML).to.equal(
158
+ [
159
+ `<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
160
+ testMetadata
161
+ )}</code>`,
162
+ '<span>[No text in field]</span>',
163
+ '<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
164
+ ].join('')
165
+ );
166
+ });
167
+
168
+ test('should render custom empty field component when provided, when field value is empty', async () => {
169
+ const field = {
170
+ value: '',
171
+ metadata: testMetadata,
172
+ };
173
+
174
+ const rendered = await renderAstroComponent(RichText, {
175
+ props: {
176
+ field: field,
177
+ emptyFieldEditingComponent: EmptyFieldEditingComponent,
178
+ },
179
+ });
180
+
181
+ expect(rendered.innerHTML).to.equal(
182
+ [
183
+ `<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
184
+ testMetadata
185
+ )}</code>`,
186
+ '<span class="empty-field-value-placeholder">Custom Empty field value</span>',
187
+ '<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
188
+ ].join('')
189
+ );
190
+ });
191
+
192
+ test('should render nothing when field value is empty, when editing is explicitly disabled ', async () => {
193
+ const field = {
194
+ value: '',
195
+ metadata: testMetadata,
196
+ };
197
+
198
+ const rendered = await renderAstroComponent(RichText, {
199
+ props: { field: field, editable: false },
200
+ });
201
+
202
+ expect(rendered.innerHTML).to.equal('');
203
+ });
204
+ });
205
+ });
@@ -2,16 +2,24 @@
2
2
  import {
3
3
  FieldMetadata,
4
4
  isFieldValueEmpty,
5
- } from '@sitecore-content-sdk/core/layout';
5
+ } from '@sitecore-content-sdk/content/layout';
6
6
  import { EditableFieldProps } from './sharedTypes';
7
7
  import WithFieldMetadata from '../enhancers/WithFieldMetadata.astro';
8
8
  import WithEmptyFieldEditingComponent from '../enhancers/WithEmptyFieldEditingComponent.astro';
9
9
  import DefaultEmptyFieldEditingComponentText from './DefaultEmptyFieldEditingComponentText.astro';
10
10
 
11
+ /**
12
+ * The interface for the Text field.
13
+ * @public
14
+ */
11
15
  export interface TextField extends FieldMetadata {
12
16
  value?: string | number;
13
17
  }
14
18
 
19
+ /**
20
+ * The interface for the Text component props.
21
+ * @public
22
+ */
15
23
  export interface TextProps extends EditableFieldProps {
16
24
  [htmlAttributes: string]: unknown;
17
25
  /** The text field data. */
@@ -87,8 +95,12 @@ const attrs: {
87
95
  >
88
96
  {!isEmptyField && (
89
97
  <>
90
- {(tag || !encode) && <Tag {...attrs} set:html={output} />}
91
- {(!tag || encode) && <Fragment {...attrs} set:html={output} />}
98
+ {(field?.metadata || tag || !encode) && (
99
+ <Tag {...attrs} set:html={output} />
100
+ )}
101
+ {!field?.metadata && (!tag || encode) && (
102
+ <Fragment {...attrs} set:html={output} />
103
+ )}
92
104
  </>
93
105
  )}
94
106
  </WithEmptyFieldEditingComponent>