@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,339 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import React from "react";
|
|
4
|
-
import type { FilterFormFieldProps } from "./VirtualTableHeader";
|
|
5
|
-
|
|
6
|
-
/** One sort key: the column, and which way it runs. */
|
|
7
|
-
export type VirtualTableSortKey = [string, "asc" | "desc"];
|
|
8
|
-
|
|
9
|
-
export type OnRowClickParams<T extends Record<string, unknown>> = {
|
|
10
|
-
rowData: T;
|
|
11
|
-
rowIndex: number;
|
|
12
|
-
event: React.SyntheticEvent
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @see Table
|
|
17
|
-
* @group Components
|
|
18
|
-
*/
|
|
19
|
-
export interface VirtualTableProps<T extends Record<string, unknown>> {
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Array of arbitrary data
|
|
23
|
-
*/
|
|
24
|
-
data?: T[];
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Properties displayed in this collection. If this property is not set
|
|
28
|
-
* every property is displayed, you can filter
|
|
29
|
-
*/
|
|
30
|
-
columns: VirtualTableColumn[];
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Custom cell renderer
|
|
34
|
-
* The renderer receives props `{ cellData, columns, column, columnIndex, rowData, rowIndex, container, isScrolling }`
|
|
35
|
-
*/
|
|
36
|
-
cellRenderer: (props: CellRendererParams<T>) => React.ReactNode;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Set this callback if you want to support some combinations
|
|
40
|
-
* of filter combinations only.
|
|
41
|
-
* @param filterValues
|
|
42
|
-
* @param sortBy
|
|
43
|
-
*/
|
|
44
|
-
checkFilterCombination?: (filterValues: VirtualTableFilterValues<Extract<keyof T, string>>,
|
|
45
|
-
sortBy?: VirtualTableSortKey[]) => boolean;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* A callback function when scrolling the table to near the end
|
|
49
|
-
*/
|
|
50
|
-
onEndReached?: () => void;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Offset in pixels where the onEndReached callback is triggered
|
|
54
|
-
*/
|
|
55
|
-
endOffset?: number;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* When the pagination should be reset. E.g. the filters or sorting
|
|
59
|
-
* has been reset.
|
|
60
|
-
*/
|
|
61
|
-
onResetPagination?: () => void;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Callback when a row is clicked
|
|
65
|
-
*/
|
|
66
|
-
onRowClick?: (props: OnRowClickParams<T>) => void;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Callback when a column is resized
|
|
70
|
-
*/
|
|
71
|
-
onColumnResize?: (params: OnVirtualTableColumnResizeParams) => void;
|
|
72
|
-
onColumnResizeEnd?: (params: OnVirtualTableColumnResizeParams) => void;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Size of the table
|
|
76
|
-
*/
|
|
77
|
-
rowHeight?: number,
|
|
78
|
-
headerHeight?: number,
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* In case this table should have some filters set by default
|
|
82
|
-
*/
|
|
83
|
-
filter?: VirtualTableFilterValues<string>;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Callback used when filters are updated
|
|
87
|
-
* @param filter
|
|
88
|
-
*/
|
|
89
|
-
onFilterUpdate?: (filter?: VirtualTableFilterValues<string> | undefined) => void;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Callback when the table is scrolled
|
|
93
|
-
* @param props
|
|
94
|
-
*/
|
|
95
|
-
onScroll?: (props: {
|
|
96
|
-
scrollDirection: "forward" | "backward",
|
|
97
|
-
scrollOffset: number,
|
|
98
|
-
scrollUpdateWasRequested: boolean
|
|
99
|
-
}) => void;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Sort applied to this collection: the keys in order of significance, the
|
|
103
|
-
* second breaking ties on the first.
|
|
104
|
-
*/
|
|
105
|
-
sortBy?: VirtualTableSortKey[];
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Callback used when sorting is updated
|
|
109
|
-
* @param sortBy
|
|
110
|
-
*/
|
|
111
|
-
onSortByUpdate?: (sortBy?: VirtualTableSortKey[]) => void;
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* If there is an error loading data you can pass it here, so it gets
|
|
115
|
-
* displayed instead of the content
|
|
116
|
-
*/
|
|
117
|
-
error?: Error;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Message displayed when there is no data
|
|
121
|
-
*/
|
|
122
|
-
emptyComponent?: React.ReactNode;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Is the table in a loading state
|
|
126
|
-
*/
|
|
127
|
-
loading?: boolean;
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Should apply a different style when hovering
|
|
131
|
-
*/
|
|
132
|
-
hoverRow?: boolean;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Apply a custom class name to the row
|
|
136
|
-
* @param rowData
|
|
137
|
-
*/
|
|
138
|
-
rowClassName?: (rowData: T) => string | undefined;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Callback to create a filter field, displayed in the header as a dropdown
|
|
142
|
-
* @param props
|
|
143
|
-
*/
|
|
144
|
-
createFilterField?: (props: FilterFormFieldProps<unknown>) => React.ReactNode;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Class name applied to the table
|
|
148
|
-
*/
|
|
149
|
-
className?: string;
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Style applied to the table
|
|
153
|
-
*/
|
|
154
|
-
style?: React.CSSProperties;
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Component rendered at the end of the table, after scroll
|
|
158
|
-
*/
|
|
159
|
-
endAdornment?: React.ReactNode;
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* If adding this callback, a button to add a new column is displayed.
|
|
163
|
-
* @param column
|
|
164
|
-
*/
|
|
165
|
-
AddColumnComponent?: React.ComponentType;
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Initial scroll position
|
|
169
|
-
*/
|
|
170
|
-
initialScroll?: number;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Callback when columns are reordered via drag-and-drop.
|
|
174
|
-
* @param columns The new column order
|
|
175
|
-
*/
|
|
176
|
-
onColumnsOrderChange?: (columns: VirtualTableColumn[]) => void;
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Extra data passed to the cell renderer
|
|
180
|
-
*/
|
|
181
|
-
extraData?: unknown;
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export type CellRendererParams<T = unknown> = {
|
|
186
|
-
column: VirtualTableColumn;
|
|
187
|
-
columns: VirtualTableColumn[];
|
|
188
|
-
columnIndex: number;
|
|
189
|
-
rowData?: T;
|
|
190
|
-
rowIndex: number;
|
|
191
|
-
width: number;
|
|
192
|
-
isScrolling?: boolean;
|
|
193
|
-
// Sortable props for dnd-kit integration
|
|
194
|
-
sortableNodeRef?: (node: HTMLElement | null) => void;
|
|
195
|
-
sortableStyle?: React.CSSProperties;
|
|
196
|
-
sortableAttributes?: Record<string, unknown>;
|
|
197
|
-
isDragging?: boolean;
|
|
198
|
-
isDraggable?: boolean;
|
|
199
|
-
frozen?: boolean;
|
|
200
|
-
extraData?: unknown;
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* @see Table
|
|
205
|
-
* @group Components
|
|
206
|
-
*/
|
|
207
|
-
export interface VirtualTableColumn<CustomProps = unknown> {
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Data key for the cell value, could be "a.b.c"
|
|
211
|
-
*/
|
|
212
|
-
key: string;
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* The width of the column, gutter width is not included
|
|
216
|
-
*/
|
|
217
|
-
width: number;
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Label displayed in the header
|
|
221
|
-
*/
|
|
222
|
-
title?: string;
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* This column is frozen to the left
|
|
226
|
-
*/
|
|
227
|
-
frozen?: boolean;
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* How is the
|
|
231
|
-
*/
|
|
232
|
-
headerAlign?: "left" | "center" | "right";
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Icon displayed in the header
|
|
236
|
-
*/
|
|
237
|
-
icon?: React.ReactNode;
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
*
|
|
241
|
-
*/
|
|
242
|
-
filter?: boolean;
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Alignment of the column cell
|
|
246
|
-
*/
|
|
247
|
-
|
|
248
|
-
align?: "left" | "right" | "center";
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Whether the column is sortable, defaults to false
|
|
252
|
-
*/
|
|
253
|
-
sortable?: boolean;
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Can it be resized
|
|
257
|
-
*/
|
|
258
|
-
resizable?: boolean;
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Custom props passed to the cell renderer
|
|
262
|
-
*/
|
|
263
|
-
custom?: CustomProps;
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Additional children to be rendered in the header when hovering
|
|
267
|
-
*/
|
|
268
|
-
AdditionalHeaderWidget?: (props: { onHover: boolean }) => React.ReactNode;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* @see Table
|
|
273
|
-
* @group Collection components
|
|
274
|
-
*/
|
|
275
|
-
export type OnVirtualTableColumnResizeParams = {
|
|
276
|
-
width: number,
|
|
277
|
-
key: string,
|
|
278
|
-
column: VirtualTableColumn
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* The filter operators this table can express.
|
|
283
|
-
*
|
|
284
|
-
* A deliberate copy of `WhereFilterOp` in `@rebasepro/types`, not an import:
|
|
285
|
-
* `@rebasepro/ui` has no dependency on the core types and is meant to stay
|
|
286
|
-
* usable on its own. The cost is that two published packages export the same
|
|
287
|
-
* name, so the two must be kept identical by hand —
|
|
288
|
-
* `packages/types/test/filter-operators-duplication.test.ts` fails if they
|
|
289
|
-
* diverge, because a table that cannot express an operator the query layer
|
|
290
|
-
* supports is a silent gap: the filter simply is not offered.
|
|
291
|
-
*
|
|
292
|
-
* @see Table
|
|
293
|
-
* @group Components
|
|
294
|
-
*/
|
|
295
|
-
export type WhereFilterOp =
|
|
296
|
-
| "<"
|
|
297
|
-
| "<="
|
|
298
|
-
| "=="
|
|
299
|
-
| "!="
|
|
300
|
-
| ">="
|
|
301
|
-
| ">"
|
|
302
|
-
| "array-contains"
|
|
303
|
-
| "in"
|
|
304
|
-
| "not-in"
|
|
305
|
-
| "array-contains-any"
|
|
306
|
-
| "like"
|
|
307
|
-
| "ilike"
|
|
308
|
-
| "not-like"
|
|
309
|
-
| "not-ilike"
|
|
310
|
-
| "is-null"
|
|
311
|
-
| "is-not-null";
|
|
312
|
-
|
|
313
|
-
export type FilterValues<Key extends string> =
|
|
314
|
-
Partial<Record<Key, [WhereFilterOp, unknown] | [WhereFilterOp, unknown][]>>;
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* @see Table
|
|
318
|
-
* @group Components
|
|
319
|
-
*/
|
|
320
|
-
export type VirtualTableSort = "asc" | "desc" | undefined;
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* @see Table
|
|
324
|
-
* @group Components
|
|
325
|
-
*/
|
|
326
|
-
export type VirtualTableFilterValues<Key extends string> = FilterValues<Key>;
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Filter conditions in a `Query.where()` clause, named by {@link WhereFilterOp}.
|
|
330
|
-
*
|
|
331
|
-
* The list is not repeated here: this comment used to name eight operators when
|
|
332
|
-
* the type had sixteen, having been written before the SQL pattern and null
|
|
333
|
-
* checks (`like`, `ilike`, `not-like`, `not-ilike`, `is-null`, `is-not-null`)
|
|
334
|
-
* were added. A prose copy of a union drifts from it silently.
|
|
335
|
-
*
|
|
336
|
-
* @see Table
|
|
337
|
-
* @group Models
|
|
338
|
-
*/
|
|
339
|
-
export type VirtualTableWhereFilterOp = WhereFilterOp;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import React, { useCallback } from "react";
|
|
2
|
-
|
|
3
|
-
import { deepEqual as equal } from "fast-equals"
|
|
4
|
-
|
|
5
|
-
import { VirtualTableRowProps } from "./types";
|
|
6
|
-
import { cls } from "../../util/cls";
|
|
7
|
-
export const VirtualTableRow = React.memo<VirtualTableRowProps<Record<string, unknown>>>(
|
|
8
|
-
function VirtualTableRow<T extends Record<string, unknown>>({
|
|
9
|
-
rowData,
|
|
10
|
-
rowIndex,
|
|
11
|
-
children,
|
|
12
|
-
onRowClick,
|
|
13
|
-
rowHeight,
|
|
14
|
-
style,
|
|
15
|
-
hoverRow,
|
|
16
|
-
rowClassName
|
|
17
|
-
}: VirtualTableRowProps<T>) {
|
|
18
|
-
|
|
19
|
-
const onClick = useCallback((event: React.SyntheticEvent) => {
|
|
20
|
-
if (onRowClick)
|
|
21
|
-
onRowClick({
|
|
22
|
-
rowData,
|
|
23
|
-
rowIndex,
|
|
24
|
-
event
|
|
25
|
-
})
|
|
26
|
-
}, [onRowClick, rowData, rowIndex]);
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<div
|
|
30
|
-
className={cls(
|
|
31
|
-
"flex min-w-full text-sm border-b border-surface-200/60 dark:border-surface-700/60 dark:bg-surface-800",
|
|
32
|
-
rowClassName ? rowClassName(rowData) : "",
|
|
33
|
-
{
|
|
34
|
-
"hover:!bg-primary/[0.03] dark:hover:!bg-primary/5": hoverRow,
|
|
35
|
-
"cursor-pointer ": onRowClick
|
|
36
|
-
}
|
|
37
|
-
)}
|
|
38
|
-
onClick={onClick}
|
|
39
|
-
style={{
|
|
40
|
-
...(style),
|
|
41
|
-
height: rowHeight,
|
|
42
|
-
width: "fit-content"
|
|
43
|
-
}}
|
|
44
|
-
>
|
|
45
|
-
{children}
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
},
|
|
50
|
-
equal
|
|
51
|
-
);
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { cls } from "../../../util";
|
|
3
|
-
import { focusedDisabled } from "../../../styles";
|
|
4
|
-
import { DateTimeField } from "../../DateTimeField";
|
|
5
|
-
|
|
6
|
-
export function VirtualTableDateField(props: {
|
|
7
|
-
name?: string;
|
|
8
|
-
error?: Error;
|
|
9
|
-
mode?: "date" | "date_time";
|
|
10
|
-
timezone?: string;
|
|
11
|
-
internalValue: Date | undefined | null;
|
|
12
|
-
updateValue: (newValue: (Date | null)) => void;
|
|
13
|
-
focused: boolean;
|
|
14
|
-
disabled: boolean;
|
|
15
|
-
small?: boolean;
|
|
16
|
-
locale?: string;
|
|
17
|
-
onBlur?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
18
|
-
}) {
|
|
19
|
-
const { disabled, error, mode, timezone, internalValue, updateValue, small = false, locale } = props;
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<DateTimeField
|
|
23
|
-
value={internalValue ?? undefined}
|
|
24
|
-
onChange={(dateValue) => updateValue(dateValue ?? null)}
|
|
25
|
-
// Same omission as `VirtualTableInput`: destructured and forwarded
|
|
26
|
-
// nowhere, so a disabled date cell was still editable. `error` went
|
|
27
|
-
// the same way — it drives `DateTimeField`'s invalid styling, and a
|
|
28
|
-
// prop a caller passes should reach something rather than sit in a
|
|
29
|
-
// destructure.
|
|
30
|
-
disabled={disabled}
|
|
31
|
-
error={Boolean(error)}
|
|
32
|
-
invisible={true}
|
|
33
|
-
// Without this the field falls back to DateTimeField's own default of
|
|
34
|
-
// `size="large"` (min-h-64px), which overflows a table cell and makes
|
|
35
|
-
// the value collide with the cell border.
|
|
36
|
-
size={small ? "small" : "medium"}
|
|
37
|
-
inputClassName={cls("w-full h-full", focusedDisabled)}
|
|
38
|
-
className={cls("w-full h-full", focusedDisabled)}
|
|
39
|
-
mode={mode}
|
|
40
|
-
timezone={timezone}
|
|
41
|
-
locale={locale}
|
|
42
|
-
/>
|
|
43
|
-
);
|
|
44
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { useDebouncedCallback } from "../../../hooks/useDebouncedCallback";
|
|
3
|
-
import { focusedDisabled } from "../../../styles";
|
|
4
|
-
import { TextareaAutosize } from "../../TextareaAutosize";
|
|
5
|
-
|
|
6
|
-
export function VirtualTableInput(props: {
|
|
7
|
-
error?: Error;
|
|
8
|
-
value: string;
|
|
9
|
-
multiline?: boolean;
|
|
10
|
-
focused: boolean;
|
|
11
|
-
disabled: boolean;
|
|
12
|
-
updateValue: (newValue: (string | null)) => void;
|
|
13
|
-
onBlur?: () => void;
|
|
14
|
-
}) {
|
|
15
|
-
const ref = React.useRef<HTMLTextAreaElement>(null);
|
|
16
|
-
const { disabled, value, multiline = false, updateValue, focused } = props;
|
|
17
|
-
const prevValue = useRef<string | null>(value);
|
|
18
|
-
const [internalValue, setInternalValue] = useState<typeof value>(value);
|
|
19
|
-
const focusedState = useRef<boolean>(false);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
if (prevValue.current !== value && value !== internalValue)
|
|
23
|
-
setInternalValue(value);
|
|
24
|
-
prevValue.current = value;
|
|
25
|
-
}, [value]);
|
|
26
|
-
|
|
27
|
-
const doUpdate = React.useCallback(() => {
|
|
28
|
-
const emptyInitialValue = !value;
|
|
29
|
-
if (emptyInitialValue && !internalValue) return;
|
|
30
|
-
if (internalValue !== value && internalValue !== prevValue.current) {
|
|
31
|
-
prevValue.current = internalValue;
|
|
32
|
-
updateValue(internalValue);
|
|
33
|
-
}
|
|
34
|
-
}, [internalValue, updateValue, value]);
|
|
35
|
-
|
|
36
|
-
useDebouncedCallback(internalValue, doUpdate, !focused, 400);
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (ref.current && focused && !focusedState.current) {
|
|
40
|
-
focusedState.current = true;
|
|
41
|
-
ref.current.focus({ preventScroll: true });
|
|
42
|
-
ref.current.selectionStart = ref.current.value.length;
|
|
43
|
-
ref.current.selectionEnd = ref.current.value.length;
|
|
44
|
-
} else {
|
|
45
|
-
focusedState.current = focused;
|
|
46
|
-
}
|
|
47
|
-
}, [focused, ref]);
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<TextareaAutosize
|
|
51
|
-
className={focusedDisabled}
|
|
52
|
-
ref={ref}
|
|
53
|
-
// Destructured above and passed to nothing, so a property carrying
|
|
54
|
-
// `admin: { disabled: true }` stayed typeable in the table and the
|
|
55
|
-
// debounced write fired on blur. `readOnly` as well as `disabled`:
|
|
56
|
-
// a disabled textarea is skipped by keyboard navigation, and a cell
|
|
57
|
-
// you cannot tab through is worse than one you cannot edit.
|
|
58
|
-
disabled={disabled}
|
|
59
|
-
readOnly={disabled}
|
|
60
|
-
style={{
|
|
61
|
-
padding: 0,
|
|
62
|
-
margin: 0,
|
|
63
|
-
width: "100%",
|
|
64
|
-
color: "unset",
|
|
65
|
-
fontWeight: "unset",
|
|
66
|
-
fontSize: "unset",
|
|
67
|
-
fontFamily: "unset",
|
|
68
|
-
background: "unset",
|
|
69
|
-
border: "unset",
|
|
70
|
-
resize: "none",
|
|
71
|
-
outline: "none"
|
|
72
|
-
}}
|
|
73
|
-
value={internalValue ?? ""}
|
|
74
|
-
onChange={(evt) => {
|
|
75
|
-
const newValue = evt.target.value as string;
|
|
76
|
-
if (multiline || !newValue.endsWith("\n"))
|
|
77
|
-
setInternalValue(newValue);
|
|
78
|
-
}}
|
|
79
|
-
onFocus={() => {
|
|
80
|
-
focusedState.current = true;
|
|
81
|
-
}}
|
|
82
|
-
onBlur={() => {
|
|
83
|
-
focusedState.current = false;
|
|
84
|
-
doUpdate();
|
|
85
|
-
if (props.onBlur) props.onBlur();
|
|
86
|
-
}}
|
|
87
|
-
/>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { useDebouncedCallback } from "../../../hooks/useDebouncedCallback";
|
|
3
|
-
import { cls } from "../../../util";
|
|
4
|
-
import { focusedDisabled } from "../../../styles";
|
|
5
|
-
import { TextField } from "../../TextField";
|
|
6
|
-
|
|
7
|
-
export function VirtualTableNumberInput(props: {
|
|
8
|
-
error?: Error;
|
|
9
|
-
value: number;
|
|
10
|
-
align?: "right" | "left" | "center";
|
|
11
|
-
updateValue: (newValue: (number | null)) => void;
|
|
12
|
-
focused: boolean;
|
|
13
|
-
disabled: boolean;
|
|
14
|
-
}) {
|
|
15
|
-
const { align = "left", value, updateValue, focused } = props;
|
|
16
|
-
const propStringValue = (value && typeof value === "number") ? value.toString() : "";
|
|
17
|
-
const [internalValue, setInternalValue] = useState<string | null>(propStringValue);
|
|
18
|
-
const prevValue = useRef<number | null>(value);
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
if (prevValue.current !== value && String(value) !== internalValue)
|
|
22
|
-
setInternalValue(value ? value.toString() : null);
|
|
23
|
-
prevValue.current = value;
|
|
24
|
-
}, [value]);
|
|
25
|
-
|
|
26
|
-
const doUpdate = React.useCallback(() => {
|
|
27
|
-
if (internalValue !== propStringValue) {
|
|
28
|
-
if (internalValue !== undefined && internalValue !== null) {
|
|
29
|
-
const numberValue = parseFloat(internalValue);
|
|
30
|
-
if (isNaN(numberValue)) return;
|
|
31
|
-
updateValue(numberValue);
|
|
32
|
-
} else {
|
|
33
|
-
updateValue(null);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}, [internalValue, value]);
|
|
37
|
-
|
|
38
|
-
useDebouncedCallback(internalValue, doUpdate, !focused, 400);
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (!focused && propStringValue !== internalValue)
|
|
42
|
-
setInternalValue(value !== undefined && value !== null ? value.toString() : null);
|
|
43
|
-
}, [value, focused]);
|
|
44
|
-
|
|
45
|
-
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
if (inputRef.current && focused) {
|
|
49
|
-
inputRef.current.focus({ preventScroll: true });
|
|
50
|
-
}
|
|
51
|
-
}, [focused, inputRef]);
|
|
52
|
-
|
|
53
|
-
const regexp = /^-?[0-9]+[,.]?[0-9]*$/;
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<TextField
|
|
57
|
-
inputRef={inputRef}
|
|
58
|
-
invisible={true}
|
|
59
|
-
size="small"
|
|
60
|
-
className="w-full"
|
|
61
|
-
inputClassName={cls("p-0 m-0 bg-transparent border-none outline-hidden font-normal leading-normal text-unset", focusedDisabled)}
|
|
62
|
-
inputStyle={{ textAlign: align }}
|
|
63
|
-
value={internalValue ?? ""}
|
|
64
|
-
onChange={(evt) => {
|
|
65
|
-
const newValue = evt.target.value.replace(",", ".");
|
|
66
|
-
if (newValue.length === 0) setInternalValue(null);
|
|
67
|
-
if (regexp.test(newValue) || newValue.startsWith("-")) setInternalValue(newValue);
|
|
68
|
-
}}
|
|
69
|
-
/>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef } from "react";
|
|
2
|
-
import { Select, SelectItem } from "../../Select";
|
|
3
|
-
import { MultiSelect, MultiSelectItem } from "../../MultiSelect";
|
|
4
|
-
import { Chip } from "../../Chip";
|
|
5
|
-
|
|
6
|
-
export interface VirtualTableSelectOption {
|
|
7
|
-
value: string | number;
|
|
8
|
-
label: string;
|
|
9
|
-
color?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function VirtualTableSelect(props: {
|
|
13
|
-
options: VirtualTableSelectOption[];
|
|
14
|
-
error?: Error;
|
|
15
|
-
multiple?: boolean;
|
|
16
|
-
disabled: boolean;
|
|
17
|
-
small?: boolean;
|
|
18
|
-
value: string | number | string[] | number[] | undefined;
|
|
19
|
-
updateValue: (newValue: (string | number | string[] | number[] | null)) => void;
|
|
20
|
-
focused: boolean;
|
|
21
|
-
onBlur?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
22
|
-
}) {
|
|
23
|
-
const { options, value, disabled, small = false, focused, updateValue, multiple = false } = props;
|
|
24
|
-
const validValue = (Array.isArray(value) && multiple) || (!Array.isArray(value) && !multiple);
|
|
25
|
-
const ref = useRef<HTMLButtonElement>(null);
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
if (ref.current && focused) {
|
|
29
|
-
ref.current?.focus({ preventScroll: true });
|
|
30
|
-
}
|
|
31
|
-
}, [focused, ref]);
|
|
32
|
-
|
|
33
|
-
const onChange = useCallback((updatedValue: string | string[]) => {
|
|
34
|
-
if (multiple) {
|
|
35
|
-
const isNumber = options.some(o => typeof o.value === "number");
|
|
36
|
-
const newValue = (updatedValue as string[]).map((v) => {
|
|
37
|
-
const opt = options.find(o => String(o.value) === v);
|
|
38
|
-
return typeof opt?.value === "number" ? parseFloat(v) : v;
|
|
39
|
-
});
|
|
40
|
-
if (isNumber) {
|
|
41
|
-
updateValue(newValue as number[]);
|
|
42
|
-
} else {
|
|
43
|
-
updateValue(newValue as string[]);
|
|
44
|
-
}
|
|
45
|
-
} else {
|
|
46
|
-
const opt = options.find(o => String(o.value) === updatedValue);
|
|
47
|
-
updateValue(typeof opt?.value === "number" ? parseFloat(updatedValue as string) : (updatedValue as string || null));
|
|
48
|
-
}
|
|
49
|
-
}, [multiple, updateValue, options]);
|
|
50
|
-
|
|
51
|
-
const renderValue = (val?: string | number) => {
|
|
52
|
-
const option = options.find(o => o.value === val);
|
|
53
|
-
return (
|
|
54
|
-
<Chip size={small ? "small" : "medium"}>
|
|
55
|
-
{option ? option.label : String(val)}
|
|
56
|
-
</Chip>
|
|
57
|
-
);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const handleOpenChange = useCallback((open: boolean) => {
|
|
61
|
-
if (!open && ref.current) {
|
|
62
|
-
setTimeout(() => {
|
|
63
|
-
ref.current?.focus({ preventScroll: true });
|
|
64
|
-
}, 0);
|
|
65
|
-
}
|
|
66
|
-
}, []);
|
|
67
|
-
|
|
68
|
-
return multiple ? (
|
|
69
|
-
<MultiSelect
|
|
70
|
-
inputRef={ref}
|
|
71
|
-
className="w-full h-full p-0 bg-transparent outline-none"
|
|
72
|
-
position={"item-aligned"}
|
|
73
|
-
disabled={disabled}
|
|
74
|
-
includeClear={false}
|
|
75
|
-
useChips={false}
|
|
76
|
-
value={validValue ? (value as (string | number)[]).map(v => String(v)) : []}
|
|
77
|
-
onValueChange={onChange}
|
|
78
|
-
onOpenChange={handleOpenChange}
|
|
79
|
-
>
|
|
80
|
-
{options.map((opt) => (
|
|
81
|
-
<MultiSelectItem key={String(opt.value)} value={String(opt.value)}>
|
|
82
|
-
<Chip size={small ? "small" : "medium"}>{opt.label}</Chip>
|
|
83
|
-
</MultiSelectItem>
|
|
84
|
-
))}
|
|
85
|
-
</MultiSelect>
|
|
86
|
-
) : (
|
|
87
|
-
<Select
|
|
88
|
-
inputRef={ref}
|
|
89
|
-
fullWidth
|
|
90
|
-
className="w-full h-full p-0 bg-transparent outline-none [&_button]:ring-0 [&_button]:ring-offset-0"
|
|
91
|
-
inputClassName="ring-0 ring-offset-0 focus:ring-0 focus-visible:ring-0 outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-offset-0"
|
|
92
|
-
position={"item-aligned"}
|
|
93
|
-
disabled={disabled}
|
|
94
|
-
padding={false}
|
|
95
|
-
value={validValue ? String(value) : ""}
|
|
96
|
-
onValueChange={onChange}
|
|
97
|
-
onOpenChange={handleOpenChange}
|
|
98
|
-
renderValue={renderValue}
|
|
99
|
-
>
|
|
100
|
-
{options.map((opt) => (
|
|
101
|
-
<SelectItem key={String(opt.value)} value={String(opt.value)}>
|
|
102
|
-
<Chip size={small ? "small" : "medium"}>{opt.label}</Chip>
|
|
103
|
-
</SelectItem>
|
|
104
|
-
))}
|
|
105
|
-
</Select>
|
|
106
|
-
);
|
|
107
|
-
}
|