@centreon/ui 23.10.18 → 23.10.20-MON-18490-widgets.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/package.json +5 -2
- package/src/Dashboard/Dashboard.styles.ts +83 -0
- package/src/Dashboard/DashboardLayout.stories.tsx +104 -0
- package/src/Dashboard/Grid.tsx +70 -0
- package/src/Dashboard/Item.tsx +72 -0
- package/src/Dashboard/Layout.tsx +74 -0
- package/src/Dashboard/index.tsx +9 -0
- package/src/Dashboard/utils.ts +28 -0
- package/src/InputField/Select/Autocomplete/index.stories.tsx +1 -10
- package/src/Typography/FluidTypography/index.stories.tsx +63 -0
- package/src/Typography/FluidTypography/index.tsx +51 -0
- package/src/Typography/FluidTypography/useFluidResizeObserver.ts +56 -0
- package/src/Typography/{index.stories.tsx → Typography.stories.tsx} +5 -5
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-dashboard-normal-1-snap.png +0 -0
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-dashboard-with-item-header-1-snap.png +0 -0
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-dashboard-with-many-panels-1-snap.png +0 -0
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-basic-1-snap.png +0 -0
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-20-px-height-1-snap.png +0 -0
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-200-px-width-1-snap.png +0 -0
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-heading-5-variant-1-snap.png +0 -0
- package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-long-text-1-snap.png +0 -0
- package/src/index.ts +3 -0
- /package/src/Typography/{index.tsx → story.utils.tsx} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "23.10.
|
|
3
|
+
"version": "23.10.20-MON-18490-widgets.0",
|
|
4
4
|
"description": "Centreon UI Components",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
|
|
@@ -89,7 +89,9 @@
|
|
|
89
89
|
"lexical": "0.8.0",
|
|
90
90
|
"notistack": "^2.0.8",
|
|
91
91
|
"react-transition-group": "^4.4.5",
|
|
92
|
-
"ulog": "^2.0.0-beta.19"
|
|
92
|
+
"ulog": "^2.0.0-beta.19",
|
|
93
|
+
"react-grid-layout": "^1.3.4",
|
|
94
|
+
"react-resizable": "^3.0.5"
|
|
93
95
|
},
|
|
94
96
|
"peerDependencies": {
|
|
95
97
|
"@centreon/ui-context": "file:../ui-context",
|
|
@@ -108,6 +110,7 @@
|
|
|
108
110
|
"ramda": "0.x",
|
|
109
111
|
"react-i18next": "12.x",
|
|
110
112
|
"react-router-dom": "6.x",
|
|
113
|
+
"react-scale-text": "1.x",
|
|
111
114
|
"resize-observer-polyfill": "1.x",
|
|
112
115
|
"ts.data.json": "2.x",
|
|
113
116
|
"tss-react": "4.x"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { makeStyles } from 'tss-react/mui';
|
|
2
|
+
|
|
3
|
+
import { alpha } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
export const useDashboardLayoutStyles = makeStyles()((theme) => ({
|
|
6
|
+
container: {
|
|
7
|
+
'& .react-grid-item': {
|
|
8
|
+
borderRadius: theme.shape.borderRadius,
|
|
9
|
+
transition: theme.transitions.create('all', {
|
|
10
|
+
delay: 0,
|
|
11
|
+
duration: 100,
|
|
12
|
+
easing: theme.transitions.easing.easeOut
|
|
13
|
+
})
|
|
14
|
+
},
|
|
15
|
+
'& .react-grid-item.react-draggable-dragging': {
|
|
16
|
+
boxShadow: theme.shadows[3]
|
|
17
|
+
},
|
|
18
|
+
'& .react-grid-item.react-grid-placeholder': {
|
|
19
|
+
backgroundColor: alpha(theme.palette.primary.main, 0.7)
|
|
20
|
+
},
|
|
21
|
+
'& .react-grid-item.resizing': {
|
|
22
|
+
boxShadow: theme.shadows[3]
|
|
23
|
+
},
|
|
24
|
+
'& .react-resizable-handle': {
|
|
25
|
+
backgroundColor: theme.palette.action.focus,
|
|
26
|
+
backgroundImage: 'none',
|
|
27
|
+
borderRadius: theme.shape.borderRadius,
|
|
28
|
+
display: 'block',
|
|
29
|
+
opacity: 0,
|
|
30
|
+
position: 'absolute'
|
|
31
|
+
},
|
|
32
|
+
'& .react-resizable-handle.react-resizable-handle-e': {
|
|
33
|
+
cursor: 'ew-resize',
|
|
34
|
+
height: `calc(100% - ${theme.spacing(3)})`,
|
|
35
|
+
marginTop: 0,
|
|
36
|
+
right: 0,
|
|
37
|
+
top: 0,
|
|
38
|
+
transform: 'rotate(0deg)',
|
|
39
|
+
width: theme.spacing(1)
|
|
40
|
+
},
|
|
41
|
+
'& .react-resizable-handle.react-resizable-handle-s': {
|
|
42
|
+
bottom: 0,
|
|
43
|
+
cursor: 'ns-resize',
|
|
44
|
+
height: theme.spacing(1),
|
|
45
|
+
left: 0,
|
|
46
|
+
marginLeft: 0,
|
|
47
|
+
transform: 'rotate(0deg)',
|
|
48
|
+
width: `calc(100% - ${theme.spacing(3)})`
|
|
49
|
+
},
|
|
50
|
+
'& .react-resizable-handle.react-resizable-handle-se': {
|
|
51
|
+
bottom: 0,
|
|
52
|
+
cursor: 'nwse-resize',
|
|
53
|
+
height: theme.spacing(2),
|
|
54
|
+
right: 0,
|
|
55
|
+
transform: 'rotate(0deg)',
|
|
56
|
+
width: theme.spacing(2)
|
|
57
|
+
},
|
|
58
|
+
'& .react-resizable-handle::after': {
|
|
59
|
+
content: 'none'
|
|
60
|
+
},
|
|
61
|
+
'& .react-resizable-handle:hover': {
|
|
62
|
+
opacity: 1
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
export const useDashboardItemStyles = makeStyles()((theme) => ({
|
|
68
|
+
widgetContainer: {
|
|
69
|
+
height: '100%',
|
|
70
|
+
width: '100%'
|
|
71
|
+
},
|
|
72
|
+
widgetContent: {
|
|
73
|
+
height: '100%',
|
|
74
|
+
padding: theme.spacing(1, 2)
|
|
75
|
+
},
|
|
76
|
+
widgetHeader: {
|
|
77
|
+
'&:hover': {
|
|
78
|
+
backgroundColor: theme.palette.action.hover
|
|
79
|
+
},
|
|
80
|
+
cursor: 'move',
|
|
81
|
+
padding: theme.spacing(0.5, 2)
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { ComponentMeta } from '@storybook/react';
|
|
2
|
+
import { Layout } from 'react-grid-layout';
|
|
3
|
+
|
|
4
|
+
import { Typography } from '@mui/material';
|
|
5
|
+
|
|
6
|
+
import FluidTypography from '../Typography/FluidTypography';
|
|
7
|
+
|
|
8
|
+
import { DashboardLayout } from '.';
|
|
9
|
+
|
|
10
|
+
interface CustomLayout extends Layout {
|
|
11
|
+
content: string;
|
|
12
|
+
shouldUseFluidTypography: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const dashboardLayout: Array<CustomLayout> = [
|
|
16
|
+
{
|
|
17
|
+
content: 'Hello world',
|
|
18
|
+
h: 4,
|
|
19
|
+
i: 'a',
|
|
20
|
+
shouldUseFluidTypography: false,
|
|
21
|
+
w: 6,
|
|
22
|
+
x: 0,
|
|
23
|
+
y: 0
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
content: 'This is a panel',
|
|
27
|
+
h: 3,
|
|
28
|
+
i: 'b',
|
|
29
|
+
minW: 2,
|
|
30
|
+
shouldUseFluidTypography: false,
|
|
31
|
+
w: 7,
|
|
32
|
+
x: 1,
|
|
33
|
+
y: 7
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
content: 'And the last panel with fluid typography',
|
|
37
|
+
h: 7,
|
|
38
|
+
i: 'c',
|
|
39
|
+
shouldUseFluidTypography: true,
|
|
40
|
+
w: 6,
|
|
41
|
+
x: 6,
|
|
42
|
+
y: 6
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const generateLayout = (maxElements: number): Array<CustomLayout> => {
|
|
47
|
+
return Array(maxElements)
|
|
48
|
+
.fill(0)
|
|
49
|
+
.map((_, i): CustomLayout => {
|
|
50
|
+
return {
|
|
51
|
+
content: `${i}`,
|
|
52
|
+
h: 3,
|
|
53
|
+
i: i.toString(),
|
|
54
|
+
shouldUseFluidTypography: false,
|
|
55
|
+
w: 3,
|
|
56
|
+
x: (i * 3) % 12,
|
|
57
|
+
y: Math.floor(i / 12)
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
interface DashboardTemplateProps {
|
|
63
|
+
header?: JSX.Element;
|
|
64
|
+
layout?: Array<CustomLayout>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const Header = (): JSX.Element => (
|
|
68
|
+
<Typography variant="body2">The title</Typography>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const DashboardTemplate = ({
|
|
72
|
+
header,
|
|
73
|
+
layout = dashboardLayout
|
|
74
|
+
}: DashboardTemplateProps): JSX.Element => (
|
|
75
|
+
<DashboardLayout.Layout<CustomLayout> layout={layout}>
|
|
76
|
+
{layout.map(({ i, content, shouldUseFluidTypography }) => (
|
|
77
|
+
<DashboardLayout.Item header={header} key={i}>
|
|
78
|
+
{shouldUseFluidTypography ? (
|
|
79
|
+
<FluidTypography text={content} />
|
|
80
|
+
) : (
|
|
81
|
+
<Typography>{content}</Typography>
|
|
82
|
+
)}
|
|
83
|
+
</DashboardLayout.Item>
|
|
84
|
+
))}
|
|
85
|
+
</DashboardLayout.Layout>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
export default {
|
|
89
|
+
argTypes: {},
|
|
90
|
+
component: DashboardTemplate,
|
|
91
|
+
title: 'Dashboard'
|
|
92
|
+
} as ComponentMeta<typeof DashboardTemplate>;
|
|
93
|
+
|
|
94
|
+
export const normal = DashboardTemplate.bind({});
|
|
95
|
+
|
|
96
|
+
export const withManyPanels = DashboardTemplate.bind({});
|
|
97
|
+
withManyPanels.args = {
|
|
98
|
+
layout: generateLayout(1000)
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const withItemHeader = DashboardTemplate.bind({});
|
|
102
|
+
withItemHeader.args = {
|
|
103
|
+
header: <Header />
|
|
104
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { FC, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Grid as VisxGrid } from '@visx/visx';
|
|
4
|
+
import { scaleLinear } from '@visx/scale';
|
|
5
|
+
|
|
6
|
+
import { useTheme } from '@mui/material';
|
|
7
|
+
|
|
8
|
+
import useMemoComponent from '../utils/useMemoComponent';
|
|
9
|
+
|
|
10
|
+
import { maxColumns, rowHeight } from './utils';
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
columns: number;
|
|
14
|
+
height: number;
|
|
15
|
+
width: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const Grid: FC<Props> = ({ width, height, columns }) => {
|
|
19
|
+
const theme = useTheme();
|
|
20
|
+
|
|
21
|
+
const xScale = useMemo(
|
|
22
|
+
() =>
|
|
23
|
+
scaleLinear({
|
|
24
|
+
domain: [0, maxColumns],
|
|
25
|
+
range: [0, width]
|
|
26
|
+
}),
|
|
27
|
+
[width]
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const numberOfRows = Math.floor(height / (rowHeight + 16));
|
|
31
|
+
|
|
32
|
+
const yScale = useMemo(
|
|
33
|
+
() =>
|
|
34
|
+
scaleLinear({
|
|
35
|
+
domain: [0, numberOfRows],
|
|
36
|
+
range: [0, height]
|
|
37
|
+
}),
|
|
38
|
+
[height]
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const tick = maxColumns / columns;
|
|
42
|
+
|
|
43
|
+
const xTickValues = Array(columns)
|
|
44
|
+
.fill(0)
|
|
45
|
+
.map((_, index) => index * tick);
|
|
46
|
+
|
|
47
|
+
return useMemoComponent({
|
|
48
|
+
Component: (
|
|
49
|
+
<svg style={{ height, position: 'absolute', width }}>
|
|
50
|
+
<VisxGrid.GridColumns
|
|
51
|
+
height={height}
|
|
52
|
+
scale={xScale}
|
|
53
|
+
stroke={theme.palette.divider}
|
|
54
|
+
tickValues={xTickValues}
|
|
55
|
+
width={width}
|
|
56
|
+
/>
|
|
57
|
+
<VisxGrid.GridRows
|
|
58
|
+
height={height}
|
|
59
|
+
scale={yScale}
|
|
60
|
+
stroke={theme.palette.divider}
|
|
61
|
+
top={-10}
|
|
62
|
+
width={width}
|
|
63
|
+
/>
|
|
64
|
+
</svg>
|
|
65
|
+
),
|
|
66
|
+
memoProps: [height, width, columns]
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default Grid;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { CSSProperties, ForwardedRef, MouseEvent, forwardRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { isNil } from 'ramda';
|
|
4
|
+
|
|
5
|
+
import { Card } from '@mui/material';
|
|
6
|
+
|
|
7
|
+
import useMemoComponent from '../utils/useMemoComponent';
|
|
8
|
+
|
|
9
|
+
import { useDashboardItemStyles } from './Dashboard.styles';
|
|
10
|
+
|
|
11
|
+
interface DashboardItemProps {
|
|
12
|
+
children: JSX.Element;
|
|
13
|
+
className?: string;
|
|
14
|
+
header?: JSX.Element;
|
|
15
|
+
key: string;
|
|
16
|
+
onMouseDown?: (e: MouseEvent<HTMLDivElement>) => void;
|
|
17
|
+
onMouseUp?: (e: MouseEvent<HTMLDivElement>) => void;
|
|
18
|
+
onTouchEnd?: (e) => void;
|
|
19
|
+
style?: CSSProperties;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const Item = forwardRef(
|
|
23
|
+
(
|
|
24
|
+
{
|
|
25
|
+
children,
|
|
26
|
+
key,
|
|
27
|
+
style,
|
|
28
|
+
className,
|
|
29
|
+
header,
|
|
30
|
+
onMouseDown,
|
|
31
|
+
onMouseUp,
|
|
32
|
+
onTouchEnd
|
|
33
|
+
}: DashboardItemProps,
|
|
34
|
+
ref: ForwardedRef<HTMLDivElement>
|
|
35
|
+
): JSX.Element => {
|
|
36
|
+
const { classes } = useDashboardItemStyles();
|
|
37
|
+
|
|
38
|
+
const hasHeader = !isNil(header);
|
|
39
|
+
|
|
40
|
+
const listeners = {
|
|
41
|
+
onMouseDown,
|
|
42
|
+
onMouseUp,
|
|
43
|
+
onTouchEnd
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const cardContainerListeners = !hasHeader ? listeners : {};
|
|
47
|
+
|
|
48
|
+
return useMemoComponent({
|
|
49
|
+
Component: (
|
|
50
|
+
<div
|
|
51
|
+
className={className}
|
|
52
|
+
key={key}
|
|
53
|
+
ref={ref}
|
|
54
|
+
style={style}
|
|
55
|
+
{...cardContainerListeners}
|
|
56
|
+
>
|
|
57
|
+
<Card className={classes.widgetContainer}>
|
|
58
|
+
{header && (
|
|
59
|
+
<div {...listeners} className={classes.widgetHeader}>
|
|
60
|
+
{header}
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
|
+
<div className={classes.widgetContent}>{children}</div>
|
|
64
|
+
</Card>
|
|
65
|
+
</div>
|
|
66
|
+
),
|
|
67
|
+
memoProps: [key, style, className, header]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
export default Item;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Responsive } from '@visx/visx';
|
|
4
|
+
import GridLayout, { WidthProvider, Layout } from 'react-grid-layout';
|
|
5
|
+
import 'react-grid-layout/css/styles.css';
|
|
6
|
+
|
|
7
|
+
import { Responsive as ResponsiveHeight, useMemoComponent } from '..';
|
|
8
|
+
|
|
9
|
+
import { useDashboardLayoutStyles } from './Dashboard.styles';
|
|
10
|
+
import { getColumnsFromScreenSize, getLayout, rowHeight } from './utils';
|
|
11
|
+
import Grid from './Grid';
|
|
12
|
+
|
|
13
|
+
const ReactGridLayout = WidthProvider(GridLayout);
|
|
14
|
+
|
|
15
|
+
interface DashboardLayoutProps<T> {
|
|
16
|
+
changeLayout?: (newLayout: Array<Layout>) => void;
|
|
17
|
+
children: Array<JSX.Element>;
|
|
18
|
+
displayGrid?: boolean;
|
|
19
|
+
layout: Array<T>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const Layout = <T extends Layout>({
|
|
23
|
+
children,
|
|
24
|
+
changeLayout,
|
|
25
|
+
displayGrid,
|
|
26
|
+
layout
|
|
27
|
+
}: DashboardLayoutProps<T>): JSX.Element => {
|
|
28
|
+
const { classes } = useDashboardLayoutStyles();
|
|
29
|
+
|
|
30
|
+
const [columns, setColumns] = useState(getColumnsFromScreenSize());
|
|
31
|
+
|
|
32
|
+
const resize = (): void => {
|
|
33
|
+
setColumns(getColumnsFromScreenSize());
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
window.addEventListener('resize', resize);
|
|
38
|
+
|
|
39
|
+
return (): void => {
|
|
40
|
+
window.removeEventListener('resize', resize);
|
|
41
|
+
};
|
|
42
|
+
}, []);
|
|
43
|
+
|
|
44
|
+
return useMemoComponent({
|
|
45
|
+
Component: (
|
|
46
|
+
<ResponsiveHeight>
|
|
47
|
+
<Responsive.ParentSize>
|
|
48
|
+
{({ width, height }): JSX.Element => (
|
|
49
|
+
<div className={classes.container}>
|
|
50
|
+
{displayGrid && (
|
|
51
|
+
<Grid columns={columns} height={height} width={width} />
|
|
52
|
+
)}
|
|
53
|
+
<ReactGridLayout
|
|
54
|
+
cols={columns}
|
|
55
|
+
containerPadding={[4, 0]}
|
|
56
|
+
layout={getLayout(layout)}
|
|
57
|
+
margin={[20, 20]}
|
|
58
|
+
resizeHandles={['s', 'e', 'se']}
|
|
59
|
+
rowHeight={rowHeight}
|
|
60
|
+
width={width}
|
|
61
|
+
onLayoutChange={changeLayout}
|
|
62
|
+
>
|
|
63
|
+
{children}
|
|
64
|
+
</ReactGridLayout>
|
|
65
|
+
</div>
|
|
66
|
+
)}
|
|
67
|
+
</Responsive.ParentSize>
|
|
68
|
+
</ResponsiveHeight>
|
|
69
|
+
),
|
|
70
|
+
memoProps: [columns, layout, displayGrid]
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export default Layout;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { lt } from 'ramda';
|
|
2
|
+
import { Layout } from 'react-grid-layout';
|
|
3
|
+
|
|
4
|
+
export const maxColumns = 12;
|
|
5
|
+
const minColumns = 1;
|
|
6
|
+
const breakpoint = 768;
|
|
7
|
+
|
|
8
|
+
export const rowHeight = 64;
|
|
9
|
+
|
|
10
|
+
export const getIsSmallScreenSize = (): boolean =>
|
|
11
|
+
lt(window.innerWidth, breakpoint);
|
|
12
|
+
|
|
13
|
+
export const getColumnsFromScreenSize = (): number =>
|
|
14
|
+
getIsSmallScreenSize() ? minColumns : maxColumns;
|
|
15
|
+
|
|
16
|
+
export const getLayout = <T extends Layout>(layout: Array<T>): Array<T> => {
|
|
17
|
+
const isSmallScreenSize = getIsSmallScreenSize();
|
|
18
|
+
if (!isSmallScreenSize) {
|
|
19
|
+
return layout;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return layout
|
|
23
|
+
.sort((a, b) => a.x + a.y - (b.x + b.y))
|
|
24
|
+
.map((widget) => ({
|
|
25
|
+
...widget,
|
|
26
|
+
w: 1
|
|
27
|
+
}));
|
|
28
|
+
};
|
|
@@ -85,7 +85,7 @@ const AutoSizeAutocompleteField = ({
|
|
|
85
85
|
endAdornment,
|
|
86
86
|
customPadding
|
|
87
87
|
}: AutoSizeAutocompleteFieldProps): JSX.Element => {
|
|
88
|
-
const [value, setValue] = React.useState(
|
|
88
|
+
const [value, setValue] = React.useState(null);
|
|
89
89
|
|
|
90
90
|
const change = (_, newValue): void => {
|
|
91
91
|
setValue(newValue);
|
|
@@ -108,12 +108,3 @@ const AutoSizeAutocompleteField = ({
|
|
|
108
108
|
export const autoSize = (): JSX.Element => {
|
|
109
109
|
return <AutoSizeAutocompleteField />;
|
|
110
110
|
};
|
|
111
|
-
|
|
112
|
-
export const autoSizeWithCustomPadding = (): JSX.Element => {
|
|
113
|
-
return (
|
|
114
|
-
<AutoSizeAutocompleteField
|
|
115
|
-
customPadding={5}
|
|
116
|
-
endAdornment={<EndAdornment />}
|
|
117
|
-
/>
|
|
118
|
-
);
|
|
119
|
-
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ComponentMeta } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { Box } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
import FluidTypography, { FluidTypographyProps } from '.';
|
|
6
|
+
|
|
7
|
+
interface Props extends FluidTypographyProps {
|
|
8
|
+
height?: string | number;
|
|
9
|
+
width?: string | number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const FluidTypographyTemplate = ({
|
|
13
|
+
width = '900px',
|
|
14
|
+
height = '700px',
|
|
15
|
+
text,
|
|
16
|
+
variant
|
|
17
|
+
}: Props): JSX.Element => {
|
|
18
|
+
return (
|
|
19
|
+
<Box sx={{ height, width }}>
|
|
20
|
+
<FluidTypography text={text} variant={variant} />
|
|
21
|
+
</Box>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
argTypes: {
|
|
27
|
+
height: { control: 'text' },
|
|
28
|
+
text: { control: 'text' },
|
|
29
|
+
variant: { control: 'text' },
|
|
30
|
+
width: { control: 'text' }
|
|
31
|
+
},
|
|
32
|
+
component: FluidTypographyTemplate,
|
|
33
|
+
title: 'Fluid Typography'
|
|
34
|
+
} as ComponentMeta<typeof FluidTypographyTemplate>;
|
|
35
|
+
|
|
36
|
+
export const basic = FluidTypographyTemplate.bind({});
|
|
37
|
+
basic.args = {
|
|
38
|
+
text: 'Hello world'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const with200pxWidth = FluidTypographyTemplate.bind({});
|
|
42
|
+
with200pxWidth.args = {
|
|
43
|
+
height: '200px',
|
|
44
|
+
text: 'Hello world',
|
|
45
|
+
width: '200px'
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const with20pxHeight = FluidTypographyTemplate.bind({});
|
|
49
|
+
with20pxHeight.args = {
|
|
50
|
+
height: '20px',
|
|
51
|
+
text: 'Hello world'
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const withLongText = FluidTypographyTemplate.bind({});
|
|
55
|
+
withLongText.args = {
|
|
56
|
+
text: 'This is a very long text becaaaaaaause it has a lot to sayyyyy !!!!!!!!'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const withHeading5Variant = FluidTypographyTemplate.bind({});
|
|
60
|
+
withHeading5Variant.args = {
|
|
61
|
+
text: 'Hello world',
|
|
62
|
+
variant: 'h5'
|
|
63
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Typography, TypographyProps } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
import useFluidResizeObserver from './useFluidResizeObserver';
|
|
6
|
+
|
|
7
|
+
type CustomTypographyProps = Pick<TypographyProps, 'variant'>;
|
|
8
|
+
export interface FluidTypographyProps extends CustomTypographyProps {
|
|
9
|
+
className?: string;
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const FluidTypography = ({
|
|
14
|
+
text,
|
|
15
|
+
variant = 'body1',
|
|
16
|
+
className
|
|
17
|
+
}: FluidTypographyProps): JSX.Element => {
|
|
18
|
+
const containerRef = useRef<HTMLElement>();
|
|
19
|
+
const parentRef = useRef<HTMLElement>();
|
|
20
|
+
|
|
21
|
+
const size = useFluidResizeObserver({ ref: containerRef });
|
|
22
|
+
const parentSize = useFluidResizeObserver({ isParent: true, ref: parentRef });
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
ref={parentRef}
|
|
27
|
+
style={{
|
|
28
|
+
height: `${parentSize.height}px`,
|
|
29
|
+
width: `100%`
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<div ref={containerRef} style={{ height: '100%', width: '100%' }}>
|
|
33
|
+
<Typography
|
|
34
|
+
className={className}
|
|
35
|
+
sx={{
|
|
36
|
+
fontSize: `clamp(10px, min(${Math.floor(
|
|
37
|
+
size.width / 6
|
|
38
|
+
)}px, ${Math.floor(size.height / 6)}px), min(${size.width}px, ${
|
|
39
|
+
size.height
|
|
40
|
+
}px))`
|
|
41
|
+
}}
|
|
42
|
+
variant={variant}
|
|
43
|
+
>
|
|
44
|
+
{text}
|
|
45
|
+
</Typography>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default FluidTypography;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MutableRefObject,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState
|
|
7
|
+
} from 'react';
|
|
8
|
+
|
|
9
|
+
interface Size {
|
|
10
|
+
height: number;
|
|
11
|
+
width: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface UseFluidResizeObserver {
|
|
15
|
+
isParent?: boolean;
|
|
16
|
+
ref: MutableRefObject<HTMLElement | undefined>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const useFluidResizeObserver = ({
|
|
20
|
+
ref,
|
|
21
|
+
isParent
|
|
22
|
+
}: UseFluidResizeObserver): Size => {
|
|
23
|
+
const [size, setSize] = useState<Size>({ height: 0, width: 0 });
|
|
24
|
+
|
|
25
|
+
const observer = useRef<ResizeObserver | null>(null);
|
|
26
|
+
|
|
27
|
+
const resizeObserver = useCallback(
|
|
28
|
+
(element) => {
|
|
29
|
+
if (observer.current) {
|
|
30
|
+
observer.current.disconnect();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
observer.current = new ResizeObserver(
|
|
34
|
+
([entry]: Array<ResizeObserverEntry>) => {
|
|
35
|
+
setSize({
|
|
36
|
+
height: entry.target?.getBoundingClientRect().height || 0,
|
|
37
|
+
width: entry.target?.getBoundingClientRect().width || 0
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (element && observer.current) {
|
|
43
|
+
observer.current.observe(element);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
[ref.current]
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
resizeObserver(isParent ? ref.current?.parentElement : ref.current);
|
|
51
|
+
}, [ref.current]);
|
|
52
|
+
|
|
53
|
+
return size;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default useFluidResizeObserver;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import TypographyStory from './story.utils';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
argTypes: {},
|
|
7
|
-
component:
|
|
7
|
+
component: TypographyStory,
|
|
8
8
|
title: 'Typography'
|
|
9
|
-
} as ComponentMeta<typeof
|
|
9
|
+
} as ComponentMeta<typeof TypographyStory>;
|
|
10
10
|
|
|
11
|
-
const TemplateTypographtStory: ComponentStory<typeof
|
|
11
|
+
const TemplateTypographtStory: ComponentStory<typeof TypographyStory> = (
|
|
12
12
|
args
|
|
13
|
-
) => <
|
|
13
|
+
) => <TypographyStory {...args} />;
|
|
14
14
|
|
|
15
15
|
export const typography = (): JSX.Element => (
|
|
16
16
|
<TemplateTypographtStory text="Hello world" />
|
package/src/__image_snapshots__/storyshots-test-js-image-story-shots-dashboard-normal-1-snap.png
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/index.ts
CHANGED
|
@@ -155,3 +155,6 @@ export { default as ActionsList } from './ActionsList';
|
|
|
155
155
|
export { getStatusColors, SeverityCode } from './utils/statuses';
|
|
156
156
|
|
|
157
157
|
export type { ResponseError, CatchErrorProps } from './api/customFetch';
|
|
158
|
+
|
|
159
|
+
export { default as FluidTypography } from './Typography/FluidTypography';
|
|
160
|
+
export * from './Dashboard';
|
|
File without changes
|