@true-engineering/true-react-common-ui-kit 3.27.0 → 3.28.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 (29) hide show
  1. package/README.md +25 -0
  2. package/dist/components/Description/Description.styles.d.ts +1 -1
  3. package/dist/components/FlexibleTable/FlexibleTable.d.ts +5 -5
  4. package/dist/components/FlexibleTable/FlexibleTable.stories.d.ts +2 -2
  5. package/dist/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.d.ts +4 -4
  6. package/dist/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.d.ts +7 -7
  7. package/dist/components/FlexibleTable/helpers.d.ts +2 -2
  8. package/dist/components/FlexibleTable/types.d.ts +10 -9
  9. package/dist/components/List/components/ListItem/ListItem.d.ts +1 -1
  10. package/dist/components/ScrollIntoViewIfNeeded/ScrollIntoViewIfNeeded.d.ts +2 -2
  11. package/dist/components/TextButton/TextButton.styles.d.ts +1 -1
  12. package/dist/helpers/misc.d.ts +2 -0
  13. package/dist/hooks/use-tweak-styles.d.ts +1 -1
  14. package/dist/true-react-common-ui-kit.js +17 -15
  15. package/dist/true-react-common-ui-kit.js.map +1 -1
  16. package/dist/true-react-common-ui-kit.umd.cjs +17 -15
  17. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  18. package/package.json +4 -4
  19. package/src/components/FlexibleTable/FlexibleTable.stories.tsx +3 -2
  20. package/src/components/FlexibleTable/FlexibleTable.tsx +23 -15
  21. package/src/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.tsx +25 -19
  22. package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.tsx +16 -9
  23. package/src/components/FlexibleTable/helpers.ts +6 -3
  24. package/src/components/FlexibleTable/types.ts +14 -9
  25. package/src/components/List/List.styles.ts +1 -0
  26. package/src/components/List/List.tsx +10 -4
  27. package/src/components/List/components/ListItem/ListItem.tsx +1 -1
  28. package/src/helpers/misc.ts +2 -0
  29. package/src/hooks/use-tweak-styles.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@true-engineering/true-react-common-ui-kit",
3
- "version": "3.27.0",
3
+ "version": "3.28.1",
4
4
  "description": "True Engineering React UI Kit with theming support",
5
5
  "author": "True Engineering (https://trueengineering.ru)",
6
6
  "keywords": [
@@ -43,19 +43,19 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@floating-ui/react": "0.26.12",
46
- "@true-engineering/true-react-platform-helpers": "0.2.2",
46
+ "@true-engineering/true-react-platform-helpers": "0.4.4",
47
47
  "clsx": "1.2.1",
48
48
  "country-flag-icons": "1.5.5",
49
49
  "date-fns": "2.29.3",
50
50
  "filesize": "10.1.1",
51
51
  "hex-to-rgba": "2.0.1",
52
- "jss": "10.9.2",
52
+ "jss": "10.10.0",
53
53
  "lodash-es": "4.17.21",
54
54
  "react": "18.2.0",
55
55
  "react-datepicker": "4.25.0",
56
56
  "react-dom": "18.2.0",
57
57
  "react-input-mask": "3.0.0-alpha.2",
58
- "react-jss": "10.9.2",
58
+ "react-jss": "10.10.0",
59
59
  "react-overlays": "5.2.1",
60
60
  "react-remove-scroll": "2.5.6",
61
61
  "react-transition-group": "4.4.5",
@@ -1,6 +1,7 @@
1
+ import { FC } from 'react';
1
2
  import { ComponentMeta, ComponentStory } from '@storybook/react';
2
3
  import { FlexibleTable } from './FlexibleTable';
3
- import { IFlexibleTableConfigType, IValueComponent } from './types';
4
+ import { IFlexibleTableConfigType, IValueComponentProps } from './types';
4
5
 
5
6
  export default {
6
7
  title: 'Table/FlexibleTable',
@@ -20,7 +21,7 @@ interface ITableContent {
20
21
  status: string;
21
22
  }
22
23
 
23
- const Temp: IValueComponent<ITableContent, string> = ({ value }) => <>{value}</>;
24
+ const Temp: FC<IValueComponentProps<ITableContent, string>> = ({ value }) => <>{value}</>;
24
25
 
25
26
  const config: IFlexibleTableConfigType<ITableContent> = {
26
27
  contractCode: {
@@ -2,6 +2,7 @@ import { ReactNode, RefObject, useCallback, useEffect, useMemo, useRef } from 'r
2
2
  import clsx from 'clsx';
3
3
  import {
4
4
  addDataTestId,
5
+ applyAction,
5
6
  indexMap,
6
7
  isArrayNotEmpty,
7
8
  isEmpty,
@@ -18,13 +19,17 @@ import {
18
19
  IFlexibleTableConfigType,
19
20
  IInfinityScrollConfig,
20
21
  IFlexibleTableRenderMode,
22
+ IHeaderContent,
21
23
  } from './types';
22
24
  import { useStyles, IFlexibleTableStyles } from './FlexibleTable.styles';
23
25
 
24
- export interface IFlexibleTableProps<Row extends ITableRow>
25
- extends ICommonProps<IFlexibleTableStyles>,
26
+ export interface IFlexibleTableProps<
27
+ Row extends ITableRow,
28
+ HeaderContent extends IHeaderContent<Row>,
29
+ UniqueField extends keyof Row,
30
+ > extends ICommonProps<IFlexibleTableStyles>,
26
31
  Pick<
27
- IFlexibleTableRowProps<Row>,
32
+ IFlexibleTableRowProps<Row, HeaderContent, UniqueField>,
28
33
  | 'uniqueField'
29
34
  | 'activeRows'
30
35
  | 'rowAttributes'
@@ -37,9 +42,8 @@ export interface IFlexibleTableProps<Row extends ITableRow>
37
42
  content: Row[];
38
43
  /** @default 'table' */
39
44
  renderMode?: IFlexibleTableRenderMode;
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- headerContent?: Partial<Record<keyof Row, any>>;
42
- config: IFlexibleTableConfigType<Row>;
45
+ headerContent?: HeaderContent;
46
+ config: IFlexibleTableConfigType<Row, HeaderContent>;
43
47
  enabledColumns?: Array<keyof Row & string>;
44
48
  /** @default false */
45
49
  isLoading?: boolean;
@@ -51,7 +55,11 @@ export interface IFlexibleTableProps<Row extends ITableRow>
51
55
  nothingFoundContent?: ReactNode;
52
56
  }
53
57
 
54
- export function FlexibleTable<Row extends ITableRow>({
58
+ export function FlexibleTable<
59
+ Row extends ITableRow,
60
+ HeaderContent extends IHeaderContent<Row> = IHeaderContent<Row>,
61
+ UniqueField extends keyof Row = keyof Row,
62
+ >({
55
63
  content,
56
64
  headerContent,
57
65
  config,
@@ -67,7 +75,7 @@ export function FlexibleTable<Row extends ITableRow>({
67
75
  tweakStyles,
68
76
  onHeadClick,
69
77
  ...restProps
70
- }: IFlexibleTableProps<Row>): JSX.Element {
78
+ }: IFlexibleTableProps<Row, HeaderContent, UniqueField>): JSX.Element {
71
79
  const classes = useStyles({ theme: tweakStyles });
72
80
 
73
81
  const tweakTableRowStyles = useTweakStyles({
@@ -84,7 +92,10 @@ export function FlexibleTable<Row extends ITableRow>({
84
92
  const hasInfiniteScroll = isNotEmpty(infinityScrollConfig);
85
93
  const { uniqueField, isFirstColumnSticky = false } = restProps;
86
94
 
87
- const tableRowProps: Omit<IFlexibleTableRowProps<Row>, 'item' | 'index'> = {
95
+ const tableRowProps: Omit<
96
+ IFlexibleTableRowProps<Row, HeaderContent, UniqueField>,
97
+ 'item' | 'index'
98
+ > = {
88
99
  ...restProps,
89
100
  renderMode,
90
101
  config,
@@ -202,7 +213,6 @@ export function FlexibleTable<Row extends ITableRow>({
202
213
  <TableRow className={classes.headerRow}>
203
214
  {columns.map((key, i) => {
204
215
  const itemConfig = config?.[key];
205
- const TitleComponent = itemConfig?.titleComponent;
206
216
 
207
217
  return (
208
218
  <TableHeader
@@ -220,11 +230,9 @@ export function FlexibleTable<Row extends ITableRow>({
220
230
  onClick={isNotEmpty(onHeadClick) ? () => onHeadClick(key) : undefined}
221
231
  {...addDataAttributes({ id: itemConfig?.shouldRenderDataId ? key : undefined })}
222
232
  >
223
- {isNotEmpty(TitleComponent) ? (
224
- <TitleComponent value={headerContent?.[key]} />
225
- ) : (
226
- itemConfig?.title ?? ''
227
- )}
233
+ {applyAction(itemConfig?.title ?? '', {
234
+ value: headerContent?.[key] as HeaderContent[string],
235
+ })}
228
236
  </TableHeader>
229
237
  );
230
238
  })}
@@ -1,21 +1,24 @@
1
1
  import clsx from 'clsx';
2
- import { isNotEmpty } from '@true-engineering/true-react-platform-helpers';
2
+ import { applyAction, isNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
3
  import { addDataAttributes } from '../../../../helpers';
4
4
  import { ICommonProps } from '../../../../types';
5
5
  import { Skeleton } from '../../../Skeleton';
6
6
  import { formatCellContent } from '../../helpers';
7
7
  import {
8
8
  ITableRow,
9
- IValueComponent,
9
+ IValueComponentProps,
10
10
  IFlexibleTableConfigType,
11
11
  IFlexibleTableRenderMode,
12
+ IHeaderContent,
12
13
  } from '../../types';
13
14
  import { useStyles, IFlexibleTableCellStyles } from './FlexibleTableCell.styles';
14
15
 
15
- export interface IFlexibleTableCellProps<Row extends ITableRow>
16
- extends Pick<ICommonProps<IFlexibleTableCellStyles>, 'tweakStyles'>,
16
+ export interface IFlexibleTableCellProps<
17
+ Row extends ITableRow,
18
+ HeaderContent extends IHeaderContent<Row>,
19
+ > extends Pick<ICommonProps<IFlexibleTableCellStyles>, 'tweakStyles'>,
17
20
  Pick<
18
- Parameters<IValueComponent<Row, unknown>>[0],
21
+ IValueComponentProps<Row, unknown>,
19
22
  | 'isFocusedRow'
20
23
  | 'isNestedComponentExpanded'
21
24
  | 'isRowNestedComponentExpanded'
@@ -23,14 +26,17 @@ export interface IFlexibleTableCellProps<Row extends ITableRow>
23
26
  > {
24
27
  row: Row;
25
28
  columnName: keyof Row;
26
- config: IFlexibleTableConfigType<Row>;
29
+ config: IFlexibleTableConfigType<Row, HeaderContent>;
27
30
  renderMode: IFlexibleTableRenderMode;
28
31
  isSecond?: boolean;
29
32
  isSticky?: boolean;
30
33
  isLoading?: boolean;
31
34
  }
32
35
 
33
- export function FlexibleTableCell<Row extends ITableRow>({
36
+ export function FlexibleTableCell<
37
+ Row extends ITableRow,
38
+ HeaderContent extends IHeaderContent<Row>,
39
+ >({
34
40
  row,
35
41
  columnName,
36
42
  config,
@@ -40,14 +46,21 @@ export function FlexibleTableCell<Row extends ITableRow>({
40
46
  isLoading,
41
47
  tweakStyles,
42
48
  ...valueComponentProps
43
- }: IFlexibleTableCellProps<Row>): JSX.Element {
49
+ }: IFlexibleTableCellProps<Row, HeaderContent>): JSX.Element {
44
50
  const classes = useStyles({ theme: tweakStyles });
45
51
 
46
- const { component, left, right, position, cellAlign, cellVerticalAlign, shouldRenderDataId } =
47
- config[columnName] ?? {};
48
-
49
52
  const value = row[columnName];
50
53
 
54
+ const {
55
+ component = formatCellContent(value, config[columnName]),
56
+ left,
57
+ right,
58
+ position,
59
+ cellAlign,
60
+ cellVerticalAlign,
61
+ shouldRenderDataId,
62
+ } = config[columnName] ?? {};
63
+
51
64
  const TableCell = renderMode === 'divs' ? 'div' : 'td';
52
65
 
53
66
  return (
@@ -71,14 +84,7 @@ export function FlexibleTableCell<Row extends ITableRow>({
71
84
  <Skeleton />
72
85
  </div>
73
86
  ) : (
74
- isNotEmpty(value) && (
75
- <>
76
- {/* TODO: Рендерить как настоящий компонент */}
77
- {isNotEmpty(component)
78
- ? component({ ...valueComponentProps, value, row })
79
- : formatCellContent(value, config[columnName])}
80
- </>
81
- )
87
+ isNotEmpty(value) && applyAction(component, { ...valueComponentProps, value, row })
82
88
  )}
83
89
  </TableCell>
84
90
  );
@@ -9,15 +9,19 @@ import {
9
9
  IFlexibleTableConfigType,
10
10
  IFlexibleTableRenderMode,
11
11
  INestedComponent,
12
+ IHeaderContent,
12
13
  } from '../../types';
13
14
  import { FlexibleTableCell } from '../FlexibleTableCell';
14
15
  import { useStyles, IFlexibleTableRowStyles } from './FlexibleTableRow.styles';
15
16
 
16
- export interface IFlexibleTableRowProps<Row extends ITableRow>
17
- extends Pick<ICommonProps<IFlexibleTableRowStyles>, 'tweakStyles'> {
17
+ export interface IFlexibleTableRowProps<
18
+ Row extends ITableRow,
19
+ HeaderContent extends IHeaderContent<Row>,
20
+ UniqueField extends keyof Row,
21
+ > extends Pick<ICommonProps<IFlexibleTableRowStyles>, 'tweakStyles'> {
18
22
  item: Row;
19
23
  index: number;
20
- uniqueField?: keyof Row;
24
+ uniqueField?: UniqueField;
21
25
  renderMode: IFlexibleTableRenderMode;
22
26
  /** Индексы строк, на которые навешивается класс `active` */
23
27
  activeRows?: number[];
@@ -25,19 +29,22 @@ export interface IFlexibleTableRowProps<Row extends ITableRow>
25
29
  isFirstColumnSticky?: boolean;
26
30
  /** @default false */
27
31
  isLoading?: boolean;
28
- config: IFlexibleTableConfigType<Row>;
32
+ config: IFlexibleTableConfigType<Row, HeaderContent>;
29
33
  columns: Array<keyof Row & string>;
30
34
  rowAttributes?: Array<keyof Row>;
31
35
  /** @default false */
32
36
  isExpandableRowComponentInitiallyOpen?: boolean | ((row: Row, index: number) => boolean);
33
37
  /** Возвращает React-элемент, который отрисуется под строкой при нажатии на неё */
34
38
  expandableRowComponent?: (item: Row, isOpen: boolean, close: () => void) => ReactNode;
35
- // TODO: Заменить string на Generic Values[uniqueField]
36
- onRowHover?: (id?: string) => void;
37
- onRowClick?: (id: string) => void;
39
+ onRowHover?: (id?: Row[UniqueField]) => void;
40
+ onRowClick?: (id: Row[UniqueField]) => void;
38
41
  }
39
42
 
40
- function FlexibleTableRowInner<Row extends ITableRow>({
43
+ function FlexibleTableRowInner<
44
+ Row extends ITableRow,
45
+ HeaderContent extends IHeaderContent<Row>,
46
+ UniqueField extends keyof Row,
47
+ >({
41
48
  item,
42
49
  index,
43
50
  config,
@@ -53,7 +60,7 @@ function FlexibleTableRowInner<Row extends ITableRow>({
53
60
  expandableRowComponent,
54
61
  onRowHover,
55
62
  onRowClick,
56
- }: IFlexibleTableRowProps<Row>): JSX.Element {
63
+ }: IFlexibleTableRowProps<Row, HeaderContent, UniqueField>): JSX.Element {
57
64
  const classes = useStyles({ theme: tweakStyles });
58
65
 
59
66
  const tweakTableCellStyles = useTweakStyles({
@@ -1,13 +1,16 @@
1
1
  import { format } from 'date-fns';
2
2
  import { isNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
3
  import { DEFAULT_DATE_FORMAT } from './constants';
4
- import { IFlexibleTableConfigType } from './types';
4
+ import { IFlexibleTableConfigType, IHeaderContent, ITableRow } from './types';
5
5
 
6
6
  export const hasHorizontalScrollBar = (el: HTMLElement | null | undefined): boolean =>
7
7
  isNotEmpty(el) && el.scrollWidth !== el.clientWidth;
8
8
 
9
- export const formatCellContent = <Values>(
9
+ export const formatCellContent = <
10
+ Values extends ITableRow,
11
+ HeaderContent extends IHeaderContent<Values>,
12
+ >(
10
13
  value: unknown,
11
- config?: IFlexibleTableConfigType<Values>[keyof Values],
14
+ config?: IFlexibleTableConfigType<Values, HeaderContent>[keyof Values],
12
15
  ): string =>
13
16
  value instanceof Date ? format(value, config?.dateFormat ?? DEFAULT_DATE_FORMAT) : String(value);
@@ -1,28 +1,33 @@
1
- import { CSSProperties, FC, ReactNode } from 'react';
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ import { IRenderNode } from '../../types';
2
3
 
3
4
  export type IFlexibleTableRenderMode = 'table' | 'divs';
4
5
 
5
6
  // TODO: Заменить Record<string, any> на Record<string, unknown>
6
7
  export type ITableRow = Record<string, any>;
7
8
 
8
- export type ITitleComponent<Value> = FC<{
9
+ export type IHeaderContent<T extends ITableRow> = Partial<Record<keyof T, unknown>>;
10
+
11
+ export interface ITitleComponentProps<Value> {
9
12
  value?: Value;
10
- }>;
13
+ }
11
14
 
12
- export type IValueComponent<Values, Value> = (props: {
15
+ export interface IValueComponentProps<Values, Value> {
13
16
  value: Value;
14
17
  row: Values;
15
18
  isFocusedRow?: boolean;
16
19
  isNestedComponentExpanded: boolean;
17
20
  isRowNestedComponentExpanded: boolean;
18
21
  onSetNestedComponent: (component?: ReactNode) => void;
19
- }) => JSX.Element | ReactNode;
22
+ }
20
23
 
21
- export type IFlexibleTableConfigType<Values> = {
24
+ export type IFlexibleTableConfigType<
25
+ Values extends ITableRow,
26
+ HeaderContent extends IHeaderContent<Values> = IHeaderContent<Values>,
27
+ > = {
22
28
  [Key in keyof Values]?: {
23
- title?: ReactNode;
24
- titleComponent?: ITitleComponent<unknown>;
25
- component?: IValueComponent<Values, NonNullable<Values[Key]>>;
29
+ title?: IRenderNode<ITitleComponentProps<HeaderContent[Key]>>;
30
+ component?: IRenderNode<IValueComponentProps<Values, NonNullable<Values[Key]>>>;
26
31
  dateFormat?: string;
27
32
  minWidth?: string | number;
28
33
  width?: string | number;
@@ -11,6 +11,7 @@ export const useStyles = createThemedStyles('List', {
11
11
  },
12
12
 
13
13
  nestedItems: {
14
+ marginTop: -8,
14
15
  paddingLeft: 4,
15
16
  },
16
17
  });
@@ -3,6 +3,7 @@ import {
3
3
  addDataTestId,
4
4
  getTestId,
5
5
  isArrayNotEmpty,
6
+ isNotEmpty,
6
7
  } from '@true-engineering/true-react-platform-helpers';
7
8
  import { addDataAttributes } from '../../helpers';
8
9
  import { ICommonProps } from '../../types';
@@ -18,9 +19,14 @@ export interface IListProps extends ICommonProps<IListStyles> {
18
19
  export const List: FC<IListProps> = ({ items, testId, data, tweakStyles, onClick }) => {
19
20
  const classes = useStyles({ theme: tweakStyles });
20
21
 
21
- const handleItemClick = (event: MouseEvent | KeyboardEvent, item: IListItem) => {
22
- item.onClick(event);
23
- onClick?.(event);
22
+ const handleItemClick = (
23
+ event: MouseEvent | KeyboardEvent,
24
+ { onClick: itemOnClick }: IListItem,
25
+ ) => {
26
+ if (isNotEmpty(itemOnClick)) {
27
+ itemOnClick(event);
28
+ onClick?.(event);
29
+ }
24
30
  };
25
31
 
26
32
  return (
@@ -44,7 +50,7 @@ export const List: FC<IListProps> = ({ items, testId, data, tweakStyles, onClick
44
50
  trigger={({ isActive }) => <ListItem {...itemProps} isFocused={isActive} />}
45
51
  >
46
52
  <div className={classes.nestedItems}>
47
- <List items={item.nestedItems} />
53
+ <List items={item.nestedItems} onClick={onClick} />
48
54
  </div>
49
55
  </WithPopup>
50
56
  ) : (
@@ -21,7 +21,7 @@ export interface IListItemProps extends ICommonProps<IListItemStyles> {
21
21
  shouldDrawSpacerAbove?: boolean;
22
22
  shouldDrawSpacerBelow?: boolean;
23
23
  withIconGap?: boolean;
24
- onClick: (event: MouseEvent | KeyboardEvent) => void;
24
+ onClick?: (event: MouseEvent | KeyboardEvent) => void;
25
25
  }
26
26
 
27
27
  export const ListItem: FC<IListItemProps> = ({
@@ -8,6 +8,7 @@ import { IDataAttributes } from '../types';
8
8
 
9
9
  export const rgba = hexToRgba;
10
10
 
11
+ /** @deprecated Используйте `toKebabCase` из `true-react-platform-helpers` */
11
12
  export const transformToKebab = (string: string): string => {
12
13
  let result = '';
13
14
  string.split('').forEach((char) => {
@@ -148,6 +149,7 @@ export const getNumberLength = (n?: number): number =>
148
149
  export const trimStringToMaxLength = (val: string, maxLength: number): string =>
149
150
  val.length > maxLength ? val.slice(0, maxLength) : val;
150
151
 
152
+ /** @deprecated Используйте `addDataAttributes` из `true-react-platform-helpers` */
151
153
  export const addDataAttributes = (data: IDataAttributes = {}): IDataAttributes =>
152
154
  Object.fromEntries(
153
155
  Object.entries(data).map(([key, value]) =>
@@ -3,7 +3,7 @@ import { isEmpty, isNotEmpty, mergeStyles } from '@true-engineering/true-react-p
3
3
  import { areStylesThemed, getTheme, IComponentName, themedStyles } from '../theme';
4
4
 
5
5
  // TODO: Можно усилить типы
6
- export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet>({
6
+ export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet & `tweak${string}`>({
7
7
  innerStyles,
8
8
  tweakStyles: currentComponentTweakStyles,
9
9
  className,