@dotcms/react 0.0.1-alpha.37 → 0.0.1-alpha.39

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 (66) hide show
  1. package/.babelrc +12 -0
  2. package/.eslintrc.json +18 -0
  3. package/jest.config.ts +11 -0
  4. package/package.json +4 -8
  5. package/project.json +56 -0
  6. package/src/lib/components/BlockEditorRenderer/BlockEditorRenderer.spec.tsx +51 -0
  7. package/src/lib/components/BlockEditorRenderer/{BlockEditorRenderer.d.ts → BlockEditorRenderer.tsx} +16 -2
  8. package/src/lib/components/BlockEditorRenderer/blocks/{Code.d.ts → Code.tsx} +14 -2
  9. package/src/lib/components/BlockEditorRenderer/blocks/{Contentlet.d.ts → Contentlet.tsx} +21 -1
  10. package/src/lib/components/BlockEditorRenderer/blocks/Image.tsx +18 -0
  11. package/src/lib/components/BlockEditorRenderer/blocks/{Lists.d.ts → Lists.tsx} +12 -3
  12. package/src/lib/components/BlockEditorRenderer/blocks/Table.tsx +60 -0
  13. package/src/lib/components/BlockEditorRenderer/blocks/Texts.tsx +126 -0
  14. package/src/lib/components/BlockEditorRenderer/blocks/Video.tsx +26 -0
  15. package/src/lib/components/BlockEditorRenderer/item/BlockEditorBlock.spec.tsx +634 -0
  16. package/src/lib/components/BlockEditorRenderer/item/BlockEditorBlock.tsx +146 -0
  17. package/src/lib/components/Column/Column.module.css +99 -0
  18. package/src/lib/components/Column/Column.spec.tsx +78 -0
  19. package/src/lib/components/Column/Column.tsx +59 -0
  20. package/src/lib/components/Container/Container.module.css +7 -0
  21. package/src/lib/components/Container/Container.spec.tsx +155 -0
  22. package/src/lib/components/Container/Container.tsx +122 -0
  23. package/src/lib/components/DotEditableText/DotEditableText.spec.tsx +232 -0
  24. package/src/lib/components/DotEditableText/DotEditableText.tsx +168 -0
  25. package/src/lib/components/DotEditableText/utils.ts +82 -0
  26. package/src/lib/components/DotcmsLayout/DotcmsLayout.module.css +7 -0
  27. package/src/lib/components/DotcmsLayout/DotcmsLayout.spec.tsx +46 -0
  28. package/src/lib/components/DotcmsLayout/{DotcmsLayout.d.ts → DotcmsLayout.tsx} +18 -2
  29. package/src/lib/components/PageProvider/PageProvider.module.css +7 -0
  30. package/src/lib/components/PageProvider/PageProvider.spec.tsx +59 -0
  31. package/src/lib/components/PageProvider/{PageProvider.d.ts → PageProvider.tsx} +10 -1
  32. package/src/lib/components/Row/Row.module.css +5 -0
  33. package/src/lib/components/Row/Row.spec.tsx +92 -0
  34. package/src/lib/components/Row/Row.tsx +52 -0
  35. package/src/lib/contexts/PageContext.tsx +10 -0
  36. package/src/lib/hooks/useDotcmsEditor.spec.ts +176 -0
  37. package/src/lib/hooks/useDotcmsEditor.ts +94 -0
  38. package/src/lib/hooks/useDotcmsPageContext.spec.tsx +47 -0
  39. package/src/lib/hooks/{useDotcmsPageContext.d.ts → useDotcmsPageContext.tsx} +7 -1
  40. package/src/lib/mocks/mockPageContext.tsx +113 -0
  41. package/src/lib/models/{blocks.interface.d.ts → blocks.interface.ts} +43 -16
  42. package/src/lib/models/content-node.interface.ts +90 -0
  43. package/src/lib/models/{index.d.ts → index.ts} +5 -2
  44. package/src/lib/utils/utils.ts +89 -0
  45. package/tsconfig.json +20 -0
  46. package/tsconfig.lib.json +23 -0
  47. package/tsconfig.spec.json +20 -0
  48. package/index.esm.d.ts +0 -1
  49. package/index.esm.js +0 -5070
  50. package/src/lib/components/BlockEditorRenderer/blocks/Image.d.ts +0 -8
  51. package/src/lib/components/BlockEditorRenderer/blocks/Table.d.ts +0 -16
  52. package/src/lib/components/BlockEditorRenderer/blocks/Texts.d.ts +0 -71
  53. package/src/lib/components/BlockEditorRenderer/blocks/Video.d.ts +0 -8
  54. package/src/lib/components/BlockEditorRenderer/item/BlockEditorBlock.d.ts +0 -12
  55. package/src/lib/components/Column/Column.d.ts +0 -5
  56. package/src/lib/components/Container/Container.d.ts +0 -5
  57. package/src/lib/components/DotEditableText/DotEditableText.d.ts +0 -3
  58. package/src/lib/components/DotEditableText/utils.d.ts +0 -36
  59. package/src/lib/components/Row/Row.d.ts +0 -25
  60. package/src/lib/contexts/PageContext.d.ts +0 -3
  61. package/src/lib/hooks/useDotcmsEditor.d.ts +0 -3
  62. package/src/lib/mocks/mockPageContext.d.ts +0 -8
  63. package/src/lib/models/content-node.interface.d.ts +0 -29
  64. package/src/lib/utils/utils.d.ts +0 -23
  65. /package/src/{index.d.ts → index.ts} +0 -0
  66. /package/src/lib/mocks/{index.d.ts → index.ts} +0 -0
@@ -0,0 +1,146 @@
1
+ import { Blocks } from '../../../models/blocks.interface';
2
+ import { ContentNode, CustomRenderer } from '../../../models/content-node.interface';
3
+ import { BlockQuote, CodeBlock } from '../blocks/Code';
4
+ import { DotContent } from '../blocks/Contentlet';
5
+ import { DotCMSImage } from '../blocks/Image';
6
+ import { BulletList, ListItem, OrderedList } from '../blocks/Lists';
7
+ import { TableRenderer } from '../blocks/Table';
8
+ import { Heading, Paragraph, TextBlock } from '../blocks/Texts';
9
+ import { DotCMSVideo } from '../blocks/Video';
10
+
11
+ /**
12
+ * Renders a block editor item based on the provided content and custom renderers.
13
+ *
14
+ * @param content - The content nodes to render.
15
+ * @param customRenderers - Optional custom renderers for specific node types.
16
+ * @returns The rendered block editor item.
17
+ */
18
+ export const BlockEditorBlock = ({
19
+ content,
20
+ customRenderers
21
+ }: {
22
+ content: ContentNode[];
23
+ customRenderers?: CustomRenderer;
24
+ }) => {
25
+ return content?.map((node: ContentNode, index) => {
26
+ const CustomRendererComponent = customRenderers?.[node.type];
27
+ if (CustomRendererComponent) {
28
+ return (
29
+ <CustomRendererComponent
30
+ key={`${node.type}-${index}`}
31
+ {...node}
32
+ content={node.content}>
33
+ <BlockEditorBlock content={node.content} customRenderers={customRenderers} />
34
+ </CustomRendererComponent>
35
+ );
36
+ }
37
+
38
+ switch (node.type) {
39
+ case Blocks.PARAGRAPH:
40
+ return (
41
+ <Paragraph key={`${node.type}-${index}`} {...node}>
42
+ <BlockEditorBlock
43
+ content={node.content}
44
+ customRenderers={customRenderers}
45
+ />
46
+ </Paragraph>
47
+ );
48
+
49
+ case Blocks.HEADING:
50
+ return (
51
+ <Heading key={`${node.type}-${index}`} {...node}>
52
+ <BlockEditorBlock
53
+ content={node.content}
54
+ customRenderers={customRenderers}
55
+ />
56
+ </Heading>
57
+ );
58
+
59
+ case Blocks.TEXT:
60
+ return <TextBlock key={`${node.type}-${index}`} {...node} />;
61
+
62
+ case Blocks.BULLET_LIST:
63
+ return (
64
+ <BulletList key={`${node.type}-${index}`}>
65
+ <BlockEditorBlock
66
+ content={node.content}
67
+ customRenderers={customRenderers}
68
+ />
69
+ </BulletList>
70
+ );
71
+
72
+ case Blocks.ORDERED_LIST:
73
+ return (
74
+ <OrderedList key={`${node.type}-${index}`}>
75
+ <BlockEditorBlock
76
+ content={node.content}
77
+ customRenderers={customRenderers}
78
+ />
79
+ </OrderedList>
80
+ );
81
+
82
+ case Blocks.LIST_ITEM:
83
+ return (
84
+ <ListItem key={`${node.type}-${index}`}>
85
+ <BlockEditorBlock
86
+ content={node.content}
87
+ customRenderers={customRenderers}
88
+ />
89
+ </ListItem>
90
+ );
91
+
92
+ case Blocks.BLOCK_QUOTE:
93
+ return (
94
+ <BlockQuote key={`${node.type}-${index}`}>
95
+ <BlockEditorBlock
96
+ content={node.content}
97
+ customRenderers={customRenderers}
98
+ />
99
+ </BlockQuote>
100
+ );
101
+
102
+ case Blocks.CODE_BLOCK:
103
+ return (
104
+ <CodeBlock key={`${node.type}-${index}`} {...node}>
105
+ <BlockEditorBlock
106
+ content={node.content}
107
+ customRenderers={customRenderers}
108
+ />
109
+ </CodeBlock>
110
+ );
111
+
112
+ case Blocks.HARDBREAK:
113
+ return <br key={`${node.type}-${index}`} />;
114
+
115
+ case Blocks.HORIZONTAL_RULE:
116
+ return <hr key={`${node.type}-${index}`} />;
117
+
118
+ case Blocks.DOT_IMAGE:
119
+ return <DotCMSImage key={`${node.type}-${index}`} {...node} />;
120
+
121
+ case Blocks.DOT_VIDEO:
122
+ return <DotCMSVideo key={`${node.type}-${index}`} {...node} />;
123
+
124
+ case Blocks.TABLE:
125
+ return (
126
+ <TableRenderer
127
+ key={`${node.type}-${index}`}
128
+ content={node.content}
129
+ blockEditorItem={BlockEditorBlock}
130
+ />
131
+ );
132
+
133
+ case Blocks.DOT_CONTENT:
134
+ return (
135
+ <DotContent
136
+ key={`${node.type}-${index}`}
137
+ {...node}
138
+ customRenderers={customRenderers}
139
+ />
140
+ );
141
+
142
+ default:
143
+ return <div key={`${node.type}-${index}`}>Unknown Block Type {node.type}</div>;
144
+ }
145
+ });
146
+ };
@@ -0,0 +1,99 @@
1
+ .col-start-1 {
2
+ grid-column-start: 1;
3
+ }
4
+
5
+ .col-start-2 {
6
+ grid-column-start: 2;
7
+ }
8
+
9
+ .col-start-3 {
10
+ grid-column-start: 3;
11
+ }
12
+
13
+ .col-start-4 {
14
+ grid-column-start: 4;
15
+ }
16
+
17
+ .col-start-5 {
18
+ grid-column-start: 5;
19
+ }
20
+
21
+ .col-start-6 {
22
+ grid-column-start: 6;
23
+ }
24
+
25
+ .col-start-7 {
26
+ grid-column-start: 7;
27
+ }
28
+
29
+ .col-start-8 {
30
+ grid-column-start: 8;
31
+ }
32
+
33
+ .col-start-9 {
34
+ grid-column-start: 9;
35
+ }
36
+
37
+ .col-start-10 {
38
+ grid-column-start: 10;
39
+ }
40
+
41
+ .col-start-11 {
42
+ grid-column-start: 11;
43
+ }
44
+
45
+ .col-start-12 {
46
+ grid-column-start: 12;
47
+ }
48
+
49
+ .col-end-1 {
50
+ grid-column-end: 1;
51
+ }
52
+
53
+ .col-end-2 {
54
+ grid-column-end: 2;
55
+ }
56
+
57
+ .col-end-3 {
58
+ grid-column-end: 3;
59
+ }
60
+
61
+ .col-end-4 {
62
+ grid-column-end: 4;
63
+ }
64
+
65
+ .col-end-5 {
66
+ grid-column-end: 5;
67
+ }
68
+
69
+ .col-end-6 {
70
+ grid-column-end: 6;
71
+ }
72
+
73
+ .col-end-7 {
74
+ grid-column-end: 7;
75
+ }
76
+
77
+ .col-end-8 {
78
+ grid-column-end: 8;
79
+ }
80
+
81
+ .col-end-9 {
82
+ grid-column-end: 9;
83
+ }
84
+
85
+ .col-end-10 {
86
+ grid-column-end: 10;
87
+ }
88
+
89
+ .col-end-11 {
90
+ grid-column-end: 11;
91
+ }
92
+
93
+ .col-end-12 {
94
+ grid-column-end: 12;
95
+ }
96
+
97
+ .col-end-13 {
98
+ grid-column-end: 13;
99
+ }
@@ -0,0 +1,78 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import '@testing-library/jest-dom';
3
+
4
+ import * as dotcmsClient from '@dotcms/client';
5
+
6
+ import { Column } from './Column';
7
+
8
+ import { MockContextRender } from '../../mocks/mockPageContext';
9
+ import { ContainerProps } from '../Container/Container';
10
+
11
+ jest.mock('../Container/Container', () => {
12
+ return {
13
+ Container: ({ containerRef }: Partial<ContainerProps>) => (
14
+ <div data-testid="mockContainer">{containerRef?.identifier}</div>
15
+ )
16
+ };
17
+ });
18
+
19
+ describe('Column', () => {
20
+ const mockColumnData = {
21
+ width: 6, // Adjust as needed
22
+ leftOffset: 3, // Adjust as needed
23
+ containers: [
24
+ { identifier: 'Container1', uuid: 'unique-id-1' },
25
+ { identifier: 'Container2', uuid: 'unique-id-2' }
26
+ // Add more containers as needed for your test
27
+ ],
28
+ styleClass: ''
29
+ };
30
+
31
+ describe('Column is inside editor', () => {
32
+ beforeEach(() => {
33
+ jest.spyOn(dotcmsClient, 'isInsideEditor').mockReturnValue(true);
34
+ render(
35
+ <MockContextRender mockContext={{ isInsideEditor: true }}>
36
+ <Column column={mockColumnData} />
37
+ </MockContextRender>
38
+ );
39
+ });
40
+
41
+ it('applies the correct width and start classes based on props', () => {
42
+ const columnElement = screen.getByTestId('column');
43
+ expect(columnElement).toHaveClass('col-end-9');
44
+ expect(columnElement).toHaveClass('col-start-3');
45
+ });
46
+
47
+ it('applies the correct data attr', () => {
48
+ expect(screen.getByTestId('column')).toHaveAttribute('data-dot', 'column');
49
+ });
50
+
51
+ it('renders the correct number of containers', () => {
52
+ const containers = screen.getAllByTestId('mockContainer');
53
+ expect(containers.length).toBe(mockColumnData.containers.length);
54
+ });
55
+
56
+ it('passes the correct props to each Container', () => {
57
+ mockColumnData.containers.forEach((container) => {
58
+ expect(screen.getByText(container.identifier)).toBeInTheDocument();
59
+ });
60
+ });
61
+ });
62
+
63
+ describe('Column is not inside editor', () => {
64
+ beforeEach(() => {
65
+ jest.spyOn(dotcmsClient, 'isInsideEditor').mockReturnValue(false);
66
+ render(
67
+ <MockContextRender mockContext={{ isInsideEditor: false }}>
68
+ <Column column={mockColumnData} />
69
+ </MockContextRender>
70
+ );
71
+ });
72
+
73
+ it('should not have dot attrs', () => {
74
+ const columnElement = screen.queryByTestId('column');
75
+ expect(columnElement).toBeNull();
76
+ });
77
+ });
78
+ });
@@ -0,0 +1,59 @@
1
+ import { useContext } from 'react';
2
+
3
+ import styles from './column.module.css';
4
+
5
+ import { PageContext } from '../../contexts/PageContext';
6
+ import { DotCMSPageContext } from '../../models';
7
+ import { combineClasses, getPositionStyleClasses } from '../../utils/utils';
8
+ import { Container } from '../Container/Container';
9
+
10
+ /**
11
+ * Props for Column component to render a column with its containers.
12
+ *
13
+ * @export
14
+ * @interface ColumnProps
15
+ */
16
+ export interface ColumnProps {
17
+ readonly column: DotCMSPageContext['pageAsset']['layout']['body']['rows'][0]['columns'][0];
18
+ }
19
+
20
+ /**
21
+ * Renders a Column with its containers using information provided by dotCMS Page API.
22
+ *
23
+ * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
24
+ * @export
25
+ * @param {ColumnProps} { column }
26
+ * @return {JSX.Element} Rendered column with containers
27
+ */
28
+ export function Column({ column }: ColumnProps) {
29
+ const { isInsideEditor } = useContext(PageContext) as DotCMSPageContext;
30
+
31
+ const { startClass, endClass } = getPositionStyleClasses(
32
+ column.leftOffset,
33
+ column.width + column.leftOffset
34
+ );
35
+
36
+ const combinedClasses = combineClasses([
37
+ styles[endClass],
38
+ styles[startClass],
39
+ column.styleClass
40
+ ]);
41
+
42
+ const columnProps = isInsideEditor
43
+ ? {
44
+ 'data-dot': 'column',
45
+ 'data-testid': 'column'
46
+ }
47
+ : {};
48
+
49
+ return (
50
+ <div {...columnProps} className={combinedClasses}>
51
+ {column.containers.map((container) => (
52
+ <Container
53
+ key={`${container.identifier}-${container.uuid}`}
54
+ containerRef={container}
55
+ />
56
+ ))}
57
+ </div>
58
+ );
59
+ }
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Replace this with your own classes
3
+ *
4
+ * e.g.
5
+ * .container {
6
+ * }
7
+ */
@@ -0,0 +1,155 @@
1
+ import '@testing-library/jest-dom';
2
+
3
+ import { render, screen } from '@testing-library/react';
4
+
5
+ import * as dotcmsClient from '@dotcms/client';
6
+
7
+ import { Container } from './Container';
8
+
9
+ import { MockContextRender, mockPageContext } from '../../mocks/mockPageContext';
10
+ import { getContainersData } from '../../utils/utils';
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ const getContainer = ({ containerRef, containers }: { containerRef: any; containers: any }) => {
14
+ const { acceptTypes, maxContentlets, variantId, path } = getContainersData(
15
+ containers,
16
+ containerRef
17
+ );
18
+
19
+ return {
20
+ acceptTypes,
21
+ identifier: path ?? containerRef.identifier,
22
+ maxContentlets,
23
+ variantId,
24
+ uuid: containerRef.uuid
25
+ };
26
+ };
27
+
28
+ describe('Container', () => {
29
+ // Mock data for your context and container
30
+ jest.spyOn(dotcmsClient, 'isInsideEditor').mockReturnValue(true);
31
+
32
+ describe('with contentlets', () => {
33
+ const mockContainerRef = {
34
+ identifier: 'container-1',
35
+ uuid: '1',
36
+ containers: []
37
+ };
38
+
39
+ it('renders NoComponent component for unsupported content types', () => {
40
+ const updatedContext = {
41
+ ...mockPageContext,
42
+ isInsideEditor: true,
43
+ components: {}
44
+ };
45
+
46
+ render(
47
+ <MockContextRender mockContext={updatedContext}>
48
+ <Container containerRef={mockContainerRef} />
49
+ </MockContextRender>
50
+ );
51
+
52
+ expect(screen.getByTestId('no-component')).toHaveTextContent(
53
+ 'No Component for content-type-1'
54
+ );
55
+ });
56
+
57
+ it('render custom NoComponent component for unsetted content types', () => {
58
+ const updatedContext = {
59
+ ...mockPageContext,
60
+ isInsideEditor: true,
61
+ components: {
62
+ CustomNoComponent: () => (
63
+ <div data-testid="custom-no-component">Custom No Component</div>
64
+ )
65
+ }
66
+ };
67
+
68
+ render(
69
+ <MockContextRender mockContext={updatedContext}>
70
+ <Container containerRef={mockContainerRef} />
71
+ </MockContextRender>
72
+ );
73
+
74
+ expect(screen.getByTestId('custom-no-component')).toHaveTextContent(
75
+ 'Custom No Component'
76
+ );
77
+ });
78
+
79
+ it('should render contentlets with the right attributes', () => {
80
+ const mockContainer = {
81
+ identifier: 'container-1',
82
+ uuid: '1',
83
+ containers: []
84
+ };
85
+
86
+ const updatedContext = {
87
+ ...mockPageContext,
88
+ components: {},
89
+ isInsideEditor: true
90
+ };
91
+
92
+ render(
93
+ <MockContextRender mockContext={updatedContext}>
94
+ <Container containerRef={mockContainer} />
95
+ </MockContextRender>
96
+ );
97
+
98
+ const container = getContainer({
99
+ containerRef: mockContainer,
100
+ containers: updatedContext.pageAsset.containers
101
+ });
102
+
103
+ const contentlet = screen.getByTestId('dot-contentlet');
104
+ expect(contentlet).toHaveAttribute('data-dot-identifier', 'contentlet-1');
105
+ expect(contentlet).toHaveAttribute('data-dot-title', 'Contentlet 1');
106
+ expect(contentlet).toHaveAttribute('data-dot-inode', 'inode-1');
107
+ expect(contentlet).toHaveAttribute('data-dot-on-number-of-pages', '1');
108
+ expect(contentlet).toHaveAttribute('data-dot-basetype', 'base-type-1');
109
+ expect(contentlet).toHaveAttribute('data-dot-container', JSON.stringify(container));
110
+ });
111
+
112
+ describe('without contentlets', () => {
113
+ const mockContainerRef = {
114
+ identifier: 'container-2',
115
+ uuid: '2',
116
+ containers: []
117
+ };
118
+ it('renders EmptyContainer component in editor mode', () => {
119
+ const updatedContext = {
120
+ ...mockPageContext,
121
+ components: {},
122
+ isInsideEditor: true
123
+ };
124
+ render(
125
+ <MockContextRender mockContext={updatedContext}>
126
+ <Container containerRef={mockContainerRef} />
127
+ </MockContextRender>
128
+ );
129
+
130
+ expect(screen.getByTestId('dot-container')).toHaveTextContent(
131
+ 'This container is empty.'
132
+ );
133
+ });
134
+
135
+ it('dont render EmptyContainer component outside editor mode', () => {
136
+ jest.spyOn(dotcmsClient, 'isInsideEditor').mockReturnValue(false);
137
+
138
+ const updatedContext = {
139
+ ...mockPageContext,
140
+ components: {},
141
+ isInsideEditor: false
142
+ };
143
+ render(
144
+ <MockContextRender mockContext={updatedContext}>
145
+ <Container containerRef={mockContainerRef} />
146
+ </MockContextRender>
147
+ );
148
+
149
+ expect(screen.queryByTestId('dot-container')).toBeNull();
150
+ });
151
+ });
152
+ });
153
+
154
+ // Add tests for pointer events, dynamic component rendering, and other scenarios...
155
+ });
@@ -0,0 +1,122 @@
1
+ import { useContext } from 'react';
2
+
3
+ import { PageContext } from '../../contexts/PageContext';
4
+ import { DotCMSPageContext } from '../../models';
5
+ import { getContainersData } from '../../utils/utils';
6
+
7
+ /**
8
+ * Component to render when there is no component for the content type.
9
+ *
10
+ * @param {{ readonly contentType: string }} { contentType }
11
+ * @return {*}
12
+ */
13
+ function NoComponent({ contentType }: { readonly contentType: string }) {
14
+ return <div data-testid="no-component">No Component for {contentType}</div>;
15
+ }
16
+
17
+ /**
18
+ * Component to render when there is no content in the container.
19
+ *
20
+ * @return {*}
21
+ */
22
+ function EmptyContent() {
23
+ return null;
24
+ }
25
+
26
+ /**
27
+ * Props for the Container component.
28
+ *
29
+ * @export
30
+ * @interface ContainerProps
31
+ */
32
+ export interface ContainerProps {
33
+ readonly containerRef: DotCMSPageContext['pageAsset']['layout']['body']['rows'][0]['columns'][0]['containers'][0];
34
+ }
35
+
36
+ /**
37
+ * Renders a Container with its content using information provided by dotCMS Page API.
38
+ *
39
+ * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
40
+ * @export
41
+ * @param {ContainerProps} { containerRef }
42
+ * @return {JSX.Element} Rendered container with content
43
+ */
44
+ export function Container({ containerRef }: ContainerProps) {
45
+ const { isInsideEditor } = useContext(PageContext) as DotCMSPageContext;
46
+
47
+ const { identifier, uuid } = containerRef;
48
+
49
+ // Get the containers from the global context
50
+ const {
51
+ pageAsset: { containers },
52
+ components
53
+ } = useContext<DotCMSPageContext | null>(PageContext) as DotCMSPageContext;
54
+
55
+ const { acceptTypes, contentlets, maxContentlets, variantId, path } = getContainersData(
56
+ containers,
57
+ containerRef
58
+ );
59
+
60
+ const container = {
61
+ acceptTypes,
62
+ identifier: path ?? identifier,
63
+ maxContentlets,
64
+ variantId,
65
+ uuid
66
+ };
67
+
68
+ const containerStyles = contentlets.length
69
+ ? undefined
70
+ : {
71
+ width: '100%',
72
+ backgroundColor: '#ECF0FD',
73
+ display: 'flex',
74
+ justifyContent: 'center',
75
+ alignItems: 'center',
76
+ color: '#030E32',
77
+ height: '10rem'
78
+ };
79
+
80
+ const ContainerChildren = contentlets.map((contentlet) => {
81
+ const ContentTypeComponent = components[contentlet.contentType];
82
+ const DefaultComponent = components['CustomNoComponent'] || NoComponent;
83
+
84
+ const Component = isInsideEditor
85
+ ? ContentTypeComponent || DefaultComponent
86
+ : ContentTypeComponent || EmptyContent;
87
+
88
+ return isInsideEditor ? (
89
+ <div
90
+ data-testid="dot-contentlet"
91
+ data-dot-object="contentlet"
92
+ data-dot-identifier={contentlet.identifier}
93
+ data-dot-basetype={contentlet.baseType}
94
+ data-dot-title={contentlet.widgetTitle || contentlet.title}
95
+ data-dot-inode={contentlet.inode}
96
+ data-dot-type={contentlet.contentType}
97
+ data-dot-container={JSON.stringify(container)}
98
+ data-dot-on-number-of-pages={contentlet.onNumberOfPages}
99
+ key={contentlet.identifier}>
100
+ <Component {...contentlet} />
101
+ </div>
102
+ ) : (
103
+ <Component {...contentlet} key={contentlet.identifier} />
104
+ );
105
+ });
106
+
107
+ return isInsideEditor ? (
108
+ <div
109
+ data-testid="dot-container"
110
+ data-dot-object="container"
111
+ data-dot-accept-types={acceptTypes}
112
+ data-dot-identifier={path ?? identifier}
113
+ data-max-contentlets={maxContentlets}
114
+ data-dot-uuid={uuid}
115
+ style={containerStyles}>
116
+ {ContainerChildren.length ? ContainerChildren : 'This container is empty.'}
117
+ </div>
118
+ ) : (
119
+ // eslint-disable-next-line react/jsx-no-useless-fragment
120
+ <>{ContainerChildren}</>
121
+ );
122
+ }