@elastic/eui-docusaurus-theme 2.1.0 → 2.2.0
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/README.md +18 -44
- package/lib/.tsbuildinfo-client +1 -1
- package/lib/components/demo/actions_bar/actions_bar.d.ts +3 -2
- package/lib/components/demo/actions_bar/actions_bar.js +2 -2
- package/lib/components/demo/code_transformer.js +1 -1
- package/lib/components/demo/codesandbox/open_action.js +7 -4
- package/lib/components/demo/demo.d.ts +30 -4
- package/lib/components/demo/demo.js +2 -2
- package/lib/theme/Demo/actions.d.ts +2 -1
- package/package.json +3 -3
- package/src/components/demo/actions_bar/actions_bar.tsx +8 -2
- package/src/components/demo/code_transformer.ts +1 -1
- package/src/components/demo/codesandbox/open_action.tsx +8 -5
- package/src/components/demo/demo.tsx +32 -3
- package/src/theme/Demo/actions.tsx +2 -1
- package/src/theme/theme.d.ts +5 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { DemoSourceMeta } from '../demo';
|
|
1
|
+
import { DemoSourceMeta, ExtraFiles } from '../demo';
|
|
2
2
|
export interface DemoActionsBarProps {
|
|
3
3
|
activeSource: DemoSourceMeta | null;
|
|
4
4
|
sources: DemoSourceMeta[];
|
|
5
|
+
extraFiles?: ExtraFiles;
|
|
5
6
|
isSourceOpen: boolean;
|
|
6
7
|
setSourceOpen(isOpen: boolean): void;
|
|
7
8
|
onClickReloadExample(): void;
|
|
8
9
|
onClickCopyToClipboard(): void;
|
|
9
10
|
}
|
|
10
|
-
export declare const DemoActionsBar: ({ isSourceOpen, setSourceOpen, activeSource, sources, onClickReloadExample, onClickCopyToClipboard, }: DemoActionsBarProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const DemoActionsBar: ({ isSourceOpen, setSourceOpen, activeSource, sources, extraFiles, onClickReloadExample, onClickCopyToClipboard, }: DemoActionsBarProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -28,7 +28,7 @@ const getDemoActionsBarStyles = (euiTheme) => {
|
|
|
28
28
|
`,
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
|
-
export const DemoActionsBar = ({ isSourceOpen, setSourceOpen, activeSource, sources, onClickReloadExample, onClickCopyToClipboard, }) => {
|
|
31
|
+
export const DemoActionsBar = ({ isSourceOpen, setSourceOpen, activeSource, sources, extraFiles, onClickReloadExample, onClickCopyToClipboard, }) => {
|
|
32
32
|
const styles = useEuiMemoizedStyles(getDemoActionsBarStyles);
|
|
33
|
-
return (_jsxs(EuiFlexGroup, { alignItems: "center", css: styles.actionsBar, gutterSize: "s", children: [_jsx(EuiButton, { css: styles.button, onClick: () => setSourceOpen(!isSourceOpen), size: "s", color: "text", minWidth: false, children: isSourceOpen ? 'Hide source' : 'Show source' }), extraActions.map((ActionComponent) => (_jsx(ActionComponent, { sources: sources, activeSource: activeSource }))), _jsx(EuiToolTip, { content: "Copy to clipboard", children: _jsx(EuiButtonIcon, { size: "s", iconType: "copyClipboard", color: "text", onClick: onClickCopyToClipboard, "aria-label": "Copy code to clipboard" }) }), _jsx(EuiToolTip, { content: "Reload example", children: _jsx(EuiButtonIcon, { size: "s", iconType: "refresh", color: "text", onClick: onClickReloadExample, "aria-label": "Reload example" }) })] }));
|
|
33
|
+
return (_jsxs(EuiFlexGroup, { alignItems: "center", css: styles.actionsBar, gutterSize: "s", children: [_jsx(EuiButton, { css: styles.button, onClick: () => setSourceOpen(!isSourceOpen), size: "s", color: "text", minWidth: false, children: isSourceOpen ? 'Hide source' : 'Show source' }), extraActions.map((ActionComponent) => (_jsx(ActionComponent, { sources: sources, extraFiles: extraFiles, activeSource: activeSource }))), _jsx(EuiToolTip, { content: "Copy to clipboard", children: _jsx(EuiButtonIcon, { size: "s", iconType: "copyClipboard", color: "text", onClick: onClickCopyToClipboard, "aria-label": "Copy code to clipboard" }) }), _jsx(EuiToolTip, { content: "Reload example", children: _jsx(EuiButtonIcon, { size: "s", iconType: "refresh", color: "text", onClick: onClickReloadExample, "aria-label": "Reload example" }) })] }));
|
|
34
34
|
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
6
6
|
* Side Public License, v 1.
|
|
7
7
|
*/
|
|
8
|
-
const IMPORT_REGEX = /^import [^'"]* from ['"]([
|
|
8
|
+
const IMPORT_REGEX = /^import [^'"]* from ['"]([^'"\n ]*)['"];?/gm;
|
|
9
9
|
const DEFAULT_EXPORT_REGEX = /export default /;
|
|
10
10
|
const COMPONENT_ONLY_REGEX = /^\(?</;
|
|
11
11
|
/**
|
|
@@ -61,11 +61,14 @@ const processTsxSource = (source) => {
|
|
|
61
61
|
// to support that setting via tsconfig.json
|
|
62
62
|
return `/** @jsxImportSource @emotion/react */\n${source}`;
|
|
63
63
|
};
|
|
64
|
-
export const createOpenInCodeSandboxAction = ({ files = {}, dependencies }) => ({ activeSource }) => {
|
|
64
|
+
export const createOpenInCodeSandboxAction = ({ files = {}, dependencies }) => ({ extraFiles, activeSource }) => {
|
|
65
65
|
const parameters = useMemo(() => {
|
|
66
66
|
const source = activeSource?.code || '';
|
|
67
67
|
// Compute list of extra files that may be passed
|
|
68
|
-
const
|
|
68
|
+
const codeSandboxFiles = Object.entries({
|
|
69
|
+
...files,
|
|
70
|
+
...extraFiles,
|
|
71
|
+
}).reduce((acc, [file, content]) => {
|
|
69
72
|
acc[file] = { content };
|
|
70
73
|
return acc;
|
|
71
74
|
}, {});
|
|
@@ -83,9 +86,9 @@ export const createOpenInCodeSandboxAction = ({ files = {}, dependencies }) => (
|
|
|
83
86
|
},
|
|
84
87
|
},
|
|
85
88
|
},
|
|
86
|
-
...
|
|
89
|
+
...codeSandboxFiles,
|
|
87
90
|
},
|
|
88
91
|
});
|
|
89
|
-
}, [activeSource]);
|
|
92
|
+
}, [activeSource, extraFiles]);
|
|
90
93
|
return (_jsxs("form", { action: "https://codesandbox.io/api/v1/sandboxes/define", method: "POST", target: "_blank", children: [_jsx("input", { type: "hidden", name: "parameters", value: parameters }), _jsx("input", { type: "hidden", name: "query", value: `module=/demo.tsx&view=split` }), _jsx(EuiToolTip, { content: "Open in CodeSandbox", children: _jsx(EuiButtonIcon, { type: "submit", size: "s", iconType: CodeSandboxIcon, color: "text", "aria-label": "Open in CodeSandbox" }) })] }));
|
|
91
94
|
};
|
|
@@ -5,19 +5,45 @@ export interface DemoSourceMeta {
|
|
|
5
5
|
isActive: boolean;
|
|
6
6
|
filename?: string;
|
|
7
7
|
}
|
|
8
|
+
export type ExtraFiles = Record<string, string>;
|
|
8
9
|
export interface DemoProps extends PropsWithChildren {
|
|
9
10
|
/**
|
|
10
11
|
* Whether the source code editor is open by default
|
|
11
12
|
*/
|
|
12
13
|
isSourceOpen?: boolean;
|
|
13
14
|
/**
|
|
14
|
-
* Allows to
|
|
15
|
-
*
|
|
15
|
+
* Allows to pass additional variables available within the demo.
|
|
16
|
+
* The key is the variable name and the value is the variable itself (component, function, object, etc).
|
|
16
17
|
*
|
|
17
|
-
*
|
|
18
|
+
* @example
|
|
19
|
+
* ````mdx
|
|
20
|
+
* ```mdx-code-block
|
|
21
|
+
* import { MyComponent } from './my_component';
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* <Demo scope={{ MyComponent }}>
|
|
25
|
+
* ```tsx
|
|
26
|
+
* export default () => <MyComponent />
|
|
27
|
+
* ```
|
|
28
|
+
* </Demo>
|
|
29
|
+
* ````
|
|
18
30
|
*/
|
|
19
31
|
scope?: Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Allows to pass extra files that will be added to the Codesandbox instance.
|
|
34
|
+
* The key is the filename and the value is the serialized file content.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ````mdx
|
|
38
|
+
* ```mdx-code-block
|
|
39
|
+
* import iconSvgSource from '!raw-loader!./icon.svg';
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* <Demo extraFiles={{ 'icon.svg': iconSvgSource }} />
|
|
43
|
+
* ````
|
|
44
|
+
*/
|
|
45
|
+
extraFiles?: ExtraFiles;
|
|
20
46
|
previewPadding?: DemoPreviewProps['padding'];
|
|
21
47
|
previewWrapper?: DemoPreviewProps['wrapperComponent'];
|
|
22
48
|
}
|
|
23
|
-
export declare const Demo: ({ children, scope, isSourceOpen: _isSourceOpen, previewPadding, previewWrapper, }: DemoProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|
|
49
|
+
export declare const Demo: ({ children, scope, extraFiles, isSourceOpen: _isSourceOpen, previewPadding, previewWrapper, }: DemoProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -31,7 +31,7 @@ const getDemoStyles = (euiTheme) => ({
|
|
|
31
31
|
word-break: break-word;
|
|
32
32
|
`,
|
|
33
33
|
});
|
|
34
|
-
export const Demo = ({ children, scope, isSourceOpen: _isSourceOpen = false, previewPadding, previewWrapper, }) => {
|
|
34
|
+
export const Demo = ({ children, scope, extraFiles, isSourceOpen: _isSourceOpen = false, previewPadding, previewWrapper, }) => {
|
|
35
35
|
const styles = useEuiMemoizedStyles(getDemoStyles);
|
|
36
36
|
const [sources, setSources] = useState([]);
|
|
37
37
|
const [isSourceOpen, setIsSourceOpen] = useState(_isSourceOpen);
|
|
@@ -52,7 +52,7 @@ export const Demo = ({ children, scope, isSourceOpen: _isSourceOpen = false, pre
|
|
|
52
52
|
const onClickReloadExample = useCallback(() => {
|
|
53
53
|
setLiveProviderKey((liveProviderKey) => liveProviderKey + 1);
|
|
54
54
|
}, []);
|
|
55
|
-
return (_jsx("div", { css: styles.demo, children: _jsxs(DemoContext.Provider, { value: { sources, addSource }, children: [_jsxs(LiveProvider, { code: activeSource?.code || '', transformCode: demoCodeTransformer, theme: prismThemes.dracula, scope: finalScope, children: [_jsx(DemoPreview, { padding: previewPadding, wrapperComponent: previewWrapper }), _jsx(DemoActionsBar, { isSourceOpen: isSourceOpen, setSourceOpen: setIsSourceOpen, activeSource: activeSource, sources: sources, onClickCopyToClipboard: onClickCopyToClipboard, onClickReloadExample: onClickReloadExample }), isSourceOpen && _jsx(DemoEditor, {})] }, liveProviderKey), Children.map(children, (child, index) => {
|
|
55
|
+
return (_jsx("div", { css: styles.demo, children: _jsxs(DemoContext.Provider, { value: { sources, addSource }, children: [_jsxs(LiveProvider, { code: activeSource?.code || '', transformCode: demoCodeTransformer, theme: prismThemes.dracula, scope: finalScope, children: [_jsx(DemoPreview, { padding: previewPadding, wrapperComponent: previewWrapper }), _jsx(DemoActionsBar, { isSourceOpen: isSourceOpen, setSourceOpen: setIsSourceOpen, activeSource: activeSource, extraFiles: extraFiles, sources: sources, onClickCopyToClipboard: onClickCopyToClipboard, onClickReloadExample: onClickReloadExample }), isSourceOpen && _jsx(DemoEditor, {})] }, liveProviderKey), Children.map(children, (child, index) => {
|
|
56
56
|
if (isElement(child) && child.type === DemoSource) {
|
|
57
57
|
return child;
|
|
58
58
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ComponentType } from 'react';
|
|
2
|
-
import { DemoSourceMeta } from '../../components/demo/demo';
|
|
2
|
+
import { DemoSourceMeta, ExtraFiles } from '../../components/demo/demo';
|
|
3
3
|
export type ActionComponentProps = {
|
|
4
4
|
activeSource: DemoSourceMeta | null;
|
|
5
5
|
sources: DemoSourceMeta[];
|
|
6
|
+
extraFiles?: ExtraFiles;
|
|
6
7
|
};
|
|
7
8
|
export type ActionComponent = ComponentType<ActionComponentProps>;
|
|
8
9
|
export declare const extraActions: ActionComponent[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elastic/eui-docusaurus-theme",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "EUI theme for Docusaurus",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"scripts": {
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@docusaurus/theme-common": "^3.7.0",
|
|
41
41
|
"@docusaurus/utils-validation": "^3.7.0",
|
|
42
42
|
"@elastic/datemath": "^5.0.3",
|
|
43
|
-
"@elastic/eui": "^
|
|
44
|
-
"@elastic/eui-theme-borealis": "^5.
|
|
43
|
+
"@elastic/eui": "^112.1.0",
|
|
44
|
+
"@elastic/eui-theme-borealis": "^5.4.0",
|
|
45
45
|
"@emotion/css": "^11.11.2",
|
|
46
46
|
"@emotion/react": "^11.11.4",
|
|
47
47
|
"@types/react-window": "^1.8.8",
|
|
@@ -17,11 +17,12 @@ import {
|
|
|
17
17
|
} from '@elastic/eui';
|
|
18
18
|
import { css } from '@emotion/react';
|
|
19
19
|
import { extraActions } from '@theme/Demo/actions';
|
|
20
|
-
import { DemoSourceMeta } from '../demo';
|
|
20
|
+
import { DemoSourceMeta, ExtraFiles } from '../demo';
|
|
21
21
|
|
|
22
22
|
export interface DemoActionsBarProps {
|
|
23
23
|
activeSource: DemoSourceMeta | null;
|
|
24
24
|
sources: DemoSourceMeta[];
|
|
25
|
+
extraFiles?: ExtraFiles;
|
|
25
26
|
isSourceOpen: boolean;
|
|
26
27
|
setSourceOpen(isOpen: boolean): void;
|
|
27
28
|
onClickReloadExample(): void;
|
|
@@ -53,6 +54,7 @@ export const DemoActionsBar = ({
|
|
|
53
54
|
setSourceOpen,
|
|
54
55
|
activeSource,
|
|
55
56
|
sources,
|
|
57
|
+
extraFiles,
|
|
56
58
|
onClickReloadExample,
|
|
57
59
|
onClickCopyToClipboard,
|
|
58
60
|
}: DemoActionsBarProps) => {
|
|
@@ -70,7 +72,11 @@ export const DemoActionsBar = ({
|
|
|
70
72
|
{isSourceOpen ? 'Hide source' : 'Show source'}
|
|
71
73
|
</EuiButton>
|
|
72
74
|
{extraActions.map((ActionComponent) => (
|
|
73
|
-
<ActionComponent
|
|
75
|
+
<ActionComponent
|
|
76
|
+
sources={sources}
|
|
77
|
+
extraFiles={extraFiles}
|
|
78
|
+
activeSource={activeSource}
|
|
79
|
+
/>
|
|
74
80
|
))}
|
|
75
81
|
<EuiToolTip content="Copy to clipboard">
|
|
76
82
|
<EuiButtonIcon
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Side Public License, v 1.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const IMPORT_REGEX = /^import [^'"]* from ['"]([
|
|
9
|
+
const IMPORT_REGEX = /^import [^'"]* from ['"]([^'"\n ]*)['"];?/gm;
|
|
10
10
|
const DEFAULT_EXPORT_REGEX = /export default /;
|
|
11
11
|
const COMPONENT_ONLY_REGEX = /^\(?</;
|
|
12
12
|
|
|
@@ -74,17 +74,20 @@ const processTsxSource = (source: string) => {
|
|
|
74
74
|
|
|
75
75
|
export const createOpenInCodeSandboxAction =
|
|
76
76
|
({ files = {}, dependencies }: Options): ActionComponent =>
|
|
77
|
-
({ activeSource }) => {
|
|
77
|
+
({ extraFiles, activeSource }) => {
|
|
78
78
|
const parameters: string = useMemo(() => {
|
|
79
79
|
const source = activeSource?.code || '';
|
|
80
80
|
|
|
81
81
|
// Compute list of extra files that may be passed
|
|
82
|
-
const
|
|
82
|
+
const codeSandboxFiles = Object.entries({
|
|
83
|
+
...files,
|
|
84
|
+
...extraFiles,
|
|
85
|
+
}).reduce(
|
|
83
86
|
(acc, [file, content]) => {
|
|
84
87
|
acc[file] = { content };
|
|
85
88
|
return acc;
|
|
86
89
|
},
|
|
87
|
-
{} as Record<string, { content:
|
|
90
|
+
{} as Record<string, { content: unknown }>
|
|
88
91
|
);
|
|
89
92
|
|
|
90
93
|
return getParameters({
|
|
@@ -101,10 +104,10 @@ export const createOpenInCodeSandboxAction =
|
|
|
101
104
|
},
|
|
102
105
|
},
|
|
103
106
|
},
|
|
104
|
-
...
|
|
107
|
+
...codeSandboxFiles,
|
|
105
108
|
},
|
|
106
109
|
} as any);
|
|
107
|
-
}, [activeSource]);
|
|
110
|
+
}, [activeSource, extraFiles]);
|
|
108
111
|
|
|
109
112
|
return (
|
|
110
113
|
<form
|
|
@@ -38,18 +38,45 @@ export interface DemoSourceMeta {
|
|
|
38
38
|
filename?: string;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
export type ExtraFiles = Record<string, string>;
|
|
42
|
+
|
|
41
43
|
export interface DemoProps extends PropsWithChildren {
|
|
42
44
|
/**
|
|
43
45
|
* Whether the source code editor is open by default
|
|
44
46
|
*/
|
|
45
47
|
isSourceOpen?: boolean;
|
|
46
48
|
/**
|
|
47
|
-
* Allows to
|
|
48
|
-
*
|
|
49
|
+
* Allows to pass additional variables available within the demo.
|
|
50
|
+
* The key is the variable name and the value is the variable itself (component, function, object, etc).
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ````mdx
|
|
54
|
+
* ```mdx-code-block
|
|
55
|
+
* import { MyComponent } from './my_component';
|
|
56
|
+
* ```
|
|
49
57
|
*
|
|
50
|
-
*
|
|
58
|
+
* <Demo scope={{ MyComponent }}>
|
|
59
|
+
* ```tsx
|
|
60
|
+
* export default () => <MyComponent />
|
|
61
|
+
* ```
|
|
62
|
+
* </Demo>
|
|
63
|
+
* ````
|
|
51
64
|
*/
|
|
52
65
|
scope?: Record<string, unknown>;
|
|
66
|
+
/**
|
|
67
|
+
* Allows to pass extra files that will be added to the Codesandbox instance.
|
|
68
|
+
* The key is the filename and the value is the serialized file content.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ````mdx
|
|
72
|
+
* ```mdx-code-block
|
|
73
|
+
* import iconSvgSource from '!raw-loader!./icon.svg';
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* <Demo extraFiles={{ 'icon.svg': iconSvgSource }} />
|
|
77
|
+
* ````
|
|
78
|
+
*/
|
|
79
|
+
extraFiles?: ExtraFiles;
|
|
53
80
|
previewPadding?: DemoPreviewProps['padding'];
|
|
54
81
|
previewWrapper?: DemoPreviewProps['wrapperComponent'];
|
|
55
82
|
}
|
|
@@ -69,6 +96,7 @@ const getDemoStyles = (euiTheme: UseEuiTheme) => ({
|
|
|
69
96
|
export const Demo = ({
|
|
70
97
|
children,
|
|
71
98
|
scope,
|
|
99
|
+
extraFiles,
|
|
72
100
|
isSourceOpen: _isSourceOpen = false,
|
|
73
101
|
previewPadding,
|
|
74
102
|
previewWrapper,
|
|
@@ -123,6 +151,7 @@ export const Demo = ({
|
|
|
123
151
|
isSourceOpen={isSourceOpen}
|
|
124
152
|
setSourceOpen={setIsSourceOpen}
|
|
125
153
|
activeSource={activeSource}
|
|
154
|
+
extraFiles={extraFiles}
|
|
126
155
|
sources={sources}
|
|
127
156
|
onClickCopyToClipboard={onClickCopyToClipboard}
|
|
128
157
|
onClickReloadExample={onClickReloadExample}
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
import { ComponentType } from 'react';
|
|
10
10
|
|
|
11
|
-
import { DemoSourceMeta } from '../../components/demo/demo';
|
|
11
|
+
import { DemoSourceMeta, ExtraFiles } from '../../components/demo/demo';
|
|
12
12
|
|
|
13
13
|
export type ActionComponentProps = {
|
|
14
14
|
activeSource: DemoSourceMeta | null;
|
|
15
15
|
sources: DemoSourceMeta[];
|
|
16
|
+
extraFiles?: ExtraFiles;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export type ActionComponent = ComponentType<ActionComponentProps>;
|
package/src/theme/theme.d.ts
CHANGED
|
@@ -585,11 +585,15 @@ declare module '@theme/Demo/default_scope' {
|
|
|
585
585
|
|
|
586
586
|
declare module '@theme/Demo/actions' {
|
|
587
587
|
import type { ComponentType } from 'react';
|
|
588
|
-
import type {
|
|
588
|
+
import type {
|
|
589
|
+
DemoSourceMeta,
|
|
590
|
+
ExtraFiles,
|
|
591
|
+
} from '@elastic/eui-docusaurus-theme/components/demo/demo';
|
|
589
592
|
|
|
590
593
|
export type ActionComponentProps = {
|
|
591
594
|
activeSource: DemoSourceMeta;
|
|
592
595
|
sources: DemoSourceMeta[];
|
|
596
|
+
extraFiles?: ExtraFiles;
|
|
593
597
|
};
|
|
594
598
|
|
|
595
599
|
export type ActionComponent = ComponentType<ActionComponentProps>;
|