@centreon/ui 23.4.50-MON-15300-dashboard-with-one-layout.13 → 23.10.1

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 (37) hide show
  1. package/jest.config.js +1 -4
  2. package/package.json +1 -2
  3. package/src/Listing/Cell/index.tsx +1 -1
  4. package/src/Listing/EmptyResult/EmptyResult.tsx +13 -0
  5. package/src/Listing/Header/SortableCell/Content.tsx +8 -5
  6. package/src/Listing/Header/index.tsx +6 -10
  7. package/src/Listing/Listing.styles.ts +77 -0
  8. package/src/Listing/Row/EmptyRow.styles.ts +14 -0
  9. package/src/Listing/Row/EmptyRow.tsx +30 -0
  10. package/src/Listing/{Row.tsx → Row/Row.tsx} +4 -6
  11. package/src/Listing/Row/SkeletonLoaderRows.tsx +23 -0
  12. package/src/Listing/index.stories.tsx +5 -1
  13. package/src/Listing/index.tsx +18 -121
  14. package/src/Typography/index.stories.tsx +1 -1
  15. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-listing-as-empty-state-1-snap.png +0 -0
  16. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-listing-loading-with-no-data-1-snap.png +0 -0
  17. package/src/index.ts +0 -3
  18. package/src/Dashboard/DashboardGrid.tsx +0 -50
  19. package/src/Dashboard/DashboardItem.tsx +0 -72
  20. package/src/Dashboard/DashboardLayout.tsx +0 -78
  21. package/src/Dashboard/index.stories.tsx +0 -104
  22. package/src/Dashboard/index.tsx +0 -3
  23. package/src/Dashboard/useDashboardStyles.ts +0 -83
  24. package/src/Dashboard/utils.ts +0 -26
  25. package/src/Listing/Skeleton.tsx +0 -11
  26. package/src/Typography/FluidTypography/index.stories.tsx +0 -63
  27. package/src/Typography/FluidTypography/index.tsx +0 -51
  28. package/src/Typography/FluidTypography/useFluidResizeObserver.ts +0 -56
  29. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-dashboard-normal-1-snap.png +0 -0
  30. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-dashboard-with-item-header-1-snap.png +0 -0
  31. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-dashboard-with-many-panels-1-snap.png +0 -0
  32. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-basic-1-snap.png +0 -0
  33. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-20-px-height-1-snap.png +0 -0
  34. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-200-px-width-1-snap.png +0 -0
  35. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-heading-5-variant-1-snap.png +0 -0
  36. package/src/__image_snapshots__/storyshots-test-js-image-story-shots-fluid-typography-with-long-text-1-snap.png +0 -0
  37. /package/src/Typography/{story.utils.tsx → index.tsx} +0 -0
package/jest.config.js CHANGED
@@ -16,8 +16,5 @@ module.exports = {
16
16
  transform: {
17
17
  ...baseConfig.transform,
18
18
  '^.+\\.mdx?$': '@storybook/addon-docs/jest-transform-mdx'
19
- },
20
- transformIgnorePatterns: [
21
- '<rootDir>/../../node_modules/(?!d3-array|d3-scale|d3-interpolation|d3-interpolate)'
22
- ]
19
+ }
23
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "23.4.50-MON-15300-dashboard-with-one-layout.13",
3
+ "version": "23.10.1",
4
4
  "description": "Centreon UI Components",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {
@@ -91,7 +91,6 @@
91
91
  "react-dom": "18.x",
92
92
  "react-i18next": "12.x",
93
93
  "react-router-dom": "6.x",
94
- "react-scale-text": "1.x",
95
94
  "resize-observer-polyfill": "1.x",
96
95
  "ts.data.json": "2.x",
97
96
  "tss-react": "4.x"
@@ -99,7 +99,7 @@ const useStyles = makeStyles<StylesProps>()(
99
99
  overflow: 'hidden',
100
100
  ...getTextStyleByViewMode({ theme, viewMode }),
101
101
  p: getRowHighlightStyle({ isRowHighlighted, theme }),
102
- padding: 0,
102
+ padding: theme.spacing(0, 1),
103
103
  whiteSpace: 'nowrap'
104
104
  }
105
105
  })
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+
3
+ import { EmptyRow } from '../Row/EmptyRow';
4
+
5
+ interface EmptyResultProps {
6
+ label: string;
7
+ }
8
+
9
+ const EmptyResult = ({ label }: EmptyResultProps): JSX.Element => (
10
+ <EmptyRow>{label}</EmptyRow>
11
+ );
12
+
13
+ export { EmptyResult };
@@ -42,13 +42,15 @@ const useStyles = makeStyles<StylesProps>()(
42
42
  borderRadius: isDragging && isInDragOverlay ? theme.spacing(0.5) : 0,
43
43
  color: theme.palette.common.white,
44
44
  display: 'flex',
45
- minHeight: theme.spacing(3)
45
+ height: '100%'
46
46
  },
47
47
  dragHandle: {
48
+ '&, &.Mui-focus, &:focus': {
49
+ outline: 'none'
50
+ },
48
51
  alignSelf: 'center',
49
52
  cursor: isDragging ? 'grabbing' : 'grab',
50
- display: 'flex',
51
- outline: 'none'
53
+ display: 'flex'
52
54
  },
53
55
  simpleHeaderCellContent: {
54
56
  alignItems: 'center',
@@ -60,7 +62,8 @@ const useStyles = makeStyles<StylesProps>()(
60
62
  ? 'transparent'
61
63
  : theme.palette.background.listingHeader,
62
64
  borderBottom: 'none',
63
- padding: 0,
65
+ height: 'inherit',
66
+ padding: theme.spacing(0, 1),
64
67
  ...getTextStyleByViewMode({ theme, viewMode })
65
68
  }
66
69
  })
@@ -148,7 +151,7 @@ const SortableHeaderCellContent = ({
148
151
  visible={cellHovered}
149
152
  {...props}
150
153
  isInteractive
151
- className={cx({ [classes.dragHandle]: cellHovered })}
154
+ className={cx(classes.dragHandle)}
152
155
  columnLabel={columnLabel}
153
156
  />
154
157
  )}
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { closestCenter, DraggableSyntheticListeners } from '@dnd-kit/core';
4
4
  import { horizontalListSortingStrategy } from '@dnd-kit/sortable';
5
5
  import { equals, find, isEmpty, map, not, pick, propEq } from 'ramda';
6
- import { makeStyles, withStyles } from 'tss-react/mui';
6
+ import { makeStyles } from 'tss-react/mui';
7
7
 
8
8
  import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
9
9
  import {
@@ -25,14 +25,6 @@ import { labelPredefinedRowsSelectionMenu } from '../translatedLabels';
25
25
  import PredefinedSelectionList from './PredefinedSelectionList';
26
26
  import SortableHeaderCellContent from './SortableCell/Content';
27
27
 
28
- const height = 28;
29
-
30
- const HeaderCell = withStyles(TableCell, (theme) => ({
31
- root: {
32
- padding: theme.spacing(0)
33
- }
34
- }));
35
-
36
28
  const useStyles = makeStyles()((theme) => ({
37
29
  checkbox: {
38
30
  '&.Mui-checked': {
@@ -49,6 +41,7 @@ const useStyles = makeStyles()((theme) => ({
49
41
  borderBottom: 'none',
50
42
  display: 'flex',
51
43
  justifyContent: 'start',
44
+ lineHeight: 'inherit',
52
45
  minWidth: theme.spacing(51 / 8),
53
46
  padding: 0
54
47
  },
@@ -59,6 +52,10 @@ const useStyles = makeStyles()((theme) => ({
59
52
  color: theme.palette.common.white,
60
53
  width: theme.spacing(2)
61
54
  },
55
+ root: {
56
+ height: '100%',
57
+ padding: theme.spacing(0, 1)
58
+ },
62
59
  row: {
63
60
  display: 'contents'
64
61
  }
@@ -240,4 +237,3 @@ const MemoizedListingHeader = React.memo<Props>(
240
237
  );
241
238
 
242
239
  export default MemoizedListingHeader;
243
- export { height as headerHeight, HeaderCell };
@@ -0,0 +1,77 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ import { ListingVariant } from '@centreon/ui-context';
4
+
5
+ import { TableStyleAtom as TableStyle } from './models';
6
+
7
+ const loadingIndicatorHeight = 3;
8
+
9
+ interface StylesProps {
10
+ dataStyle: TableStyle;
11
+ getGridTemplateColumn: string;
12
+ limit: number;
13
+ rows: Array<unknown>;
14
+ viewMode: ListingVariant;
15
+ }
16
+
17
+ const useStyles = makeStyles<StylesProps>()(
18
+ (theme, { dataStyle, getGridTemplateColumn, rows, limit }) => ({
19
+ actionBar: {
20
+ alignItems: 'center',
21
+ display: 'flex'
22
+ },
23
+ checkbox: {
24
+ justifyContent: 'start'
25
+ },
26
+ container: {
27
+ background: 'none',
28
+ display: 'flex',
29
+ flexDirection: 'column',
30
+ height: '100%',
31
+ width: '100%'
32
+ },
33
+ loadingIndicator: {
34
+ height: loadingIndicatorHeight,
35
+ width: '100%'
36
+ },
37
+ table: {
38
+ '.listingHeader': {
39
+ backgroundColor: theme.palette.background.listingHeader,
40
+ boxShadow: `-1px 0px 0px 0px ${theme.palette.background.listingHeader}`,
41
+ padding: theme.spacing(0, 1)
42
+ },
43
+ '.listingHeader > div > div': {
44
+ backgroundColor: theme.palette.background.listingHeader,
45
+ height: theme.spacing(dataStyle.header.height / 8)
46
+ },
47
+ '.listingHeader > div > div:first-of-type': {
48
+ height: '100%',
49
+ paddingLeft: theme.spacing(1.5)
50
+ },
51
+ alignItems: 'center',
52
+ display: 'grid',
53
+ gridTemplateColumns: getGridTemplateColumn,
54
+ gridTemplateRows: `${theme.spacing(dataStyle.header.height / 8)} repeat(${
55
+ rows?.length || limit
56
+ }, ${dataStyle.body.height}px)`,
57
+ position: 'relative'
58
+ },
59
+ tableBody: {
60
+ '.MuiTableRow-root > div:first-of-type': {
61
+ paddingLeft: theme.spacing(1.5)
62
+ },
63
+
64
+ display: 'contents',
65
+ 'div:first-of-type': {
66
+ gridColumnStart: 1
67
+ },
68
+ position: 'relative'
69
+ },
70
+ tableWrapper: {
71
+ borderBottom: 'none',
72
+ overflow: 'auto'
73
+ }
74
+ })
75
+ );
76
+
77
+ export { useStyles, loadingIndicatorHeight };
@@ -0,0 +1,14 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ const useStyles = makeStyles()(() => ({
4
+ emptyDataCell: {
5
+ flexDirection: 'column',
6
+ gridColumn: 'auto / -1',
7
+ justifyContent: 'center'
8
+ },
9
+ emptyDataRow: {
10
+ display: 'contents'
11
+ }
12
+ }));
13
+
14
+ export { useStyles };
@@ -0,0 +1,30 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ import { TableRow } from '@mui/material';
4
+
5
+ import Cell from '../Cell';
6
+
7
+ import { useStyles } from './EmptyRow.styles';
8
+
9
+ interface EmptyRowProps {
10
+ children: ReactNode;
11
+ }
12
+
13
+ const EmptyRow = ({ children }: EmptyRowProps): JSX.Element => {
14
+ const { classes } = useStyles();
15
+
16
+ return (
17
+ <TableRow className={classes.emptyDataRow} component="div" tabIndex={-1}>
18
+ <Cell
19
+ align="center"
20
+ className={classes.emptyDataCell}
21
+ disableRowCondition={(): boolean => false}
22
+ isRowHovered={false}
23
+ >
24
+ {children}
25
+ </Cell>
26
+ </TableRow>
27
+ );
28
+ };
29
+
30
+ export { EmptyRow };
@@ -9,12 +9,10 @@ import { TableRowProps, TableRow, useTheme } from '@mui/material';
9
9
 
10
10
  import { ListingVariant } from '@centreon/ui-context';
11
11
 
12
- import { useViewportIntersection } from '../utils/useViewportIntersection';
13
- import LoadingSkeleton from '../LoadingSkeleton';
14
-
15
- import { Column, ColumnConfiguration, RowColorCondition } from './models';
16
-
17
- import { performanceRowsLimit } from '.';
12
+ import { useViewportIntersection } from '../../utils/useViewportIntersection';
13
+ import LoadingSkeleton from '../../LoadingSkeleton';
14
+ import { Column, ColumnConfiguration, RowColorCondition } from '../models';
15
+ import { performanceRowsLimit } from '../index';
18
16
 
19
17
  const useStyles = makeStyles()((theme) => {
20
18
  return {
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+
3
+ import LoadingSkeleton from '../../LoadingSkeleton';
4
+
5
+ import { EmptyRow } from './EmptyRow';
6
+
7
+ interface SkeletonLoaderProps {
8
+ rows?: number;
9
+ }
10
+
11
+ const SkeletonLoader = ({ rows = 10 }: SkeletonLoaderProps): JSX.Element => (
12
+ <>
13
+ {[...Array(rows)].map((_v, i) => (
14
+ <EmptyRow
15
+ key={`skeleton-row-${i}`} // eslint-disable-line react/no-array-index-key
16
+ >
17
+ <LoadingSkeleton variant="text" width="100%" />
18
+ </EmptyRow>
19
+ ))}
20
+ </>
21
+ );
22
+
23
+ export { SkeletonLoader };
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable react/prop-types */
2
- import { React, useState } from 'react';
2
+ import { useState } from 'react';
3
3
 
4
4
  import { ComponentMeta, ComponentStory } from '@storybook/react';
5
5
  import { equals, prop } from 'ramda';
@@ -191,6 +191,10 @@ export const loadingWithData = (): JSX.Element => {
191
191
  return <Story loading />;
192
192
  };
193
193
 
194
+ export const asEmptyState = (): JSX.Element => {
195
+ return <Story rows={[]} />;
196
+ };
197
+
194
198
  const actions = (
195
199
  <Button color="primary" size="small" variant="contained">
196
200
  Action
@@ -26,16 +26,8 @@ import {
26
26
  uniqBy
27
27
  } from 'ramda';
28
28
  import { useTranslation } from 'react-i18next';
29
- import { makeStyles } from 'tss-react/mui';
30
29
 
31
- import {
32
- Box,
33
- LinearProgress,
34
- Table,
35
- TableBody,
36
- TableRow,
37
- useTheme
38
- } from '@mui/material';
30
+ import { Box, LinearProgress, Table, TableBody, useTheme } from '@mui/material';
39
31
 
40
32
  import { ListingVariant } from '@centreon/ui-context';
41
33
 
@@ -47,21 +39,22 @@ import Cell from './Cell';
47
39
  import DataCell from './Cell/DataCell';
48
40
  import Checkbox from './Checkbox';
49
41
  import getCumulativeOffset from './getCumulativeOffset';
50
- import ListingHeader, { headerHeight } from './Header/index';
42
+ import ListingHeader from './Header/index';
51
43
  import {
52
44
  Column,
53
45
  ColumnConfiguration,
54
46
  PredefinedRowSelection,
55
47
  RowColorCondition,
56
48
  RowId,
57
- SortOrder,
58
- TableStyleAtom as TableStyle
49
+ SortOrder
59
50
  } from './models';
60
- import ListingRow from './Row';
61
- import ListingLoadingSkeleton from './Skeleton';
51
+ import ListingRow from './Row/Row';
62
52
  import { labelNoResultFound } from './translatedLabels';
63
53
  import useResizeObserver from './useResizeObserver';
64
54
  import useStyleTable from './useStyleTable';
55
+ import { loadingIndicatorHeight, useStyles } from './Listing.styles';
56
+ import { EmptyResult } from './EmptyResult/EmptyResult';
57
+ import { SkeletonLoader } from './Row/SkeletonLoaderRows';
65
58
 
66
59
  const getVisibleColumns = ({
67
60
  columnConfiguration,
@@ -78,88 +71,6 @@ const getVisibleColumns = ({
78
71
  ) as Array<Column>;
79
72
  };
80
73
 
81
- const loadingIndicatorHeight = 3;
82
-
83
- interface StylesProps {
84
- checkable: boolean;
85
- currentVisibleColumns: Array<Column>;
86
- dataStyle: TableStyle;
87
- getGridTemplateColumn: string;
88
- rows: Array<unknown>;
89
- viewMode: ListingVariant;
90
- }
91
-
92
- const useStyles = makeStyles<StylesProps>()(
93
- (
94
- theme,
95
- { dataStyle, getGridTemplateColumn, rows, checkable, currentVisibleColumns }
96
- ) => ({
97
- actionBar: {
98
- alignItems: 'center',
99
- display: 'flex'
100
- },
101
- checkbox: {
102
- justifyContent: 'start'
103
- },
104
- container: {
105
- background: 'none',
106
- display: 'flex',
107
- flexDirection: 'column',
108
- height: '100%',
109
- width: '100%'
110
- },
111
- emptyDataCell: {
112
- flexDirection: 'column',
113
- gridColumn: `auto / span ${
114
- checkable
115
- ? currentVisibleColumns.length + 1
116
- : currentVisibleColumns.length
117
- }`,
118
- justifyContent: 'center'
119
- },
120
- emptyDataRow: {
121
- display: 'contents'
122
- },
123
- loadingIndicator: {
124
- height: loadingIndicatorHeight,
125
- width: '100%'
126
- },
127
- table: {
128
- '.listingHeader > div > div:first-of-type': {
129
- paddingLeft: theme.spacing(1.5)
130
- },
131
- '.listingHeader div div': {
132
- backgroundColor: theme.palette.background.listingHeader,
133
- boxShadow: `-1px 0px 0px 0px ${theme.palette.background.listingHeader}`,
134
- height: dataStyle.header.height,
135
- padding: 0
136
- },
137
- alignItems: 'center',
138
- display: 'grid',
139
- gridTemplateColumns: getGridTemplateColumn,
140
- gridTemplateRows: `${theme.spacing(dataStyle.header.height / 8)} repeat(${
141
- rows?.length
142
- }, ${dataStyle.body.height}px)`,
143
- position: 'relative'
144
- },
145
- tableBody: {
146
- '.MuiTableRow-root > div:first-of-type': {
147
- paddingLeft: theme.spacing(1.5)
148
- },
149
-
150
- display: 'contents',
151
- 'div:first-of-type': {
152
- gridColumnStart: 1
153
- },
154
- position: 'relative'
155
- },
156
- tableWrapper: {
157
- borderBottom: 'none',
158
- overflow: 'auto'
159
- }
160
- })
161
- );
162
-
163
74
  interface CustomStyle {
164
75
  customStyleViewerModeContainer?: string;
165
76
  customStyleViewerModeIcon?: string;
@@ -263,10 +174,9 @@ const Listing = <TRow extends { id: RowId }>({
263
174
  });
264
175
 
265
176
  const { classes } = useStyles({
266
- checkable,
267
- currentVisibleColumns,
268
177
  dataStyle,
269
178
  getGridTemplateColumn,
179
+ limit,
270
180
  rows,
271
181
  viewMode
272
182
  });
@@ -490,9 +400,9 @@ const Listing = <TRow extends { id: RowId }>({
490
400
 
491
401
  return `calc(100vh - ${tableTopOffset}px - ${
492
402
  actionBarRef.current?.offsetHeight
493
- }px - ${headerHeight}px - ${loadingIndicatorHeight}px - ${theme.spacing(
494
- 1
495
- )})`;
403
+ }px - ${
404
+ dataStyle.header.height
405
+ }px - ${loadingIndicatorHeight}px - ${theme.spacing(1)})`;
496
406
  };
497
407
 
498
408
  const changeLimit = (updatedLimit: string): void => {
@@ -661,26 +571,13 @@ const Listing = <TRow extends { id: RowId }>({
661
571
  </ListingRow>
662
572
  );
663
573
  })}
664
- {rows.length < 1 && (
665
- <TableRow
666
- className={classes.emptyDataRow}
667
- component="div"
668
- tabIndex={-1}
669
- >
670
- <Cell
671
- align="center"
672
- className={classes.emptyDataCell}
673
- disableRowCondition={(): boolean => false}
674
- isRowHovered={false}
675
- >
676
- {loading ? (
677
- <ListingLoadingSkeleton />
678
- ) : (
679
- t(labelNoResultFound)
680
- )}
681
- </Cell>
682
- </TableRow>
683
- )}
574
+
575
+ {rows.length < 1 &&
576
+ (loading ? (
577
+ <SkeletonLoader rows={limit} />
578
+ ) : (
579
+ <EmptyResult label={t(labelNoResultFound)} />
580
+ ))}
684
581
  </TableBody>
685
582
  </Table>
686
583
  </Box>
@@ -1,6 +1,6 @@
1
1
  import { ComponentMeta, ComponentStory } from '@storybook/react';
2
2
 
3
- import TypographtStory from './story.utils';
3
+ import TypographtStory from '.';
4
4
 
5
5
  export default {
6
6
  argTypes: {},
package/src/index.ts CHANGED
@@ -155,6 +155,3 @@ 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';
@@ -1,50 +0,0 @@
1
- import { FC, useMemo } from 'react';
2
-
3
- import { Grid } 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
- interface Props {
11
- columns: number;
12
- height: number;
13
- width: number;
14
- }
15
-
16
- const DashboardGrid: FC<Props> = ({ width, height, columns }) => {
17
- const theme = useTheme();
18
-
19
- const xScale = useMemo(
20
- () =>
21
- scaleLinear({
22
- domain: [0, 12],
23
- range: [0, width]
24
- }),
25
- [width]
26
- );
27
-
28
- const tick = 12 / columns;
29
-
30
- const xTickValues = Array(columns)
31
- .fill(0)
32
- .map((_, index) => index * tick);
33
-
34
- return useMemoComponent({
35
- Component: (
36
- <svg style={{ height, position: 'absolute', width }}>
37
- <Grid.GridColumns
38
- height={height}
39
- scale={xScale}
40
- stroke={theme.palette.divider}
41
- tickValues={xTickValues}
42
- width={width}
43
- />
44
- </svg>
45
- ),
46
- memoProps: [height, width, columns]
47
- });
48
- };
49
-
50
- export default DashboardGrid;
@@ -1,72 +0,0 @@
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 './useDashboardStyles';
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 DashboardItem = 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 DashboardItem;
@@ -1,78 +0,0 @@
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 './useDashboardStyles';
10
- import { getColumnsFromScreenSize, getLayout } from './utils';
11
- import DashboardGrid from './DashboardGrid';
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 DashboardLayout = <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
- <DashboardGrid
52
- columns={columns}
53
- height={height}
54
- width={width}
55
- />
56
- )}
57
- <ReactGridLayout
58
- cols={columns}
59
- containerPadding={[4, 0]}
60
- layout={getLayout(layout)}
61
- margin={[20, 20]}
62
- resizeHandles={['s', 'e', 'se']}
63
- rowHeight={64}
64
- width={width}
65
- onLayoutChange={changeLayout}
66
- >
67
- {children}
68
- </ReactGridLayout>
69
- </div>
70
- )}
71
- </Responsive.ParentSize>
72
- </ResponsiveHeight>
73
- ),
74
- memoProps: [columns, layout, displayGrid]
75
- });
76
- };
77
-
78
- export default DashboardLayout;
@@ -1,104 +0,0 @@
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, DashboardItem } 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<CustomLayout> layout={layout}>
76
- {layout.map(({ i, content, shouldUseFluidTypography }) => (
77
- <DashboardItem header={header} key={i}>
78
- {shouldUseFluidTypography ? (
79
- <FluidTypography text={content} />
80
- ) : (
81
- <Typography>{content}</Typography>
82
- )}
83
- </DashboardItem>
84
- ))}
85
- </DashboardLayout>
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
- };
@@ -1,3 +0,0 @@
1
- export { default as DashboardLayout } from './DashboardLayout';
2
- export { default as DashboardItem } from './DashboardItem';
3
- export * from './utils';
@@ -1,83 +0,0 @@
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
- }));
@@ -1,26 +0,0 @@
1
- import { lt } from 'ramda';
2
- import { Layout } from 'react-grid-layout';
3
-
4
- const maxColumns = 12;
5
- const minColumns = 1;
6
- const breakpoint = 768;
7
-
8
- export const getIsSmallScreenSize = (): boolean =>
9
- lt(window.innerWidth, breakpoint);
10
-
11
- export const getColumnsFromScreenSize = (): number =>
12
- getIsSmallScreenSize() ? minColumns : maxColumns;
13
-
14
- export const getLayout = <T extends Layout>(layout: Array<T>): Array<T> => {
15
- const isSmallScreenSize = getIsSmallScreenSize();
16
- if (!isSmallScreenSize) {
17
- return layout;
18
- }
19
-
20
- return layout
21
- .sort((a, b) => a.x + a.y - (b.x + b.y))
22
- .map((widget) => ({
23
- ...widget,
24
- w: 1
25
- }));
26
- };
@@ -1,11 +0,0 @@
1
- import LoadingSkeleton from '../LoadingSkeleton';
2
-
3
- const ListingLoadingSkeleton = (): JSX.Element => (
4
- <>
5
- {['skeleton1', 'skeleton2', 'skeleton3'].map((key) => (
6
- <LoadingSkeleton height={20} key={key} variant="text" width="100%" />
7
- ))}
8
- </>
9
- );
10
-
11
- export default ListingLoadingSkeleton;
@@ -1,63 +0,0 @@
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
- };
@@ -1,51 +0,0 @@
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;
@@ -1,56 +0,0 @@
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;
File without changes