@qoretechnologies/reqore 0.34.12 → 0.35.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.
Files changed (117) hide show
  1. package/__tests__/collection.test.tsx +2 -2
  2. package/__tests__/helpers/table.test.tsx +47 -0
  3. package/__tests__/pagination.test.tsx +35 -4
  4. package/__tests__/table.test.tsx +158 -123
  5. package/dist/components/Button/index.d.ts +2 -0
  6. package/dist/components/Button/index.d.ts.map +1 -1
  7. package/dist/components/Button/index.js +7 -4
  8. package/dist/components/Button/index.js.map +1 -1
  9. package/dist/components/Collection/index.d.ts +2 -1
  10. package/dist/components/Collection/index.d.ts.map +1 -1
  11. package/dist/components/Collection/index.js +5 -11
  12. package/dist/components/Collection/index.js.map +1 -1
  13. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  14. package/dist/components/ControlGroup/index.js +4 -3
  15. package/dist/components/ControlGroup/index.js.map +1 -1
  16. package/dist/components/Dropdown/index.d.ts +4 -1
  17. package/dist/components/Dropdown/index.d.ts.map +1 -1
  18. package/dist/components/Dropdown/index.js +2 -2
  19. package/dist/components/Dropdown/index.js.map +1 -1
  20. package/dist/components/Dropdown/list.d.ts +4 -1
  21. package/dist/components/Dropdown/list.d.ts.map +1 -1
  22. package/dist/components/Dropdown/list.js +10 -5
  23. package/dist/components/Dropdown/list.js.map +1 -1
  24. package/dist/components/Input/index.js +4 -4
  25. package/dist/components/Input/index.js.map +1 -1
  26. package/dist/components/Paging/index.d.ts +4 -1
  27. package/dist/components/Paging/index.d.ts.map +1 -1
  28. package/dist/components/Paging/index.js +8 -6
  29. package/dist/components/Paging/index.js.map +1 -1
  30. package/dist/components/Panel/index.d.ts +4 -1
  31. package/dist/components/Panel/index.d.ts.map +1 -1
  32. package/dist/components/Panel/index.js.map +1 -1
  33. package/dist/components/Table/cell.d.ts +12 -0
  34. package/dist/components/Table/cell.d.ts.map +1 -0
  35. package/dist/components/Table/cell.js +89 -0
  36. package/dist/components/Table/cell.js.map +1 -0
  37. package/dist/components/Table/header.d.ts +15 -2
  38. package/dist/components/Table/header.d.ts.map +1 -1
  39. package/dist/components/Table/header.js +31 -14
  40. package/dist/components/Table/header.js.map +1 -1
  41. package/dist/components/Table/headerCell.d.ts +8 -6
  42. package/dist/components/Table/headerCell.d.ts.map +1 -1
  43. package/dist/components/Table/headerCell.js +60 -51
  44. package/dist/components/Table/headerCell.js.map +1 -1
  45. package/dist/components/Table/helpers.d.ts +39 -1
  46. package/dist/components/Table/helpers.d.ts.map +1 -1
  47. package/dist/components/Table/helpers.js +145 -1
  48. package/dist/components/Table/helpers.js.map +1 -1
  49. package/dist/components/Table/index.d.ts +39 -25
  50. package/dist/components/Table/index.d.ts.map +1 -1
  51. package/dist/components/Table/index.js +139 -52
  52. package/dist/components/Table/index.js.map +1 -1
  53. package/dist/components/Table/row.d.ts +9 -4
  54. package/dist/components/Table/row.d.ts.map +1 -1
  55. package/dist/components/Table/row.js +30 -54
  56. package/dist/components/Table/row.js.map +1 -1
  57. package/dist/hooks/useQueryWithDelay.d.ts +8 -0
  58. package/dist/hooks/useQueryWithDelay.d.ts.map +1 -0
  59. package/dist/hooks/useQueryWithDelay.js +25 -0
  60. package/dist/hooks/useQueryWithDelay.js.map +1 -0
  61. package/dist/index.d.ts +3 -0
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +7 -1
  64. package/dist/index.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/components/Button/index.tsx +6 -1
  67. package/src/components/Collection/index.tsx +9 -15
  68. package/src/components/ControlGroup/index.tsx +10 -5
  69. package/src/components/Dropdown/index.tsx +9 -0
  70. package/src/components/Dropdown/list.tsx +18 -6
  71. package/src/components/Input/index.tsx +3 -3
  72. package/src/components/Paging/index.tsx +35 -13
  73. package/src/components/Panel/index.tsx +3 -1
  74. package/src/components/Table/cell.tsx +117 -0
  75. package/src/components/Table/header.tsx +102 -45
  76. package/src/components/Table/headerCell.tsx +123 -80
  77. package/src/components/Table/helpers.ts +206 -1
  78. package/src/components/Table/index.tsx +288 -90
  79. package/src/components/Table/row.tsx +47 -125
  80. package/src/hooks/useQueryWithDelay.ts +30 -0
  81. package/src/index.tsx +3 -0
  82. package/src/mock/tableData.ts +40 -20
  83. package/src/stories/Breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  84. package/src/stories/Button/Button.stories.tsx +1 -1
  85. package/src/stories/Checkbox/Checkbox.stories.tsx +1 -1
  86. package/src/stories/Collection/Collection.stories.tsx +19 -1
  87. package/src/stories/Columns/Columns.stories.tsx +1 -1
  88. package/src/stories/Comment/Comment.stories.tsx +1 -1
  89. package/src/stories/ControlGroup/ControlGroup.stories.tsx +1 -1
  90. package/src/stories/Drawer/Drawer.stories.tsx +5 -5
  91. package/src/stories/Dropdown/Dropdown.stories.tsx +11 -1
  92. package/src/stories/Header/Header.stories.tsx +1 -1
  93. package/src/stories/Icon/Icon.stories.tsx +1 -1
  94. package/src/stories/Input/Input.stories.tsx +1 -1
  95. package/src/stories/Menu/Menu.stories.tsx +1 -1
  96. package/src/stories/Message/Message.stories.tsx +1 -1
  97. package/src/stories/Modal/Modal.stories.tsx +1 -1
  98. package/src/stories/MultiSelect/MultiSelect.stories.tsx +1 -1
  99. package/src/stories/Navbar/Navbar.stories.tsx +1 -1
  100. package/src/stories/Notifications/Interactive.stories.tsx +1 -1
  101. package/src/stories/Notifications/Notification.stories.tsx +1 -1
  102. package/src/stories/Notifications/Notifications.stories.tsx +1 -1
  103. package/src/stories/Paging/Paging.stories.tsx +6 -2
  104. package/src/stories/Panel/Panel.stories.tsx +5 -5
  105. package/src/stories/Paragraph/Paragraph.stories.tsx +1 -1
  106. package/src/stories/Popover/Popover.stories.tsx +2 -2
  107. package/src/stories/RadioGroup/RadioGroup.stories.tsx +1 -1
  108. package/src/stories/Sidebar/Sidebar.stories.tsx +2 -2
  109. package/src/stories/Spacer/Spacer.stories.tsx +1 -1
  110. package/src/stories/Spinner/Spinner.stories.tsx +1 -1
  111. package/src/stories/Table/Table.stories.tsx +277 -78
  112. package/src/stories/Tabs/Tabs.stories.tsx +1 -1
  113. package/src/stories/Tag/Tag.stories.tsx +1 -1
  114. package/src/stories/TextArea/TextArea.stories.tsx +2 -2
  115. package/src/stories/Tree/Tree.stories.tsx +2 -2
  116. package/src/stories/utils/args.ts +1 -1
  117. package/tests.json +1 -1
@@ -1,12 +1,33 @@
1
+ import { omit } from 'lodash';
1
2
  import styled, { css } from 'styled-components';
2
3
  import { IReqoreTableColumn, IReqoreTableSort } from '.';
3
4
  import { IReqoreTheme } from '../../constants/theme';
4
5
  import { changeLightness } from '../../helpers/colors';
5
6
  import { alignToFlexAlign } from '../../helpers/utils';
7
+ import { IWithReqoreSize } from '../../types/global';
6
8
  import { IReqoreIconName } from '../../types/icons';
7
- import ReqoreTableHeaderCell, { StyledTableHeader } from './headerCell';
9
+ import { IReqoreButtonProps } from '../Button';
10
+ import { IReqoreTableHeaderCellProps, ReqoreTableHeaderCell } from './headerCell';
11
+ import { calculateMinimumCellWidth, getOnlyShownColumns } from './helpers';
12
+
13
+ export type TColumnsUpdater = <T extends keyof IReqoreTableColumn>(
14
+ id: string,
15
+ key: T,
16
+ value: IReqoreTableColumn[T]
17
+ ) => void;
18
+
19
+ export interface IReqoreCustomHeaderCellProps
20
+ extends Pick<
21
+ IReqoreTableHeaderCellProps,
22
+ 'sortData' | 'onSortChange' | 'onColumnsUpdate' | 'onFilterChange'
23
+ >,
24
+ Omit<IReqoreTableColumn, 'cell' | 'header'>,
25
+ IReqoreButtonProps {
26
+ hasColumns?: boolean;
27
+ }
28
+ export interface IReqoreCustomHeaderCellComponent extends React.FC<IReqoreCustomHeaderCellProps> {}
8
29
 
9
- export interface IReqoreTableSectionProps {
30
+ export interface IReqoreTableSectionProps extends IWithReqoreSize {
10
31
  columns: IReqoreTableColumn[];
11
32
  leftScroll: number;
12
33
  onSortChange?: (sort: string) => void;
@@ -16,6 +37,9 @@ export interface IReqoreTableSectionProps {
16
37
  onToggleSelectClick: () => void;
17
38
  hasVerticalScroll: boolean;
18
39
  selectToggleTooltip?: string;
40
+ onColumnsUpdate: TColumnsUpdater;
41
+ onFilterChange?: (dataId: string, value: any) => void;
42
+ component?: IReqoreCustomHeaderCellComponent;
19
43
  }
20
44
 
21
45
  export interface IReqoreTableSectionStyle {
@@ -70,11 +94,7 @@ const StyledTableHeaderRow = styled.div<{ theme: IReqoreTheme }>`
70
94
  display: flex;
71
95
  flex: 1;
72
96
 
73
- ${({ leftScroll }) => css`
74
- transform: translate3d(${-leftScroll}px, 0, 0);
75
- `}
76
-
77
- ${StyledTableHeader}, ${StyledColumnGroupHeader} {
97
+ ${StyledColumnGroupHeader} {
78
98
  font-size: 13px;
79
99
  font-weight: 600;
80
100
  padding: 5px 10px;
@@ -95,39 +115,72 @@ const ReqoreTableHeader = ({
95
115
  onToggleSelectClick,
96
116
  selectToggleTooltip,
97
117
  hasVerticalScroll,
118
+ onColumnsUpdate,
119
+ onFilterChange,
120
+ size,
121
+ component,
98
122
  }: IReqoreTableSectionProps) => {
123
+ const renderHeaderCell = (
124
+ headerCellComponent: IReqoreCustomHeaderCellComponent,
125
+ props: IReqoreCustomHeaderCellProps
126
+ ) => {
127
+ const HeaderCell = headerCellComponent || component || ReqoreTableHeaderCell;
128
+
129
+ return <HeaderCell key={props.dataId} {...props} />;
130
+ };
131
+
99
132
  const renderColumns = (columns: IReqoreTableColumn[]) =>
100
- columns.map(
101
- ({ grow, header, props = {}, columns: cols, align, content, onCellClick, ...rest }, index) =>
102
- cols ? (
133
+ getOnlyShownColumns(columns).map(
134
+ (
135
+ {
136
+ grow,
137
+ align,
138
+ dataId,
139
+ header: { columns, onClick, component: headerComponent, ...rest },
140
+ ...colRest
141
+ },
142
+ index
143
+ ) =>
144
+ columns ? (
103
145
  <StyledColumnGroup
104
- width={cols.reduce((wid, col) => wid + (col.width || 80), 0)}
105
146
  grow={grow}
106
147
  key={index}
107
148
  className='reqore-table-column-group'
149
+ width={getOnlyShownColumns(columns).reduce(
150
+ (wid, col) => wid + (col.resizedWidth || col.width || 80),
151
+ 0
152
+ )}
108
153
  >
109
- <StyledColumnGroupHeader
110
- align={align}
111
- {...props}
112
- className='reqore-table-column-group-header'
113
- >
114
- {header}
115
- </StyledColumnGroupHeader>
154
+ {renderHeaderCell(headerComponent, {
155
+ ...rest,
156
+ ...omit(colRest, ['cell']),
157
+ dataId,
158
+ size,
159
+ readOnly: !onClick,
160
+ rounded: false,
161
+ textAlign: align,
162
+ className: 'reqore-table-column-group-header',
163
+ resizable: false,
164
+ hideable: false,
165
+ hasColumns: true,
166
+ })}
116
167
  <StyledColumnGroupHeaders className='reqore-table-headers'>
117
- {renderColumns(cols)}
168
+ {renderColumns(columns)}
118
169
  </StyledColumnGroupHeaders>
119
170
  </StyledColumnGroup>
120
171
  ) : (
121
- <ReqoreTableHeaderCell
122
- {...props}
123
- {...rest}
124
- key={index}
125
- sortData={sortData}
126
- grow={grow}
127
- align={align}
128
- header={header}
129
- onSortChange={onSortChange}
130
- />
172
+ renderHeaderCell(headerComponent, {
173
+ ...rest,
174
+ ...omit(colRest, ['cell']),
175
+ dataId,
176
+ size,
177
+ sortData,
178
+ grow,
179
+ align,
180
+ onSortChange,
181
+ onColumnsUpdate,
182
+ onFilterChange,
183
+ })
131
184
  )
132
185
  );
133
186
 
@@ -147,23 +200,27 @@ const ReqoreTableHeader = ({
147
200
  className='reqore-table-header-wrapper'
148
201
  hasVerticalScroll={hasVerticalScroll}
149
202
  >
150
- <StyledTableHeaderRow leftScroll={leftScroll}>
151
- {selectable && (
152
- <ReqoreTableHeaderCell
153
- dataId='selectbox'
154
- key='selectbox'
155
- sortData={sortData}
156
- align='center'
157
- onSortChange={onSortChange}
158
- icon={getSelectedIcon()}
159
- iconSize='15px'
160
- width={60}
161
- tooltip={selectToggleTooltip || 'Toggle selection on all data'}
162
- onClick={() => {
203
+ <StyledTableHeaderRow
204
+ style={{
205
+ transform: `translate3d(${leftScroll ? -leftScroll : 0}px, 0, 0)`,
206
+ }}
207
+ >
208
+ {selectable &&
209
+ renderHeaderCell(component, {
210
+ dataId: 'selectbox',
211
+ sortData,
212
+ align: 'center',
213
+ size,
214
+ onSortChange,
215
+ icon: getSelectedIcon(),
216
+ width: calculateMinimumCellWidth(50, size),
217
+ resizable: false,
218
+ hideable: false,
219
+ tooltip: selectToggleTooltip || 'Toggle selection on all data',
220
+ onClick: () => {
163
221
  onToggleSelectClick();
164
- }}
165
- />
166
- )}
222
+ },
223
+ })}
167
224
  {renderColumns(columns)}
168
225
  </StyledTableHeaderRow>
169
226
  </StyledTableHeaderWrapper>
@@ -1,18 +1,23 @@
1
1
  /* @flow */
2
- import React, { useState } from 'react';
3
- import styled, { css } from 'styled-components';
2
+ import { rgba } from 'polished';
3
+ import { Resizable } from 're-resizable';
4
+ import { useMemo } from 'react';
5
+ import styled from 'styled-components';
4
6
  import { IReqoreTableColumn, IReqoreTableSort } from '.';
7
+ import { ReqoreButton, ReqoreControlGroup, ReqoreDropdown } from '../..';
5
8
  import { IReqoreTheme } from '../../constants/theme';
6
- import { changeLightness, getReadableColor } from '../../helpers/colors';
7
- import { alignToFlexAlign } from '../../helpers/utils';
8
- import { useTooltip } from '../../hooks/useTooltip';
9
- import ReqoreIcon from '../Icon';
9
+ import { getReadableColor } from '../../helpers/colors';
10
+ import { IReqoreButtonProps } from '../Button';
11
+ import { IReqoreDropdownItem } from '../Dropdown/list';
12
+ import { TColumnsUpdater } from './header';
10
13
 
11
14
  export interface IReqoreTableHeaderCellProps
12
- extends React.HTMLAttributes<HTMLDivElement>,
13
- IReqoreTableColumn {
15
+ extends Omit<IReqoreTableColumn, 'cell'>,
16
+ IReqoreButtonProps {
14
17
  onSortChange?: (sort: string) => void;
15
- sortData: IReqoreTableSort;
18
+ sortData?: IReqoreTableSort;
19
+ onColumnsUpdate?: TColumnsUpdater;
20
+ onFilterChange?: (dataId: string, filter: string) => void;
16
21
  }
17
22
 
18
23
  export interface IReqoreTableHeaderStyle {
@@ -23,95 +28,133 @@ export interface IReqoreTableHeaderStyle {
23
28
  interactive?: boolean;
24
29
  }
25
30
 
26
- export const StyledTableHeader = styled.div<IReqoreTableHeaderStyle>`
27
- ${({ width, grow }) =>
28
- css`
29
- width: ${!width || width < 80 ? 80 : width}px;
30
- flex-grow: ${grow || (width ? undefined : 1)};
31
- `};
32
-
33
- ${({ align, theme }) => css`
34
- background-color: ${changeLightness(theme.main, 0.03)};
35
- justify-content: ${align ? alignToFlexAlign(align) : 'flex-start'};
36
- `}
37
-
38
- ${({ interactive, theme }) =>
39
- interactive &&
40
- css`
41
- cursor: pointer;
42
- transition: background-color 0.2s ease-out;
43
-
44
- &:hover {
45
- color: ${getReadableColor(theme, undefined, undefined)};
46
- background-color: ${changeLightness(theme.main, 0.06)};
47
- }
48
- `};
49
- `;
50
-
51
- const StyledTableHeaderLabel = styled.span`
52
- overflow: hidden;
53
- text-overflow: ellipsis;
54
- white-space: nowrap;
31
+ export const StyledTableHeaderResize = styled.div`
32
+ &:before {
33
+ content: '';
34
+ position: absolute;
35
+ left: 50%;
36
+ top: 50%;
37
+ transform: translateX(-50%) translateY(-50%);
38
+ width: 1px;
39
+ height: 70%;
40
+ border-left: 1px dashed ${({ theme }) => rgba(getReadableColor(theme), 0.3)};
41
+ }
55
42
  `;
56
43
 
57
- const ReqoreTableHeaderCell = ({
44
+ export const ReqoreTableHeaderCell = ({
58
45
  width,
46
+ resizedWidth,
59
47
  grow,
60
48
  align,
61
- header,
62
49
  onSortChange,
63
50
  dataId,
64
51
  sortable,
65
52
  sortData,
66
- onClick,
67
53
  className,
68
- icon,
69
- iconSize,
70
- tooltip,
71
- ...props
54
+ onClick,
55
+ onColumnsUpdate,
56
+ resizable = true,
57
+ filterPlaceholder,
58
+ filterable,
59
+ hideable = true,
60
+ filter,
61
+ onFilterChange,
62
+ ...rest
72
63
  }: IReqoreTableHeaderCellProps) => {
73
- const [ref, setRef] = useState(null);
64
+ const items = useMemo(() => {
65
+ const _items: IReqoreDropdownItem[] = [];
74
66
 
75
- useTooltip(ref, { content: tooltip || header, delay: 300 });
67
+ if (resizable || hideable) {
68
+ _items.push({
69
+ divider: true,
70
+ label: 'Options',
71
+ });
72
+
73
+ if (resizable) {
74
+ _items.push({
75
+ label: 'Reset size',
76
+ icon: 'HistoryLine',
77
+ disabled: !resizedWidth || width === resizedWidth,
78
+ onClick: () => {
79
+ onColumnsUpdate?.(dataId, 'resizedWidth', width);
80
+ },
81
+ });
82
+ }
83
+
84
+ if (hideable) {
85
+ _items.push({
86
+ label: 'Hide column',
87
+ icon: 'EyeCloseLine',
88
+ onClick: () => {
89
+ onColumnsUpdate?.(dataId, 'show', false);
90
+ },
91
+ });
92
+ }
93
+ }
94
+
95
+ return _items;
96
+ }, [resizable, hideable, width, resizedWidth, onColumnsUpdate, dataId]);
76
97
 
77
98
  return (
78
- <StyledTableHeader
79
- {...props}
80
- className={`${className || ''} reqore-table-header-cell`}
81
- ref={setRef}
82
- width={width}
83
- grow={grow}
84
- align={align}
85
- interactive={sortable || !!onClick}
86
- onClick={(event: React.MouseEvent<HTMLDivElement>) => {
87
- if (sortable) {
88
- onSortChange(dataId);
89
- }
90
- if (onClick) {
91
- onClick(event);
92
- }
99
+ <Resizable
100
+ minWidth={width}
101
+ onResize={(_event, _direction, _component) => {
102
+ onColumnsUpdate?.(dataId, 'resizedWidth', parseInt(_component.style.width));
103
+ }}
104
+ handleComponent={{
105
+ right: <StyledTableHeaderResize />,
106
+ }}
107
+ style={{
108
+ overflow: 'hidden',
109
+ flexGrow: grow,
110
+ }}
111
+ size={{
112
+ width: resizedWidth || width,
113
+ height: undefined,
114
+ }}
115
+ enable={{
116
+ right: resizable,
93
117
  }}
94
118
  >
95
- {icon && (
96
- <ReqoreIcon icon={icon} size={iconSize || '13px'} margin={header ? 'right' : undefined} />
97
- )}
98
- <StyledTableHeaderLabel>{header}</StyledTableHeaderLabel>
99
- {sortable && (
100
- <ReqoreIcon
101
- icon={
102
- `Arrow${sortData.direction === 'desc' ? 'Down' : 'Up'}Fill` as
103
- | 'ArrowDownFill'
104
- | 'ArrowUpFill'
119
+ <ReqoreControlGroup fluid stack rounded={false} fill style={{ height: '100%' }}>
120
+ <ReqoreButton
121
+ {...rest}
122
+ readOnly={!sortable && !onClick}
123
+ className={`${className || ''} reqore-table-header-cell`}
124
+ rounded={false}
125
+ textAlign={align}
126
+ rightIcon={
127
+ sortable && sortData.by === dataId
128
+ ? (`Arrow${sortData.direction === 'desc' ? 'Down' : 'Up'}Fill` as
129
+ | 'ArrowDownFill'
130
+ | 'ArrowUpFill')
131
+ : rest.rightIcon
105
132
  }
106
- size={iconSize || '13px'}
107
- margin='left'
108
- style={{
109
- opacity: sortData.by === dataId ? 1 : 0.2,
133
+ onClick={(e) => {
134
+ if (sortable) {
135
+ onSortChange?.(dataId);
136
+ }
137
+
138
+ onClick?.(e);
110
139
  }}
111
140
  />
112
- )}
113
- </StyledTableHeader>
141
+ {filterable || hideable || resizable ? (
142
+ <ReqoreDropdown<IReqoreButtonProps>
143
+ icon='MoreLine'
144
+ className='reqore-table-header-cell-options'
145
+ fixed
146
+ rounded={false}
147
+ intent={filter ? 'info' : undefined}
148
+ filterable={filterable}
149
+ filterPlaceholder={filterPlaceholder || 'Filter by this column...'}
150
+ filter={filter}
151
+ onFilterChange={(value) => {
152
+ onFilterChange?.(dataId, value);
153
+ }}
154
+ items={items}
155
+ />
156
+ ) : null}
157
+ </ReqoreControlGroup>
158
+ </Resizable>
114
159
  );
115
160
  };
116
-
117
- export default ReqoreTableHeaderCell;
@@ -1,5 +1,9 @@
1
+ import { size } from 'lodash';
1
2
  import { firstBy } from 'thenby';
2
- import { IReqoreTableSort } from '.';
3
+ import { IReqoreTableColumn, IReqoreTableSort } from '.';
4
+ import { ICON_FROM_SIZE, SIZE_TO_PX, TSizes } from '../../constants/sizes';
5
+ import { IReqoreIconName } from '../../types/icons';
6
+ import { IReqorePanelAction } from '../Panel';
3
7
 
4
8
  export const flipSortDirection = (direction: 'asc' | 'desc'): 'asc' | 'desc' =>
5
9
  direction === 'asc' ? 'desc' : 'asc';
@@ -23,3 +27,204 @@ export const sortTableData = (data: any[], sort: IReqoreTableSort) => {
23
27
 
24
28
  return [...data].sort(firstBy(by, { ignoreCase: true, direction }));
25
29
  };
30
+
31
+ export const updateColumnData = (
32
+ columns: IReqoreTableColumn[],
33
+ columnId: string,
34
+ key: keyof IReqoreTableColumn,
35
+ value: any
36
+ ): IReqoreTableColumn[] => {
37
+ const newColumns: IReqoreTableColumn[] = columns.map((column): IReqoreTableColumn => {
38
+ if (column.dataId === columnId) {
39
+ return { ...column, [key]: value };
40
+ }
41
+
42
+ if (column.header?.columns) {
43
+ return {
44
+ ...column,
45
+ header: {
46
+ ...column.header,
47
+ columns: updateColumnData(column.header.columns, columnId, key, value),
48
+ },
49
+ };
50
+ }
51
+
52
+ return column;
53
+ });
54
+
55
+ return newColumns;
56
+ };
57
+
58
+ export const sizeToZoom = {
59
+ tiny: 0,
60
+ small: 0.5,
61
+ normal: 1,
62
+ big: 1.5,
63
+ huge: 2,
64
+ };
65
+
66
+ export const zoomToSize = {
67
+ 0: 'tiny',
68
+ 0.5: 'small',
69
+ 1: 'normal',
70
+ 1.5: 'big',
71
+ 2: 'huge',
72
+ };
73
+
74
+ export const zoomToWidth = {
75
+ 0: '200px',
76
+ 0.5: '300px',
77
+ 1: '400px',
78
+ 1.5: '500px',
79
+ 2: '600px',
80
+ };
81
+
82
+ // This code converts a zoom level to a label.
83
+ export const zoomToLabel = {
84
+ 0: '0.6x',
85
+ 0.5: '0.8x',
86
+ 1: '1x',
87
+ 1.5: '1.2x',
88
+ 2: '1.4x',
89
+ };
90
+
91
+ export const getZoomActions = (
92
+ type: string,
93
+ zoom: number,
94
+ setter: (zoom: number) => void
95
+ ): IReqorePanelAction[] => [
96
+ {
97
+ icon: 'ZoomInLine',
98
+ tooltip: 'Zoom in',
99
+ disabled: zoom === 2,
100
+ className: `${type}-zoom-in`,
101
+ onClick: () => {
102
+ setter(zoom + 0.5);
103
+ },
104
+ },
105
+ {
106
+ icon: 'RestartLine',
107
+ label: zoomToLabel[zoom],
108
+ tooltip: 'Reset zoom',
109
+ disabled: zoom === 1,
110
+ className: `${type}-zoom-reset`,
111
+ onClick: () => {
112
+ setter(1);
113
+ },
114
+ },
115
+ {
116
+ icon: 'ZoomOutLine',
117
+ tooltip: 'Zoom out',
118
+ disabled: zoom === 0,
119
+ className: `${type}-zoom-out`,
120
+ onClick: () => {
121
+ setter(zoom - 0.5);
122
+ },
123
+ },
124
+ ];
125
+
126
+ export const getColumnsCount = (columns: IReqoreTableColumn[]): number => {
127
+ let count = 0;
128
+
129
+ columns.forEach((column) => {
130
+ if (column.header.columns) {
131
+ count += getColumnsCount(column.header.columns);
132
+ } else {
133
+ count += 1;
134
+ }
135
+ });
136
+
137
+ return count;
138
+ };
139
+
140
+ export const hasHiddenColumns = (columns: IReqoreTableColumn[]): boolean => {
141
+ return columns.some((column) => {
142
+ if (column.header.columns) {
143
+ return column.header.columns.some((subColumn) => subColumn.show === false);
144
+ }
145
+
146
+ return column.show === false;
147
+ });
148
+ };
149
+
150
+ export const getOnlyShownColumns = (columns: IReqoreTableColumn[]): IReqoreTableColumn[] => {
151
+ return columns.reduce((newColumns, column) => {
152
+ if (column.header.columns) {
153
+ const subColumns = getOnlyShownColumns(column.header.columns);
154
+
155
+ if (size(subColumns)) {
156
+ return [
157
+ ...newColumns,
158
+ {
159
+ ...column,
160
+ header: { ...column.header, columns: getOnlyShownColumns(column.header.columns) },
161
+ },
162
+ ];
163
+ }
164
+
165
+ return newColumns;
166
+ }
167
+
168
+ if (column.show !== false) {
169
+ return [...newColumns, column];
170
+ }
171
+
172
+ return newColumns;
173
+ }, []);
174
+ };
175
+
176
+ export const prepareColumns = (
177
+ columns: IReqoreTableColumn[],
178
+ size: TSizes = 'normal'
179
+ ): IReqoreTableColumn[] => {
180
+ // We need to set the width of each column
181
+ return columns.map((column) => {
182
+ if (column.header.columns) {
183
+ return {
184
+ ...column,
185
+ header: { ...column.header, columns: prepareColumns(column.header.columns) },
186
+ };
187
+ }
188
+
189
+ let newWidth = calculateMinimumCellWidth(
190
+ column.width || 50,
191
+ size,
192
+ column.header.icon,
193
+ column.sortable,
194
+ column.filterable,
195
+ column.hideable,
196
+ column.resizable
197
+ );
198
+
199
+ return {
200
+ ...column,
201
+ width: newWidth,
202
+ };
203
+ });
204
+ };
205
+
206
+ export const calculateMinimumCellWidth = (
207
+ currentWidth: number = 50,
208
+ size?: TSizes,
209
+ icon?: IReqoreIconName,
210
+ sortable?: boolean,
211
+ filterable?: boolean,
212
+ hideable?: boolean,
213
+ resizable?: boolean
214
+ ): number => {
215
+ let width = currentWidth;
216
+
217
+ if (icon) {
218
+ width += ICON_FROM_SIZE[size];
219
+ }
220
+
221
+ if (sortable) {
222
+ width += ICON_FROM_SIZE[size];
223
+ }
224
+
225
+ if (filterable || hideable || resizable) {
226
+ width += SIZE_TO_PX[size];
227
+ }
228
+
229
+ return width;
230
+ };