@takaro/lib-components 0.0.1 → 0.0.5

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 (144) hide show
  1. package/package.json +5 -6
  2. package/src/components/actions/Button/index.tsx +68 -70
  3. package/src/components/actions/Button/style.ts +1 -1
  4. package/src/components/actions/ContextMenu/Group.tsx +1 -1
  5. package/src/components/actions/ContextMenu/MenuItem.tsx +4 -1
  6. package/src/components/actions/ContextMenu/index.tsx +11 -12
  7. package/src/components/actions/Dropdown/DropdownMenu.tsx +5 -2
  8. package/src/components/actions/Dropdown/DropdownTrigger.tsx +55 -57
  9. package/src/components/actions/Dropdown/useDropdown.tsx +1 -1
  10. package/src/components/actions/IconButton/index.tsx +11 -10
  11. package/src/components/actions/IconButton/style.ts +5 -2
  12. package/src/components/actions/ToggleButton/ToggleButton.tsx +26 -28
  13. package/src/components/actions/ToggleButton/ToggleButtonGroup.tsx +3 -8
  14. package/src/components/actions/ToggleButton/style.ts +5 -7
  15. package/src/components/charts/AreaChart/index.tsx +7 -8
  16. package/src/components/charts/BarChart/index.tsx +4 -4
  17. package/src/components/charts/GeoMercator/index.tsx +1 -1
  18. package/src/components/charts/Heatmap/index.tsx +3 -4
  19. package/src/components/charts/LineChart/index.tsx +3 -3
  20. package/src/components/charts/PieChart/index.tsx +1 -1
  21. package/src/components/charts/RadarChart/index.tsx +1 -1
  22. package/src/components/charts/RadialBarChart/index.tsx +1 -1
  23. package/src/components/charts/index.tsx +3 -0
  24. package/src/components/data/Avatar/index.tsx +7 -3
  25. package/src/components/data/Avatar/style.ts +2 -2
  26. package/src/components/data/Chip/index.tsx +39 -41
  27. package/src/components/data/Chip/style.ts +3 -2
  28. package/src/components/data/Console/Console.tsx +14 -12
  29. package/src/components/data/CopyId/index.tsx +3 -2
  30. package/src/components/data/Drawer/Drawer.stories.tsx +3 -5
  31. package/src/components/data/Drawer/DrawerContent.tsx +1 -1
  32. package/src/components/data/Drawer/DrawerHeading.tsx +30 -29
  33. package/src/components/data/Drawer/useDrawer.tsx +1 -1
  34. package/src/components/data/InfiniteScroll/index.tsx +37 -36
  35. package/src/components/data/Table/Table.stories.tsx +6 -2
  36. package/src/components/data/Table/index.tsx +63 -44
  37. package/src/components/data/Table/style.ts +3 -2
  38. package/src/components/data/Table/subcomponents/ColumnHeader/ColumnSettings.tsx +22 -19
  39. package/src/components/data/Table/subcomponents/ColumnHeader/index.tsx +3 -3
  40. package/src/components/data/Table/subcomponents/ColumnHeader/style.ts +2 -1
  41. package/src/components/data/Table/subcomponents/Filter/field.tsx +2 -3
  42. package/src/components/data/Table/subcomponents/Filter/index.tsx +6 -10
  43. package/src/components/data/Table/subcomponents/Pagination/{index.tsx → PagePicker.tsx} +7 -7
  44. package/src/components/data/Table/subcomponents/Pagination/PageSizeSelect.tsx +37 -0
  45. package/src/components/data/Table/subcomponents/Pagination/style.ts +1 -1
  46. package/src/components/dialogs/Dialog/Dialog.stories.tsx +1 -2
  47. package/src/components/dialogs/Dialog/DialogBody.tsx +18 -17
  48. package/src/components/dialogs/Dialog/DialogContent.tsx +30 -28
  49. package/src/components/dialogs/Dialog/DialogHeading.tsx +1 -1
  50. package/src/components/dialogs/Dialog/useDialog.tsx +1 -1
  51. package/src/components/feedback/Alert/index.tsx +74 -73
  52. package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx +1 -1
  53. package/src/components/feedback/NotificationBanner/index.tsx +1 -1
  54. package/src/components/feedback/Popover/PopoverContent.tsx +4 -1
  55. package/src/components/feedback/Popover/PopoverTrigger.tsx +33 -31
  56. package/src/components/feedback/Popover/usePopover.tsx +1 -1
  57. package/src/components/feedback/ProgressBar/index.tsx +1 -1
  58. package/src/components/feedback/QuestionTooltip/index.tsx +1 -2
  59. package/src/components/feedback/Tooltip/TooltipContent.tsx +4 -1
  60. package/src/components/feedback/Tooltip/TooltipTrigger.tsx +3 -3
  61. package/src/components/feedback/Tooltip/useTooltip.tsx +1 -1
  62. package/src/components/feedback/snacks/CookieConsent/index.tsx +5 -2
  63. package/src/components/feedback/snacks/Default/index.tsx +51 -50
  64. package/src/components/feedback/snacks/Drawer/index.tsx +22 -21
  65. package/src/components/feedback/snacks/NetworkDetector/index.tsx +35 -31
  66. package/src/components/inputs/CheckBox/Controlled.tsx +2 -3
  67. package/src/components/inputs/CheckBox/Generic.tsx +18 -72
  68. package/src/components/inputs/CheckBox/style.ts +40 -97
  69. package/src/components/inputs/CodeField/CodeField.stories.tsx +4 -5
  70. package/src/components/inputs/CodeField/index.tsx +1 -0
  71. package/src/components/inputs/Date/DatePicker/DatePicker.stories.tsx +2 -3
  72. package/src/components/inputs/Date/DatePicker/Generic.tsx +20 -10
  73. package/src/components/inputs/Date/DateRangePicker/Context.tsx +12 -1
  74. package/src/components/inputs/Date/DateRangePicker/Controlled.tsx +74 -0
  75. package/src/components/inputs/Date/DateRangePicker/DateRangePicker.stories.tsx +11 -6
  76. package/src/components/inputs/Date/DateRangePicker/DateSelector/Absolute.tsx +3 -3
  77. package/src/components/inputs/Date/DateRangePicker/DateSelector/Relative.tsx +1 -1
  78. package/src/components/inputs/Date/DateRangePicker/DateSelector/index.tsx +1 -1
  79. package/src/components/inputs/Date/DateRangePicker/{index.tsx → Generic.tsx} +43 -11
  80. package/src/components/inputs/Date/DateRangePicker/QuickSelect/index.tsx +1 -1
  81. package/src/components/inputs/Date/DateRangePicker/style.ts +19 -5
  82. package/src/components/inputs/Date/subcomponents/Calendar/index.tsx +1 -1
  83. package/src/components/inputs/Date/subcomponents/RelativePicker/index.tsx +1 -1
  84. package/src/components/inputs/DurationField/Generic.tsx +149 -152
  85. package/src/components/inputs/FileField/FileField.stories.tsx +6 -6
  86. package/src/components/inputs/FileField/Generic.tsx +101 -99
  87. package/src/components/inputs/InputProps.ts +0 -2
  88. package/src/components/inputs/RadioGroup/Controlled.tsx +1 -2
  89. package/src/components/inputs/RadioGroup/RadioGroup.stories.tsx +6 -4
  90. package/src/components/inputs/RadioGroup/RadioItem.tsx +54 -53
  91. package/src/components/inputs/Slider/Generic.tsx +1 -1
  92. package/src/components/inputs/Slider/Slider.stories.tsx +1 -1
  93. package/src/components/inputs/Slider/handle.tsx +1 -0
  94. package/src/components/inputs/Switch/Controlled.tsx +1 -2
  95. package/src/components/inputs/Switch/Generic.tsx +18 -45
  96. package/src/components/inputs/Switch/Switch.stories.tsx +2 -4
  97. package/src/components/inputs/Switch/style.ts +44 -38
  98. package/src/components/inputs/TagField/Generic.tsx +109 -109
  99. package/src/components/inputs/TextAreaField/Generic.tsx +41 -39
  100. package/src/components/inputs/TextAreaField/TextAreaField.stories.tsx +2 -3
  101. package/src/components/inputs/TextField/Generic.tsx +81 -79
  102. package/src/components/inputs/TextField/TextField.stories.tsx +3 -4
  103. package/src/components/inputs/index.ts +3 -2
  104. package/src/components/inputs/layout/Description.tsx +1 -2
  105. package/src/components/inputs/layout/InputWrapper.ts +2 -2
  106. package/src/components/inputs/selects/SelectField/Controlled.tsx +1 -2
  107. package/src/components/inputs/selects/SelectField/Generic/FilterInput.tsx +4 -1
  108. package/src/components/inputs/selects/SelectField/SelectField.stories.tsx +9 -10
  109. package/src/components/inputs/selects/SelectQueryField/Generic/index.tsx +200 -197
  110. package/src/components/inputs/selects/SelectQueryField/SelectQueryField.stories.tsx +1 -1
  111. package/src/components/inputs/selects/SubComponents/Option.tsx +3 -3
  112. package/src/components/inputs/selects/SubComponents/OptionGroup.tsx +1 -1
  113. package/src/components/inputs/selects/SubComponents/style.ts +18 -4
  114. package/src/components/inputs/selects/index.tsx +5 -2
  115. package/src/components/inputs/selects/sharedStyle.ts +1 -0
  116. package/src/components/navigation/HorizontalNav/index.tsx +5 -32
  117. package/src/components/navigation/HorizontalNav/style.ts +11 -26
  118. package/src/components/navigation/IconNav/index.tsx +1 -1
  119. package/src/components/navigation/Steppers/SlimStepper/index.tsx +1 -1
  120. package/src/components/navigation/Steppers/SlimStepper/style.ts +1 -2
  121. package/src/components/navigation/Steppers/Stepper/index.tsx +1 -1
  122. package/src/components/navigation/Steppers/context.tsx +2 -2
  123. package/src/components/navigation/Tabs/Content.tsx +4 -1
  124. package/src/components/navigation/Tabs/Trigger.tsx +24 -23
  125. package/src/components/navigation/index.ts +1 -1
  126. package/src/components/other/ActionMenu/ActionMenu.stories.tsx +1 -2
  127. package/src/components/other/ActionMenu/index.tsx +30 -29
  128. package/src/components/other/Collapsible/CollapsibleTrigger.tsx +8 -4
  129. package/src/components/other/Company/index.tsx +25 -26
  130. package/src/components/other/Empty/Empty.stories.tsx +1 -1
  131. package/src/components/other/Empty/index.tsx +1 -3
  132. package/src/components/other/PermissionsGuard/index.tsx +2 -2
  133. package/src/components/visual/Card/index.tsx +4 -1
  134. package/src/errors/base.ts +4 -1
  135. package/src/errors/errors.ts +19 -2
  136. package/src/helpers/getSnackbarProvider.tsx +3 -3
  137. package/src/helpers/regexprs.ts +1 -0
  138. package/src/hooks/useFocus.tsx +3 -1
  139. package/src/hooks/useOnScreen.ts +1 -1
  140. package/src/hooks/useTableActions.ts +10 -5
  141. package/src/styled/GlobalStyle.ts +2 -1
  142. package/src/styled/zIndex.ts +1 -1
  143. package/src/test/testUtils.tsx +3 -0
  144. package/src/components/data/Table/subcomponents/index.ts +0 -4
@@ -1,5 +1,5 @@
1
1
  /// <reference path="./react-table.d.ts" />
2
- import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react';
2
+ import { Dispatch, SetStateAction, useEffect, useMemo, useState, JSX } from 'react';
3
3
  import { DndProvider } from 'react-dnd';
4
4
  import { HTML5Backend } from 'react-dnd-html5-backend';
5
5
  import { Density } from '../../../styled';
@@ -18,19 +18,23 @@ import {
18
18
  ColumnPinningState,
19
19
  RowSelectionState,
20
20
  } from '@tanstack/react-table';
21
- import { Wrapper, StyledTable, Toolbar, PaginationContainer, Flex, TableWrapper } from './style';
22
- import { Empty, Spinner, ToggleButtonGroup } from '../../../components';
21
+ import { Wrapper, StyledTable, Toolbar, Flex, TableWrapper } from './style';
22
+ import { Button, Empty, Spinner, ToggleButtonGroup } from '../../../components';
23
23
  import { AiOutlinePicCenter as RelaxedDensityIcon, AiOutlinePicRight as TightDensityIcon } from 'react-icons/ai';
24
- import { ColumnHeader, ColumnVisibility, Filter, Pagination } from './subcomponents';
24
+
25
+ import { ColumnHeader } from './subcomponents/ColumnHeader';
26
+ import { ColumnVisibility } from './subcomponents/ColumnVisibility';
27
+ import { Filter } from './subcomponents/Filter';
28
+ import { PagePicker } from './subcomponents/Pagination/PagePicker';
29
+ import { PageSizeSelect } from './subcomponents/Pagination/PageSizeSelect';
30
+
25
31
  import { ColumnFilter, PageOptions } from '../../../hooks/useTableActions';
26
32
  import { GenericCheckBox as CheckBox } from '../../inputs/CheckBox/Generic';
27
33
  import { useLocalStorage } from '../../../hooks';
28
34
 
29
35
  export interface TableProps<DataType extends object> {
30
36
  id: string;
31
-
32
37
  data: DataType[];
33
-
34
38
  isLoading?: boolean;
35
39
 
36
40
  // currently not possible to type this properly: https://github.com/TanStack/table/issues/4241
@@ -84,13 +88,16 @@ export function Table<DataType extends object>({
84
88
  isLoading = false,
85
89
  }: TableProps<DataType>) {
86
90
  const [columnVisibility, setColumnVisibility] = useState<VisibilityState>(() => {
87
- return columns.reduce((acc, column) => {
88
- if (column.id === undefined) {
89
- throw new Error('ColumnDef must have an id');
90
- }
91
- acc[column.id] = column?.meta?.hiddenColumn ? !column.meta.hiddenColumn : true;
92
- return acc;
93
- }, {} as Record<string, boolean>);
91
+ return columns.reduce(
92
+ (acc, column) => {
93
+ if (column.id === undefined) {
94
+ throw new Error('ColumnDef must have an id');
95
+ }
96
+ acc[column.id] = column?.meta?.hiddenColumn ? !column.meta.hiddenColumn : true;
97
+ return acc;
98
+ },
99
+ {} as Record<string, boolean>,
100
+ );
94
101
  });
95
102
  const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({});
96
103
  const { storedValue: density, setValue: setDensity } = useLocalStorage<Density>(`table-density-${id}`, 'tight');
@@ -103,19 +110,11 @@ export function Table<DataType extends object>({
103
110
  throw new Error('ColumnDef must have an id');
104
111
  }
105
112
  return column.id;
106
- })
113
+ }),
107
114
  );
108
115
 
109
116
  const ROW_SELECTION_COL_SPAN = rowSelection ? 1 : 0;
110
-
111
- // table size
112
- useEffect(() => {
113
- if (density === 'tight') {
114
- table.setPageSize(19);
115
- } else {
116
- table.resetPageSize(true);
117
- }
118
- }, [density]);
117
+ const MINIMUM_ROW_COUNT_FOR_PAGINATION = 5;
119
118
 
120
119
  // handles the column visibility tooltip (shows tooltip when the first column is hidden)
121
120
  useEffect(() => {
@@ -155,6 +154,7 @@ export function Table<DataType extends object>({
155
154
  enableSorting: !!sorting,
156
155
  enableSortingRemoval: false,
157
156
  enableColumnResizing: true,
157
+ enablePinning: true,
158
158
  enableHiding: !!columnVisibility,
159
159
  enableRowSelection: !!rowSelection,
160
160
  autoResetPageIndex: false,
@@ -170,7 +170,8 @@ export function Table<DataType extends object>({
170
170
  onRowSelectionChange: rowSelection ? rowSelection?.setRowSelectionState : undefined,
171
171
 
172
172
  initialState: {
173
- columnVisibility: columnVisibility,
173
+ columnVisibility,
174
+ columnOrder,
174
175
  sorting: sorting.sortingState,
175
176
  columnFilters: columnFiltering.columnFiltersState,
176
177
  globalFilter: columnSearch.columnSearchState,
@@ -181,15 +182,17 @@ export function Table<DataType extends object>({
181
182
  state: {
182
183
  columnVisibility,
183
184
  columnOrder,
184
- sorting: sorting?.sortingState,
185
- columnFilters: columnFiltering?.columnFiltersState,
186
- globalFilter: columnSearch?.columnSearchState,
185
+ sorting: sorting.sortingState,
186
+ columnFilters: columnFiltering.columnFiltersState,
187
+ globalFilter: columnSearch.columnSearchState,
187
188
  pagination: pagination?.paginationState,
188
189
  rowSelection: rowSelection ? rowSelection.rowSelectionState : undefined,
189
190
  columnPinning,
190
191
  },
191
192
  });
192
193
 
194
+ const tableHasNoData = isLoading === false && table.getRowModel().rows.length === 0;
195
+
193
196
  // rowSelection.rowSelectionState has the following shape: { [rowId: string]: boolean }
194
197
  const hasRowSelection = useMemo(() => {
195
198
  return (
@@ -222,10 +225,10 @@ export function Table<DataType extends object>({
222
225
  orientation="horizontal"
223
226
  defaultValue={density}
224
227
  >
225
- <ToggleButtonGroup.Button value="relaxed" tooltip="Relaxed layout">
228
+ <ToggleButtonGroup.Button value="relaxed" tooltip="Relaxed layout" disabled={tableHasNoData}>
226
229
  <RelaxedDensityIcon size={20} />
227
230
  </ToggleButtonGroup.Button>
228
- <ToggleButtonGroup.Button value="tight" tooltip="Tight layout">
231
+ <ToggleButtonGroup.Button value="tight" tooltip="Tight layout" disabled={tableHasNoData}>
229
232
  <TightDensityIcon size={20} />
230
233
  </ToggleButtonGroup.Button>
231
234
  </ToggleButtonGroup>
@@ -285,11 +288,22 @@ export function Table<DataType extends object>({
285
288
  )}
286
289
 
287
290
  {/* empty state */}
288
- {!isLoading && table.getRowModel().rows.length === 0 && (
291
+ {tableHasNoData && (
289
292
  <tr>
290
293
  <td colSpan={table.getAllColumns().length + ROW_SELECTION_COL_SPAN}>
291
294
  <div style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
292
- <Empty header="No data" description="We couldn't find what you are looking for." actions={[]} />
295
+ <Empty
296
+ header=""
297
+ description="Items will appear here. Add your first item to begin!"
298
+ actions={[
299
+ <Button
300
+ key={id + '-learn-more-button'}
301
+ variant="clear"
302
+ onClick={() => window.open('https://docs.takaro.io')}
303
+ text="Learn more"
304
+ />,
305
+ ]}
306
+ />
293
307
  </div>
294
308
  </td>
295
309
  </tr>
@@ -323,26 +337,25 @@ export function Table<DataType extends object>({
323
337
  </tr>
324
338
  ))}
325
339
  </tbody>
326
- {!isLoading && table.getRowModel().rows.length > 1 && (
340
+
341
+ {!isLoading && table.getPageCount() * table.getRowCount() > MINIMUM_ROW_COUNT_FOR_PAGINATION && (
327
342
  <tfoot>
328
343
  <tr>
329
- <td colSpan={1} />
344
+ {/* This is the row selection */}
345
+ {ROW_SELECTION_COL_SPAN ? <td colSpan={1} /> : null}
330
346
  {pagination && (
331
- <td
332
- colSpan={
333
- columns.length +
334
- ROW_SELECTION_COL_SPAN /* +1 here is because we have an extra column for the selection */ -
335
- 2 /* We use 2 columns for padding (1 start one at end) */
336
- }
337
- >
338
- <PaginationContainer>
347
+ <>
348
+ <td colSpan={table.getVisibleLeafColumns().length - 3 - ROW_SELECTION_COL_SPAN} />
349
+ <td colSpan={1}>
339
350
  <span>
340
351
  showing {table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}-
341
352
  {table.getState().pagination.pageIndex * table.getState().pagination.pageSize +
342
353
  table.getRowModel().rows.length}{' '}
343
354
  of {pagination.pageOptions.total} entries
344
355
  </span>
345
- <Pagination
356
+ </td>
357
+ <td colSpan={1}>
358
+ <PagePicker
346
359
  pageCount={table.getPageCount()}
347
360
  hasNext={table.getCanNextPage()}
348
361
  hasPrevious={table.getCanPreviousPage()}
@@ -351,8 +364,14 @@ export function Table<DataType extends object>({
351
364
  pageIndex={table.getState().pagination.pageIndex}
352
365
  setPageIndex={table.setPageIndex}
353
366
  />
354
- </PaginationContainer>
355
- </td>
367
+ </td>
368
+ <td colSpan={1} style={{ paddingRight: '10px' }}>
369
+ <PageSizeSelect
370
+ onPageSizeChange={(pageSize) => table.setPageSize(Number(pageSize))}
371
+ pageSize={table.getState().pagination.pageSize.toString()}
372
+ />
373
+ </td>
374
+ </>
356
375
  )}
357
376
  </tr>
358
377
  </tfoot>
@@ -14,6 +14,7 @@ export const Toolbar = styled.div`
14
14
  border-left: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
15
15
  border-right: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
16
16
  border-top: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
17
+ background: ${({ theme }) => theme.colors.backgroundAlt};
17
18
 
18
19
  border-top-left-radius: ${({ theme }) => theme.borderRadius.large};
19
20
  border-top-right-radius: ${({ theme }) => theme.borderRadius.large};
@@ -30,6 +31,7 @@ export const TableWrapper = styled.div`
30
31
  padding-bottom: ${({ theme }) => theme.spacing['0_5']};
31
32
  border-bottom-left-radius: ${({ theme }) => theme.borderRadius.large};
32
33
  border-bottom-right-radius: ${({ theme }) => theme.borderRadius.large};
34
+ overflow: hidden;
33
35
  `;
34
36
 
35
37
  export const StyledTable = styled.table<{ density: Density }>`
@@ -37,8 +39,8 @@ export const StyledTable = styled.table<{ density: Density }>`
37
39
  width: 100%;
38
40
  text-align: left;
39
41
  background-color: ${({ theme }) => theme.colors.background};
40
- overflow: hidden;
41
42
  border-collapse: collapse;
43
+ position: relative;
42
44
 
43
45
  tr:last-child td {
44
46
  border-bottom: none;
@@ -57,7 +59,6 @@ export const StyledTable = styled.table<{ density: Density }>`
57
59
 
58
60
  tfoot {
59
61
  border-top: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
60
- padding: ${({ theme }) => theme.spacing[2]};
61
62
  tr {
62
63
  td {
63
64
  border-bottom: none;
@@ -46,20 +46,19 @@ export function ColumnSettings<DataType extends object>({
46
46
  <Tooltip.Content>Toggle to ascending</Tooltip.Content>
47
47
  </Tooltip>
48
48
  );
49
- } else {
50
- return (
51
- <Tooltip>
52
- <Tooltip.Trigger asChild>
53
- <IconButton
54
- icon={<SortAscendingIcon />}
55
- ariaLabel="toggle to descending"
56
- onClick={() => toggleSorting(true)}
57
- />
58
- </Tooltip.Trigger>
59
- <Tooltip.Content>Toggle to descending</Tooltip.Content>
60
- </Tooltip>
61
- );
62
49
  }
50
+ return (
51
+ <Tooltip>
52
+ <Tooltip.Trigger asChild>
53
+ <IconButton
54
+ icon={<SortAscendingIcon />}
55
+ ariaLabel="toggle to descending"
56
+ onClick={() => toggleSorting(true)}
57
+ />
58
+ </Tooltip.Trigger>
59
+ <Tooltip.Content>Toggle to descending</Tooltip.Content>
60
+ </Tooltip>
61
+ );
63
62
  }
64
63
  }, [table.getState().sorting, header.column.id]);
65
64
 
@@ -129,9 +128,11 @@ export function ColumnSettings<DataType extends object>({
129
128
  icon={<PinIcon />}
130
129
  label="Pin to left"
131
130
  onClick={() => {
132
- !header.column.getIsPinned() && header.column.getCanPin()
133
- ? header.column.pin('left')
134
- : header.column.pin(false);
131
+ if (!header.column.getIsPinned() && header.column.getCanPin()) {
132
+ header.column.pin('left');
133
+ } else {
134
+ header.column.pin(false);
135
+ }
135
136
  }}
136
137
  />
137
138
  <Dropdown.Menu.Item
@@ -140,9 +141,11 @@ export function ColumnSettings<DataType extends object>({
140
141
  icon={<PinIcon style={{ transform: 'scaleX(-1)' }} />}
141
142
  label="Pin to right"
142
143
  onClick={() => {
143
- !header.column.getIsPinned() && header.column.getCanPin()
144
- ? header.column.pin('right')
145
- : header.column.pin(false);
144
+ if (!header.column.getIsPinned() && header.column.getCanPin()) {
145
+ header.column.pin('right');
146
+ } else {
147
+ header.column.pin(false);
148
+ }
146
149
  }}
147
150
  />
148
151
  <Dropdown.Menu.Item disabled={true} icon={<DeleteIcon />} label="Delete column" onClick={() => {}} />
@@ -27,7 +27,7 @@ const reorder = (draggedColumnId: string, targetColumnId: string, columnOrder: s
27
27
  columnOrder.splice(
28
28
  columnOrder.indexOf(targetColumnId),
29
29
  0,
30
- columnOrder.splice(columnOrder.indexOf(draggedColumnId), 1)[0] as string
30
+ columnOrder.splice(columnOrder.indexOf(draggedColumnId), 1)[0] as string,
31
31
  );
32
32
  return [...columnOrder];
33
33
  };
@@ -134,7 +134,7 @@ export function ColumnHeader<DataType extends object>({ header, table, isLoading
134
134
  isRowSelection={false}
135
135
  >
136
136
  <InnerTh>
137
- <Target ref={ref} isDragging={isDragging} role="DraggableBox" draggable={true} aria-dropeffect="move">
137
+ <Target ref={ref} isDragging={isDragging} role="DraggableBox" draggable={true}>
138
138
  <CustomDragLayer />
139
139
  <Content canDrag={canDrag}>
140
140
  {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
@@ -175,7 +175,7 @@ export const Inner = styled.div<{ initialOffset: XYCoord | null; currentOffset:
175
175
  transform: ${({ currentOffset }) => `translate(${currentOffset?.x}px, ${currentOffset?.y}px)`};
176
176
  `;
177
177
 
178
- export const CustomDragLayer = forwardRef<HTMLDivElement>((_, ref) => {
178
+ export const CustomDragLayer = forwardRef<HTMLDivElement>(function ColumnHeaderDragLayer(_, ref) {
179
179
  const { itemType, isDragging, initialOffset, currentOffset } = useDragLayer((monitor) => ({
180
180
  item: monitor.getItem(),
181
181
  itemType: monitor.getItemType(),
@@ -8,10 +8,11 @@ export const Th = styled.th<{
8
8
  canDrag: boolean;
9
9
  isRowSelection: boolean;
10
10
  }>`
11
- position: relative;
11
+ top: 0;
12
12
  width: ${({ width }) => width}px;
13
13
  padding: ${({ theme }) => `${theme.spacing['0_75']} 0`};
14
14
  border-bottom: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
15
+ box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.4);
15
16
 
16
17
  &:first-child {
17
18
  padding-left: ${({ theme, isRowSelection }) => (isRowSelection ? 0 : theme.spacing['1'])};
@@ -1,7 +1,6 @@
1
1
  import { Control, UseFormSetValue, useWatch } from 'react-hook-form';
2
2
  import { SelectField, TextField } from '../../../../../components';
3
- import { FilterInputType, IFormInputs } from '.';
4
- import { Operators } from '.';
3
+ import { Operators, FilterInputType, IFormInputs } from '.';
5
4
  import { Column } from '@tanstack/react-table';
6
5
  import { useLayoutEffect } from 'react';
7
6
  import { camelCaseToSpaces } from '../../../../../helpers';
@@ -45,7 +44,7 @@ export function FilterRow<DataType extends object>({
45
44
  }
46
45
 
47
46
  const meta = column?.columnDef?.meta as Record<string, unknown> | undefined;
48
- switch (meta?.type) {
47
+ switch (meta?.dataType) {
49
48
  case 'uuid':
50
49
  case 'datetime':
51
50
  return [Operators.is];
@@ -67,24 +67,18 @@ export function Filter<DataType extends object>({ table }: FilterProps<DataType>
67
67
  .discriminatedUnion('type', [
68
68
  z.object({
69
69
  type: z.literal(FilterInputType.string),
70
- value: z.string().nonempty({
71
- message: 'Value is required.',
72
- }),
70
+ value: z.string().min(1),
73
71
  }),
74
72
  z.object({
75
73
  type: z.literal(FilterInputType.uuid),
76
- value: z.string().uuid().nonempty({
77
- message: 'Value is required.',
78
- }),
74
+ value: z.string().uuid().min(1),
79
75
  }),
80
76
  z.object({
81
77
  type: z.literal(FilterInputType.datetime),
82
- value: z.string().datetime().nonempty({
83
- message: 'Value is required.',
84
- }),
78
+ value: z.string().datetime().min(1),
85
79
  }),
86
80
  ])
87
- .and(basedShape)
81
+ .and(basedShape),
88
82
  ),
89
83
  });
90
84
  }, [columnIds]);
@@ -165,6 +159,8 @@ export function Filter<DataType extends object>({ table }: FilterProps<DataType>
165
159
 
166
160
  table.setColumnFilters(columnFiltersArray);
167
161
  table.setGlobalFilter(globalFiltersArray);
162
+ table.resetPagination();
163
+
168
164
  setOpen(false);
169
165
  };
170
166
 
@@ -1,6 +1,6 @@
1
1
  import { FC, useMemo } from 'react';
2
2
  import { Button, IconButton } from '../../../../../components';
3
- import { PaginationContainer } from './style';
3
+ import { PagePickerContainer } from './style';
4
4
  import {
5
5
  FaAngleRight as NextIcon,
6
6
  FaAnglesRight as LastIcon,
@@ -22,12 +22,11 @@ const getPageWindow = (pageCount: number, windowSize: number, currentPage: numbe
22
22
  return { start: 1, end: windowSize + 1 };
23
23
  } else if (currentPage + floor >= pageCount) {
24
24
  return { start: pageCount - windowSize + 1, end: pageCount + 1 };
25
- } else {
26
- return { start: currentPage - ceiling + 1, end: currentPage + floor + 1 };
27
25
  }
26
+ return { start: currentPage - ceiling + 1, end: currentPage + floor + 1 };
28
27
  };
29
28
 
30
- export interface PaginationProps {
29
+ export interface PagePickerProps {
31
30
  setPageIndex: (index: number) => void;
32
31
  pageIndex: number;
33
32
  hasPrevious: boolean;
@@ -37,7 +36,7 @@ export interface PaginationProps {
37
36
  pageCount: number;
38
37
  }
39
38
 
40
- export const Pagination: FC<PaginationProps> = ({
39
+ export const PagePicker: FC<PagePickerProps> = ({
41
40
  setPageIndex,
42
41
  hasPrevious,
43
42
  pageIndex,
@@ -63,7 +62,7 @@ export const Pagination: FC<PaginationProps> = ({
63
62
  };
64
63
 
65
64
  return (
66
- <PaginationContainer border={false}>
65
+ <PagePickerContainer border={false}>
67
66
  {showJumps && (
68
67
  <IconButton
69
68
  size="tiny"
@@ -85,6 +84,7 @@ export const Pagination: FC<PaginationProps> = ({
85
84
  {showButtons &&
86
85
  pages.map((i) => (
87
86
  <Button
87
+ key={`page-${i}`}
88
88
  variant="outline"
89
89
  onClick={() => setPageIndex(i - 1)}
90
90
  className={i === pageIndex + 1 ? 'active' : ''}
@@ -103,6 +103,6 @@ export const Pagination: FC<PaginationProps> = ({
103
103
  ariaLabel="Last page"
104
104
  />
105
105
  )}
106
- </PaginationContainer>
106
+ </PagePickerContainer>
107
107
  );
108
108
  };
@@ -0,0 +1,37 @@
1
+ import { FC } from 'react';
2
+ import { UnControlledSelectField } from '../../../../../components';
3
+
4
+ interface PageSizeSelectProps {
5
+ onPageSizeChange: (pageSize: string) => void;
6
+ pageSize: string;
7
+ }
8
+
9
+ export const PageSizeSelect: FC<PageSizeSelectProps> = ({ onPageSizeChange, pageSize }) => {
10
+ return (
11
+ <UnControlledSelectField
12
+ hasError={false}
13
+ hasDescription={false}
14
+ id="page-size"
15
+ multiple={false}
16
+ name="pageSize"
17
+ value={pageSize.toString() || '10'}
18
+ onChange={onPageSizeChange}
19
+ render={(selectedItems) => {
20
+ if (selectedItems.length === 0) {
21
+ return <div>Select...</div>;
22
+ }
23
+ return <div>{selectedItems[0].label} items</div>;
24
+ }}
25
+ >
26
+ <UnControlledSelectField.OptionGroup label="Options">
27
+ {[5, 10, 25, 50, 100, 200].map((val: number) => (
28
+ <UnControlledSelectField.Option key={`${val}-table`} value={val.toString()} label={val.toString()}>
29
+ <div>
30
+ <span>{val} items</span>
31
+ </div>
32
+ </UnControlledSelectField.Option>
33
+ ))}
34
+ </UnControlledSelectField.OptionGroup>
35
+ </UnControlledSelectField>
36
+ );
37
+ };
@@ -1,6 +1,6 @@
1
1
  import { styled } from '../../../../../styled';
2
2
 
3
- export const PaginationContainer = styled.div<{ border?: boolean }>`
3
+ export const PagePickerContainer = styled.div<{ border?: boolean }>`
4
4
  display: flex;
5
5
  justify-content: flex-end;
6
6
 
@@ -1,5 +1,4 @@
1
- import React from 'react';
2
- import { useState } from 'react';
1
+ import React, { useState } from 'react';
3
2
  import { SubmitHandler, useForm } from 'react-hook-form';
4
3
  import { Meta, StoryFn } from '@storybook/react';
5
4
 
@@ -41,22 +41,23 @@ export interface DialogBodyProps {
41
41
  size?: Size;
42
42
  }
43
43
 
44
- export const DialogBody = forwardRef<HTMLParagraphElement, PropsWithChildren<DialogBodyProps>>(
45
- ({ children, size = 'medium', ...props }, ref) => {
46
- const { setDescriptionId } = useDialogContext();
47
- const id = useId();
44
+ export const DialogBody = forwardRef<HTMLParagraphElement, PropsWithChildren<DialogBodyProps>>(function DialogBody(
45
+ { children, size = 'medium', ...props },
46
+ ref,
47
+ ) {
48
+ const { setDescriptionId } = useDialogContext();
49
+ const id = useId();
48
50
 
49
- // Only sets `aria-describedby` on the Dialog root element
50
- // if this component is mounted inside it.
51
- useLayoutEffect(() => {
52
- setDescriptionId(id);
53
- return () => setDescriptionId(undefined);
54
- }, [id, setDescriptionId]);
51
+ // Only sets `aria-describedby` on the Dialog root element
52
+ // if this component is mounted inside it.
53
+ useLayoutEffect(() => {
54
+ setDescriptionId(id);
55
+ return () => setDescriptionId(undefined);
56
+ }, [id, setDescriptionId]);
55
57
 
56
- return (
57
- <Container {...props} ref={ref} id={id} size={size}>
58
- {children}
59
- </Container>
60
- );
61
- }
62
- );
58
+ return (
59
+ <Container {...props} ref={ref} id={id} size={size}>
60
+ {children}
61
+ </Container>
62
+ );
63
+ });
@@ -14,33 +14,35 @@ const CardBody = styled.div`
14
14
  min-width: 300px;
15
15
  `;
16
16
 
17
- export const DialogContent = forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>((props, propRef) => {
18
- const { context: floatingContext, ...context } = useDialogContext();
19
- const ref = useMergeRefs([context.refs.setFloating, propRef]);
17
+ export const DialogContent = forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
18
+ function DialogContent(props, propRef) {
19
+ const { context: floatingContext, ...context } = useDialogContext();
20
+ const ref = useMergeRefs([context.refs.setFloating, propRef]);
20
21
 
21
- const root = document.getElementById('dialog');
22
- if (!root) {
23
- throw new Error('Dialog need to render in a <div id="dialog"></div>');
24
- }
22
+ const root = document.getElementById('dialog');
23
+ if (!root) {
24
+ throw new Error('Dialog need to render in a <div id="dialog"></div>');
25
+ }
25
26
 
26
- return (
27
- <FloatingPortal root={root}>
28
- {context.open && (
29
- <StyledFloatingOverlay lockScroll>
30
- <FloatingFocusManager context={floatingContext}>
31
- <Card
32
- ref={ref}
33
- aria-labelledby={context.labelId}
34
- aria-describedby={context.descriptionId}
35
- {...context.getFloatingProps({
36
- ...props,
37
- })}
38
- >
39
- <CardBody>{props.children}</CardBody>
40
- </Card>
41
- </FloatingFocusManager>
42
- </StyledFloatingOverlay>
43
- )}
44
- </FloatingPortal>
45
- );
46
- });
27
+ return (
28
+ <FloatingPortal root={root}>
29
+ {context.open && (
30
+ <StyledFloatingOverlay lockScroll>
31
+ <FloatingFocusManager context={floatingContext}>
32
+ <Card
33
+ ref={ref}
34
+ aria-labelledby={context.labelId}
35
+ aria-describedby={context.descriptionId}
36
+ {...context.getFloatingProps({
37
+ ...props,
38
+ })}
39
+ >
40
+ <CardBody>{props.children}</CardBody>
41
+ </Card>
42
+ </FloatingFocusManager>
43
+ </StyledFloatingOverlay>
44
+ )}
45
+ </FloatingPortal>
46
+ );
47
+ },
48
+ );
@@ -21,7 +21,7 @@ interface DialogHeadingProps extends HTMLProps<HTMLHeadingElement> {
21
21
 
22
22
  export const DialogHeading = forwardRef<HTMLHeadingElement, DialogHeadingProps>(function DialogHeading(
23
23
  { children, hasClose = true, ...props },
24
- ref
24
+ ref,
25
25
  ) {
26
26
  const { setLabelId, setOpen } = useDialogContext();
27
27
  const id = useId();
@@ -45,6 +45,6 @@ export function useDialog({
45
45
  setLabelId,
46
46
  setDescriptionId,
47
47
  }),
48
- [open, setOpen, interactions, data, labelId, descriptionId]
48
+ [open, setOpen, interactions, data, labelId, descriptionId],
49
49
  );
50
50
  }