@dotcms/react 0.0.1-beta.2 → 0.0.1-beta.21

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/next.esm.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
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';
3
+ import { s as styleInject } from './es.json.stringify.esm.js';
4
+ import { getUVEState, initUVE, createUVESubscription } from '@dotcms/uve';
5
+ import { DEVELOPMENT_MODE, EMPTY_CONTAINER_STYLE_REACT, getDotContentletAttributes, CUSTOM_NO_COMPONENT, getContainersData, getContentletsInContainer, getDotContainerAttributes, getColumnPositionClasses, combineClasses } from '@dotcms/uve/internal';
6
+ import { UVE_MODE, UVEEventType } from '@dotcms/uve/types';
7
+ import { updateNavigation } from '@dotcms/client';
6
8
 
7
9
  /**
8
10
  * The `PageContext` is a React context that provides access to the DotCMS page context.
@@ -20,18 +22,15 @@ const DotCMSPageContext = /*#__PURE__*/createContext({
20
22
  * A React hook that determines if the current environment is in development mode.
21
23
  *
22
24
  * 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
+ * - The application is running inside the DotCMS editor (as determined by `getUVEState()`).
25
26
  *
26
- * @param {DotCMSPageRendererMode} [renderMode] - Optional override for the render mode.
27
27
  * @returns {boolean} - `true` if in development mode or inside the editor; otherwise, `false`.
28
28
  */
29
- const useIsDevMode = renderMode => {
29
+ const useIsDevMode = () => {
30
30
  const {
31
31
  mode
32
32
  } = useContext(DotCMSPageContext);
33
- const effectiveMode = renderMode != null ? renderMode : mode;
34
- const [isDevMode, setIsDevMode] = useState(effectiveMode === 'development');
33
+ const [isDevMode, setIsDevMode] = useState(mode === 'development');
35
34
  useEffect(() => {
36
35
  var _getUVEState;
37
36
  // Inside UVE we rely on the UVE state to determine if we are in development mode
@@ -41,9 +40,8 @@ const useIsDevMode = renderMode => {
41
40
  setIsDevMode(isUVEInEditor);
42
41
  return;
43
42
  }
44
- const effectiveMode = renderMode != null ? renderMode : mode;
45
- setIsDevMode(effectiveMode === 'development');
46
- }, [renderMode, mode]);
43
+ setIsDevMode(mode === DEVELOPMENT_MODE);
44
+ }, [mode]);
47
45
  return isDevMode;
48
46
  };
49
47
 
@@ -52,17 +50,12 @@ const useIsDevMode = renderMode => {
52
50
  *
53
51
  * @return {JSX.Element} Error message component
54
52
  */
55
- const ErrorMessage = ({
56
- mode
57
- }) => {
53
+ const ErrorMessage = () => {
54
+ const isDevMode = useIsDevMode();
58
55
  useEffect(() => {
59
56
  console.warn('Missing required layout.body property in page');
60
57
  }, []);
61
- const isDevMode = useIsDevMode(mode);
62
- if (!isDevMode) {
63
- return null;
64
- }
65
- return jsxs("div", {
58
+ return isDevMode && jsxs("div", {
66
59
  "data-testid": "error-message",
67
60
  style: {
68
61
  padding: '1rem',
@@ -97,207 +90,6 @@ var css_248z = ".Column-module_col-start-1__xylw6 {\n grid-column-start: 1;\n
97
90
  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
91
  styleInject(css_248z);
99
92
 
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
93
  /**
302
94
  * @internal
303
95
  *
@@ -309,7 +101,7 @@ const EMPTY_CONTAINER_STYLE = {
309
101
  * @param {string} props.identifier - Container identifier
310
102
  * @returns {JSX.Element | null} Message about missing container or null in production
311
103
  */
312
- const ContainerNoFound = ({
104
+ const ContainerNotFound = ({
313
105
  identifier
314
106
  }) => {
315
107
  const isDevMode = useIsDevMode();
@@ -324,7 +116,7 @@ const ContainerNoFound = ({
324
116
  }
325
117
  return jsxs("div", {
326
118
  "data-testid": "container-not-found",
327
- style: EMPTY_CONTAINER_STYLE,
119
+ style: EMPTY_CONTAINER_STYLE_REACT,
328
120
  children: ["This container with identifier ", identifier, " was not found."]
329
121
  });
330
122
  };
@@ -342,7 +134,7 @@ const EmptyContainer = dotAttributes => {
342
134
  return null;
343
135
  }
344
136
  return jsx("div", Object.assign({}, dotAttributes, {
345
- style: EMPTY_CONTAINER_STYLE,
137
+ style: EMPTY_CONTAINER_STYLE_REACT,
346
138
  children: jsx("span", {
347
139
  "data-testid": "empty-container-message",
348
140
  children: "This container is empty."
@@ -493,7 +285,7 @@ function CustomComponent({
493
285
  if (UserComponent) {
494
286
  return jsx(UserComponent, Object.assign({}, contentlet));
495
287
  }
496
- const UserNoComponent = userComponents['CustomNoComponent'];
288
+ const UserNoComponent = userComponents[CUSTOM_NO_COMPONENT];
497
289
  return jsx(FallbackComponent, {
498
290
  UserNoComponent: UserNoComponent,
499
291
  contentlet: contentlet
@@ -528,7 +320,7 @@ function Container({
528
320
  const containerData = useMemo(() => getContainersData(pageAsset, container), [pageAsset, container]);
529
321
  const contentlets = useMemo(() => getContentletsInContainer(pageAsset, container), [pageAsset, container]);
530
322
  if (!containerData) {
531
- return jsx(ContainerNoFound, {
323
+ return jsx(ContainerNotFound, {
532
324
  identifier: container.identifier
533
325
  });
534
326
  }
@@ -598,7 +390,7 @@ function Column({
598
390
  const Row = ({
599
391
  row
600
392
  }) => {
601
- const customRowClass = `${row.styleClass || ''} ${styles$1.row}`;
393
+ const customRowClass = combineClasses([row.styleClass || '', styles$1.row]);
602
394
  return jsx("div", {
603
395
  className: "dot-row-container",
604
396
  children: jsx("div", {
@@ -614,28 +406,18 @@ const Row = ({
614
406
  /**
615
407
  * DotCMSLayoutBody component renders the layout body for a DotCMS page.
616
408
  *
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.
409
+ * It utilizes the dotCMS page asset's layout body to render the page body.
410
+ * If the layout body does not exist, it renders an error message in the mode is `development`.
621
411
  *
622
412
  * @public
623
413
  * @component
624
414
  * @param {Object} props - Component properties.
625
415
  * @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.
416
+ * @param {Record<string, React.ComponentType<DotCMSContentlet>>} [props.components] - mapping of custom components for content rendering.
627
417
  * @param {DotCMSPageRendererMode} [props.mode='production'] - The renderer mode; defaults to 'production'. Alternate modes might trigger different behaviors.
628
418
  *
629
419
  * @returns {JSX.Element} The rendered DotCMS page body or an error message if the layout body is missing.
630
420
  *
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
421
  */
640
422
  const DotCMSLayoutBody = ({
641
423
  page,
@@ -644,11 +426,6 @@ const DotCMSLayoutBody = ({
644
426
  }) => {
645
427
  var _page$layout;
646
428
  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
429
  const contextValue = {
653
430
  pageAsset: page,
654
431
  userComponents: _components,
@@ -656,10 +433,211 @@ const DotCMSLayoutBody = ({
656
433
  };
657
434
  return jsx(DotCMSPageContext.Provider, {
658
435
  value: contextValue,
659
- children: dotCMSPageBody.rows.map((row, index) => jsx(Row, {
436
+ children: dotCMSPageBody ? dotCMSPageBody.rows.map((row, index) => jsx(Row, {
660
437
  row: row
661
- }, index))
438
+ }, index)) : jsx(ErrorMessage, {})
662
439
  });
663
440
  };
664
441
 
665
- export { DotCMSLayoutBody };
442
+ /**
443
+ * Custom hook to determine if the current UVE (Universal Visual Editor) mode
444
+ * matches the specified mode. This hook is useful for conditionally rendering
445
+ * components based on the UVE mode.
446
+ *
447
+ * @param {UVE_MODE} when - The UVE mode to check against.
448
+ * @returns {boolean} True if the current UVE mode matches the specified mode, otherwise false.
449
+ *
450
+ * @example
451
+ * // Basic usage: Check if the UVE is in edit mode
452
+ * const showInEditMode = useDotCMSShowWhen(UVE_MODE.EDIT);
453
+ * if (showInEditMode) {
454
+ * // Render edit-specific components
455
+ * }
456
+ *
457
+ * @example
458
+ * // Check if the UVE is in preview mode
459
+ * const showInPreviewMode = useDotCMSShowWhen(UVE_MODE.PREVIEW);
460
+ * if (showInPreviewMode) {
461
+ * // Render preview-specific components
462
+ * }
463
+ *
464
+ * @example
465
+ * // Check if the UVE is in live mode
466
+ * const showInLiveMode = useDotCMSShowWhen(UVE_MODE.LIVE);
467
+ * if (showInLiveMode) {
468
+ * // Render live-specific components
469
+ * }
470
+ */
471
+ const useDotCMSShowWhen = when => {
472
+ const [show, setShow] = useState(false);
473
+ useEffect(() => {
474
+ var _getUVEState;
475
+ setShow(((_getUVEState = getUVEState()) == null ? void 0 : _getUVEState.mode) === when);
476
+ }, [when]);
477
+ return show;
478
+ };
479
+
480
+ /**
481
+ * DotCMSShow component is used to conditionally render its children
482
+ * based on the Universal Visual Editor (UVE) mode. It checks if the UVE
483
+ * is in a specified mode and only renders its children in that case.
484
+ *
485
+ * @param {Object} props - The component props.
486
+ * @param {React.ReactNode} props.children - The children to be rendered when the condition is met.
487
+ * @param {UVE_MODE} [props.when=UVE_MODE.EDIT] - The UVE mode in which the children should be rendered.
488
+ * @returns {React.ReactNode | null} The children if the current UVE mode matches the `when` prop, otherwise null.
489
+ *
490
+ * @example
491
+ * // Basic usage: Render content only in edit mode
492
+ * <DotCMSShow when={UVE_MODE.EDIT}>
493
+ * <div>Edit Mode Content</div>
494
+ * </DotCMSShow>
495
+ *
496
+ * // This will render <div>Edit Mode Content</div> only if the UVE is in edit mode.
497
+ *
498
+ * @example
499
+ * // Render content in preview mode
500
+ * <DotCMSShow when={UVE_MODE.PREVIEW}>
501
+ * <MyCustomPreviewComponent />
502
+ * </DotCMSShow>
503
+ *
504
+ * // MyCustomPreviewComponent will only be rendered if the UVE is in preview mode.
505
+ *
506
+ * @example
507
+ * // Render content in live mode
508
+ * <DotCMSShow when={UVE_MODE.LIVE}>
509
+ * <LiveContentComponent />
510
+ * </DotCMSShow>
511
+ *
512
+ * // LiveContentComponent will only be rendered if the UVE is in live mode.
513
+ */
514
+ const DotCMSShow = ({
515
+ children,
516
+ when: _when = UVE_MODE.EDIT
517
+ }) => {
518
+ const show = useDotCMSShowWhen(_when);
519
+ if (!show) {
520
+ return null;
521
+ }
522
+ return children;
523
+ };
524
+
525
+ /**
526
+ * Custom hook to manage the editable state of a DotCMS page.
527
+ *
528
+ * This hook initializes the Universal Visual Editor (UVE) and subscribes to content changes.
529
+ * It updates the editable page state when content changes are detected in the UVE,
530
+ * ensuring your React components always display the latest content when editing in DotCMS.
531
+ *
532
+ * @example
533
+ * ```ts
534
+ * // Import the hook and the client
535
+ * import { useEditableDotCMSPage } from '@dotcms/react';
536
+ * import { createDotCMSClient } from '@dotcms/client';
537
+ *
538
+ * // Create the client
539
+ * const client = createDotCMSClient({
540
+ * dotcmsURL: 'https://your-dotcms-instance.com',
541
+ * authToken: 'your-auth-token'
542
+ * });
543
+ *
544
+ * // Get the page
545
+ * const page = await client.page.get('/', {
546
+ * languageId: '1',
547
+ * });
548
+ *
549
+ * // Use the hook to get an editable version of the page
550
+ * const editablePage = useEditableDotCMSPage(page);
551
+ *
552
+ * // Then use the page data in your component
553
+ * return (
554
+ * <div>
555
+ * <h1>{editablePage.page.title}</h1>
556
+ * <div dangerouslySetInnerHTML={{ __html: editablePage.page.body }} />
557
+ * </div>
558
+ * );
559
+ * ```
560
+ *
561
+ * @example
562
+ * ```ts
563
+ * // Import the hook and the client
564
+ * import { useEditableDotCMSPage } from '@dotcms/react';
565
+ * import { createDotCMSClient } from '@dotcms/client';
566
+ *
567
+ * // Create the client
568
+ * const client = createDotCMSClient({
569
+ * dotcmsURL: 'https://your-dotcms-instance.com',
570
+ * authToken: 'your-auth-token'
571
+ * });
572
+ *
573
+ * // Get the page with GraphQL content
574
+ * const page = await client.page.get('/', {
575
+ * languageId: '1',
576
+ * graphql: {
577
+ * content: {
578
+ * products: `ProductCollection(query: "+title:snow", limit: 10, offset: 0, sortBy: "score") {
579
+ * title
580
+ * urlMap
581
+ * category {
582
+ * name
583
+ * inode
584
+ * }
585
+ * retailPrice
586
+ * image {
587
+ * versionPath
588
+ * }
589
+ * }`
590
+ * }
591
+ * }
592
+ * });
593
+ *
594
+ * // Use the hook to get an editable version of the page and its content
595
+ * const editablePage = useEditableDotCMSPage(page);
596
+ *
597
+ * // Access both page data and GraphQL content
598
+ * const { page: pageData, content } = editablePage;
599
+ *
600
+ * // Use the products from GraphQL content
601
+ * return (
602
+ * <div>
603
+ * <h1>{pageData.title}</h1>
604
+ * <ProductList products={content.products} />
605
+ * </div>
606
+ * );
607
+ * ```
608
+ * @param {DotCMSEditablePage} editablePage - The initial editable page data from client.page.get().
609
+ *
610
+ * @returns {DotCMSEditablePage} The updated editable page state that reflects any changes made in the UVE.
611
+ * The structure includes page data and any GraphQL content that was requested.
612
+ */
613
+ const useEditableDotCMSPage = editablePage => {
614
+ const [updatedEditablePage, setUpdatedEditablePage] = useState(editablePage);
615
+ useEffect(() => {
616
+ var _editablePage$page$pa, _editablePage$page;
617
+ if (!getUVEState()) {
618
+ return;
619
+ }
620
+ const pageURI = (_editablePage$page$pa = editablePage == null || (_editablePage$page = editablePage.page) == null ? void 0 : _editablePage$page.pageURI) != null ? _editablePage$page$pa : '/';
621
+ const {
622
+ destroyUVESubscriptions
623
+ } = initUVE(editablePage);
624
+ // Update the navigation to the pageURI
625
+ updateNavigation(pageURI);
626
+ return () => {
627
+ destroyUVESubscriptions();
628
+ };
629
+ }, [editablePage]);
630
+ useEffect(() => {
631
+ const {
632
+ unsubscribe
633
+ } = createUVESubscription(UVEEventType.CONTENT_CHANGES, payload => {
634
+ setUpdatedEditablePage(payload);
635
+ });
636
+ return () => {
637
+ unsubscribe();
638
+ };
639
+ }, []);
640
+ return updatedEditablePage;
641
+ };
642
+
643
+ export { DotCMSLayoutBody, DotCMSShow, useDotCMSShowWhen, useEditableDotCMSPage };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@dotcms/react",
3
- "version": "0.0.1-beta.2",
3
+ "version": "0.0.1-beta.21",
4
4
  "peerDependencies": {
5
5
  "react": ">=18",
6
6
  "react-dom": ">=18",
7
- "@dotcms/client": "0.0.1-beta.2",
8
- "@dotcms/uve": "0.0.1-beta.2",
7
+ "@dotcms/client": "0.0.1-beta.21",
8
+ "@dotcms/uve": "0.0.1-beta.21",
9
9
  "@tinymce/tinymce-react": "^5.1.1"
10
10
  },
11
11
  "description": "Official React Components library to render a dotCMS page.",
@@ -22,6 +22,27 @@
22
22
  "React",
23
23
  "Components"
24
24
  ],
25
+ "exports": {
26
+ "./package.json": "./package.json",
27
+ ".": {
28
+ "import": "./index.esm.js",
29
+ "types": "./index.esm.d.ts"
30
+ },
31
+ "./next": {
32
+ "import": "./next.esm.js",
33
+ "types": "./next.esm.d.ts"
34
+ }
35
+ },
36
+ "typesVersions": {
37
+ "*": {
38
+ ".": [
39
+ "./src/index.d.ts"
40
+ ],
41
+ "next": [
42
+ "./src/next.d.ts"
43
+ ]
44
+ }
45
+ },
25
46
  "author": "dotcms <dev@dotcms.com>",
26
47
  "license": "MIT",
27
48
  "bugs": {
@@ -1,4 +1,4 @@
1
- import { DotCMSColumnContainer, DotCMSPageAsset, DotPageAssetLayoutColumn } from '../types';
1
+ import { DotCMSColumnContainer, DotCMSPageAsset, DotPageAssetLayoutColumn } from '@dotcms/uve/types';
2
2
  export declare const MOCK_COLUMN: DotPageAssetLayoutColumn;
3
3
  export declare const MOCK_CONTAINER: DotCMSColumnContainer;
4
4
  export declare const MOCK_PAGE_ASSET: DotCMSPageAsset;
@@ -1,4 +1,4 @@
1
- import { DotPageAssetLayoutColumn } from '../../types';
1
+ import { DotPageAssetLayoutColumn } from '@dotcms/uve/types';
2
2
  /**
3
3
  * @internal
4
4
  *
@@ -1,4 +1,4 @@
1
- import { DotCMSColumnContainer } from '../../types';
1
+ import { DotCMSColumnContainer } from '@dotcms/uve/types';
2
2
  /**
3
3
  * @internal
4
4
  *
@@ -1,4 +1,4 @@
1
- import { DotContainerAttributes } from '../../utils';
1
+ import { DotContainerAttributes } from '@dotcms/uve/types';
2
2
  /**
3
3
  * @internal
4
4
  *
@@ -10,7 +10,7 @@ import { DotContainerAttributes } from '../../utils';
10
10
  * @param {string} props.identifier - Container identifier
11
11
  * @returns {JSX.Element | null} Message about missing container or null in production
12
12
  */
13
- export declare const ContainerNoFound: ({ identifier }: {
13
+ export declare const ContainerNotFound: ({ identifier }: {
14
14
  identifier: string;
15
15
  }) => import("react/jsx-runtime").JSX.Element | null;
16
16
  /**
@@ -1,4 +1,4 @@
1
- import { DotCMSContentlet } from '../../types';
1
+ import { DotCMSContentlet } from '@dotcms/uve/types';
2
2
  /**
3
3
  * @internal
4
4
  *