@dotcms/react 0.0.1-alpha.1 → 0.0.1-alpha.11
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/.babelrc +12 -0
- package/.eslintrc.json +18 -0
- package/README.md +16 -21
- package/jest.config.ts +11 -0
- package/package.json +27 -31
- package/project.json +51 -0
- package/src/{index.d.ts → index.ts} +4 -5
- package/src/lib/components/Column/Column.module.css +99 -0
- package/src/lib/components/Column/Column.spec.tsx +78 -0
- package/src/lib/components/Column/Column.tsx +45 -0
- package/src/lib/components/Container/Container.module.css +7 -0
- package/src/lib/components/Container/Container.spec.tsx +82 -0
- package/src/lib/components/Container/Container.tsx +106 -0
- package/src/lib/components/DotcmsLayout/DotcmsLayout.module.css +7 -0
- package/src/lib/components/DotcmsLayout/DotcmsLayout.spec.tsx +41 -0
- package/src/lib/components/DotcmsLayout/{DotcmsLayout.d.ts → DotcmsLayout.tsx} +48 -32
- package/src/lib/components/PageProvider/PageProvider.module.css +7 -0
- package/src/lib/components/PageProvider/PageProvider.spec.tsx +54 -0
- package/src/lib/components/PageProvider/{PageProvider.d.ts → PageProvider.tsx} +95 -81
- package/src/lib/components/Row/Row.module.css +5 -0
- package/src/lib/components/Row/Row.spec.tsx +92 -0
- package/src/lib/components/Row/Row.tsx +51 -0
- package/src/lib/contexts/PageContext.tsx +5 -0
- package/src/lib/hooks/useDotcmsEditor.spec.ts +56 -0
- package/src/lib/hooks/useDotcmsEditor.ts +29 -0
- package/src/lib/hooks/useDotcmsPageContext.spec.tsx +43 -0
- package/src/lib/hooks/{useDotcmsPageContext.d.ts → useDotcmsPageContext.tsx} +15 -9
- package/src/lib/mocks/{index.d.ts → index.ts} +1 -1
- package/src/lib/mocks/mockPageContext.tsx +84 -0
- package/src/lib/utils/utils.ts +69 -0
- package/tsconfig.json +20 -0
- package/tsconfig.lib.json +23 -0
- package/tsconfig.spec.json +20 -0
- package/index.js +0 -2413
- package/src/lib/components/Column/Column.d.ts +0 -7
- package/src/lib/components/Container/Container.d.ts +0 -6
- package/src/lib/components/Row/Row.d.ts +0 -25
- package/src/lib/contexts/PageContext.d.ts +0 -3
- package/src/lib/hooks/usePageEditor.d.ts +0 -48
- package/src/lib/mocks/mockPageContext.d.ts +0 -2
- package/src/lib/utils/utils.d.ts +0 -50
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PageContext } from '../../contexts/PageContext';
|
|
4
|
+
import { getContainersData } from '../../utils/utils';
|
|
5
|
+
import { PageProviderContext } from '../PageProvider/PageProvider';
|
|
6
|
+
|
|
7
|
+
const FAKE_CONTENLET = {
|
|
8
|
+
identifier: 'TEMP_EMPTY_CONTENTLET',
|
|
9
|
+
title: 'TEMP_EMPTY_CONTENTLET',
|
|
10
|
+
contentType: 'TEMP_EMPTY_CONTENTLET_TYPE',
|
|
11
|
+
inode: 'TEMPY_EMPTY_CONTENTLET_INODE',
|
|
12
|
+
widgetTitle: 'TEMP_EMPTY_CONTENTLET',
|
|
13
|
+
onNumberOfPages: 1
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function EmptyContainer() {
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
data-testid="empty-container"
|
|
20
|
+
style={{
|
|
21
|
+
width: '100%',
|
|
22
|
+
backgroundColor: '#ECF0FD',
|
|
23
|
+
display: 'flex',
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
color: '#030E32',
|
|
27
|
+
height: '10rem'
|
|
28
|
+
}}>
|
|
29
|
+
This container is empty.
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function NoContent({ contentType }: { readonly contentType: string }) {
|
|
35
|
+
return <div data-testid="no-component">No Component for {contentType}</div>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ContainerProps {
|
|
39
|
+
readonly containerRef: PageProviderContext['layout']['body']['rows'][0]['columns'][0]['containers'][0];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function Container({ containerRef }: ContainerProps) {
|
|
43
|
+
const { isInsideEditor } = useContext(PageContext) as PageProviderContext;
|
|
44
|
+
|
|
45
|
+
const { identifier, uuid } = containerRef;
|
|
46
|
+
|
|
47
|
+
// Get the containers from the global context
|
|
48
|
+
const { containers, components } = useContext<PageProviderContext | null>(
|
|
49
|
+
PageContext
|
|
50
|
+
) as PageProviderContext;
|
|
51
|
+
|
|
52
|
+
const { acceptTypes, contentlets, maxContentlets, variantId, path } = getContainersData(
|
|
53
|
+
containers,
|
|
54
|
+
containerRef
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const updatedContentlets =
|
|
58
|
+
contentlets.length === 0 && isInsideEditor ? [FAKE_CONTENLET] : contentlets;
|
|
59
|
+
|
|
60
|
+
const container = {
|
|
61
|
+
acceptTypes,
|
|
62
|
+
identifier: path ?? identifier,
|
|
63
|
+
maxContentlets,
|
|
64
|
+
variantId,
|
|
65
|
+
uuid
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const renderContentlets = updatedContentlets.map((contentlet) => {
|
|
69
|
+
const ContentTypeComponent = components[contentlet.contentType] || NoContent;
|
|
70
|
+
|
|
71
|
+
const Component =
|
|
72
|
+
contentlet.identifier === 'TEMP_EMPTY_CONTENTLET'
|
|
73
|
+
? EmptyContainer
|
|
74
|
+
: ContentTypeComponent;
|
|
75
|
+
|
|
76
|
+
return isInsideEditor ? (
|
|
77
|
+
<div
|
|
78
|
+
data-dot-object="contentlet"
|
|
79
|
+
data-dot-identifier={contentlet.identifier}
|
|
80
|
+
data-dot-title={contentlet.widgetTitle || contentlet.title}
|
|
81
|
+
data-dot-inode={contentlet.inode}
|
|
82
|
+
data-dot-type={contentlet.contentType}
|
|
83
|
+
data-dot-container={JSON.stringify(container)}
|
|
84
|
+
data-dot-on-number-of-pages={contentlet.onNumberOfPages}
|
|
85
|
+
key={contentlet.identifier}>
|
|
86
|
+
<Component {...contentlet} />
|
|
87
|
+
</div>
|
|
88
|
+
) : (
|
|
89
|
+
<Component {...contentlet} key={contentlet.identifier} />
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return isInsideEditor ? (
|
|
94
|
+
<div
|
|
95
|
+
data-dot-object="container"
|
|
96
|
+
data-dot-accept-types={acceptTypes}
|
|
97
|
+
data-dot-identifier={path ?? identifier}
|
|
98
|
+
data-max-contentlets={maxContentlets}
|
|
99
|
+
data-uuid={uuid}>
|
|
100
|
+
{renderContentlets}
|
|
101
|
+
</div>
|
|
102
|
+
) : (
|
|
103
|
+
// eslint-disable-next-line react/jsx-no-useless-fragment
|
|
104
|
+
<>{renderContentlets}</>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { ElementRef, ForwardRefExoticComponent } from 'react';
|
|
4
|
+
|
|
5
|
+
import { DotcmsLayout } from './DotcmsLayout';
|
|
6
|
+
|
|
7
|
+
import { mockPageContext } from '../../mocks/mockPageContext';
|
|
8
|
+
|
|
9
|
+
jest.mock('../Row/Row', () => {
|
|
10
|
+
const { forwardRef } = jest.requireActual('react');
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
Row: forwardRef(
|
|
14
|
+
(
|
|
15
|
+
{ children }: { children: JSX.Element },
|
|
16
|
+
ref: ElementRef<ForwardRefExoticComponent<unknown>>
|
|
17
|
+
) => (
|
|
18
|
+
<div data-testid="mockRow" ref={ref}>
|
|
19
|
+
{children}
|
|
20
|
+
</div>
|
|
21
|
+
)
|
|
22
|
+
)
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
jest.mock('../PageProvider/PageProvider', () => {
|
|
27
|
+
return {
|
|
28
|
+
PageProvider: ({ children }: { children: JSX.Element }) => (
|
|
29
|
+
<div data-testid="mockPageProvider">{children}</div>
|
|
30
|
+
)
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('DotcmsLayout', () => {
|
|
35
|
+
it('renders correctly with PageProvider and rows', () => {
|
|
36
|
+
render(<DotcmsLayout entity={{ ...mockPageContext, isInsideEditor: true }} />);
|
|
37
|
+
expect(screen.getAllByTestId('mockRow').length).toBe(
|
|
38
|
+
mockPageContext.layout.body.rows.length
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -1,32 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* @
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
1
|
+
import { DotCMSPageEditorConfig } from '@dotcms/client';
|
|
2
|
+
|
|
3
|
+
import { useDotcmsEditor } from '../../hooks/useDotcmsEditor';
|
|
4
|
+
import { PageProvider, PageProviderContext } from '../PageProvider/PageProvider';
|
|
5
|
+
import { Row } from '../Row/Row';
|
|
6
|
+
/**
|
|
7
|
+
* `DotcmsPageProps` is a type that defines the properties for the `DotcmsLayout` component.
|
|
8
|
+
* It includes a readonly `entity` property that represents the context for a DotCMS page.
|
|
9
|
+
*
|
|
10
|
+
* @typedef {Object} DotcmsPageProps
|
|
11
|
+
*
|
|
12
|
+
* @property {PageProviderContext} entity - The context for a DotCMS page.
|
|
13
|
+
* @readonly
|
|
14
|
+
*/
|
|
15
|
+
export type DotcmsPageProps = {
|
|
16
|
+
/**
|
|
17
|
+
* `entity` is a readonly property of the `DotcmsPageProps` type.
|
|
18
|
+
* It represents the context for a DotCMS page and is of type `PageProviderContext`.
|
|
19
|
+
*
|
|
20
|
+
* @property {PageProviderContext} entity
|
|
21
|
+
* @memberof DotcmsPageProps
|
|
22
|
+
* @type {PageProviderContext}
|
|
23
|
+
* @readonly
|
|
24
|
+
*/
|
|
25
|
+
readonly entity: PageProviderContext;
|
|
26
|
+
|
|
27
|
+
readonly config?: DotCMSPageEditorConfig;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* `DotcmsLayout` is a functional component that renders a layout for a DotCMS page.
|
|
32
|
+
* It takes a `DotcmsPageProps` object as a parameter and returns a JSX element.
|
|
33
|
+
*
|
|
34
|
+
* @category Components
|
|
35
|
+
* @param {DotcmsPageProps} props - The properties for the DotCMS page.
|
|
36
|
+
* @returns {JSX.Element} - A JSX element that represents the layout for a DotCMS page.
|
|
37
|
+
*/
|
|
38
|
+
export function DotcmsLayout({ entity, config }: DotcmsPageProps): JSX.Element {
|
|
39
|
+
const isInsideEditor = useDotcmsEditor(config);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<PageProvider entity={{ ...entity, isInsideEditor }}>
|
|
43
|
+
{entity.layout.body.rows.map((row, index) => (
|
|
44
|
+
<Row key={index} row={row} />
|
|
45
|
+
))}
|
|
46
|
+
</PageProvider>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
|
+
import { PageProvider } from './PageProvider';
|
|
6
|
+
|
|
7
|
+
import { PageContext } from '../../contexts/PageContext';
|
|
8
|
+
|
|
9
|
+
const MockChildComponent = () => {
|
|
10
|
+
const context = React.useContext(PageContext);
|
|
11
|
+
|
|
12
|
+
return <div data-testid="mockChild">{JSON.stringify(context?.page.title)}</div>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe('PageProvider', () => {
|
|
16
|
+
const mockEntity = {
|
|
17
|
+
page: {
|
|
18
|
+
title: 'Test Page',
|
|
19
|
+
identifier: 'test-page-1'
|
|
20
|
+
}
|
|
21
|
+
// ... add other context properties as needed
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
it('provides the context to its children', () => {
|
|
25
|
+
render(
|
|
26
|
+
<PageProvider entity={mockEntity}>
|
|
27
|
+
<MockChildComponent />
|
|
28
|
+
</PageProvider>
|
|
29
|
+
);
|
|
30
|
+
expect(screen.getByTestId('mockChild')).toHaveTextContent(mockEntity.page.title);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('updates context when entity changes', () => {
|
|
34
|
+
const { rerender } = render(
|
|
35
|
+
<PageProvider entity={mockEntity}>
|
|
36
|
+
<MockChildComponent />
|
|
37
|
+
</PageProvider>
|
|
38
|
+
);
|
|
39
|
+
// Change the context
|
|
40
|
+
const newEntity = {
|
|
41
|
+
...mockEntity,
|
|
42
|
+
page: {
|
|
43
|
+
...mockEntity.page,
|
|
44
|
+
title: 'Updated Test Page'
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
rerender(
|
|
48
|
+
<PageProvider entity={newEntity}>
|
|
49
|
+
<MockChildComponent />
|
|
50
|
+
</PageProvider>
|
|
51
|
+
);
|
|
52
|
+
expect(screen.getByTestId('mockChild')).toHaveTextContent(newEntity.page.title);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,81 +1,95 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PageContext } from '../../contexts/PageContext';
|
|
4
|
+
|
|
5
|
+
export interface PageProviderProps {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
readonly entity: any;
|
|
8
|
+
readonly children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ContainerData {
|
|
12
|
+
[key: string]: {
|
|
13
|
+
container: {
|
|
14
|
+
path: string;
|
|
15
|
+
identifier: string;
|
|
16
|
+
maxContentlets: number;
|
|
17
|
+
parentPermissionable: Record<string, string>;
|
|
18
|
+
};
|
|
19
|
+
containerStructures: {
|
|
20
|
+
contentTypeVar: string;
|
|
21
|
+
}[];
|
|
22
|
+
contentlets: {
|
|
23
|
+
[key: string]: {
|
|
24
|
+
contentType: string;
|
|
25
|
+
identifier: string;
|
|
26
|
+
title: string;
|
|
27
|
+
inode: string;
|
|
28
|
+
onNumberOfPages: number;
|
|
29
|
+
widgetTitle?: string;
|
|
30
|
+
}[];
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PageProviderContext {
|
|
36
|
+
/**
|
|
37
|
+
* `components` is a property of the `PageProviderProps` type.
|
|
38
|
+
* It is an object that maps content type variables to their corresponding React components.
|
|
39
|
+
*
|
|
40
|
+
* It will be use to render the contentlets in the page.
|
|
41
|
+
*
|
|
42
|
+
* @property {Object} components
|
|
43
|
+
* @memberof PageProviderProps
|
|
44
|
+
* @type {Object.<string, React.ElementType>}
|
|
45
|
+
*/
|
|
46
|
+
components: {
|
|
47
|
+
[contentTypeVariable: string]: React.ElementType;
|
|
48
|
+
};
|
|
49
|
+
containers: ContainerData;
|
|
50
|
+
layout: {
|
|
51
|
+
header: boolean;
|
|
52
|
+
footer: boolean;
|
|
53
|
+
body: {
|
|
54
|
+
rows: {
|
|
55
|
+
styleClass: string;
|
|
56
|
+
columns: {
|
|
57
|
+
styleClass: string;
|
|
58
|
+
width: number;
|
|
59
|
+
leftOffset: number;
|
|
60
|
+
containers: {
|
|
61
|
+
identifier: string;
|
|
62
|
+
uuid: string;
|
|
63
|
+
}[];
|
|
64
|
+
}[];
|
|
65
|
+
}[];
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
page: {
|
|
69
|
+
title: string;
|
|
70
|
+
identifier: string;
|
|
71
|
+
};
|
|
72
|
+
viewAs: {
|
|
73
|
+
language: {
|
|
74
|
+
id: string;
|
|
75
|
+
};
|
|
76
|
+
persona: {
|
|
77
|
+
keyTag: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
isInsideEditor: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* `PageProvider` is a functional component that provides a context for a DotCMS page.
|
|
85
|
+
* It takes a `PageProviderProps` object as a parameter and returns a JSX element.
|
|
86
|
+
*
|
|
87
|
+
* @category Components
|
|
88
|
+
* @param {PageProviderProps} props - The properties for the PageProvider. Includes an `entity` and `children`.
|
|
89
|
+
* @returns {JSX.Element} - A JSX element that provides a context for a DotCMS page.
|
|
90
|
+
*/
|
|
91
|
+
export function PageProvider(props: PageProviderProps): JSX.Element {
|
|
92
|
+
const { entity, children } = props;
|
|
93
|
+
|
|
94
|
+
return <PageContext.Provider value={entity}>{children}</PageContext.Provider>;
|
|
95
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
|
|
3
|
+
import { Row } from './Row';
|
|
4
|
+
|
|
5
|
+
import { MockContextRender } from '../../mocks/mockPageContext';
|
|
6
|
+
import { ColumnProps } from '../Column/Column';
|
|
7
|
+
import { PageProviderContext } from '../PageProvider/PageProvider';
|
|
8
|
+
|
|
9
|
+
import '@testing-library/jest-dom';
|
|
10
|
+
|
|
11
|
+
jest.mock('../Column/Column', () => {
|
|
12
|
+
return {
|
|
13
|
+
Column: ({ column }: ColumnProps) => (
|
|
14
|
+
<div data-testid="mockColumn">{JSON.stringify(column)}</div>
|
|
15
|
+
)
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('Row', () => {
|
|
20
|
+
const mockRowData: PageProviderContext['layout']['body']['rows'][0] = {
|
|
21
|
+
columns: [
|
|
22
|
+
{
|
|
23
|
+
width: 60,
|
|
24
|
+
leftOffset: 2,
|
|
25
|
+
containers: [
|
|
26
|
+
{
|
|
27
|
+
identifier: '123',
|
|
28
|
+
uuid: '1'
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
styleClass: ''
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
width: 20,
|
|
35
|
+
leftOffset: 0,
|
|
36
|
+
containers: [
|
|
37
|
+
{
|
|
38
|
+
identifier: '456',
|
|
39
|
+
uuid: '2'
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
styleClass: ''
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
styleClass: ''
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
describe('row is inside editor', () => {
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
render(
|
|
51
|
+
<MockContextRender mockContext={{ isInsideEditor: true }}>
|
|
52
|
+
<Row row={mockRowData} />
|
|
53
|
+
</MockContextRender>
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should set the data-dot attribute', () => {
|
|
58
|
+
expect(screen.getByTestId('row')).toHaveAttribute('data-dot', 'row');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('renders the correct number of mock columns', () => {
|
|
62
|
+
const mockColumns = screen.getAllByTestId('mockColumn');
|
|
63
|
+
expect(mockColumns.length).toBe(mockRowData.columns.length);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('passes the correct props to each mock Column', () => {
|
|
67
|
+
mockRowData.columns.forEach((column, index) => {
|
|
68
|
+
expect(screen.getAllByTestId('mockColumn')[index].innerHTML).toBe(
|
|
69
|
+
JSON.stringify(column)
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('renders the correct number of columns', () => {
|
|
75
|
+
const columns = screen.getAllByTestId('mockColumn');
|
|
76
|
+
expect(columns.length).toBe(mockRowData.columns.length);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe('row is not inside editor', () => {
|
|
80
|
+
beforeEach(() => {
|
|
81
|
+
render(
|
|
82
|
+
<MockContextRender mockContext={{ isInsideEditor: false }}>
|
|
83
|
+
<Row row={mockRowData} />
|
|
84
|
+
</MockContextRender>
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should not have dot attr', () => {
|
|
89
|
+
expect(screen.queryByTestId('row')).toBeNull();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { forwardRef, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import styles from './row.module.css';
|
|
4
|
+
|
|
5
|
+
import { PageContext } from '../../contexts/PageContext';
|
|
6
|
+
import { combineClasses } from '../../utils/utils';
|
|
7
|
+
import { Column } from '../Column/Column';
|
|
8
|
+
import { PageProviderContext } from '../PageProvider/PageProvider';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Props for the row component
|
|
12
|
+
*
|
|
13
|
+
* @interface RowProps
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export interface RowProps {
|
|
17
|
+
/**
|
|
18
|
+
* Row data
|
|
19
|
+
*
|
|
20
|
+
* @type {PageProviderContext['layout']['body']['rows'][0]}
|
|
21
|
+
* @memberof RowProps
|
|
22
|
+
*/
|
|
23
|
+
row: PageProviderContext['layout']['body']['rows'][0];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Renders a row
|
|
28
|
+
*
|
|
29
|
+
* @category Components
|
|
30
|
+
* @param {React.ForwardedRef<HTMLDivElement, RowProps>} ref
|
|
31
|
+
* @return {*}
|
|
32
|
+
*/
|
|
33
|
+
export const Row = forwardRef<HTMLDivElement, RowProps>((props: RowProps, ref) => {
|
|
34
|
+
const { isInsideEditor } = useContext<PageProviderContext | null>(
|
|
35
|
+
PageContext
|
|
36
|
+
) as PageProviderContext;
|
|
37
|
+
|
|
38
|
+
const { row } = props;
|
|
39
|
+
|
|
40
|
+
const combinedClasses = combineClasses([styles.row, row.styleClass]);
|
|
41
|
+
|
|
42
|
+
const rowProps = isInsideEditor ? { 'data-dot': 'row', 'data-testid': 'row', ref } : {};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div {...rowProps} className={combinedClasses}>
|
|
46
|
+
{row.columns.map((column, index) => (
|
|
47
|
+
<Column key={index} column={column} />
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
});
|