@dotcms/react 0.0.1-alpha.9 → 0.0.1-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 (79) hide show
  1. package/README.md +24 -4
  2. package/es.regexp.to-string.esm.js +1878 -0
  3. package/index.esm.d.ts +1 -0
  4. package/index.esm.js +3461 -0
  5. package/next.esm.d.ts +1 -0
  6. package/next.esm.js +665 -0
  7. package/package.json +34 -28
  8. package/src/index.d.ts +1 -0
  9. package/src/lib/deprecated/components/BlockEditorRenderer/BlockEditorRenderer.d.ts +37 -0
  10. package/src/lib/deprecated/components/BlockEditorRenderer/blocks/Code.d.ts +17 -0
  11. package/src/lib/deprecated/components/BlockEditorRenderer/blocks/Contentlet.d.ts +41 -0
  12. package/src/lib/deprecated/components/BlockEditorRenderer/blocks/Image.d.ts +8 -0
  13. package/src/lib/deprecated/components/BlockEditorRenderer/blocks/Lists.d.ts +22 -0
  14. package/src/lib/deprecated/components/BlockEditorRenderer/blocks/Table.d.ts +16 -0
  15. package/src/lib/deprecated/components/BlockEditorRenderer/blocks/Texts.d.ts +71 -0
  16. package/src/lib/deprecated/components/BlockEditorRenderer/blocks/Video.d.ts +8 -0
  17. package/src/lib/deprecated/components/BlockEditorRenderer/item/BlockEditorBlock.d.ts +12 -0
  18. package/src/lib/deprecated/components/Column/Column.d.ts +19 -0
  19. package/src/lib/deprecated/components/Container/Container.d.ts +19 -0
  20. package/src/lib/deprecated/components/DotEditableText/DotEditableText.d.ts +30 -0
  21. package/src/lib/deprecated/components/DotEditableText/utils.d.ts +36 -0
  22. package/src/lib/{components/DotcmsLayout/DotcmsLayout.tsx → deprecated/components/DotcmsLayout/DotcmsLayout.d.ts} +9 -23
  23. package/src/lib/deprecated/components/PageProvider/PageProvider.d.ts +14 -0
  24. package/src/lib/deprecated/components/Row/Row.d.ts +26 -0
  25. package/src/lib/deprecated/contexts/PageContext.d.ts +8 -0
  26. package/src/lib/deprecated/deprecated_api.d.ts +7 -0
  27. package/src/lib/deprecated/hooks/useCheckHaveContent.d.ts +5 -0
  28. package/src/lib/deprecated/hooks/useDotcmsEditor.d.ts +13 -0
  29. package/src/lib/deprecated/hooks/useDotcmsPageContext.d.ts +9 -0
  30. package/src/lib/deprecated/mocks/mockPageContext.d.ts +7 -0
  31. package/src/lib/deprecated/models/blocks.interface.d.ts +89 -0
  32. package/src/lib/deprecated/models/content-node.interface.d.ts +82 -0
  33. package/src/lib/deprecated/models/index.d.ts +127 -0
  34. package/src/lib/deprecated/utils/utils.d.ts +58 -0
  35. package/src/lib/next/__test__/mock.d.ts +11 -0
  36. package/src/lib/next/components/Column/Column.d.ts +37 -0
  37. package/src/lib/next/components/Container/Container.d.ts +32 -0
  38. package/src/lib/next/components/Container/ContainerFallbakcs.d.ts +24 -0
  39. package/src/lib/next/components/Contentlet/Contentlet.d.ts +32 -0
  40. package/src/lib/next/components/DotCMSLayoutBody/DotCMSLayoutBody.d.ts +36 -0
  41. package/src/lib/next/components/DotCMSLayoutBody/components/ErrorMessage.d.ts +9 -0
  42. package/src/lib/next/components/FallbackComponent/FallbackComponent.d.ts +41 -0
  43. package/src/lib/next/components/Row/Row.d.ts +21 -0
  44. package/src/lib/next/contexts/DotCMSPageContext.d.ts +23 -0
  45. package/src/lib/next/hooks/useCheckVisibleContent.d.ts +24 -0
  46. package/src/lib/next/hooks/useIsDevMode.d.ts +13 -0
  47. package/src/lib/next/types.d.ts +421 -0
  48. package/src/lib/next/utils/index.d.ts +136 -0
  49. package/src/next.d.ts +1 -0
  50. package/.babelrc +0 -12
  51. package/.eslintrc.json +0 -18
  52. package/jest.config.ts +0 -11
  53. package/project.json +0 -51
  54. package/src/index.ts +0 -4
  55. package/src/lib/components/Column/Column.module.css +0 -99
  56. package/src/lib/components/Column/Column.spec.tsx +0 -78
  57. package/src/lib/components/Column/Column.tsx +0 -45
  58. package/src/lib/components/Container/Container.module.css +0 -7
  59. package/src/lib/components/Container/Container.spec.tsx +0 -82
  60. package/src/lib/components/Container/Container.tsx +0 -105
  61. package/src/lib/components/DotcmsLayout/DotcmsLayout.module.css +0 -7
  62. package/src/lib/components/DotcmsLayout/DotcmsLayout.spec.tsx +0 -41
  63. package/src/lib/components/PageProvider/PageProvider.module.css +0 -7
  64. package/src/lib/components/PageProvider/PageProvider.spec.tsx +0 -54
  65. package/src/lib/components/PageProvider/PageProvider.tsx +0 -95
  66. package/src/lib/components/Row/Row.module.css +0 -5
  67. package/src/lib/components/Row/Row.spec.tsx +0 -92
  68. package/src/lib/components/Row/Row.tsx +0 -51
  69. package/src/lib/contexts/PageContext.tsx +0 -5
  70. package/src/lib/hooks/useDotcmsEditor.spec.ts +0 -56
  71. package/src/lib/hooks/useDotcmsEditor.ts +0 -29
  72. package/src/lib/hooks/useDotcmsPageContext.spec.tsx +0 -43
  73. package/src/lib/hooks/useDotcmsPageContext.tsx +0 -15
  74. package/src/lib/mocks/mockPageContext.tsx +0 -84
  75. package/src/lib/utils/utils.ts +0 -69
  76. package/tsconfig.json +0 -20
  77. package/tsconfig.lib.json +0 -23
  78. package/tsconfig.spec.json +0 -20
  79. /package/src/lib/{mocks/index.ts → deprecated/mocks/index.d.ts} +0 -0
package/next.esm.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/next";
package/next.esm.js ADDED
@@ -0,0 +1,665 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { createContext, useContext, useState, useEffect, useLayoutEffect, useRef, useMemo } from 'react';
3
+ import { s as styleInject } from './es.regexp.to-string.esm.js';
4
+ import { getUVEState } from '@dotcms/uve';
5
+ import { UVE_MODE } from '@dotcms/uve/types';
6
+
7
+ /**
8
+ * The `PageContext` is a React context that provides access to the DotCMS page context.
9
+ *
10
+ * @category Contexts
11
+ */
12
+ const DotCMSPageContext = /*#__PURE__*/createContext({
13
+ pageAsset: {},
14
+ mode: 'production',
15
+ userComponents: {}
16
+ });
17
+
18
+ /**
19
+ * @internal
20
+ * A React hook that determines if the current environment is in development mode.
21
+ *
22
+ * The hook returns `true` if either:
23
+ * - The context mode (or the optional `renderMode` argument) is set to 'development', or
24
+ * - The application is running inside the DotCMS editor (as determined by `isInsideEditor()`).
25
+ *
26
+ * @param {DotCMSPageRendererMode} [renderMode] - Optional override for the render mode.
27
+ * @returns {boolean} - `true` if in development mode or inside the editor; otherwise, `false`.
28
+ */
29
+ const useIsDevMode = renderMode => {
30
+ const {
31
+ mode
32
+ } = useContext(DotCMSPageContext);
33
+ const effectiveMode = renderMode != null ? renderMode : mode;
34
+ const [isDevMode, setIsDevMode] = useState(effectiveMode === 'development');
35
+ useEffect(() => {
36
+ var _getUVEState;
37
+ // Inside UVE we rely on the UVE state to determine if we are in development mode
38
+ if ((_getUVEState = getUVEState()) != null && _getUVEState.mode) {
39
+ var _getUVEState2;
40
+ const isUVEInEditor = ((_getUVEState2 = getUVEState()) == null ? void 0 : _getUVEState2.mode) === UVE_MODE.EDIT;
41
+ setIsDevMode(isUVEInEditor);
42
+ return;
43
+ }
44
+ const effectiveMode = renderMode != null ? renderMode : mode;
45
+ setIsDevMode(effectiveMode === 'development');
46
+ }, [renderMode, mode]);
47
+ return isDevMode;
48
+ };
49
+
50
+ /**
51
+ * Error message component for when the page body is missing
52
+ *
53
+ * @return {JSX.Element} Error message component
54
+ */
55
+ const ErrorMessage = ({
56
+ mode
57
+ }) => {
58
+ useEffect(() => {
59
+ console.warn('Missing required layout.body property in page');
60
+ }, []);
61
+ const isDevMode = useIsDevMode(mode);
62
+ if (!isDevMode) {
63
+ return null;
64
+ }
65
+ return jsxs("div", {
66
+ "data-testid": "error-message",
67
+ style: {
68
+ padding: '1rem',
69
+ border: '1px solid #e0e0e0',
70
+ borderRadius: '4px'
71
+ },
72
+ children: [jsxs("p", {
73
+ style: {
74
+ margin: '0 0 0.5rem',
75
+ color: '#666'
76
+ },
77
+ children: ["The ", jsx("code", {
78
+ children: "page"
79
+ }), " is missing the required ", jsx("code", {
80
+ children: "layout.body"
81
+ }), " property."]
82
+ }), jsx("p", {
83
+ style: {
84
+ margin: 0,
85
+ color: '#666'
86
+ },
87
+ children: "Make sure the page asset is properly loaded and includes a layout configuration."
88
+ })]
89
+ });
90
+ };
91
+
92
+ var css_248z$1 = ".Row-module_row__PS0UP {\n display: grid;\n grid-template-columns: repeat(12, 1fr);\n gap: 1rem;\n}\n";
93
+ var styles$1 = {"row":"Row-module_row__PS0UP"};
94
+ styleInject(css_248z$1);
95
+
96
+ var css_248z = ".Column-module_col-start-1__xylw6 {\n grid-column-start: 1;\n}\n\n.Column-module_col-start-2__Mod81 {\n grid-column-start: 2;\n}\n\n.Column-module_col-start-3__HHbXB {\n grid-column-start: 3;\n}\n\n.Column-module_col-start-4__Uk-Qj {\n grid-column-start: 4;\n}\n\n.Column-module_col-start-5__jlV8e {\n grid-column-start: 5;\n}\n\n.Column-module_col-start-6__oi8k0 {\n grid-column-start: 6;\n}\n\n.Column-module_col-start-7__EmPky {\n grid-column-start: 7;\n}\n\n.Column-module_col-start-8__hLI1h {\n grid-column-start: 8;\n}\n\n.Column-module_col-start-9__Kcv9X {\n grid-column-start: 9;\n}\n\n.Column-module_col-start-10__-MOrt {\n grid-column-start: 10;\n}\n\n.Column-module_col-start-11__gDEQM {\n grid-column-start: 11;\n}\n\n.Column-module_col-start-12__omVX6 {\n grid-column-start: 12;\n}\n\n.Column-module_col-end-1__Ho2y9 {\n grid-column-end: 1;\n}\n\n.Column-module_col-end-2__KwFu9 {\n grid-column-end: 2;\n}\n\n.Column-module_col-end-3__vfbJk {\n grid-column-end: 3;\n}\n\n.Column-module_col-end-4__d4pyL {\n grid-column-end: 4;\n}\n\n.Column-module_col-end-5__6yPd4 {\n grid-column-end: 5;\n}\n\n.Column-module_col-end-6__xQpAX {\n grid-column-end: 6;\n}\n\n.Column-module_col-end-7__CCF7e {\n grid-column-end: 7;\n}\n\n.Column-module_col-end-8__fVWEi {\n grid-column-end: 8;\n}\n\n.Column-module_col-end-9__tpIGv {\n grid-column-end: 9;\n}\n\n.Column-module_col-end-10__SX75K {\n grid-column-end: 10;\n}\n\n.Column-module_col-end-11__9K1zv {\n grid-column-end: 11;\n}\n\n.Column-module_col-end-12__oqTiE {\n grid-column-end: 12;\n}\n\n.Column-module_col-end-13__L-nK9 {\n grid-column-end: 13;\n}\n";
97
+ var styles = {"col-start-1":"Column-module_col-start-1__xylw6","col-start-2":"Column-module_col-start-2__Mod81","col-start-3":"Column-module_col-start-3__HHbXB","col-start-4":"Column-module_col-start-4__Uk-Qj","col-start-5":"Column-module_col-start-5__jlV8e","col-start-6":"Column-module_col-start-6__oi8k0","col-start-7":"Column-module_col-start-7__EmPky","col-start-8":"Column-module_col-start-8__hLI1h","col-start-9":"Column-module_col-start-9__Kcv9X","col-start-10":"Column-module_col-start-10__-MOrt","col-start-11":"Column-module_col-start-11__gDEQM","col-start-12":"Column-module_col-start-12__omVX6","col-end-1":"Column-module_col-end-1__Ho2y9","col-end-2":"Column-module_col-end-2__KwFu9","col-end-3":"Column-module_col-end-3__vfbJk","col-end-4":"Column-module_col-end-4__d4pyL","col-end-5":"Column-module_col-end-5__6yPd4","col-end-6":"Column-module_col-end-6__xQpAX","col-end-7":"Column-module_col-end-7__CCF7e","col-end-8":"Column-module_col-end-8__fVWEi","col-end-9":"Column-module_col-end-9__tpIGv","col-end-10":"Column-module_col-end-10__SX75K","col-end-11":"Column-module_col-end-11__9K1zv","col-end-12":"Column-module_col-end-12__oqTiE","col-end-13":"Column-module_col-end-13__L-nK9"};
98
+ styleInject(css_248z);
99
+
100
+ const endClassMap = {
101
+ 1: 'col-end-1',
102
+ 2: 'col-end-2',
103
+ 3: 'col-end-3',
104
+ 4: 'col-end-4',
105
+ 5: 'col-end-5',
106
+ 6: 'col-end-6',
107
+ 7: 'col-end-7',
108
+ 8: 'col-end-8',
109
+ 9: 'col-end-9',
110
+ 10: 'col-end-10',
111
+ 11: 'col-end-11',
112
+ 12: 'col-end-12',
113
+ 13: 'col-end-13'
114
+ };
115
+ const startClassMap = {
116
+ 1: 'col-start-1',
117
+ 2: 'col-start-2',
118
+ 3: 'col-start-3',
119
+ 4: 'col-start-4',
120
+ 5: 'col-start-5',
121
+ 6: 'col-start-6',
122
+ 7: 'col-start-7',
123
+ 8: 'col-start-8',
124
+ 9: 'col-start-9',
125
+ 10: 'col-start-10',
126
+ 11: 'col-start-11',
127
+ 12: 'col-start-12'
128
+ };
129
+ /**
130
+ * @internal
131
+ *
132
+ * Combine classes into a single string.
133
+ *
134
+ * @param {string[]} classes
135
+ * @returns {string} Combined classes
136
+ */
137
+ const combineClasses = classes => classes.filter(Boolean).join(' ');
138
+ /**
139
+ * @internal
140
+ *
141
+ * Calculates and returns the CSS Grid positioning classes for a column based on its configuration.
142
+ * Uses a 12-column grid system where columns are positioned using grid-column-start and grid-column-end.
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * const classes = getColumnPositionClasses({
147
+ * leftOffset: 1, // Starts at the first column
148
+ * width: 6 // Spans 6 columns
149
+ * });
150
+ * // Returns: { startClass: 'col-start-1', endClass: 'col-end-7' }
151
+ * ```
152
+ *
153
+ * @param {DotPageAssetLayoutColumn} column - Column configuration object
154
+ * @param {number} column.leftOffset - Starting position (0-based) in the grid
155
+ * @param {number} column.width - Number of columns to span
156
+ * @returns {{ startClass: string, endClass: string }} Object containing CSS class names for grid positioning
157
+ */
158
+ const getColumnPositionClasses = column => {
159
+ const {
160
+ leftOffset,
161
+ width
162
+ } = column;
163
+ const startClass = startClassMap[leftOffset];
164
+ const endClass = endClassMap[leftOffset + width];
165
+ return {
166
+ startClass,
167
+ endClass
168
+ };
169
+ };
170
+ /**
171
+ * @internal
172
+ *
173
+ * Helper function that returns an object containing the dotCMS data attributes.
174
+ * @param {DotCMSContentlet} contentlet - The contentlet to get the attributes for
175
+ * @param {string} container - The container to get the attributes for
176
+ * @returns {DotContentletAttributes} The dotCMS data attributes
177
+ */
178
+ function getDotContentletAttributes(contentlet, container) {
179
+ return {
180
+ 'data-dot-identifier': contentlet == null ? void 0 : contentlet.identifier,
181
+ 'data-dot-basetype': contentlet == null ? void 0 : contentlet.baseType,
182
+ 'data-dot-title': (contentlet == null ? void 0 : contentlet.widgetTitle) || (contentlet == null ? void 0 : contentlet.title),
183
+ 'data-dot-inode': contentlet == null ? void 0 : contentlet.inode,
184
+ 'data-dot-type': contentlet == null ? void 0 : contentlet.contentType,
185
+ 'data-dot-container': container,
186
+ 'data-dot-on-number-of-pages': contentlet == null ? void 0 : contentlet.onNumberOfPages
187
+ };
188
+ }
189
+ /**
190
+ * @internal
191
+ *
192
+ * Retrieves container data from a DotCMS page asset using the container reference.
193
+ * This function processes the container information and returns a standardized format
194
+ * for container editing.
195
+ *
196
+ * @param {DotCMSPageAsset} dotCMSPageAsset - The page asset containing all containers data
197
+ * @param {DotCMSColumnContainer} columContainer - The container reference from the layout
198
+ * @throws {Error} When page asset is invalid or container is not found
199
+ * @returns {EditableContainerData} Formatted container data for editing
200
+ *
201
+ * @example
202
+ * const containerData = getContainersData(pageAsset, containerRef);
203
+ * // Returns: { uuid: '123', identifier: 'cont1', acceptTypes: 'type1,type2', maxContentlets: 5 }
204
+ */
205
+ const getContainersData = (dotCMSPageAsset, columContainer) => {
206
+ var _containerStructures$, _container$parentPerm, _container$maxContent;
207
+ const {
208
+ identifier,
209
+ uuid
210
+ } = columContainer;
211
+ const dotContainer = dotCMSPageAsset.containers[identifier];
212
+ if (!dotContainer) {
213
+ return null;
214
+ }
215
+ const {
216
+ containerStructures,
217
+ container
218
+ } = dotContainer;
219
+ const acceptTypes = (_containerStructures$ = containerStructures == null ? void 0 : containerStructures.map(structure => structure.contentTypeVar).join(',')) != null ? _containerStructures$ : '';
220
+ const variantId = container == null || (_container$parentPerm = container.parentPermissionable) == null ? void 0 : _container$parentPerm.variantId;
221
+ const maxContentlets = (_container$maxContent = container == null ? void 0 : container.maxContentlets) != null ? _container$maxContent : 0;
222
+ const path = container == null ? void 0 : container.path;
223
+ return {
224
+ uuid,
225
+ variantId,
226
+ acceptTypes,
227
+ maxContentlets,
228
+ identifier: path != null ? path : identifier
229
+ };
230
+ };
231
+ /**
232
+ * @internal
233
+ *
234
+ * Retrieves the contentlets (content items) associated with a specific container.
235
+ * Handles different UUID formats and provides warning for missing contentlets.
236
+ *
237
+ * @param {DotCMSPageAsset} dotCMSPageAsset - The page asset containing all containers data
238
+ * @param {DotCMSColumnContainer} columContainer - The container reference from the layout
239
+ * @returns {DotCMSContentlet[]} Array of contentlets in the container
240
+ *
241
+ * @example
242
+ * const contentlets = getContentletsInContainer(pageAsset, containerRef);
243
+ * // Returns: [{ identifier: 'cont1', ... }, { identifier: 'cont2', ... }]
244
+ */
245
+ const getContentletsInContainer = (dotCMSPageAsset, columContainer) => {
246
+ const {
247
+ identifier,
248
+ uuid
249
+ } = columContainer;
250
+ const {
251
+ contentlets
252
+ } = dotCMSPageAsset.containers[identifier];
253
+ const contentletsInContainer = contentlets[`uuid-${uuid}`] || contentlets[`uuid-dotParser_${uuid}`] || [];
254
+ if (!contentletsInContainer) {
255
+ console.warn(`We couldn't find the contentlets for the container with the identifier ${identifier} and the uuid ${uuid} becareful by adding content to this container.\nWe recommend to change the container in the layout and add the content again.`);
256
+ }
257
+ return contentletsInContainer;
258
+ };
259
+ /**
260
+ * @internal
261
+ *
262
+ * Generates the required DotCMS data attributes for a container element.
263
+ * These attributes are used by DotCMS for container identification and functionality.
264
+ *
265
+ * @param {EditableContainerData} params - Container data including uuid, identifier, acceptTypes, and maxContentlets
266
+ * @returns {DotContainerAttributes} Object containing all necessary data attributes
267
+ *
268
+ * @example
269
+ * const attributes = getDotContainerAttributes({
270
+ * uuid: '123',
271
+ * identifier: 'cont1',
272
+ * acceptTypes: 'type1,type2',
273
+ * maxContentlets: 5
274
+ * });
275
+ * // Returns: { 'data-dot-object': 'container', 'data-dot-identifier': 'cont1', ... }
276
+ */
277
+ function getDotContainerAttributes({
278
+ uuid,
279
+ identifier,
280
+ acceptTypes,
281
+ maxContentlets
282
+ }) {
283
+ return {
284
+ 'data-dot-object': 'container',
285
+ 'data-dot-accept-types': acceptTypes,
286
+ 'data-dot-identifier': identifier,
287
+ 'data-max-contentlets': maxContentlets.toString(),
288
+ 'data-dot-uuid': uuid
289
+ };
290
+ }
291
+
292
+ const EMPTY_CONTAINER_STYLE = {
293
+ width: '100%',
294
+ backgroundColor: '#ECF0FD',
295
+ display: 'flex',
296
+ justifyContent: 'center',
297
+ alignItems: 'center',
298
+ color: '#030E32',
299
+ height: '10rem'
300
+ };
301
+ /**
302
+ * @internal
303
+ *
304
+ * Component to display when a container is not found in the system.
305
+ * Only renders in development mode for debugging purposes.
306
+ *
307
+ * @component
308
+ * @param {Object} props - Component properties
309
+ * @param {string} props.identifier - Container identifier
310
+ * @returns {JSX.Element | null} Message about missing container or null in production
311
+ */
312
+ const ContainerNoFound = ({
313
+ identifier
314
+ }) => {
315
+ const isDevMode = useIsDevMode();
316
+ useEffect(() => {
317
+ if (!isDevMode) {
318
+ return;
319
+ }
320
+ console.error(`Container with identifier ${identifier} not found`);
321
+ }, [identifier, isDevMode]);
322
+ if (!isDevMode) {
323
+ return null;
324
+ }
325
+ return jsxs("div", {
326
+ "data-testid": "container-not-found",
327
+ style: EMPTY_CONTAINER_STYLE,
328
+ children: ["This container with identifier ", identifier, " was not found."]
329
+ });
330
+ };
331
+ /**
332
+ * @internal
333
+ *
334
+ * Component to display when a container is empty.
335
+ *
336
+ * @param {DotContainerAttributes} dotAttributes
337
+ * @return {*}
338
+ */
339
+ const EmptyContainer = dotAttributes => {
340
+ const isDevMode = useIsDevMode();
341
+ if (!isDevMode) {
342
+ return null;
343
+ }
344
+ return jsx("div", Object.assign({}, dotAttributes, {
345
+ style: EMPTY_CONTAINER_STYLE,
346
+ children: jsx("span", {
347
+ "data-testid": "empty-container-message",
348
+ children: "This container is empty."
349
+ })
350
+ }));
351
+ };
352
+
353
+ /**
354
+ * @internal
355
+ * A custom React hook that checks whether a referenced HTMLDivElement has visible content based on its height.
356
+ *
357
+ * @param {RefObject<HTMLDivElement>} ref - A React ref object pointing to an HTMLDivElement.
358
+ * @returns {boolean} - Returns true if the element's height is greater than zero (indicating visible content), otherwise false.
359
+ *
360
+ * @example
361
+ * import { useRef } from 'react';
362
+ * import { useCheckVisibleContent } from 'src/lib/next/hooks/useCheckVisibleContent';
363
+ *
364
+ * function MyComponent() {
365
+ * const contentRef = useRef<HTMLDivElement>(null);
366
+ * const isContentVisible = useCheckVisibleContent(contentRef);
367
+ *
368
+ * return (
369
+ * <div ref={contentRef}>
370
+ * {isContentVisible ? 'Content is visible' : 'Content is not visible'}
371
+ * </div>
372
+ * );
373
+ * }
374
+ */
375
+ const useCheckVisibleContent = ref => {
376
+ const [haveContent, setHaveContent] = useState(false);
377
+ useLayoutEffect(() => {
378
+ if (!ref.current) {
379
+ setHaveContent(false);
380
+ return;
381
+ }
382
+ const {
383
+ height
384
+ } = ref.current.getBoundingClientRect();
385
+ setHaveContent(height > 0);
386
+ }, [ref]);
387
+ return haveContent;
388
+ };
389
+
390
+ /**
391
+ * @internal
392
+ *
393
+ * Renders a fallback component when no matching component is found for a content type
394
+ *
395
+ * @component
396
+ * @param {DotCMSFallbackComponentProps} props - Component properties
397
+ * @param {NoComponentType} [props.UserNoComponent] - Optional custom component to render
398
+ * @param {DotCMSContentlet} [props.contentlet] - The contentlet that couldn't be rendered
399
+ * @returns {JSX.Element} The rendered fallback component
400
+ *
401
+ * @example
402
+ * ```tsx
403
+ * <FallbackComponent
404
+ * UserNoComponent={CustomNoComponent}
405
+ * contentlet={contentlet}
406
+ * />
407
+ * ```
408
+ */
409
+ function FallbackComponent({
410
+ UserNoComponent,
411
+ contentlet
412
+ }) {
413
+ const isDevMode = useIsDevMode();
414
+ if (!isDevMode) {
415
+ return null;
416
+ }
417
+ const NoComponentFound = UserNoComponent || NoComponent;
418
+ return jsx(NoComponentFound, Object.assign({}, contentlet));
419
+ }
420
+ /**
421
+ * @internal
422
+ *
423
+ * Component to render when there is no component for the content type.
424
+ *
425
+ * @param {DotCMSContentlet} contentType - The content type that couldn't be rendered
426
+ * @return {*}
427
+ */
428
+ function NoComponent({
429
+ contentType
430
+ }) {
431
+ return jsxs("div", {
432
+ "data-testid": "no-component",
433
+ children: ["No Component for ", jsx("strong", {
434
+ children: contentType
435
+ }), "."]
436
+ });
437
+ }
438
+
439
+ /**
440
+ * Contentlet component that renders DotCMS content with development mode support
441
+ *
442
+ * @component
443
+ * @param {DotCMSContentletRendererProps} props - Component properties
444
+ * @param {DotCMSContentlet} props.contentlet - The contentlet to be rendered
445
+ * @param {string} props.container - The container identifier
446
+ * @returns {JSX.Element} Rendered contentlet with appropriate wrapper and attributes
447
+ *
448
+ * @example
449
+ * ```tsx
450
+ * <Contentlet
451
+ * contentlet={myContentlet}
452
+ * container="container-1"
453
+ * />
454
+ * ```
455
+ */
456
+ function Contentlet({
457
+ contentlet,
458
+ container
459
+ }) {
460
+ const ref = useRef(null);
461
+ const isDevMode = useIsDevMode();
462
+ const haveContent = useCheckVisibleContent(ref);
463
+ const style = useMemo(() => isDevMode ? {
464
+ minHeight: haveContent ? undefined : '4rem'
465
+ } : {}, [isDevMode, haveContent]);
466
+ const dotAttributes = useMemo(() => isDevMode ? getDotContentletAttributes(contentlet, container) : {}, [isDevMode, contentlet, container]);
467
+ return jsx("div", Object.assign({}, dotAttributes, {
468
+ "data-dot-object": "contentlet",
469
+ ref: ref,
470
+ style: style,
471
+ children: jsx(CustomComponent, {
472
+ contentlet: contentlet
473
+ })
474
+ }));
475
+ }
476
+ /**
477
+ * Renders a custom component based on the contentlet type or falls back to a default component
478
+ *
479
+ * @component
480
+ * @param {CustomComponentProps} props - Component properties
481
+ * @param {DotCMSContentlet} props.contentlet - The contentlet data to render
482
+ * @returns {JSX.Element} The rendered custom component or fallback component
483
+ *
484
+ * @internal
485
+ */
486
+ function CustomComponent({
487
+ contentlet
488
+ }) {
489
+ const {
490
+ userComponents
491
+ } = useContext(DotCMSPageContext);
492
+ const UserComponent = userComponents[contentlet == null ? void 0 : contentlet.contentType];
493
+ if (UserComponent) {
494
+ return jsx(UserComponent, Object.assign({}, contentlet));
495
+ }
496
+ const UserNoComponent = userComponents['CustomNoComponent'];
497
+ return jsx(FallbackComponent, {
498
+ UserNoComponent: UserNoComponent,
499
+ contentlet: contentlet
500
+ });
501
+ }
502
+
503
+ /**
504
+ * @internal
505
+ *
506
+ * Container component that renders DotCMS containers and their contentlets.
507
+ * This component is responsible for:
508
+ * - Rendering container content based on DotCMS Page API data
509
+ * - Handling empty container states
510
+ * - Providing proper data attributes for DotCMS functionality
511
+ * - Managing container contentlets rendering
512
+ *
513
+ * @component
514
+ * @param {DotCMSContainerRendererProps} props - Component properties
515
+ * @returns {JSX.Element} Rendered container with its contentlets or empty state message
516
+ *
517
+ * @example
518
+ * ```tsx
519
+ * <Container container={containerData} />
520
+ * ```
521
+ */
522
+ function Container({
523
+ container
524
+ }) {
525
+ const {
526
+ pageAsset
527
+ } = useContext(DotCMSPageContext);
528
+ const containerData = useMemo(() => getContainersData(pageAsset, container), [pageAsset, container]);
529
+ const contentlets = useMemo(() => getContentletsInContainer(pageAsset, container), [pageAsset, container]);
530
+ if (!containerData) {
531
+ return jsx(ContainerNoFound, {
532
+ identifier: container.identifier
533
+ });
534
+ }
535
+ const isEmpty = contentlets.length === 0;
536
+ const dotAttributes = getDotContainerAttributes(containerData);
537
+ if (isEmpty) {
538
+ return jsx(EmptyContainer, Object.assign({}, dotAttributes));
539
+ }
540
+ return jsx("div", Object.assign({}, dotAttributes, {
541
+ children: contentlets.map(contentlet => jsx(Contentlet, {
542
+ contentlet: contentlet,
543
+ container: JSON.stringify(containerData)
544
+ }, contentlet.identifier))
545
+ }));
546
+ }
547
+
548
+ /**
549
+ * @internal
550
+ *
551
+ * Renders a Column component that represents a single column in a 12-column grid system.
552
+ * The column's position and width are determined by the leftOffset and width properties
553
+ * from the dotCMS Page API. Uses CSS Grid classes for positioning.
554
+ *
555
+ * @example
556
+ * ```tsx
557
+ * <Column column={{
558
+ * leftOffset: 0,
559
+ * width: 6,
560
+ * styleClass: "custom-class",
561
+ * containers: []
562
+ * }} />
563
+ * ```
564
+ *
565
+ * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
566
+ * @export
567
+ * @param {ColumnProps} { column } - Column configuration object
568
+ * @return {JSX.Element} Rendered column with its containers positioned in the grid
569
+ */
570
+ function Column({
571
+ column
572
+ }) {
573
+ const {
574
+ startClass,
575
+ endClass
576
+ } = getColumnPositionClasses(column);
577
+ const combinedClasses = combineClasses([styles[endClass], styles[startClass]]);
578
+ return jsx("div", {
579
+ "data-dot": "column",
580
+ className: combinedClasses,
581
+ children: jsx("div", {
582
+ className: column.styleClass,
583
+ children: column.containers.map(container => jsx(Container, {
584
+ container: container
585
+ }, `${container.identifier}-${container.uuid}`))
586
+ })
587
+ });
588
+ }
589
+
590
+ /**
591
+ * This component renders a row with all it's content using the layout provided by dotCMS Page API.
592
+ *
593
+ * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
594
+ * @category Components
595
+ * @param {React.ForwardedRef<HTMLDivElement, DotCMS>} ref
596
+ * @return {JSX.Element} Rendered rows with columns
597
+ */
598
+ const Row = ({
599
+ row
600
+ }) => {
601
+ const customRowClass = `${row.styleClass || ''} ${styles$1.row}`;
602
+ return jsx("div", {
603
+ className: "dot-row-container",
604
+ children: jsx("div", {
605
+ className: customRowClass,
606
+ "data-dot-object": 'row',
607
+ children: row.columns.map((column, index) => jsx(Column, {
608
+ column: column
609
+ }, index))
610
+ })
611
+ });
612
+ };
613
+
614
+ /**
615
+ * DotCMSLayoutBody component renders the layout body for a DotCMS page.
616
+ *
617
+ * It utilizes the page asset's layout body to render rows using the Row component.
618
+ * If the layout body does not exist, it renders an error message.
619
+ * It also provides context (DotCMSPageContext) with the page asset, optional user components,
620
+ * and the renderer mode to its children.
621
+ *
622
+ * @public
623
+ * @component
624
+ * @param {Object} props - Component properties.
625
+ * @param {DotCMSPageAsset} props.page - The DotCMS page asset containing the layout information.
626
+ * @param {Record<string, React.ComponentType<DotCMSContentlet>>} [props.components] - Optional mapping of custom components for content rendering.
627
+ * @param {DotCMSPageRendererMode} [props.mode='production'] - The renderer mode; defaults to 'production'. Alternate modes might trigger different behaviors.
628
+ *
629
+ * @returns {JSX.Element} The rendered DotCMS page body or an error message if the layout body is missing.
630
+ *
631
+ * -------------------------------------------------------------------
632
+ *
633
+ * El componente DotCMSLayoutBody renderiza el cuerpo del layout para una página de DotCMS.
634
+ *
635
+ * Utiliza el "body" del layout del asset de la página para renderizar las filas mediante el componente Row.
636
+ * Si el "body" del layout no está presente, renderiza un mensaje de error.
637
+ * También provee un contexto (DotCMSPageContext) con el asset de la página, componentes de usuario opcionales,
638
+ * y el modo del renderizado para sus componentes hijos.
639
+ */
640
+ const DotCMSLayoutBody = ({
641
+ page,
642
+ components: _components = {},
643
+ mode: _mode = 'production'
644
+ }) => {
645
+ var _page$layout;
646
+ const dotCMSPageBody = page == null || (_page$layout = page.layout) == null ? void 0 : _page$layout.body;
647
+ if (!dotCMSPageBody) {
648
+ return jsx(ErrorMessage, {
649
+ mode: _mode
650
+ });
651
+ }
652
+ const contextValue = {
653
+ pageAsset: page,
654
+ userComponents: _components,
655
+ mode: _mode
656
+ };
657
+ return jsx(DotCMSPageContext.Provider, {
658
+ value: contextValue,
659
+ children: dotCMSPageBody.rows.map((row, index) => jsx(Row, {
660
+ row: row
661
+ }, index))
662
+ });
663
+ };
664
+
665
+ export { DotCMSLayoutBody };