@rebasepro/ui 0.17.3 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/components/MultiSelect.d.ts +10 -0
- package/dist/index.es.js +2 -1
- package/dist/index.es.js.map +1 -1
- package/package.json +32 -23
- package/src/components/Alert.tsx +0 -118
- package/src/components/Autocomplete.tsx +0 -93
- package/src/components/Avatar.tsx +0 -73
- package/src/components/Badge.tsx +0 -44
- package/src/components/BooleanSwitch.tsx +0 -116
- package/src/components/BooleanSwitchWithLabel.tsx +0 -120
- package/src/components/Button.tsx +0 -110
- package/src/components/Card.tsx +0 -43
- package/src/components/CenteredView.tsx +0 -35
- package/src/components/Checkbox.tsx +0 -129
- package/src/components/Chip.tsx +0 -131
- package/src/components/CircularProgress.tsx +0 -53
- package/src/components/CircularProgressCenter.tsx +0 -27
- package/src/components/Collapse.tsx +0 -66
- package/src/components/ColorPicker.tsx +0 -140
- package/src/components/Container.tsx +0 -51
- package/src/components/DateTimeField.tsx +0 -363
- package/src/components/DebouncedTextField.tsx +0 -76
- package/src/components/Dialog.tsx +0 -159
- package/src/components/DialogActions.tsx +0 -29
- package/src/components/DialogContent.tsx +0 -27
- package/src/components/DialogTitle.tsx +0 -41
- package/src/components/ErrorBoundary.tsx +0 -236
- package/src/components/ExpandablePanel.tsx +0 -130
- package/src/components/FileUpload.tsx +0 -103
- package/src/components/FilterChip.tsx +0 -89
- package/src/components/IconButton.tsx +0 -101
- package/src/components/InfoLabel.tsx +0 -23
- package/src/components/InputLabel.tsx +0 -40
- package/src/components/Label.tsx +0 -32
- package/src/components/LoadingButton.tsx +0 -32
- package/src/components/Markdown.tsx +0 -55
- package/src/components/Menu.tsx +0 -114
- package/src/components/Menubar.tsx +0 -355
- package/src/components/MultiSelect.tsx +0 -433
- package/src/components/Paper.tsx +0 -23
- package/src/components/Popover.tsx +0 -162
- package/src/components/RadioGroup.tsx +0 -74
- package/src/components/ResizablePanels.tsx +0 -189
- package/src/components/SearchBar.tsx +0 -136
- package/src/components/Select.tsx +0 -326
- package/src/components/Separator.tsx +0 -28
- package/src/components/Sheet.tsx +0 -135
- package/src/components/Skeleton.tsx +0 -54
- package/src/components/Slider.tsx +0 -110
- package/src/components/Table.tsx +0 -178
- package/src/components/Tabs.tsx +0 -185
- package/src/components/TextField.tsx +0 -270
- package/src/components/TextareaAutosize.tsx +0 -368
- package/src/components/ToggleButtonGroup.tsx +0 -69
- package/src/components/Tooltip.tsx +0 -153
- package/src/components/Typography.tsx +0 -132
- package/src/components/VirtualTable/VirtualTable.performance.test.tsx +0 -90
- package/src/components/VirtualTable/VirtualTable.tsx +0 -700
- package/src/components/VirtualTable/VirtualTableCell.tsx +0 -59
- package/src/components/VirtualTable/VirtualTableHeader.tsx +0 -327
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +0 -250
- package/src/components/VirtualTable/VirtualTableProps.tsx +0 -339
- package/src/components/VirtualTable/VirtualTableRow.tsx +0 -51
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +0 -44
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -89
- package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +0 -71
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +0 -107
- package/src/components/VirtualTable/fields/VirtualTableSwitch.tsx +0 -28
- package/src/components/VirtualTable/index.tsx +0 -10
- package/src/components/VirtualTable/selection/SelectionContext.tsx +0 -36
- package/src/components/VirtualTable/selection/SelectionStore.ts +0 -54
- package/src/components/VirtualTable/types.tsx +0 -47
- package/src/components/common/SelectInputLabel.tsx +0 -23
- package/src/components/index.tsx +0 -62
- package/src/hooks/PortalContainerContext.tsx +0 -50
- package/src/hooks/index.ts +0 -7
- package/src/hooks/useDebounceCallback.tsx +0 -21
- package/src/hooks/useDebounceValue.tsx +0 -20
- package/src/hooks/useDebouncedCallback.ts +0 -39
- package/src/hooks/useInjectStyles.tsx +0 -31
- package/src/hooks/useOutsideAlerter.tsx +0 -46
- package/src/icons/GitHubIcon.tsx +0 -21
- package/src/icons/HandleIcon.tsx +0 -23
- package/src/icons/Icon.tsx +0 -33
- package/src/icons/LucideIconByName.tsx +0 -117
- package/src/icons/cool_icon_keys.ts +0 -12
- package/src/icons/icon_keys.ts +0 -1936
- package/src/icons/index.ts +0 -179
- package/src/index.css +0 -169
- package/src/index.ts +0 -47
- package/src/scripts/fixIconSizes.cjs +0 -92
- package/src/scripts/fixIconSizesToConst.cjs +0 -106
- package/src/scripts/generateIconKeys.ts +0 -41
- package/src/scripts/generateIcons.ts +0 -4
- package/src/scripts/saveIconFiles.ts +0 -89
- package/src/styles.ts +0 -141
- package/src/theme.css +0 -168
- package/src/util/chip_colors.ts +0 -242
- package/src/util/cls.ts +0 -8
- package/src/util/debounce.ts +0 -28
- package/src/util/hash.ts +0 -11
- package/src/util/index.ts +0 -4
- package/src/util/key_to_icon_component.ts +0 -11
- package/src/util/lazy_chunk.ts +0 -101
- package/src/views/CardView.tsx +0 -281
- package/src/views/CollectionView/CollectionCardView.tsx +0 -265
- package/src/views/CollectionView/CollectionKanbanView.tsx +0 -246
- package/src/views/CollectionView/CollectionListView.tsx +0 -240
- package/src/views/CollectionView/CollectionTableView.tsx +0 -229
- package/src/views/CollectionView/CollectionView.tsx +0 -450
- package/src/views/CollectionView/CollectionViewToolbar.tsx +0 -242
- package/src/views/CollectionView/CollectionViewTypes.ts +0 -181
- package/src/views/CollectionView/DefaultCellRenderer.tsx +0 -404
- package/src/views/CollectionView/index.ts +0 -39
- package/src/views/CollectionView/resolveTitleProperty.ts +0 -52
- package/src/views/CollectionView/utils.ts +0 -14
- package/src/views/Kanban/Board.tsx +0 -384
- package/src/views/Kanban/BoardColumn.tsx +0 -138
- package/src/views/Kanban/BoardColumnTitle.tsx +0 -47
- package/src/views/Kanban/BoardSortableList.tsx +0 -182
- package/src/views/Kanban/board_types.ts +0 -80
- package/src/views/Kanban/index.tsx +0 -5
- package/src/views/Kanban/placement.ts +0 -62
- package/src/views/KanbanView.tsx +0 -32
- package/src/views/ListView.tsx +0 -296
- package/src/views/index.ts +0 -5
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import { deepEqual as equal } from "fast-equals"
|
|
4
|
-
|
|
5
|
-
import { CellRendererParams, VirtualTableColumn } from "./VirtualTableProps";
|
|
6
|
-
|
|
7
|
-
type VirtualTableCellProps<T> = {
|
|
8
|
-
dataKey: string;
|
|
9
|
-
column: VirtualTableColumn;
|
|
10
|
-
columns: VirtualTableColumn[];
|
|
11
|
-
rowData: T;
|
|
12
|
-
cellData: unknown;
|
|
13
|
-
rowIndex: number;
|
|
14
|
-
columnIndex: number;
|
|
15
|
-
cellRenderer: (props: CellRendererParams<T>) => React.ReactNode;
|
|
16
|
-
// Sortable props
|
|
17
|
-
sortableNodeRef?: (node: HTMLElement | null) => void;
|
|
18
|
-
sortableStyle?: React.CSSProperties;
|
|
19
|
-
sortableAttributes?: Record<string, unknown>;
|
|
20
|
-
isDragging?: boolean;
|
|
21
|
-
isDraggable?: boolean;
|
|
22
|
-
frozen?: boolean;
|
|
23
|
-
extraData?: unknown;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const VirtualTableCell = React.memo<VirtualTableCellProps<unknown>>(
|
|
27
|
-
function VirtualTableCell<T>(props: VirtualTableCellProps<T>) {
|
|
28
|
-
return props.rowData ? props.cellRenderer(
|
|
29
|
-
{
|
|
30
|
-
cellData: props.cellData,
|
|
31
|
-
rowData: props.rowData,
|
|
32
|
-
rowIndex: props.rowIndex,
|
|
33
|
-
isScrolling: false,
|
|
34
|
-
column: props.column,
|
|
35
|
-
columns: props.columns,
|
|
36
|
-
columnIndex: props.columnIndex,
|
|
37
|
-
width: props.column.width,
|
|
38
|
-
sortableNodeRef: props.sortableNodeRef,
|
|
39
|
-
sortableStyle: props.sortableStyle,
|
|
40
|
-
sortableAttributes: props.sortableAttributes,
|
|
41
|
-
isDragging: props.isDragging,
|
|
42
|
-
isDraggable: props.isDraggable,
|
|
43
|
-
frozen: props.frozen,
|
|
44
|
-
extraData: props.extraData
|
|
45
|
-
} as CellRendererParams<T>
|
|
46
|
-
) : null;
|
|
47
|
-
},
|
|
48
|
-
(a, b) => {
|
|
49
|
-
return equal(a.rowData, b.rowData) &&
|
|
50
|
-
equal(a.column, b.column) &&
|
|
51
|
-
equal(a.cellData, b.cellData) &&
|
|
52
|
-
a.rowIndex === b.rowIndex &&
|
|
53
|
-
a.columnIndex === b.columnIndex &&
|
|
54
|
-
a.isDragging === b.isDragging &&
|
|
55
|
-
a.isDraggable === b.isDraggable &&
|
|
56
|
-
a.frozen === b.frozen &&
|
|
57
|
-
equal(a.extraData, b.extraData)
|
|
58
|
-
}
|
|
59
|
-
);
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
import { ArrowUpIcon, FilterIcon } from "lucide-react";
|
|
2
|
-
import { iconSize } from "../../icons/Icon";
|
|
3
|
-
|
|
4
|
-
import React, { RefObject, useCallback, useEffect, useState } from "react";
|
|
5
|
-
import { deepEqual as equal } from "fast-equals";
|
|
6
|
-
|
|
7
|
-
import { VirtualTableColumn, VirtualTableSort, VirtualTableWhereFilterOp } from "./VirtualTableProps";
|
|
8
|
-
import { ErrorBoundary } from "../ErrorBoundary";
|
|
9
|
-
import { Badge } from "../Badge";
|
|
10
|
-
import { Button } from "../Button";
|
|
11
|
-
import { IconButton } from "../IconButton";
|
|
12
|
-
import { Popover } from "../Popover";
|
|
13
|
-
import { defaultBorderMixin } from "../../styles";
|
|
14
|
-
import { cls } from "../../util/cls";
|
|
15
|
-
interface FilterFormProps<T> {
|
|
16
|
-
column: VirtualTableColumn<T>;
|
|
17
|
-
onFilterUpdate: (filter?: [VirtualTableWhereFilterOp, unknown], newOpenFilterState?: boolean) => void;
|
|
18
|
-
filter?: [VirtualTableWhereFilterOp, unknown];
|
|
19
|
-
onHover: boolean,
|
|
20
|
-
createFilterField: (props: FilterFormFieldProps<T>) => React.ReactNode;
|
|
21
|
-
hidden: boolean;
|
|
22
|
-
setHidden: (hidden: boolean) => void;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type FilterFormFieldProps<CustomProps> = {
|
|
26
|
-
id: React.Key,
|
|
27
|
-
filterValue: [VirtualTableWhereFilterOp, unknown] | undefined,
|
|
28
|
-
setFilterValue: (filterValue?: [VirtualTableWhereFilterOp, unknown]) => void;
|
|
29
|
-
column: VirtualTableColumn<CustomProps>;
|
|
30
|
-
hidden: boolean;
|
|
31
|
-
setHidden: (hidden: boolean) => void;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
type VirtualTableHeaderProps<M extends Record<string, unknown>> = {
|
|
35
|
-
resizeHandleRef: React.Ref<HTMLDivElement>;
|
|
36
|
-
columnIndex: number;
|
|
37
|
-
isResizingIndex: number;
|
|
38
|
-
column: VirtualTableColumn<unknown>;
|
|
39
|
-
onColumnSort: (key: Extract<keyof M, string>, additive?: boolean) => void;
|
|
40
|
-
filter?: [VirtualTableWhereFilterOp, unknown];
|
|
41
|
-
sort: VirtualTableSort;
|
|
42
|
-
/**
|
|
43
|
-
* This column's zero-based rank in a multi-key sort, or `undefined` when
|
|
44
|
-
* only one column is sorted and a rank would say nothing.
|
|
45
|
-
*/
|
|
46
|
-
sortPosition?: number;
|
|
47
|
-
onFilterUpdate: (column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, unknown]) => void;
|
|
48
|
-
onClickResizeColumn?: (columnIndex: number, column: VirtualTableColumn) => void;
|
|
49
|
-
createFilterField?: (props: FilterFormFieldProps<unknown>) => React.ReactNode;
|
|
50
|
-
AdditionalHeaderWidget?: (props: { onHover: boolean }) => React.ReactNode;
|
|
51
|
-
isDragging?: boolean;
|
|
52
|
-
isDraggable?: boolean;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* What the next click on this column's sort control will do, spelled out for
|
|
57
|
-
* the tooltip and for screen readers. An unlabelled arrow that means three
|
|
58
|
-
* different things depending on the state it is in is a control you have to
|
|
59
|
-
* click to learn.
|
|
60
|
-
*/
|
|
61
|
-
function sortActionTitle(sort: VirtualTableSort, sortPosition?: number): string {
|
|
62
|
-
const rank = sortPosition !== undefined ? ` (sort key ${sortPosition + 1})` : "";
|
|
63
|
-
const addKey = " — shift-click to add it under the current sort instead";
|
|
64
|
-
if (sort === "asc") return `Sorted ascending${rank}. Click to sort descending.${addKey}`;
|
|
65
|
-
if (sort === "desc") return `Sorted descending${rank}. Click to remove this sort.${addKey}`;
|
|
66
|
-
return `Click to sort ascending.${addKey}`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<Record<string, unknown>>>(
|
|
70
|
-
function VirtualTableHeader<M extends Record<string, unknown>>({
|
|
71
|
-
resizeHandleRef,
|
|
72
|
-
columnIndex,
|
|
73
|
-
isResizingIndex,
|
|
74
|
-
sort,
|
|
75
|
-
sortPosition,
|
|
76
|
-
onColumnSort,
|
|
77
|
-
onFilterUpdate,
|
|
78
|
-
filter,
|
|
79
|
-
column,
|
|
80
|
-
onClickResizeColumn,
|
|
81
|
-
createFilterField,
|
|
82
|
-
AdditionalHeaderWidget,
|
|
83
|
-
isDragging,
|
|
84
|
-
isDraggable
|
|
85
|
-
}: VirtualTableHeaderProps<M>) {
|
|
86
|
-
|
|
87
|
-
const [onHover, setOnHover] = useState(false);
|
|
88
|
-
|
|
89
|
-
const [openFilter, setOpenFilter] = React.useState(false);
|
|
90
|
-
const [hidden, setHidden] = React.useState(false);
|
|
91
|
-
|
|
92
|
-
const handleSettingsClick = useCallback((_event: React.MouseEvent) => {
|
|
93
|
-
setOpenFilter(true);
|
|
94
|
-
}, []);
|
|
95
|
-
|
|
96
|
-
const update = useCallback((filterForProperty?: [VirtualTableWhereFilterOp, unknown], newOpenFilterState?: boolean) => {
|
|
97
|
-
onFilterUpdate(column, filterForProperty);
|
|
98
|
-
if (newOpenFilterState !== undefined)
|
|
99
|
-
setOpenFilter(newOpenFilterState);
|
|
100
|
-
}, [column, onFilterUpdate]);
|
|
101
|
-
|
|
102
|
-
const thisColumnIsResizing = isResizingIndex === columnIndex;
|
|
103
|
-
const anotherColumnIsResizing = isResizingIndex !== columnIndex && isResizingIndex > 0;
|
|
104
|
-
|
|
105
|
-
const hovered = !anotherColumnIsResizing && (onHover || thisColumnIsResizing);
|
|
106
|
-
|
|
107
|
-
return (
|
|
108
|
-
<ErrorBoundary>
|
|
109
|
-
<div
|
|
110
|
-
className={cls("flex py-0 px-3 h-full text-xs uppercase font-semibold relative select-none items-center",
|
|
111
|
-
isDragging
|
|
112
|
-
? "bg-primary-bg dark:bg-primary-bg-dark"
|
|
113
|
-
: "bg-surface-50 dark:bg-surface-900",
|
|
114
|
-
"text-text-secondary hover:text-text-primary dark:text-text-secondary-dark dark:hover:text-text-primary-dark",
|
|
115
|
-
!isDragging && "hover:bg-surface-100 dark:hover:bg-surface-900 hover:bg-opacity-50 hover:bg-surface-100/50 dark:hover:bg-opacity-50 dark:hover:bg-surface-900/50",
|
|
116
|
-
column.frozen ? "sticky left-0 z-10" : "relative z-0",
|
|
117
|
-
isDraggable && "cursor-grab"
|
|
118
|
-
)}
|
|
119
|
-
style={{
|
|
120
|
-
left: column.frozen ? 0 : undefined,
|
|
121
|
-
minWidth: column.width,
|
|
122
|
-
maxWidth: column.width
|
|
123
|
-
}}
|
|
124
|
-
onMouseEnter={() => setOnHover(true)}
|
|
125
|
-
onMouseMove={() => setOnHover(true)}
|
|
126
|
-
onMouseLeave={() => setOnHover(false)}
|
|
127
|
-
>
|
|
128
|
-
|
|
129
|
-
<div className="overflow-hidden grow">
|
|
130
|
-
<div
|
|
131
|
-
className={`flex items-center justify-${column.headerAlign} flex-row`}>
|
|
132
|
-
|
|
133
|
-
{column.icon && (
|
|
134
|
-
<div className="flex-shrink-0 flex items-center justify-center mr-1">
|
|
135
|
-
{React.isValidElement(column.icon) ? (
|
|
136
|
-
React.cloneElement(column.icon as React.ReactElement<any>, {
|
|
137
|
-
size: 14,
|
|
138
|
-
className: cls((column.icon as React.ReactElement<any>).props?.className, "flex-shrink-0")
|
|
139
|
-
})
|
|
140
|
-
) : (
|
|
141
|
-
column.icon
|
|
142
|
-
)}
|
|
143
|
-
</div>
|
|
144
|
-
)}
|
|
145
|
-
|
|
146
|
-
<div
|
|
147
|
-
className="truncate -webkit-box w-full mr-1 overflow-hidden"
|
|
148
|
-
style={{
|
|
149
|
-
WebkitBoxOrient: "vertical",
|
|
150
|
-
WebkitLineClamp: 2,
|
|
151
|
-
justifyContent: column.align
|
|
152
|
-
}}>
|
|
153
|
-
{column.title}
|
|
154
|
-
</div>
|
|
155
|
-
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
<>
|
|
159
|
-
|
|
160
|
-
{AdditionalHeaderWidget &&
|
|
161
|
-
<AdditionalHeaderWidget onHover={onHover || openFilter}/>}
|
|
162
|
-
|
|
163
|
-
{column.sortable && (sort || hovered || openFilter) &&
|
|
164
|
-
<div className="flex-shrink-0 flex items-center">
|
|
165
|
-
<Badge color="secondary"
|
|
166
|
-
invisible={!sort}>
|
|
167
|
-
<IconButton
|
|
168
|
-
size={"small"}
|
|
169
|
-
className={onHover || openFilter ? "bg-white dark:bg-surface-900" : undefined}
|
|
170
|
-
// Shift keeps the sort already in place
|
|
171
|
-
// and adds this column beneath it, which
|
|
172
|
-
// is how a two-key order is built from
|
|
173
|
-
// header clicks. Plain click still
|
|
174
|
-
// replaces the whole sort, so the common
|
|
175
|
-
// case takes no modifier and nothing a
|
|
176
|
-
// user knew before stops working.
|
|
177
|
-
title={sortActionTitle(sort, sortPosition)}
|
|
178
|
-
aria-label={sortActionTitle(sort, sortPosition)}
|
|
179
|
-
onClick={(event: React.MouseEvent) => {
|
|
180
|
-
onColumnSort(column.key as Extract<keyof M, string>, event.shiftKey);
|
|
181
|
-
}}
|
|
182
|
-
>
|
|
183
|
-
{!sort &&
|
|
184
|
-
<ArrowUpIcon size={14} className="flex-shrink-0" />}
|
|
185
|
-
{sort === "asc" &&
|
|
186
|
-
<ArrowUpIcon size={14} className="flex-shrink-0" />}
|
|
187
|
-
{sort === "desc" &&
|
|
188
|
-
<ArrowUpIcon size={14} className="flex-shrink-0 rotate-180" />}
|
|
189
|
-
</IconButton>
|
|
190
|
-
</Badge>
|
|
191
|
-
{/* The rank, shown only once there is more than
|
|
192
|
-
one key: two arrows with no numbers beside
|
|
193
|
-
them say a table is sorted by both columns
|
|
194
|
-
and nothing about which one decides. */}
|
|
195
|
-
{sort && sortPosition !== undefined && (
|
|
196
|
-
<span
|
|
197
|
-
className="flex-shrink-0 -ml-0.5 mr-0.5 text-[10px] font-semibold leading-none tabular-nums text-text-secondary dark:text-text-secondary-dark"
|
|
198
|
-
aria-hidden={true}
|
|
199
|
-
>
|
|
200
|
-
{sortPosition + 1}
|
|
201
|
-
</span>
|
|
202
|
-
)}
|
|
203
|
-
</div>
|
|
204
|
-
}
|
|
205
|
-
</>
|
|
206
|
-
|
|
207
|
-
{column.filter && createFilterField && <div className="flex-shrink-0">
|
|
208
|
-
<Badge color="secondary"
|
|
209
|
-
invisible={!filter}>
|
|
210
|
-
|
|
211
|
-
<Popover
|
|
212
|
-
open={openFilter}
|
|
213
|
-
onOpenChange={setOpenFilter}
|
|
214
|
-
className={hidden ? "hidden" : undefined}
|
|
215
|
-
modal={true}
|
|
216
|
-
trigger={
|
|
217
|
-
<IconButton
|
|
218
|
-
className={onHover || openFilter ? "bg-white dark:bg-surface-900" : undefined}
|
|
219
|
-
size={"small"}
|
|
220
|
-
onClick={handleSettingsClick}>
|
|
221
|
-
<FilterIcon size={14} className="flex-shrink-0"/>
|
|
222
|
-
</IconButton>}
|
|
223
|
-
>
|
|
224
|
-
<FilterForm column={column}
|
|
225
|
-
filter={filter}
|
|
226
|
-
onHover={onHover}
|
|
227
|
-
onFilterUpdate={update}
|
|
228
|
-
createFilterField={createFilterField}
|
|
229
|
-
hidden={hidden}
|
|
230
|
-
setHidden={setHidden}/>
|
|
231
|
-
|
|
232
|
-
</Popover>
|
|
233
|
-
|
|
234
|
-
</Badge>
|
|
235
|
-
|
|
236
|
-
</div>}
|
|
237
|
-
|
|
238
|
-
{column.resizable && <div
|
|
239
|
-
ref={resizeHandleRef as React.Ref<HTMLDivElement>}
|
|
240
|
-
data-no-dnd="true"
|
|
241
|
-
className={cls(
|
|
242
|
-
"absolute h-full w-[6px] top-0 right-0 cursor-col-resize",
|
|
243
|
-
hovered && "bg-surface-300 dark:bg-surface-700"
|
|
244
|
-
)}
|
|
245
|
-
onPointerDown={(e) => {
|
|
246
|
-
e.stopPropagation();
|
|
247
|
-
if (onClickResizeColumn) {
|
|
248
|
-
onClickResizeColumn(columnIndex, column);
|
|
249
|
-
}
|
|
250
|
-
}}
|
|
251
|
-
/>}
|
|
252
|
-
</div>
|
|
253
|
-
|
|
254
|
-
</ErrorBoundary>
|
|
255
|
-
);
|
|
256
|
-
}, equal) as React.FunctionComponent<VirtualTableHeaderProps<Record<string, unknown>>>;
|
|
257
|
-
|
|
258
|
-
function FilterForm<M>({
|
|
259
|
-
column,
|
|
260
|
-
onFilterUpdate,
|
|
261
|
-
filter,
|
|
262
|
-
onHover,
|
|
263
|
-
createFilterField,
|
|
264
|
-
hidden,
|
|
265
|
-
setHidden
|
|
266
|
-
}: FilterFormProps<M>) {
|
|
267
|
-
|
|
268
|
-
const id = column.key;
|
|
269
|
-
|
|
270
|
-
const [filterInternal, setFilterInternal] = useState<[VirtualTableWhereFilterOp, unknown] | undefined>(filter);
|
|
271
|
-
|
|
272
|
-
useEffect(() => {
|
|
273
|
-
setFilterInternal(filter);
|
|
274
|
-
}, [filter]);
|
|
275
|
-
|
|
276
|
-
if (!column.filter) return null;
|
|
277
|
-
|
|
278
|
-
const submit = () => {
|
|
279
|
-
onFilterUpdate(filterInternal, false);
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
const reset = (_e: React.MouseEvent) => {
|
|
283
|
-
onFilterUpdate(undefined, false);
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const filterIsSet = !!filter;
|
|
287
|
-
|
|
288
|
-
const filterField = createFilterField({
|
|
289
|
-
id,
|
|
290
|
-
filterValue: filterInternal,
|
|
291
|
-
setFilterValue: setFilterInternal,
|
|
292
|
-
column,
|
|
293
|
-
hidden,
|
|
294
|
-
setHidden
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
if (!filterField) return null;
|
|
298
|
-
return (
|
|
299
|
-
<form noValidate={true}
|
|
300
|
-
onSubmit={(e) => {
|
|
301
|
-
e.stopPropagation();
|
|
302
|
-
e.preventDefault();
|
|
303
|
-
submit();
|
|
304
|
-
}}
|
|
305
|
-
className={"text-surface-900 dark:text-white"}>
|
|
306
|
-
<div
|
|
307
|
-
className={cls(defaultBorderMixin, "py-4 px-6 typography-label border-b")}>
|
|
308
|
-
{column.title ?? id}
|
|
309
|
-
</div>
|
|
310
|
-
{filterField && <div className="m-4 w-[400px]">
|
|
311
|
-
{filterField}
|
|
312
|
-
</div>}
|
|
313
|
-
<div className="flex justify-end m-4">
|
|
314
|
-
<Button
|
|
315
|
-
className="mr-4"
|
|
316
|
-
disabled={!filterIsSet}
|
|
317
|
-
variant={"text"}
|
|
318
|
-
type="reset"
|
|
319
|
-
aria-label="filter clear"
|
|
320
|
-
onClick={reset}>Clear</Button>
|
|
321
|
-
<Button
|
|
322
|
-
type="submit">Filter</Button>
|
|
323
|
-
</div>
|
|
324
|
-
</form>
|
|
325
|
-
);
|
|
326
|
-
|
|
327
|
-
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import React, { createRef, useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
-
|
|
3
|
-
import { VirtualTableColumn, VirtualTableWhereFilterOp } from "./VirtualTableProps";
|
|
4
|
-
import { ErrorBoundary } from "../ErrorBoundary";
|
|
5
|
-
import { VirtualTableHeader } from "./VirtualTableHeader";
|
|
6
|
-
import { VirtualTableContextProps } from "./types";
|
|
7
|
-
import { defaultBorderMixin } from "../../styles";
|
|
8
|
-
import { cls } from "../../util/cls";import { useSortable } from "@dnd-kit/sortable";
|
|
9
|
-
import { CSS } from "@dnd-kit/utilities";
|
|
10
|
-
|
|
11
|
-
// Sortable column header wrapper
|
|
12
|
-
const SortableColumnHeader = ({
|
|
13
|
-
column,
|
|
14
|
-
columnIndex,
|
|
15
|
-
columnRefs,
|
|
16
|
-
isResizing,
|
|
17
|
-
onFilterUpdate,
|
|
18
|
-
filter,
|
|
19
|
-
sortIndex,
|
|
20
|
-
sortCount,
|
|
21
|
-
onColumnSort,
|
|
22
|
-
onClickResizeColumn,
|
|
23
|
-
createFilterField,
|
|
24
|
-
isDragging,
|
|
25
|
-
isDraggable
|
|
26
|
-
}: {
|
|
27
|
-
column: VirtualTableColumn;
|
|
28
|
-
columnIndex: number;
|
|
29
|
-
columnRefs: React.Ref<HTMLDivElement>[];
|
|
30
|
-
isResizing: number;
|
|
31
|
-
onFilterUpdate: (column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, unknown]) => void;
|
|
32
|
-
filter: [VirtualTableWhereFilterOp, unknown] | undefined;
|
|
33
|
-
sortIndex: Map<string, { direction: "asc" | "desc"; position: number }>;
|
|
34
|
-
sortCount: number;
|
|
35
|
-
onColumnSort: (key: string, additive?: boolean) => void;
|
|
36
|
-
onClickResizeColumn: (index: number) => void;
|
|
37
|
-
createFilterField: ((props: import("./VirtualTableHeader").FilterFormFieldProps<unknown>) => React.ReactNode) | undefined;
|
|
38
|
-
isDragging: boolean;
|
|
39
|
-
isDraggable: boolean;
|
|
40
|
-
}) => {
|
|
41
|
-
const [isPressing, setIsPressing] = useState(false);
|
|
42
|
-
|
|
43
|
-
const {
|
|
44
|
-
attributes,
|
|
45
|
-
listeners,
|
|
46
|
-
setNodeRef,
|
|
47
|
-
transform,
|
|
48
|
-
transition
|
|
49
|
-
} = useSortable({
|
|
50
|
-
id: column.key,
|
|
51
|
-
disabled: !isDraggable || column.frozen
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const style = {
|
|
55
|
-
// Only use translate, ignore any scale transforms
|
|
56
|
-
transform: transform ? `translateX(${transform.x}px)` : undefined,
|
|
57
|
-
// Don't transition the dragged item - only other items should animate
|
|
58
|
-
transition: isDragging ? undefined : transition,
|
|
59
|
-
minWidth: column.width,
|
|
60
|
-
maxWidth: column.width,
|
|
61
|
-
width: column.width
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// Combine our press handlers with dnd-kit listeners
|
|
65
|
-
const combinedListeners = isDraggable ? {
|
|
66
|
-
...listeners,
|
|
67
|
-
onPointerDown: (e: React.PointerEvent) => {
|
|
68
|
-
setIsPressing(true);
|
|
69
|
-
listeners?.onPointerDown?.(e);
|
|
70
|
-
},
|
|
71
|
-
onPointerUp: () => setIsPressing(false),
|
|
72
|
-
onPointerCancel: () => setIsPressing(false)
|
|
73
|
-
} : {};
|
|
74
|
-
|
|
75
|
-
// Reset pressing state when drag ends
|
|
76
|
-
React.useEffect(() => {
|
|
77
|
-
if (!isDragging) {
|
|
78
|
-
setIsPressing(false);
|
|
79
|
-
}
|
|
80
|
-
}, [isDragging]);
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<div
|
|
84
|
-
ref={setNodeRef}
|
|
85
|
-
style={style}
|
|
86
|
-
className={cls(
|
|
87
|
-
"flex-shrink-0 h-full",
|
|
88
|
-
column.frozen && "sticky left-0 z-10"
|
|
89
|
-
)}
|
|
90
|
-
{...attributes}
|
|
91
|
-
{...combinedListeners}
|
|
92
|
-
>
|
|
93
|
-
<VirtualTableHeader
|
|
94
|
-
resizeHandleRef={columnRefs[columnIndex]}
|
|
95
|
-
columnIndex={columnIndex}
|
|
96
|
-
isResizingIndex={isResizing}
|
|
97
|
-
onFilterUpdate={onFilterUpdate}
|
|
98
|
-
filter={filter}
|
|
99
|
-
sort={sortIndex.get(column.key)?.direction}
|
|
100
|
-
sortPosition={sortCount > 1 ? sortIndex.get(column.key)?.position : undefined}
|
|
101
|
-
onColumnSort={onColumnSort}
|
|
102
|
-
onClickResizeColumn={onClickResizeColumn}
|
|
103
|
-
column={column}
|
|
104
|
-
createFilterField={createFilterField}
|
|
105
|
-
AdditionalHeaderWidget={column.AdditionalHeaderWidget}
|
|
106
|
-
isDragging={isDragging || isPressing}
|
|
107
|
-
isDraggable={isDraggable}/>
|
|
108
|
-
</div>
|
|
109
|
-
);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export const VirtualTableHeaderRow = ({
|
|
113
|
-
columns,
|
|
114
|
-
sortIndex,
|
|
115
|
-
onColumnSort,
|
|
116
|
-
onFilterUpdate,
|
|
117
|
-
filter,
|
|
118
|
-
onColumnResize,
|
|
119
|
-
onColumnResizeEnd,
|
|
120
|
-
createFilterField,
|
|
121
|
-
AddColumnComponent,
|
|
122
|
-
onColumnsOrderChange,
|
|
123
|
-
data,
|
|
124
|
-
cellRenderer: CellRenderer,
|
|
125
|
-
rowHeight = 54,
|
|
126
|
-
draggingColumnId,
|
|
127
|
-
headerHeight = 48
|
|
128
|
-
}: VirtualTableContextProps<Record<string, unknown>>) => {
|
|
129
|
-
|
|
130
|
-
const columnRefs = useMemo(() => columns.map(() => createRef<HTMLDivElement>()), [columns.length]);
|
|
131
|
-
const [isResizing, setIsResizing] = useState(-1);
|
|
132
|
-
|
|
133
|
-
const adjustWidthColumn = useCallback((index: number, width: number, end: boolean) => {
|
|
134
|
-
const column = columns[index];
|
|
135
|
-
const minWidth = 100;
|
|
136
|
-
const maxWidth = 800;
|
|
137
|
-
const newWidth = width > maxWidth ? maxWidth : (width < minWidth ? minWidth : width);
|
|
138
|
-
const params = {
|
|
139
|
-
width: newWidth,
|
|
140
|
-
key: column.key as string,
|
|
141
|
-
column: {
|
|
142
|
-
...column,
|
|
143
|
-
width: newWidth
|
|
144
|
-
} as VirtualTableColumn
|
|
145
|
-
};
|
|
146
|
-
if (!end)
|
|
147
|
-
onColumnResize(params);
|
|
148
|
-
else
|
|
149
|
-
onColumnResizeEnd(params);
|
|
150
|
-
}, [columns, onColumnResize, onColumnResizeEnd]);
|
|
151
|
-
|
|
152
|
-
const getEventNewWidth = useCallback((e: MouseEvent) => {
|
|
153
|
-
if (isResizing >= 0) {
|
|
154
|
-
const left = columnRefs[isResizing].current?.parentElement?.getBoundingClientRect().left;
|
|
155
|
-
if (!left) return;
|
|
156
|
-
return e.clientX - left;
|
|
157
|
-
}
|
|
158
|
-
return undefined;
|
|
159
|
-
}, [columnRefs, isResizing]);
|
|
160
|
-
|
|
161
|
-
const setCursorDocument = useCallback((isResizing: boolean) => {
|
|
162
|
-
document.body.style.cursor = isResizing ? "col-resize" : "auto";
|
|
163
|
-
}, []);
|
|
164
|
-
|
|
165
|
-
const handleOnMouseMove = useCallback((e: MouseEvent) => {
|
|
166
|
-
e.stopPropagation();
|
|
167
|
-
e.preventDefault();
|
|
168
|
-
const newWidth = getEventNewWidth(e);
|
|
169
|
-
if (newWidth)
|
|
170
|
-
adjustWidthColumn(isResizing, newWidth, false);
|
|
171
|
-
}, [adjustWidthColumn, getEventNewWidth, isResizing]);
|
|
172
|
-
|
|
173
|
-
const handleOnMouseUp = useCallback((e: MouseEvent) => {
|
|
174
|
-
e.stopPropagation();
|
|
175
|
-
e.preventDefault();
|
|
176
|
-
const newWidth = getEventNewWidth(e);
|
|
177
|
-
if (newWidth)
|
|
178
|
-
adjustWidthColumn(isResizing, newWidth, true);
|
|
179
|
-
setIsResizing(-1);
|
|
180
|
-
setCursorDocument(false);
|
|
181
|
-
}, [adjustWidthColumn, getEventNewWidth, isResizing, setCursorDocument]);
|
|
182
|
-
|
|
183
|
-
const removeResizingListeners = useCallback(() => {
|
|
184
|
-
document.removeEventListener("mousemove", handleOnMouseMove);
|
|
185
|
-
document.removeEventListener("mouseup", handleOnMouseUp);
|
|
186
|
-
}, [handleOnMouseMove, handleOnMouseUp]);
|
|
187
|
-
|
|
188
|
-
const attachResizeListeners = useCallback(() => {
|
|
189
|
-
document.addEventListener("mousemove", handleOnMouseMove);
|
|
190
|
-
document.addEventListener("mouseup", handleOnMouseUp);
|
|
191
|
-
}, [handleOnMouseMove, handleOnMouseUp]);
|
|
192
|
-
|
|
193
|
-
useEffect(() => {
|
|
194
|
-
if (isResizing >= 0) {
|
|
195
|
-
attachResizeListeners();
|
|
196
|
-
} else {
|
|
197
|
-
removeResizingListeners();
|
|
198
|
-
}
|
|
199
|
-
return () => {
|
|
200
|
-
removeResizingListeners();
|
|
201
|
-
};
|
|
202
|
-
}, [attachResizeListeners, isResizing, removeResizingListeners]);
|
|
203
|
-
|
|
204
|
-
const onClickResizeColumn = useCallback((index: number) => {
|
|
205
|
-
setIsResizing(index);
|
|
206
|
-
setCursorDocument(true);
|
|
207
|
-
}, [setCursorDocument]);
|
|
208
|
-
|
|
209
|
-
return (
|
|
210
|
-
<>
|
|
211
|
-
<div
|
|
212
|
-
className={cls(defaultBorderMixin, "z-20 sticky min-w-full flex w-fit flex-row top-0 left-0 border-b bg-surface-50 dark:bg-surface-900")}
|
|
213
|
-
style={{ height: headerHeight }}>
|
|
214
|
-
{columns.map((column, columnIndex) => {
|
|
215
|
-
const columnFilter = column && filter && filter[column.key] ? filter[column.key] : undefined;
|
|
216
|
-
const filterForThisProperty: [VirtualTableWhereFilterOp, unknown] | undefined =
|
|
217
|
-
columnFilter
|
|
218
|
-
? (Array.isArray(columnFilter[0]) ? (columnFilter as [VirtualTableWhereFilterOp, unknown][])[0] : (columnFilter as [VirtualTableWhereFilterOp, unknown]))
|
|
219
|
-
: undefined;
|
|
220
|
-
|
|
221
|
-
const isDraggable = !column.frozen && !!onColumnsOrderChange;
|
|
222
|
-
const isDragging = draggingColumnId === column.key;
|
|
223
|
-
|
|
224
|
-
return (
|
|
225
|
-
<ErrorBoundary key={"header_" + column.key}>
|
|
226
|
-
<SortableColumnHeader
|
|
227
|
-
column={column}
|
|
228
|
-
columnIndex={columnIndex}
|
|
229
|
-
columnRefs={columnRefs}
|
|
230
|
-
isResizing={isResizing}
|
|
231
|
-
onFilterUpdate={onFilterUpdate}
|
|
232
|
-
filter={filterForThisProperty}
|
|
233
|
-
sortIndex={sortIndex}
|
|
234
|
-
sortCount={sortIndex.size}
|
|
235
|
-
onColumnSort={onColumnSort}
|
|
236
|
-
onClickResizeColumn={onClickResizeColumn}
|
|
237
|
-
createFilterField={createFilterField}
|
|
238
|
-
isDragging={isDragging}
|
|
239
|
-
isDraggable={isDraggable}
|
|
240
|
-
/>
|
|
241
|
-
</ErrorBoundary>
|
|
242
|
-
);
|
|
243
|
-
})}
|
|
244
|
-
|
|
245
|
-
{AddColumnComponent && <AddColumnComponent/>}
|
|
246
|
-
|
|
247
|
-
</div>
|
|
248
|
-
</>
|
|
249
|
-
);
|
|
250
|
-
};
|