@qoretechnologies/reqore 0.34.13 → 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 (110) hide show
  1. package/__tests__/helpers/table.test.tsx +47 -0
  2. package/__tests__/table.test.tsx +158 -123
  3. package/dist/components/Button/index.d.ts +2 -0
  4. package/dist/components/Button/index.d.ts.map +1 -1
  5. package/dist/components/Button/index.js +7 -4
  6. package/dist/components/Button/index.js.map +1 -1
  7. package/dist/components/Collection/index.d.ts +2 -1
  8. package/dist/components/Collection/index.d.ts.map +1 -1
  9. package/dist/components/Collection/index.js +5 -11
  10. package/dist/components/Collection/index.js.map +1 -1
  11. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  12. package/dist/components/ControlGroup/index.js +4 -3
  13. package/dist/components/ControlGroup/index.js.map +1 -1
  14. package/dist/components/Dropdown/index.d.ts +4 -1
  15. package/dist/components/Dropdown/index.d.ts.map +1 -1
  16. package/dist/components/Dropdown/index.js +2 -2
  17. package/dist/components/Dropdown/index.js.map +1 -1
  18. package/dist/components/Dropdown/list.d.ts +4 -1
  19. package/dist/components/Dropdown/list.d.ts.map +1 -1
  20. package/dist/components/Dropdown/list.js +10 -5
  21. package/dist/components/Dropdown/list.js.map +1 -1
  22. package/dist/components/Input/index.js +4 -4
  23. package/dist/components/Input/index.js.map +1 -1
  24. package/dist/components/Panel/index.d.ts +4 -1
  25. package/dist/components/Panel/index.d.ts.map +1 -1
  26. package/dist/components/Panel/index.js.map +1 -1
  27. package/dist/components/Table/cell.d.ts +12 -0
  28. package/dist/components/Table/cell.d.ts.map +1 -0
  29. package/dist/components/Table/cell.js +89 -0
  30. package/dist/components/Table/cell.js.map +1 -0
  31. package/dist/components/Table/header.d.ts +15 -2
  32. package/dist/components/Table/header.d.ts.map +1 -1
  33. package/dist/components/Table/header.js +31 -14
  34. package/dist/components/Table/header.js.map +1 -1
  35. package/dist/components/Table/headerCell.d.ts +8 -6
  36. package/dist/components/Table/headerCell.d.ts.map +1 -1
  37. package/dist/components/Table/headerCell.js +60 -51
  38. package/dist/components/Table/headerCell.js.map +1 -1
  39. package/dist/components/Table/helpers.d.ts +39 -1
  40. package/dist/components/Table/helpers.d.ts.map +1 -1
  41. package/dist/components/Table/helpers.js +145 -1
  42. package/dist/components/Table/helpers.js.map +1 -1
  43. package/dist/components/Table/index.d.ts +39 -25
  44. package/dist/components/Table/index.d.ts.map +1 -1
  45. package/dist/components/Table/index.js +139 -52
  46. package/dist/components/Table/index.js.map +1 -1
  47. package/dist/components/Table/row.d.ts +9 -4
  48. package/dist/components/Table/row.d.ts.map +1 -1
  49. package/dist/components/Table/row.js +30 -54
  50. package/dist/components/Table/row.js.map +1 -1
  51. package/dist/hooks/useQueryWithDelay.d.ts +8 -0
  52. package/dist/hooks/useQueryWithDelay.d.ts.map +1 -0
  53. package/dist/hooks/useQueryWithDelay.js +25 -0
  54. package/dist/hooks/useQueryWithDelay.js.map +1 -0
  55. package/dist/index.d.ts +3 -0
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +7 -1
  58. package/dist/index.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/components/Button/index.tsx +6 -1
  61. package/src/components/Collection/index.tsx +9 -15
  62. package/src/components/ControlGroup/index.tsx +10 -5
  63. package/src/components/Dropdown/index.tsx +9 -0
  64. package/src/components/Dropdown/list.tsx +18 -6
  65. package/src/components/Input/index.tsx +3 -3
  66. package/src/components/Panel/index.tsx +3 -1
  67. package/src/components/Table/cell.tsx +117 -0
  68. package/src/components/Table/header.tsx +102 -45
  69. package/src/components/Table/headerCell.tsx +123 -80
  70. package/src/components/Table/helpers.ts +206 -1
  71. package/src/components/Table/index.tsx +288 -90
  72. package/src/components/Table/row.tsx +47 -125
  73. package/src/hooks/useQueryWithDelay.ts +30 -0
  74. package/src/index.tsx +3 -0
  75. package/src/mock/tableData.ts +40 -20
  76. package/src/stories/Breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  77. package/src/stories/Button/Button.stories.tsx +1 -1
  78. package/src/stories/Checkbox/Checkbox.stories.tsx +1 -1
  79. package/src/stories/Collection/Collection.stories.tsx +19 -1
  80. package/src/stories/Columns/Columns.stories.tsx +1 -1
  81. package/src/stories/Comment/Comment.stories.tsx +1 -1
  82. package/src/stories/ControlGroup/ControlGroup.stories.tsx +1 -1
  83. package/src/stories/Drawer/Drawer.stories.tsx +5 -5
  84. package/src/stories/Dropdown/Dropdown.stories.tsx +11 -1
  85. package/src/stories/Header/Header.stories.tsx +1 -1
  86. package/src/stories/Icon/Icon.stories.tsx +1 -1
  87. package/src/stories/Input/Input.stories.tsx +1 -1
  88. package/src/stories/Menu/Menu.stories.tsx +1 -1
  89. package/src/stories/Message/Message.stories.tsx +1 -1
  90. package/src/stories/Modal/Modal.stories.tsx +1 -1
  91. package/src/stories/MultiSelect/MultiSelect.stories.tsx +1 -1
  92. package/src/stories/Navbar/Navbar.stories.tsx +1 -1
  93. package/src/stories/Notifications/Interactive.stories.tsx +1 -1
  94. package/src/stories/Notifications/Notification.stories.tsx +1 -1
  95. package/src/stories/Notifications/Notifications.stories.tsx +1 -1
  96. package/src/stories/Paging/Paging.stories.tsx +1 -1
  97. package/src/stories/Panel/Panel.stories.tsx +5 -5
  98. package/src/stories/Paragraph/Paragraph.stories.tsx +1 -1
  99. package/src/stories/Popover/Popover.stories.tsx +2 -2
  100. package/src/stories/RadioGroup/RadioGroup.stories.tsx +1 -1
  101. package/src/stories/Sidebar/Sidebar.stories.tsx +2 -2
  102. package/src/stories/Spacer/Spacer.stories.tsx +1 -1
  103. package/src/stories/Spinner/Spinner.stories.tsx +1 -1
  104. package/src/stories/Table/Table.stories.tsx +277 -78
  105. package/src/stories/Tabs/Tabs.stories.tsx +1 -1
  106. package/src/stories/Tag/Tag.stories.tsx +1 -1
  107. package/src/stories/TextArea/TextArea.stories.tsx +2 -2
  108. package/src/stories/Tree/Tree.stories.tsx +2 -2
  109. package/src/stories/utils/args.ts +1 -1
  110. package/tests.json +1 -1
@@ -28,7 +28,12 @@ export interface IReqoreDropdownListProps extends IReqoreComponent {
28
28
  listStyle?: React.CSSProperties;
29
29
  width?: string;
30
30
  height?: string;
31
+
31
32
  filterable?: boolean;
33
+ onFilterChange?: (query: string) => void;
34
+ filter?: string | number;
35
+ filterPlaceholder?: string;
36
+
32
37
  onItemSelect?: TDropdownItemOnClick;
33
38
  inputProps?: IReqoreInputProps;
34
39
  scrollToSelected?: boolean;
@@ -48,9 +53,12 @@ const ReqoreDropdownList = memo(
48
53
  inputProps,
49
54
  scrollToSelected,
50
55
  paging,
56
+ onFilterChange,
57
+ filterPlaceholder,
58
+ filter,
51
59
  }: IReqoreDropdownListProps) => {
52
60
  const [_items, setItems] = useState<TReqoreDropdownItems>(items);
53
- const [query, setQuery] = useState<string>('');
61
+ const [query, setQuery] = useState<string | number>(onFilterChange ? '' : filter || '');
54
62
  const [menuRef, setMenuRef] = useState<HTMLDivElement>(undefined);
55
63
 
56
64
  useEffect(() => {
@@ -73,12 +81,16 @@ const ReqoreDropdownList = memo(
73
81
  return false;
74
82
  }
75
83
 
76
- return text.toString().toLowerCase().indexOf(query.toLowerCase()) !== -1;
84
+ return text.toString().toLowerCase().indexOf(query.toString().toLowerCase()) !== -1;
77
85
  });
78
86
  }, [items, query, _items]);
79
87
 
80
88
  const handleQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => {
81
- setQuery(event.target.value);
89
+ if (onFilterChange) {
90
+ onFilterChange(event.target.value);
91
+ } else {
92
+ setQuery(event.target.value);
93
+ }
82
94
  };
83
95
 
84
96
  const handleItemClick = (item: IReqoreDropdownItem): void => {
@@ -96,11 +108,11 @@ const ReqoreDropdownList = memo(
96
108
  {filterable && (
97
109
  <>
98
110
  <ReqoreInput
99
- value={query}
111
+ value={onFilterChange ? filter : query}
100
112
  icon='SearchLine'
101
113
  onChange={handleQueryChange}
102
- placeholder={`Search ${size(_items)} items...`}
103
- onClearClick={() => setQuery('')}
114
+ placeholder={filterPlaceholder || `Search ${size(_items)} items...`}
115
+ onClearClick={() => (onFilterChange ? onFilterChange('') : setQuery(''))}
104
116
  {...inputProps}
105
117
  />
106
118
  <ReqoreVerticalSpacer height={PADDING_FROM_SIZE.normal} />
@@ -73,7 +73,7 @@ export const StyledInputWrapper = styled.div<IReqoreInputStyle>`
73
73
  position: relative;
74
74
  overflow: hidden;
75
75
  border-radius: ${({ minimal, rounded, _size }) =>
76
- minimal || !rounded ? 0 : RADIUS_FROM_SIZE[_size]}px;
76
+ minimal || rounded === false ? 0 : RADIUS_FROM_SIZE[_size]}px;
77
77
  `;
78
78
 
79
79
  const StyledIconWrapper = styled.div<IReqoreInputStyle>`
@@ -109,7 +109,7 @@ export const StyledInput = styled(StyledEffect)<IReqoreInputStyle>`
109
109
  font-size: ${({ _size }) => TEXT_FROM_SIZE[_size]}px;
110
110
  transition: all 0.2s ease-out;
111
111
  border-radius: ${({ minimal, rounded, _size }) =>
112
- minimal || !rounded ? 0 : RADIUS_FROM_SIZE[_size]}px;
112
+ minimal || rounded === false ? 0 : RADIUS_FROM_SIZE[_size]}px;
113
113
  border: ${({ minimal, theme, flat }) =>
114
114
  !minimal && !flat ? `1px solid ${changeLightness(theme.main, 0.2)}` : 0};
115
115
  border-bottom: ${({ minimal, theme, flat }) =>
@@ -175,7 +175,7 @@ const ReqoreInput = forwardRef<HTMLDivElement, IReqoreInputProps>(
175
175
  iconColor,
176
176
  rightIconColor,
177
177
  flat,
178
- rounded = true,
178
+ rounded,
179
179
  minimal,
180
180
  children,
181
181
  readOnly,
@@ -47,11 +47,13 @@ import { ReqoreHeading, StyledHeader } from '../Header';
47
47
  import ReqoreIcon, { IReqoreIconProps, StyledIconWrapper } from '../Icon';
48
48
  import { ReqorePanelNonResponsiveActions } from './NonResponsiveActions';
49
49
 
50
+ export interface IReqorePanelSubAction extends Omit<IReqoreDropdownItem, 'value'> {}
50
51
  export interface IReqorePanelAction extends IReqoreButtonProps, IWithReqoreTooltip, IReqoreIntent {
51
52
  label?: string | number;
52
53
  onClick?: () => void;
53
54
  group?: IReqorePanelAction[];
54
- actions?: Omit<IReqoreDropdownItem[], 'value'>;
55
+ actions?: IReqorePanelSubAction[];
56
+ multiSelect?: boolean;
55
57
  // Custom react element
56
58
  as?: React.ElementType;
57
59
  props?: { [key: string | number]: any } | undefined;
@@ -0,0 +1,117 @@
1
+ import { lighten, rgba } from 'polished';
2
+ import styled, { css } from 'styled-components';
3
+ import { IReqoreTableColumn } from '.';
4
+ import { TEXT_FROM_SIZE } from '../../constants/sizes';
5
+ import { changeLightness, getReadableColorFrom } from '../../helpers/colors';
6
+ import { alignToFlexAlign } from '../../helpers/utils';
7
+ import { TReqoreColor } from '../Effect';
8
+ import { IReqoreTableCellStyle } from './row';
9
+
10
+ export interface IReqoreCustomTableBodyCellProps extends IReqoreTableBodyCellProps {}
11
+ export interface IReqoreCustomTableBodyCell extends React.FC<IReqoreCustomTableBodyCellProps> {}
12
+ export interface IReqoreTableBodyCellProps
13
+ extends Partial<IReqoreTableColumn>,
14
+ React.HTMLAttributes<HTMLDivElement> {
15
+ children?: React.ReactNode;
16
+ }
17
+
18
+ export const StyledTableCell = styled.div<IReqoreTableCellStyle>`
19
+ ${({ width, grow }) =>
20
+ css`
21
+ width: ${width}px;
22
+ flex-grow: ${grow || (width ? undefined : 1)};
23
+ `}
24
+
25
+ ${({
26
+ theme,
27
+ align,
28
+ interactive,
29
+ interactiveCell,
30
+ intent,
31
+ size,
32
+ flat,
33
+ striped,
34
+ even,
35
+ selected,
36
+ selectedIntent,
37
+ disabled,
38
+ hovered,
39
+ }: IReqoreTableCellStyle) => {
40
+ const getBackgroundColor = (): TReqoreColor => {
41
+ let color = theme.main;
42
+ let opacity = 0;
43
+ // Is there any intent
44
+ if (intent || (selected && selectedIntent)) {
45
+ color = theme.intents[intent || selectedIntent];
46
+ opacity += 0.02;
47
+ }
48
+ // Is the table striped and this row odd
49
+ if (striped && !even) {
50
+ opacity += 0.05;
51
+ }
52
+ // Is this row selected
53
+ if (selected) {
54
+ opacity += 0.02;
55
+ }
56
+ // Is this row hovered
57
+ if (hovered) {
58
+ opacity += 0.08;
59
+ }
60
+
61
+ // Set the color as transparent if opacity is 0
62
+ if (opacity === 0) {
63
+ return 'transparent';
64
+ }
65
+
66
+ return changeLightness(color, opacity);
67
+ };
68
+
69
+ const backgroundColor = getBackgroundColor();
70
+
71
+ return css`
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: ${align ? alignToFlexAlign(align) : 'flex-start'};
75
+ flex-shrink: 0;
76
+ border-bottom: ${!flat ? '1px solid ' : undefined};
77
+
78
+ height: 100%;
79
+ padding: 0 10px;
80
+ font-size: ${TEXT_FROM_SIZE[size]}px;
81
+ background-color: ${backgroundColor === 'transparent'
82
+ ? 'transparent'
83
+ : rgba(getBackgroundColor(), 0.8)};
84
+ color: ${getReadableColorFrom(
85
+ backgroundColor === 'transparent' ? theme.main : backgroundColor,
86
+ !hovered
87
+ )};
88
+ border-color: ${changeLightness(
89
+ backgroundColor === 'transparent' ? theme.main : backgroundColor,
90
+ 0.1
91
+ )};
92
+ transition: background-color 0.2s ease-out;
93
+ opacity: ${disabled ? 0.2 : 1};
94
+ pointer-events: ${disabled ? 'none' : undefined};
95
+ cursor: ${interactive || interactiveCell ? 'pointer' : 'default'};
96
+
97
+ ${interactiveCell &&
98
+ css`
99
+ &:hover {
100
+ background-color: ${lighten(0.2, getBackgroundColor())};
101
+ }
102
+ `}
103
+
104
+ p.reqore-table-text {
105
+ overflow: hidden;
106
+ white-space: nowrap;
107
+ text-overflow: ellipsis;
108
+ margin: 0;
109
+ padding: 0;
110
+ }
111
+ `;
112
+ }}
113
+ `;
114
+
115
+ export const ReqoreTableBodyCell = (props: IReqoreTableBodyCellProps) => {
116
+ return <StyledTableCell {...props} />;
117
+ };
@@ -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;