@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
@@ -1,4 +1,4 @@
1
- ---
1
+ ---
2
2
  /**
3
3
  * An Astro component to generate metadata blocks for a placeholder or rendering.
4
4
  * It utilizes dynamic attributes based on whether the component acts as a placeholder
@@ -9,11 +9,11 @@ import {
9
9
  ComponentRendering,
10
10
  getDynamicPlaceholderPattern,
11
11
  isDynamicPlaceholder,
12
- } from '@sitecore-content-sdk/core/layout';
12
+ } from '@sitecore-content-sdk/content/layout';
13
13
  import {
14
14
  MetadataKind,
15
15
  DEFAULT_PLACEHOLDER_UID,
16
- } from '@sitecore-content-sdk/core/editing';
16
+ } from '@sitecore-content-sdk/content/editing';
17
17
 
18
18
  /**
19
19
  * Props containing the component data to render.
@@ -21,6 +21,10 @@ import {
21
21
  export interface PlaceholderMetadataProps {
22
22
  rendering: ComponentRendering;
23
23
  placeholderName?: string;
24
+ /**
25
+ * Component runtime type. Used to add data-csdk-component-runtime attribute to rendering chromes
26
+ */
27
+ componentRuntime?: 'server';
24
28
  }
25
29
 
26
30
  export type CodeBlockAttributes = {
@@ -29,15 +33,20 @@ export type CodeBlockAttributes = {
29
33
  className: string;
30
34
  kind: string;
31
35
  id?: string;
36
+ 'data-csdk-component-runtime'?: 'server';
32
37
  };
33
38
 
34
39
  const props = Astro.props as PlaceholderMetadataProps;
35
40
 
36
- const getCodeBlockAttributes = (
37
- kind: MetadataKind,
38
- id?: string,
39
- placeholderName?: string
40
- ): CodeBlockAttributes => {
41
+ const getCodeBlockAttributes = ({
42
+ kind,
43
+ id,
44
+ placeholderName,
45
+ }: {
46
+ kind: MetadataKind;
47
+ id?: string;
48
+ placeholderName?: string;
49
+ }): CodeBlockAttributes => {
41
50
  const chrometype = placeholderName ? 'placeholder' : 'rendering';
42
51
 
43
52
  const attributes: CodeBlockAttributes = {
@@ -79,6 +88,11 @@ const getCodeBlockAttributes = (
79
88
  } else {
80
89
  attributes.id = id;
81
90
  }
91
+
92
+ // Add component runtime attribute for rendering chromes
93
+ if (chrometype === 'rendering' && props.componentRuntime) {
94
+ attributes['data-csdk-component-runtime'] = 'server';
95
+ }
82
96
  }
83
97
 
84
98
  return attributes;
@@ -87,16 +101,8 @@ const getCodeBlockAttributes = (
87
101
 
88
102
  <>
89
103
  <code
90
- {...getCodeBlockAttributes(
91
- MetadataKind.Open,
92
- props.rendering.uid,
93
- props.placeholderName
94
- )}></code>
104
+ {...getCodeBlockAttributes({ kind: MetadataKind.Open, id: props.rendering.uid, placeholderName: props.placeholderName })}></code>
95
105
  <slot />
96
106
  <code
97
- {...getCodeBlockAttributes(
98
- MetadataKind.Close,
99
- props.rendering.uid,
100
- props.placeholderName
101
- )}></code>
107
+ {...getCodeBlockAttributes({ kind: MetadataKind.Close, placeholderName: props.placeholderName })}></code>
102
108
  </>
@@ -0,0 +1,228 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { renderAstroComponent } from '../../tests/astro-helpers';
3
+ import PlaceholderMetadata from './PlaceholderMetadata.astro';
4
+
5
+ describe('PlaceholderMetadata', () => {
6
+ test('renders rendering code blocks for metadataType rendering', async () => {
7
+ const children = '<div class="richtext-class"></div>';
8
+
9
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
10
+ props: { rendering: { uid: '123', componentName: 'RichText' } },
11
+ slots: {
12
+ default: children,
13
+ },
14
+ });
15
+
16
+ expect(wrapper.innerHTML).to.equal(
17
+ [
18
+ '<code type="text/sitecore" chrometype="rendering" class="scpm" kind="open" id="123"></code>',
19
+ '<div class="richtext-class"></div>',
20
+ '<code type="text/sitecore" chrometype="rendering" class="scpm" kind="close"></code>',
21
+ ].join('')
22
+ );
23
+ });
24
+
25
+ test('renders placeholder code blocks when metadataType is placeholder', async () => {
26
+ const children = '<div class="richtext-mock"></div>';
27
+
28
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
29
+ props: {
30
+ rendering: {
31
+ uid: '123',
32
+ componentName: 'RichText',
33
+ placeholders: { main: [] },
34
+ },
35
+ placeholderName: 'main',
36
+ },
37
+ slots: {
38
+ default: children,
39
+ },
40
+ });
41
+
42
+ expect(wrapper.innerHTML).to.equal(
43
+ [
44
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="open" id="main_123"></code>',
45
+ '<div class="richtext-mock"></div>',
46
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="close"></code>',
47
+ ].join('')
48
+ );
49
+ });
50
+
51
+ test('renders placeholder code blocks with DEFAULT_PLACEHOLDER_UID value when metadataType is a placeholder(root) and uid is not present', async () => {
52
+ const children = '<div class="richtext-mock"></div>';
53
+
54
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
55
+ props: {
56
+ rendering: {
57
+ componentName: 'RichText',
58
+ placeholders: { main: [] },
59
+ },
60
+ placeholderName: 'main',
61
+ },
62
+ slots: {
63
+ default: children,
64
+ },
65
+ });
66
+
67
+ expect(wrapper.innerHTML).to.equal(
68
+ [
69
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="open" id="main_00000000-0000-0000-0000-000000000000"></code>',
70
+ '<div class="richtext-mock"></div>',
71
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="close"></code>',
72
+ ].join('')
73
+ );
74
+ });
75
+
76
+ test('renders placeholder blocks with rendering uid when metadataType is dynamic placeholder', async () => {
77
+ const children = '<div class="richtext-mock"></div>';
78
+
79
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
80
+ props: {
81
+ rendering: {
82
+ uid: 'renderinguid',
83
+ componentName: 'RichText',
84
+ placeholders: { 'main-{*}': [] },
85
+ },
86
+ placeholderName: 'main-1',
87
+ },
88
+ slots: {
89
+ default: children,
90
+ },
91
+ });
92
+
93
+ expect(wrapper.innerHTML).to.equal(
94
+ [
95
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="open" id="main-{*}_renderinguid"></code>',
96
+ '<div class="richtext-mock"></div>',
97
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="close"></code>',
98
+ ].join('')
99
+ );
100
+ });
101
+
102
+ test('renders placeholder blocks with DEFAULT_PLACEHOLDER_UID value when metadataType is dynamic placeholder and uid is not present', async () => {
103
+ const children = '<div class="richtext-mock"></div>';
104
+
105
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
106
+ props: {
107
+ rendering: {
108
+ componentName: 'RichText',
109
+ placeholders: { 'main-{*}': [] },
110
+ },
111
+ placeholderName: 'main-1',
112
+ },
113
+ slots: {
114
+ default: children,
115
+ },
116
+ });
117
+
118
+ expect(wrapper.innerHTML).to.equal(
119
+ [
120
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="open" id="main-{*}_00000000-0000-0000-0000-000000000000"></code>',
121
+ '<div class="richtext-mock"></div>',
122
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="close"></code>',
123
+ ].join('')
124
+ );
125
+ });
126
+
127
+ test('renders placeholder code blocks when metadataType is double digit dynamic placeholder', async () => {
128
+ const children = '<div class="richtext-mock"></div>';
129
+
130
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
131
+ props: {
132
+ rendering: {
133
+ uid: 'renderinguid',
134
+ componentName: 'RichText',
135
+ placeholders: { 'main-1-{*}': [] },
136
+ },
137
+ placeholderName: 'main-1-1',
138
+ },
139
+ slots: {
140
+ default: children,
141
+ },
142
+ });
143
+
144
+ expect(wrapper.innerHTML).to.equal(
145
+ [
146
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="open" id="main-1-{*}_renderinguid"></code>',
147
+ '<div class="richtext-mock"></div>',
148
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="close"></code>',
149
+ ].join('')
150
+ );
151
+ });
152
+
153
+ test('adds data-csdk-component-runtime attribute to rendering chrome', async () => {
154
+ const children = '<div class="richtext-class"></div>';
155
+
156
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
157
+ props: {
158
+ rendering: {
159
+ uid: '123',
160
+ componentName: 'RichText',
161
+ },
162
+ componentRuntime: 'server',
163
+ },
164
+ slots: {
165
+ default: children,
166
+ },
167
+ });
168
+
169
+ expect(wrapper.innerHTML).to.equal(
170
+ [
171
+ '<code type="text/sitecore" chrometype="rendering" class="scpm" kind="open" id="123" data-csdk-component-runtime="server"></code>',
172
+ '<div class="richtext-class"></div>',
173
+ '<code type="text/sitecore" chrometype="rendering" class="scpm" kind="close"></code>',
174
+ ].join('')
175
+ );
176
+ });
177
+
178
+ test('does not add data-csdk-component-runtime attribute to placeholder chrome even when componentRuntime is provided', async () => {
179
+ const children = '<div class="richtext-mock"></div>';
180
+
181
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
182
+ props: {
183
+ rendering: {
184
+ uid: '123',
185
+ componentName: 'RichText',
186
+ placeholders: { main: [] },
187
+ },
188
+ componentRuntime: 'server',
189
+ placeholderName: 'main',
190
+ },
191
+ slots: {
192
+ default: children,
193
+ },
194
+ });
195
+
196
+ expect(wrapper.innerHTML).to.equal(
197
+ [
198
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="open" id="main_123"></code>',
199
+ '<div class="richtext-mock"></div>',
200
+ '<code type="text/sitecore" chrometype="placeholder" class="scpm" kind="close"></code>',
201
+ ].join('')
202
+ );
203
+ });
204
+
205
+ test('does not add data-csdk-component-runtime attribute when componentRuntime is not provided', async () => {
206
+ const children = '<div class="richtext-class"></div>';
207
+
208
+ const wrapper = await renderAstroComponent(PlaceholderMetadata, {
209
+ props: {
210
+ rendering: {
211
+ uid: '123',
212
+ componentName: 'RichText',
213
+ },
214
+ },
215
+ slots: {
216
+ default: children,
217
+ },
218
+ });
219
+
220
+ expect(wrapper.innerHTML).to.equal(
221
+ [
222
+ '<code type="text/sitecore" chrometype="rendering" class="scpm" kind="open" id="123"></code>',
223
+ '<div class="richtext-class"></div>',
224
+ '<code type="text/sitecore" chrometype="rendering" class="scpm" kind="close"></code>',
225
+ ].join('')
226
+ );
227
+ });
228
+ });
@@ -1,37 +1,31 @@
1
1
  ---
2
- import { ComponentRendering } from "@sitecore-content-sdk/core/layout";
3
- import { constants } from '@sitecore-content-sdk/core';
2
+ import { ComponentRendering } from "@sitecore-content-sdk/content/layout";
4
3
  import EmptyRendering from "../EmptyRendering.astro";
5
4
  import HiddenRendering from "../HiddenRendering.astro";
6
5
  import MissingComponent from "../MissingComponent.astro";
7
- import { getSXAParams } from "./placeholder-utils";
6
+ import { getChildComponentProps } from "./placeholder-utils";
8
7
  import { ComponentForRendering, PlaceholderProps } from "./models";
9
8
  import { AstroContentSdkComponent, ComponentMap } from "../../sharedTypes/component-props";
9
+ import { HIDDEN_RENDERING_NAME } from "@sitecore-content-sdk/content";
10
10
  import { useComponentMap } from "../../context";
11
11
 
12
- export const getComponentsForRenderingData = (
13
- placeholderData: ComponentRendering[],
14
- props: PlaceholderProps
12
+ export const getPlaceholderComponents = (
13
+ placeholderProps: PlaceholderProps,
14
+ placeholderRenderings: ComponentRendering[],
15
15
  ) => {
16
+
16
17
  const {
17
18
  name,
18
- fields: placeholderFields,
19
- params: placeholderParams,
19
+ rendering,
20
20
  missingComponentComponent,
21
21
  hiddenRenderingComponent,
22
- ...placeholderProps
23
- } = props;
24
-
25
- const transformedComponents = placeholderData
26
- .map((rendering: ComponentRendering, index: number) => {
27
- const key = (rendering as ComponentRendering).uid
28
- ? (rendering as ComponentRendering).uid
29
- : `component-${index}`;
30
- const commonProps = { key };
22
+ modifyComponentProps,
23
+ } = placeholderProps;
31
24
 
32
- const componentRendering = rendering as ComponentRendering;
33
- const componentMap = useComponentMap();
25
+ const componentMap = useComponentMap();
34
26
 
27
+ const transformedComponents = placeholderRenderings
28
+ .map((componentRendering: ComponentRendering) => {
35
29
  const component = getComponentForRendering(
36
30
  componentRendering,
37
31
  name,
@@ -39,28 +33,15 @@ export const getComponentsForRenderingData = (
39
33
  hiddenRenderingComponent,
40
34
  missingComponentComponent
41
35
  );
42
-
43
- const finalProps = {
44
- ...commonProps,
45
- ...placeholderProps,
46
- ...((placeholderFields || componentRendering.fields) && {
47
- fields: { ...placeholderFields, ...componentRendering.fields },
48
- }),
49
- ...((placeholderParams || componentRendering.params) && {
50
- params: {
51
- ...placeholderParams,
52
- ...componentRendering.params,
53
- // Provide SXA styles
54
- ...getSXAParams(componentRendering),
55
- },
56
- }),
57
- rendering: componentRendering,
58
- };
36
+
37
+ const renderedProps = modifyComponentProps
38
+ ? modifyComponentProps(getChildComponentProps(placeholderProps, componentRendering))
39
+ : getChildComponentProps(placeholderProps, componentRendering);
59
40
 
60
41
  let components = {
61
42
  component: component,
62
- props: props.modifyComponentProps ? props.modifyComponentProps(finalProps) : finalProps,
63
- rendering: rendering,
43
+ props: renderedProps,
44
+ rendering: componentRendering,
64
45
  placeholderName: name
65
46
  };
66
47
 
@@ -90,7 +71,7 @@ export const getComponentForRendering = (
90
71
 
91
72
  let component;
92
73
 
93
- if (renderingDefinition.componentName === constants.HIDDEN_RENDERING_NAME) {
74
+ if (renderingDefinition.componentName === HIDDEN_RENDERING_NAME) {
94
75
  return {
95
76
  component: hiddenRenderingComponent ?? HiddenRendering,
96
77
  isEmpty: true
@@ -128,7 +109,7 @@ export const getComponentForRendering = (
128
109
  // isEmpty: false,
129
110
  // };
130
111
  // } else if (renderingDefinition.componentName === BYOC_WRAPPER_RENDERING_NAME) {
131
- // // wrapping with error boundary could cause problems in case where parent component uses withPlaceholder HOC and tries to access its children props
112
+ // // wrapping with error boundary could cause problems in case where parent component uses withPlaceholder HOCs and tries to access its children props
132
113
  // // that's why we need to mark BYOC wrapper dynamic
133
114
  // return {
134
115
  // component: BYOCWrapper,
@@ -0,0 +1,149 @@
1
+ /* eslint-disable no-unused-expressions */
2
+ import { describe, test, expect, beforeEach, afterEach } from 'vitest';
3
+ import { ComponentRendering } from '@sitecore-content-sdk/content/layout';
4
+ import { ComponentMap } from '../../sharedTypes/component-props';
5
+ import { createSandbox } from 'sinon';
6
+ import { getComponentForRendering } from './PlaceholderUtils.astro';
7
+ import MissingComponent from '../MissingComponent.astro';
8
+ import HiddenRendering from '../HiddenRendering.astro';
9
+ import TestComponent from '../../tests/test-components/TestComponent.astro';
10
+ import CustomMissingComponent from '../../tests/test-components/CustomMissingComponent.astro';
11
+ import CustomHiddenRendering from '../../tests/test-components/CustomHiddenRendering.astro';
12
+ import { HIDDEN_RENDERING_NAME } from '@sitecore-content-sdk/content';
13
+
14
+ describe('placeholder-utils', () => {
15
+ const sandbox = createSandbox();
16
+ let consoleWarnStub: ReturnType<typeof sandbox.stub>;
17
+
18
+ beforeEach(() => {
19
+ consoleWarnStub = sandbox.stub(console, 'warn');
20
+ sandbox.stub(console, 'error');
21
+ });
22
+
23
+ afterEach(() => {
24
+ sandbox.restore();
25
+ });
26
+
27
+ describe('getComponentForRendering', () => {
28
+ let componentMap: ComponentMap;
29
+
30
+ beforeEach(() => {
31
+ componentMap = new Map();
32
+ });
33
+
34
+ test('should return null when componentMap is empty', () => {
35
+ const rendering: ComponentRendering = {
36
+ componentName: 'TestComponent',
37
+ uid: 'test-uid',
38
+ };
39
+
40
+ const result = getComponentForRendering(rendering, 'test-placeholder');
41
+
42
+ expect(result?.component).to.equal(MissingComponent);
43
+ expect(result?.isEmpty).to.be.true;
44
+ expect(consoleWarnStub.calledOnce).to.be.true;
45
+ });
46
+
47
+ test('should return null when componentMap is not provided', () => {
48
+ const rendering: ComponentRendering = {
49
+ componentName: 'TestComponent',
50
+ uid: 'test-uid',
51
+ };
52
+
53
+ const result = getComponentForRendering(rendering, 'test-placeholder', undefined);
54
+
55
+ expect(result?.component).to.equal(MissingComponent);
56
+ expect(result?.isEmpty).to.be.true;
57
+ expect(consoleWarnStub.calledOnce).to.be.true;
58
+ });
59
+
60
+ test('should return component directly when it is not a module', () => {
61
+ componentMap.set('TestComponent', TestComponent);
62
+
63
+ const rendering: ComponentRendering = {
64
+ componentName: 'TestComponent',
65
+ uid: 'test-uid',
66
+ };
67
+
68
+ const result = getComponentForRendering(rendering, 'test-placeholder', componentMap);
69
+
70
+ expect(result?.component).to.equal(TestComponent);
71
+ });
72
+
73
+ test('should return default missing component when component not found in component map', () => {
74
+ // Add a dummy entry so componentMap is not empty
75
+ componentMap.set('DummyComponent', TestComponent);
76
+
77
+ const rendering: ComponentRendering = {
78
+ componentName: 'NonExistentComponent',
79
+ uid: 'test-uid',
80
+ };
81
+
82
+ const result = getComponentForRendering(rendering, 'test-placeholder', componentMap);
83
+
84
+ expect(result?.component).to.equal(MissingComponent);
85
+ expect(result?.isEmpty).to.be.true;
86
+ });
87
+
88
+ test('should return custom missing component when specified and component not found in component map', () => {
89
+ // Add a dummy entry so componentMap is not empty
90
+ componentMap.set('DummyComponent', TestComponent);
91
+
92
+ const rendering: ComponentRendering = {
93
+ componentName: 'NonExistentComponent',
94
+ uid: 'test-uid',
95
+ };
96
+
97
+ const result = getComponentForRendering(
98
+ rendering,
99
+ 'test-placeholder',
100
+ componentMap,
101
+ undefined,
102
+ CustomMissingComponent
103
+ );
104
+
105
+ expect(result?.component).to.equal(CustomMissingComponent);
106
+ expect(result?.isEmpty).to.be.true;
107
+ });
108
+
109
+ test('should return hiddenRenderingComponent when component is hidden', () => {
110
+ const rendering: ComponentRendering = {
111
+ componentName: HIDDEN_RENDERING_NAME,
112
+ uid: 'test-uid',
113
+ };
114
+
115
+ const result = getComponentForRendering(
116
+ rendering,
117
+ 'test-placeholder',
118
+ componentMap,
119
+ CustomHiddenRendering
120
+ );
121
+
122
+ expect(result?.component).to.equal(CustomHiddenRendering);
123
+ expect(result?.isEmpty).to.be.true;
124
+ });
125
+
126
+ test('should return default HiddenRendering when component is hidden and no custom hidden component provided', () => {
127
+ const rendering: ComponentRendering = {
128
+ componentName: HIDDEN_RENDERING_NAME,
129
+ uid: 'test-uid',
130
+ };
131
+
132
+ const result = getComponentForRendering(rendering, 'test-placeholder', componentMap);
133
+
134
+ expect(result?.component).to.equal(HiddenRendering);
135
+ expect(result?.isEmpty).to.be.true;
136
+ });
137
+
138
+ test('should handle rendering without componentName', () => {
139
+ const rendering: ComponentRendering = {
140
+ componentName: '',
141
+ uid: 'test-uid',
142
+ };
143
+
144
+ const result = getComponentForRendering(rendering, 'test-placeholder', componentMap);
145
+
146
+ expect(result?.isEmpty).to.be.true;
147
+ });
148
+ });
149
+ });
@@ -1,15 +1,12 @@
1
- import { Page } from '@sitecore-content-sdk/core/client';
1
+ import { Page } from '@sitecore-content-sdk/content/client';
2
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
- };
3
+ import { ComponentRendering, Field, Item, RouteData } from '@sitecore-content-sdk/content/layout';
10
4
 
5
+ /**
6
+ * Base Placeholder props
7
+ * @public
8
+ */
11
9
  export interface PlaceholderProps {
12
- [key: string]: unknown;
13
10
  /** Name of the placeholder to render. */
14
11
  name: string;
15
12
  /** Rendering data to be used when rendering the placeholder. */
@@ -28,13 +25,7 @@ export interface PlaceholderProps {
28
25
  params?: {
29
26
  [name: string]: string;
30
27
  };
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;
28
+
38
29
  /**
39
30
  * A component that is rendered in place of any components that are in this placeholder,
40
31
  * but do not have a definition in the componentMap (i.e. don't have an implementation)
@@ -55,7 +46,7 @@ export interface PlaceholderProps {
55
46
  * Page data.
56
47
  * This data is passed by the SitecoreProvider.
57
48
  */
58
- page: Page;
49
+ page?: Page;
59
50
 
60
51
  /**
61
52
  * Render HTML or an Astro component when the placeholder contains no content components.
@@ -74,6 +65,24 @@ export interface PlaceholderProps {
74
65
  * Mutually exclusive with `render`.
75
66
  */
76
67
  renderEach?: string | AstroContentSdkComponent;
68
+
69
+ /**
70
+ * Modify final props of component (before render) provided by rendering data.
71
+ * Can be used in case when you need to insert additional data into the component.
72
+ * @param {ChildComponentProps} componentProps component props to be modified
73
+ * @returns {ChildComponentProps} modified or initial props
74
+ */
75
+ modifyComponentProps?: (componentProps: ChildComponentProps) => ChildComponentProps;
76
+ }
77
+
78
+ export interface ChildComponentProps {
79
+ fields: {
80
+ [name: string]: Field | Item | Item[];
81
+ };
82
+ params: {
83
+ [name: string]: string;
84
+ };
85
+ rendering: ComponentRendering;
77
86
  }
78
87
 
79
88
  export interface ComponentForRendering {