@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.
- package/package.json +5 -6
- package/src/components/actions/Button/index.tsx +68 -70
- package/src/components/actions/Button/style.ts +1 -1
- package/src/components/actions/ContextMenu/Group.tsx +1 -1
- package/src/components/actions/ContextMenu/MenuItem.tsx +4 -1
- package/src/components/actions/ContextMenu/index.tsx +11 -12
- package/src/components/actions/Dropdown/DropdownMenu.tsx +5 -2
- package/src/components/actions/Dropdown/DropdownTrigger.tsx +55 -57
- package/src/components/actions/Dropdown/useDropdown.tsx +1 -1
- package/src/components/actions/IconButton/index.tsx +11 -10
- package/src/components/actions/IconButton/style.ts +5 -2
- package/src/components/actions/ToggleButton/ToggleButton.tsx +26 -28
- package/src/components/actions/ToggleButton/ToggleButtonGroup.tsx +3 -8
- package/src/components/actions/ToggleButton/style.ts +5 -7
- package/src/components/charts/AreaChart/index.tsx +7 -8
- package/src/components/charts/BarChart/index.tsx +4 -4
- package/src/components/charts/GeoMercator/index.tsx +1 -1
- package/src/components/charts/Heatmap/index.tsx +3 -4
- package/src/components/charts/LineChart/index.tsx +3 -3
- package/src/components/charts/PieChart/index.tsx +1 -1
- package/src/components/charts/RadarChart/index.tsx +1 -1
- package/src/components/charts/RadialBarChart/index.tsx +1 -1
- package/src/components/charts/index.tsx +3 -0
- package/src/components/data/Avatar/index.tsx +7 -3
- package/src/components/data/Avatar/style.ts +2 -2
- package/src/components/data/Chip/index.tsx +39 -41
- package/src/components/data/Chip/style.ts +3 -2
- package/src/components/data/Console/Console.tsx +14 -12
- package/src/components/data/CopyId/index.tsx +3 -2
- package/src/components/data/Drawer/Drawer.stories.tsx +3 -5
- package/src/components/data/Drawer/DrawerContent.tsx +1 -1
- package/src/components/data/Drawer/DrawerHeading.tsx +30 -29
- package/src/components/data/Drawer/useDrawer.tsx +1 -1
- package/src/components/data/InfiniteScroll/index.tsx +37 -36
- package/src/components/data/Table/Table.stories.tsx +6 -2
- package/src/components/data/Table/index.tsx +63 -44
- package/src/components/data/Table/style.ts +3 -2
- package/src/components/data/Table/subcomponents/ColumnHeader/ColumnSettings.tsx +22 -19
- package/src/components/data/Table/subcomponents/ColumnHeader/index.tsx +3 -3
- package/src/components/data/Table/subcomponents/ColumnHeader/style.ts +2 -1
- package/src/components/data/Table/subcomponents/Filter/field.tsx +2 -3
- package/src/components/data/Table/subcomponents/Filter/index.tsx +6 -10
- package/src/components/data/Table/subcomponents/Pagination/{index.tsx → PagePicker.tsx} +7 -7
- package/src/components/data/Table/subcomponents/Pagination/PageSizeSelect.tsx +37 -0
- package/src/components/data/Table/subcomponents/Pagination/style.ts +1 -1
- package/src/components/dialogs/Dialog/Dialog.stories.tsx +1 -2
- package/src/components/dialogs/Dialog/DialogBody.tsx +18 -17
- package/src/components/dialogs/Dialog/DialogContent.tsx +30 -28
- package/src/components/dialogs/Dialog/DialogHeading.tsx +1 -1
- package/src/components/dialogs/Dialog/useDialog.tsx +1 -1
- package/src/components/feedback/Alert/index.tsx +74 -73
- package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx +1 -1
- package/src/components/feedback/NotificationBanner/index.tsx +1 -1
- package/src/components/feedback/Popover/PopoverContent.tsx +4 -1
- package/src/components/feedback/Popover/PopoverTrigger.tsx +33 -31
- package/src/components/feedback/Popover/usePopover.tsx +1 -1
- package/src/components/feedback/ProgressBar/index.tsx +1 -1
- package/src/components/feedback/QuestionTooltip/index.tsx +1 -2
- package/src/components/feedback/Tooltip/TooltipContent.tsx +4 -1
- package/src/components/feedback/Tooltip/TooltipTrigger.tsx +3 -3
- package/src/components/feedback/Tooltip/useTooltip.tsx +1 -1
- package/src/components/feedback/snacks/CookieConsent/index.tsx +5 -2
- package/src/components/feedback/snacks/Default/index.tsx +51 -50
- package/src/components/feedback/snacks/Drawer/index.tsx +22 -21
- package/src/components/feedback/snacks/NetworkDetector/index.tsx +35 -31
- package/src/components/inputs/CheckBox/Controlled.tsx +2 -3
- package/src/components/inputs/CheckBox/Generic.tsx +18 -72
- package/src/components/inputs/CheckBox/style.ts +40 -97
- package/src/components/inputs/CodeField/CodeField.stories.tsx +4 -5
- package/src/components/inputs/CodeField/index.tsx +1 -0
- package/src/components/inputs/Date/DatePicker/DatePicker.stories.tsx +2 -3
- package/src/components/inputs/Date/DatePicker/Generic.tsx +20 -10
- package/src/components/inputs/Date/DateRangePicker/Context.tsx +12 -1
- package/src/components/inputs/Date/DateRangePicker/Controlled.tsx +74 -0
- package/src/components/inputs/Date/DateRangePicker/DateRangePicker.stories.tsx +11 -6
- package/src/components/inputs/Date/DateRangePicker/DateSelector/Absolute.tsx +3 -3
- package/src/components/inputs/Date/DateRangePicker/DateSelector/Relative.tsx +1 -1
- package/src/components/inputs/Date/DateRangePicker/DateSelector/index.tsx +1 -1
- package/src/components/inputs/Date/DateRangePicker/{index.tsx → Generic.tsx} +43 -11
- package/src/components/inputs/Date/DateRangePicker/QuickSelect/index.tsx +1 -1
- package/src/components/inputs/Date/DateRangePicker/style.ts +19 -5
- package/src/components/inputs/Date/subcomponents/Calendar/index.tsx +1 -1
- package/src/components/inputs/Date/subcomponents/RelativePicker/index.tsx +1 -1
- package/src/components/inputs/DurationField/Generic.tsx +149 -152
- package/src/components/inputs/FileField/FileField.stories.tsx +6 -6
- package/src/components/inputs/FileField/Generic.tsx +101 -99
- package/src/components/inputs/InputProps.ts +0 -2
- package/src/components/inputs/RadioGroup/Controlled.tsx +1 -2
- package/src/components/inputs/RadioGroup/RadioGroup.stories.tsx +6 -4
- package/src/components/inputs/RadioGroup/RadioItem.tsx +54 -53
- package/src/components/inputs/Slider/Generic.tsx +1 -1
- package/src/components/inputs/Slider/Slider.stories.tsx +1 -1
- package/src/components/inputs/Slider/handle.tsx +1 -0
- package/src/components/inputs/Switch/Controlled.tsx +1 -2
- package/src/components/inputs/Switch/Generic.tsx +18 -45
- package/src/components/inputs/Switch/Switch.stories.tsx +2 -4
- package/src/components/inputs/Switch/style.ts +44 -38
- package/src/components/inputs/TagField/Generic.tsx +109 -109
- package/src/components/inputs/TextAreaField/Generic.tsx +41 -39
- package/src/components/inputs/TextAreaField/TextAreaField.stories.tsx +2 -3
- package/src/components/inputs/TextField/Generic.tsx +81 -79
- package/src/components/inputs/TextField/TextField.stories.tsx +3 -4
- package/src/components/inputs/index.ts +3 -2
- package/src/components/inputs/layout/Description.tsx +1 -2
- package/src/components/inputs/layout/InputWrapper.ts +2 -2
- package/src/components/inputs/selects/SelectField/Controlled.tsx +1 -2
- package/src/components/inputs/selects/SelectField/Generic/FilterInput.tsx +4 -1
- package/src/components/inputs/selects/SelectField/SelectField.stories.tsx +9 -10
- package/src/components/inputs/selects/SelectQueryField/Generic/index.tsx +200 -197
- package/src/components/inputs/selects/SelectQueryField/SelectQueryField.stories.tsx +1 -1
- package/src/components/inputs/selects/SubComponents/Option.tsx +3 -3
- package/src/components/inputs/selects/SubComponents/OptionGroup.tsx +1 -1
- package/src/components/inputs/selects/SubComponents/style.ts +18 -4
- package/src/components/inputs/selects/index.tsx +5 -2
- package/src/components/inputs/selects/sharedStyle.ts +1 -0
- package/src/components/navigation/HorizontalNav/index.tsx +5 -32
- package/src/components/navigation/HorizontalNav/style.ts +11 -26
- package/src/components/navigation/IconNav/index.tsx +1 -1
- package/src/components/navigation/Steppers/SlimStepper/index.tsx +1 -1
- package/src/components/navigation/Steppers/SlimStepper/style.ts +1 -2
- package/src/components/navigation/Steppers/Stepper/index.tsx +1 -1
- package/src/components/navigation/Steppers/context.tsx +2 -2
- package/src/components/navigation/Tabs/Content.tsx +4 -1
- package/src/components/navigation/Tabs/Trigger.tsx +24 -23
- package/src/components/navigation/index.ts +1 -1
- package/src/components/other/ActionMenu/ActionMenu.stories.tsx +1 -2
- package/src/components/other/ActionMenu/index.tsx +30 -29
- package/src/components/other/Collapsible/CollapsibleTrigger.tsx +8 -4
- package/src/components/other/Company/index.tsx +25 -26
- package/src/components/other/Empty/Empty.stories.tsx +1 -1
- package/src/components/other/Empty/index.tsx +1 -3
- package/src/components/other/PermissionsGuard/index.tsx +2 -2
- package/src/components/visual/Card/index.tsx +4 -1
- package/src/errors/base.ts +4 -1
- package/src/errors/errors.ts +19 -2
- package/src/helpers/getSnackbarProvider.tsx +3 -3
- package/src/helpers/regexprs.ts +1 -0
- package/src/hooks/useFocus.tsx +3 -1
- package/src/hooks/useOnScreen.ts +1 -1
- package/src/hooks/useTableActions.ts +10 -5
- package/src/styled/GlobalStyle.ts +2 -1
- package/src/styled/zIndex.ts +1 -1
- package/src/test/testUtils.tsx +3 -0
- 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,
|
|
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
|
-
|
|
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(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
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
|
|
185
|
-
columnFilters: columnFiltering
|
|
186
|
-
globalFilter: columnSearch
|
|
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
|
-
{
|
|
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
|
|
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
|
-
|
|
340
|
+
|
|
341
|
+
{!isLoading && table.getPageCount() * table.getRowCount() > MINIMUM_ROW_COUNT_FOR_PAGINATION && (
|
|
327
342
|
<tfoot>
|
|
328
343
|
<tr>
|
|
329
|
-
|
|
344
|
+
{/* This is the row selection */}
|
|
345
|
+
{ROW_SELECTION_COL_SPAN ? <td colSpan={1} /> : null}
|
|
330
346
|
{pagination && (
|
|
331
|
-
|
|
332
|
-
colSpan={
|
|
333
|
-
|
|
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
|
-
|
|
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
|
-
</
|
|
355
|
-
|
|
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
|
-
|
|
134
|
-
|
|
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
|
-
|
|
145
|
-
|
|
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}
|
|
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
|
-
|
|
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?.
|
|
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().
|
|
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().
|
|
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().
|
|
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 {
|
|
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
|
|
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
|
|
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
|
-
<
|
|
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
|
-
</
|
|
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
|
+
};
|
|
@@ -41,22 +41,23 @@ export interface DialogBodyProps {
|
|
|
41
41
|
size?: Size;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export const DialogBody = forwardRef<HTMLParagraphElement, PropsWithChildren<DialogBodyProps>>(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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>>(
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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();
|