@dxos/react-ui-table 0.8.1-staging.391c573 → 0.8.1-staging.9eaf14f
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/dist/lib/browser/{chunk-3FR6NHPD.mjs → chunk-YWNRUF4J.mjs} +8 -6
- package/dist/lib/browser/chunk-YWNRUF4J.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +625 -225
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node/{chunk-NB3SFHGA.cjs → chunk-TGG6OZ54.cjs} +10 -8
- package/dist/lib/node/chunk-TGG6OZ54.cjs.map +7 -0
- package/dist/lib/node/index.cjs +618 -220
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +3 -3
- package/dist/lib/node/types/index.cjs.map +1 -1
- package/dist/lib/node-esm/{chunk-RLVVOZW5.mjs → chunk-KKLP54L3.mjs} +8 -6
- package/dist/lib/node-esm/chunk-KKLP54L3.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +625 -225
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/types/index.mjs +1 -1
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts +24 -0
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -0
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +10 -0
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -0
- package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +1 -0
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +4 -3
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/index.d.ts +1 -0
- package/dist/types/src/components/Table/index.d.ts.map +1 -1
- package/dist/types/src/components/Table/relations.stories.d.ts +9 -0
- package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -0
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +7 -7
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useTableModel.d.ts +8 -9
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/index.d.ts +1 -0
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts +6 -3
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +42 -16
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +4 -4
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/model/table-sorting.d.ts +2 -2
- package/dist/types/src/model/table-sorting.d.ts.map +1 -1
- package/dist/types/src/types/table.d.ts +7 -32
- package/dist/types/src/types/table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +31 -0
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +1 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/table-controls.d.ts +2 -2
- package/dist/types/src/util/table-controls.d.ts.map +1 -1
- package/dist/types/src/util/table.d.ts +5 -3
- package/dist/types/src/util/table.d.ts.map +1 -1
- package/package.json +37 -36
- package/src/components/Table/ColumnActionsMenu.tsx +6 -4
- package/src/components/Table/ColumnSettings.tsx +5 -6
- package/src/components/Table/CreateRefPanel.tsx +3 -3
- package/src/components/Table/DynamicTable.stories.tsx +155 -0
- package/src/components/Table/DynamicTable.tsx +104 -0
- package/src/components/Table/RefPanel.tsx +3 -3
- package/src/components/Table/RowActionsMenu.tsx +18 -3
- package/src/components/Table/Table.stories.tsx +170 -115
- package/src/components/Table/Table.tsx +71 -26
- package/src/components/Table/index.ts +1 -0
- package/src/components/Table/relations.stories.tsx +113 -0
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +15 -5
- package/src/components/TableCellEditor/TableCellEditor.tsx +102 -4
- package/src/components/testing.ts +0 -1
- package/src/hooks/useTableModel.ts +35 -14
- package/src/model/index.ts +1 -0
- package/src/model/selection-model.ts +12 -2
- package/src/model/table-model.test.ts +2 -2
- package/src/model/table-model.ts +117 -32
- package/src/model/table-presentation.test.ts +2 -2
- package/src/model/table-presentation.ts +94 -22
- package/src/model/table-sorting.ts +3 -2
- package/src/playwright/smoke.spec.ts +2 -3
- package/src/types/table.ts +9 -10
- package/src/util/dynamic-table.ts +103 -0
- package/src/util/index.ts +1 -0
- package/src/util/table-controls.ts +4 -4
- package/src/util/table.ts +68 -65
- package/dist/lib/browser/_deprecated/index.mjs +0 -1483
- package/dist/lib/browser/_deprecated/index.mjs.map +0 -7
- package/dist/lib/browser/chunk-3FR6NHPD.mjs.map +0 -7
- package/dist/lib/node/_deprecated/index.cjs +0 -1511
- package/dist/lib/node/_deprecated/index.cjs.map +0 -7
- package/dist/lib/node/chunk-NB3SFHGA.cjs.map +0 -7
- package/dist/lib/node-esm/_deprecated/index.mjs +0 -1485
- package/dist/lib/node-esm/_deprecated/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +0 -7
- package/dist/types/src/_deprecated/components/Cell/Cell.d.ts +0 -12
- package/dist/types/src/_deprecated/components/Cell/Cell.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts +0 -13
- package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Cell/index.d.ts +0 -2
- package/dist/types/src/_deprecated/components/Cell/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts +0 -23
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts +0 -36
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts +0 -15
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts +0 -84
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts +0 -3
- package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/Table.d.ts +0 -20
- package/dist/types/src/_deprecated/components/Table/Table.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts +0 -116
- package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableBody.d.ts +0 -12
- package/dist/types/src/_deprecated/components/Table/TableBody.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableContext.d.ts +0 -13
- package/dist/types/src/_deprecated/components/Table/TableContext.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableHead.d.ts +0 -9
- package/dist/types/src/_deprecated/components/Table/TableHead.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts +0 -17
- package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/index.d.ts +0 -5
- package/dist/types/src/_deprecated/components/Table/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/props.d.ts +0 -42
- package/dist/types/src/_deprecated/components/Table/props.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/index.d.ts +0 -4
- package/dist/types/src/_deprecated/components/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/helpers.d.ts +0 -91
- package/dist/types/src/_deprecated/helpers.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/index.d.ts +0 -5
- package/dist/types/src/_deprecated/hooks/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts +0 -12
- package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts +0 -15
- package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts +0 -3
- package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts +0 -7
- package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts.map +0 -1
- package/dist/types/src/_deprecated/index.d.ts +0 -8
- package/dist/types/src/_deprecated/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/Schema.stories.d.ts +0 -11
- package/dist/types/src/_deprecated/schema/Schema.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/column-utils.d.ts +0 -7
- package/dist/types/src/_deprecated/schema/column-utils.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/index.d.ts +0 -3
- package/dist/types/src/_deprecated/schema/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/types.d.ts +0 -27
- package/dist/types/src/_deprecated/schema/types.d.ts.map +0 -1
- package/dist/types/src/_deprecated/theme.d.ts +0 -29
- package/dist/types/src/_deprecated/theme.d.ts.map +0 -1
- package/dist/types/src/_deprecated/translations.d.ts +0 -21
- package/dist/types/src/_deprecated/translations.d.ts.map +0 -1
- package/dist/types/src/_deprecated/types.d.ts +0 -26
- package/dist/types/src/_deprecated/types.d.ts.map +0 -1
- package/src/_deprecated/components/Cell/Cell.tsx +0 -88
- package/src/_deprecated/components/Cell/CellCombobox.tsx +0 -103
- package/src/_deprecated/components/Cell/index.ts +0 -5
- package/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.tsx +0 -129
- package/src/_deprecated/components/ColumnMenu/ColumnMenu.tsx +0 -182
- package/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.tsx +0 -108
- package/src/_deprecated/components/ColumnMenu/ColumnSettings.tsx +0 -207
- package/src/_deprecated/components/ColumnMenu/index.ts +0 -6
- package/src/_deprecated/components/Table/Table.stories.tsx +0 -508
- package/src/_deprecated/components/Table/Table.tsx +0 -301
- package/src/_deprecated/components/Table/TableBody.tsx +0 -82
- package/src/_deprecated/components/Table/TableContext.tsx +0 -34
- package/src/_deprecated/components/Table/TableHead.tsx +0 -78
- package/src/_deprecated/components/Table/TableRootContext.ts +0 -39
- package/src/_deprecated/components/Table/index.ts +0 -8
- package/src/_deprecated/components/Table/props.ts +0 -60
- package/src/_deprecated/components/index.ts +0 -7
- package/src/_deprecated/helpers.tsx +0 -526
- package/src/_deprecated/hooks/index.ts +0 -8
- package/src/_deprecated/hooks/useColumnSizing.ts +0 -46
- package/src/_deprecated/hooks/useColumnSorting.ts +0 -64
- package/src/_deprecated/hooks/usePinLastRow.ts +0 -47
- package/src/_deprecated/hooks/useRowSelection.ts +0 -40
- package/src/_deprecated/index.ts +0 -12
- package/src/_deprecated/schema/Schema.stories.tsx +0 -59
- package/src/_deprecated/schema/column-utils.ts +0 -54
- package/src/_deprecated/schema/index.ts +0 -6
- package/src/_deprecated/schema/types.ts +0 -40
- package/src/_deprecated/theme.ts +0 -82
- package/src/_deprecated/translations.ts +0 -26
- package/src/_deprecated/types.ts +0 -38
|
@@ -1,526 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { useFocusFinders } from '@fluentui/react-tabster';
|
|
6
|
-
import { Check, ClipboardText, type Icon, X } from '@phosphor-icons/react';
|
|
7
|
-
import {
|
|
8
|
-
createColumnHelper,
|
|
9
|
-
type ColumnDef,
|
|
10
|
-
type ColumnMeta,
|
|
11
|
-
type RowData,
|
|
12
|
-
type ColumnHelper,
|
|
13
|
-
type CellContext,
|
|
14
|
-
} from '@tanstack/react-table';
|
|
15
|
-
import { format } from 'date-fns/format';
|
|
16
|
-
import { formatDistanceToNow } from 'date-fns/formatDistanceToNow';
|
|
17
|
-
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
18
|
-
|
|
19
|
-
import { type PublicKey } from '@dxos/keys';
|
|
20
|
-
import { log } from '@dxos/log';
|
|
21
|
-
import { type ClassNameValue, Input, Tooltip } from '@dxos/react-ui';
|
|
22
|
-
import { defaultSizeRow } from '@dxos/react-ui-grid';
|
|
23
|
-
import { getSize, mx } from '@dxos/react-ui-theme';
|
|
24
|
-
|
|
25
|
-
import { CellCombobox, useTableContext } from './components';
|
|
26
|
-
import { textPadding } from './theme';
|
|
27
|
-
|
|
28
|
-
export type ValueUpdater<TData extends RowData, TValue> = (row: TData, id: string, value: TValue) => void;
|
|
29
|
-
|
|
30
|
-
export const createColumnBuilder = <TData extends RowData>() => ({
|
|
31
|
-
helper: createColumnHelper<TData>(),
|
|
32
|
-
builder: new ColumnBuilder<TData>(),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// TODO(thure): This interface is redundant, e.g. `classNames` == `meta.cell.classNames`
|
|
36
|
-
/**
|
|
37
|
-
* NOTE: Can use `meta` for custom properties.
|
|
38
|
-
*/
|
|
39
|
-
export type BaseColumnOptions<TData, TValue> = Partial<ColumnDef<TData, TValue>> & {
|
|
40
|
-
meta?: ColumnMeta<TData, TValue>;
|
|
41
|
-
label?: string;
|
|
42
|
-
classNames?: ClassNameValue;
|
|
43
|
-
onUpdate?: ValueUpdater<TData, TValue | undefined>;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// TODO(burdon): Better abstraction?
|
|
47
|
-
export type SearchListQueryModel<TData extends RowData> = {
|
|
48
|
-
getId(object: TData): string;
|
|
49
|
-
getText(object: TData): string;
|
|
50
|
-
query(text?: string): Promise<TData[]>;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export type ComboboxColumnOptions<TData extends RowData> = BaseColumnOptions<TData, any> & {
|
|
54
|
-
model: SearchListQueryModel<TData>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export type StringColumnOptions<TData extends RowData> = BaseColumnOptions<TData, string> & {};
|
|
58
|
-
export type SelectRowColumnOptions<TData extends RowData> = BaseColumnOptions<TData, string> & {};
|
|
59
|
-
|
|
60
|
-
export type NumberColumnOptions<TData extends RowData> = BaseColumnOptions<TData, number> & {
|
|
61
|
-
digits?: number;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export type KeyColumnOptions<TData extends RowData> = BaseColumnOptions<TData, PublicKey> & {
|
|
65
|
-
tooltip?: boolean;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export type DateColumnOptions<TData extends RowData> = BaseColumnOptions<TData, Date> & {
|
|
69
|
-
format?: string;
|
|
70
|
-
relative?: boolean;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export type SwitchColumnOptions<TData extends RowData> = BaseColumnOptions<TData, boolean> & {};
|
|
74
|
-
|
|
75
|
-
export type IconColumnOptions<TData extends RowData> = BaseColumnOptions<TData, boolean> & {
|
|
76
|
-
on?: {
|
|
77
|
-
Icon?: Icon;
|
|
78
|
-
className?: string;
|
|
79
|
-
};
|
|
80
|
-
off?: {
|
|
81
|
-
Icon?: Icon;
|
|
82
|
-
className?: string;
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const ComboboxBuilderCell = <TData extends RowData>(cellContext: CellContext<TData, TData>) => {
|
|
87
|
-
const { model, onUpdate } = cellContext.column.columnDef.meta as ColumnMeta<TData, TData>;
|
|
88
|
-
return model ? (
|
|
89
|
-
<CellCombobox<TData>
|
|
90
|
-
model={model}
|
|
91
|
-
value={cellContext.getValue()}
|
|
92
|
-
onValueChange={(value) => onUpdate?.(cellContext.row.original, cellContext.column.id, value)}
|
|
93
|
-
/>
|
|
94
|
-
) : null;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const StringBuilderCell = <TData extends RowData>(cellContext: CellContext<TData, string>) => {
|
|
98
|
-
const ref = useRef<HTMLInputElement>(null);
|
|
99
|
-
const { findPrevFocusable } = useFocusFinders();
|
|
100
|
-
|
|
101
|
-
const { onUpdate, cell } = cellContext.column.columnDef.meta as ColumnMeta<TData, string>;
|
|
102
|
-
|
|
103
|
-
// https://tanstack.com/table/v8/docs/examples/react/editable-data
|
|
104
|
-
const initialValue = cellContext.getValue();
|
|
105
|
-
|
|
106
|
-
const getInitialValue = useCallback(() => {
|
|
107
|
-
// TODO(burdon): Temporary shim for automerge.
|
|
108
|
-
return (initialValue as any)?.content ?? initialValue;
|
|
109
|
-
}, [initialValue]);
|
|
110
|
-
|
|
111
|
-
const [value, setValue] = useState(getInitialValue);
|
|
112
|
-
|
|
113
|
-
// Update value if initialValue changes externally (cell reactivity).
|
|
114
|
-
useEffect(() => setValue(getInitialValue()), [getInitialValue]);
|
|
115
|
-
|
|
116
|
-
const handleSave = () => {
|
|
117
|
-
ref.current && document.activeElement === ref.current && findPrevFocusable(ref.current)?.focus();
|
|
118
|
-
|
|
119
|
-
if (value !== initialValue) {
|
|
120
|
-
onUpdate?.(cellContext.row.original, cellContext.column.id, value);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const handleCancel = () => setValue(initialValue);
|
|
125
|
-
|
|
126
|
-
let placeholder = false;
|
|
127
|
-
const columns = cellContext.table.getVisibleFlatColumns();
|
|
128
|
-
|
|
129
|
-
// Calling getRowModel is expensive, so only do it when we're a cell in the first position.
|
|
130
|
-
if (columns[0].id === cellContext.column.id) {
|
|
131
|
-
const rowCount = cellContext.table.getRowModel().rows.length;
|
|
132
|
-
placeholder = cellContext.row.index === rowCount - 1 && columns[0].id === cellContext.column.id;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// TODO(burdon): Don't render inputs unless mouse over (Show ellipsis when div)?
|
|
136
|
-
return (
|
|
137
|
-
<Input.Root>
|
|
138
|
-
<Input.TextInput
|
|
139
|
-
ref={ref}
|
|
140
|
-
variant='subdued'
|
|
141
|
-
placeholder={placeholder ? 'Add row...' : undefined}
|
|
142
|
-
classNames={['is-full', textPadding, cell?.classNames]}
|
|
143
|
-
value={value ?? ''}
|
|
144
|
-
onBlur={handleSave}
|
|
145
|
-
onChange={(event) => setValue(event.target.value)}
|
|
146
|
-
onKeyDown={(event) => (event.key === 'Enter' && handleSave()) || (event.key === 'Escape' && handleCancel())}
|
|
147
|
-
autoComplete='off'
|
|
148
|
-
/>
|
|
149
|
-
</Input.Root>
|
|
150
|
-
);
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const parseNumber = (text?: string) => (text?.trim().length ? Number(text) : NaN);
|
|
154
|
-
|
|
155
|
-
const displayNumber = (value?: number, digits?: number) =>
|
|
156
|
-
value || value === 0
|
|
157
|
-
? value.toLocaleString(undefined, {
|
|
158
|
-
minimumFractionDigits: digits ?? 0,
|
|
159
|
-
maximumFractionDigits: digits ?? 2,
|
|
160
|
-
})
|
|
161
|
-
: '';
|
|
162
|
-
|
|
163
|
-
const NumberBuilderCell = <TData extends RowData>(cellContext: CellContext<TData, number>) => {
|
|
164
|
-
const { onUpdate, digits } = cellContext.column.columnDef.meta as ColumnMeta<TData, string>;
|
|
165
|
-
const value = cellContext.getValue();
|
|
166
|
-
const [text, setText] = useState<string>(displayNumber(value, digits));
|
|
167
|
-
const { findPrevFocusable } = useFocusFinders();
|
|
168
|
-
const ref = useRef<HTMLInputElement | null>(null);
|
|
169
|
-
|
|
170
|
-
// Update display value if `digits` changes and input is not in focus.
|
|
171
|
-
useEffect(() => {
|
|
172
|
-
(!document.activeElement || document.activeElement !== ref.current) && setText(displayNumber(value, digits));
|
|
173
|
-
}, [digits, value]);
|
|
174
|
-
|
|
175
|
-
const handleEdit = () => setText(value !== undefined ? String(value) : '');
|
|
176
|
-
|
|
177
|
-
// TODO(burdon): Property is encoded as float (e.g., 6.1 => 6.099)
|
|
178
|
-
const handleSave = () => {
|
|
179
|
-
const nextValue = parseNumber(text);
|
|
180
|
-
|
|
181
|
-
if (!isNaN(nextValue)) {
|
|
182
|
-
onUpdate?.(cellContext.row.original, cellContext.column.id, nextValue);
|
|
183
|
-
setText(displayNumber(nextValue, digits));
|
|
184
|
-
} else {
|
|
185
|
-
// Reset the text to display the original value without updating the model.
|
|
186
|
-
setText(displayNumber(value, digits));
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Shift focus only if input is focused on save (e.g. on `Enter`).
|
|
190
|
-
ref.current && document.activeElement === ref.current && findPrevFocusable(ref.current)?.focus();
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
const _handleCancel = () => {
|
|
194
|
-
setText(displayNumber(value, digits));
|
|
195
|
-
ref.current && findPrevFocusable(ref.current)?.focus();
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
return (
|
|
199
|
-
<Input.Root>
|
|
200
|
-
<Input.TextInput
|
|
201
|
-
ref={ref}
|
|
202
|
-
variant='subdued'
|
|
203
|
-
value={text}
|
|
204
|
-
classNames={['is-full text-end font-mono', textPadding]}
|
|
205
|
-
onBlur={handleSave}
|
|
206
|
-
onFocus={handleEdit}
|
|
207
|
-
onChange={({ target: { value } }) => setText(value)}
|
|
208
|
-
onKeyDown={(event) => {
|
|
209
|
-
// TODO(thure): `Escape` is reserved for blurring the input and moving focus to the cell.
|
|
210
|
-
return /* (event.key === 'Escape' && handleCancel()) || */ event.key === 'Enter' && handleSave();
|
|
211
|
-
}}
|
|
212
|
-
autoComplete='off'
|
|
213
|
-
/>
|
|
214
|
-
</Input.Root>
|
|
215
|
-
);
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
const RowSelectorBuilderCell = <TData extends RowData>(cellContext: CellContext<TData, unknown>) => {
|
|
219
|
-
const { cell } = cellContext.column.columnDef.meta as ColumnMeta<TData, unknown>;
|
|
220
|
-
const { row } = cellContext;
|
|
221
|
-
|
|
222
|
-
const checked = row.getCanSelect()
|
|
223
|
-
? row.getIsSelected()
|
|
224
|
-
: row.getCanSelectSubRows() && (row.getIsSomeSelected() ? 'indeterminate' : row.getIsAllSubRowsSelected());
|
|
225
|
-
|
|
226
|
-
return (
|
|
227
|
-
<div className='flex justify-center w-full h-full' role='presentation'>
|
|
228
|
-
<Input.Root>
|
|
229
|
-
<Input.Checkbox
|
|
230
|
-
size={4}
|
|
231
|
-
classNames={[cell?.classNames]}
|
|
232
|
-
checked={checked}
|
|
233
|
-
onCheckedChange={(event) => {
|
|
234
|
-
if (row.getCanSelect()) {
|
|
235
|
-
row.getToggleSelectedHandler()(event);
|
|
236
|
-
}
|
|
237
|
-
}}
|
|
238
|
-
disabled={!(row.getCanSelect() || row.getCanSelectSubRows())}
|
|
239
|
-
/>
|
|
240
|
-
</Input.Root>
|
|
241
|
-
</div>
|
|
242
|
-
);
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const SwitchBuilderCell = <TData extends RowData>(cellContext: CellContext<TData, boolean>) => {
|
|
246
|
-
const { onUpdate } = cellContext.column.columnDef.meta as ColumnMeta<TData, boolean>;
|
|
247
|
-
const value = cellContext.getValue();
|
|
248
|
-
return (
|
|
249
|
-
<Input.Root>
|
|
250
|
-
<Input.Switch
|
|
251
|
-
classNames='block mli-auto'
|
|
252
|
-
onClick={(event) => event.stopPropagation()}
|
|
253
|
-
disabled={!onUpdate}
|
|
254
|
-
checked={!!value}
|
|
255
|
-
onCheckedChange={(value) => {
|
|
256
|
-
onUpdate?.(cellContext.row.original, cellContext.column.id, !!value);
|
|
257
|
-
}}
|
|
258
|
-
/>
|
|
259
|
-
</Input.Root>
|
|
260
|
-
);
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Util to create column definitions.
|
|
265
|
-
*/
|
|
266
|
-
export class ColumnBuilder<TData extends RowData> {
|
|
267
|
-
/**
|
|
268
|
-
* Combobox value
|
|
269
|
-
*/
|
|
270
|
-
combobox({
|
|
271
|
-
label,
|
|
272
|
-
classNames,
|
|
273
|
-
model,
|
|
274
|
-
onUpdate,
|
|
275
|
-
...props
|
|
276
|
-
}: ComboboxColumnOptions<TData>): Partial<ColumnDef<TData, any>> {
|
|
277
|
-
return {
|
|
278
|
-
minSize: 100,
|
|
279
|
-
header: (column) => {
|
|
280
|
-
return label ?? column.header.id;
|
|
281
|
-
},
|
|
282
|
-
cell:
|
|
283
|
-
model && onUpdate
|
|
284
|
-
? ComboboxBuilderCell
|
|
285
|
-
: (cellContext) => {
|
|
286
|
-
const cellValue = cellContext.getValue();
|
|
287
|
-
return <div className={mx('truncate', classNames)}>{cellValue ? model?.getText(cellValue) : ''}</div>;
|
|
288
|
-
},
|
|
289
|
-
...props,
|
|
290
|
-
meta: {
|
|
291
|
-
...props.meta,
|
|
292
|
-
model,
|
|
293
|
-
onUpdate,
|
|
294
|
-
cell: { classNames, ...props.meta?.cell },
|
|
295
|
-
},
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* String formats.
|
|
301
|
-
*/
|
|
302
|
-
string({ label, classNames, onUpdate, ...props }: StringColumnOptions<TData> = {}): Partial<
|
|
303
|
-
ColumnDef<TData, string>
|
|
304
|
-
> {
|
|
305
|
-
return {
|
|
306
|
-
minSize: 100,
|
|
307
|
-
// TODO(burdon): Default.
|
|
308
|
-
header: (column) => {
|
|
309
|
-
return label ?? column.header.id;
|
|
310
|
-
},
|
|
311
|
-
cell: onUpdate
|
|
312
|
-
? StringBuilderCell
|
|
313
|
-
: (cell) => {
|
|
314
|
-
let value = cell.getValue();
|
|
315
|
-
// TODO(burdon): Hack to support automerge.
|
|
316
|
-
if (typeof value === 'object' && (value as any)?.type === 'dxos.Text.v0') {
|
|
317
|
-
value = (value as any).content;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return <div className={mx('truncate', textPadding, classNames)}>{value}</div>;
|
|
321
|
-
},
|
|
322
|
-
...props,
|
|
323
|
-
meta: {
|
|
324
|
-
...props.meta,
|
|
325
|
-
onUpdate,
|
|
326
|
-
cell: { ...props.meta?.cell, classNames },
|
|
327
|
-
},
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Number formats.
|
|
333
|
-
*/
|
|
334
|
-
number({ label, minSize, classNames, digits, onUpdate, ...props }: NumberColumnOptions<TData> = {}): Partial<
|
|
335
|
-
ColumnDef<TData, number>
|
|
336
|
-
> {
|
|
337
|
-
return {
|
|
338
|
-
size: 100,
|
|
339
|
-
minSize: 100,
|
|
340
|
-
header: (cell) => label ?? cell.header.id,
|
|
341
|
-
cell: NumberBuilderCell,
|
|
342
|
-
...props,
|
|
343
|
-
meta: {
|
|
344
|
-
...props.meta,
|
|
345
|
-
onUpdate,
|
|
346
|
-
digits,
|
|
347
|
-
header: { ...props.meta?.header },
|
|
348
|
-
cell: { ...props.meta?.cell, classNames },
|
|
349
|
-
},
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Date formats.
|
|
355
|
-
*/
|
|
356
|
-
// TODO(burdon): Date picker (pluggable renderers?)
|
|
357
|
-
date({ label, format: formatSpec, relative, classNames, ...props }: DateColumnOptions<TData> = {}): Partial<
|
|
358
|
-
ColumnDef<TData, Date>
|
|
359
|
-
> {
|
|
360
|
-
return {
|
|
361
|
-
size: 220, // TODO(burdon): Depends on format.
|
|
362
|
-
minSize: 100,
|
|
363
|
-
header: (cell) => label ?? cell.header.id,
|
|
364
|
-
cell: (cell) => {
|
|
365
|
-
const value = cell.getValue();
|
|
366
|
-
|
|
367
|
-
try {
|
|
368
|
-
const str = value
|
|
369
|
-
? formatSpec
|
|
370
|
-
? format(value, formatSpec)
|
|
371
|
-
: relative
|
|
372
|
-
? formatDistanceToNow(value, { addSuffix: true })
|
|
373
|
-
: value.toISOString()
|
|
374
|
-
: undefined;
|
|
375
|
-
|
|
376
|
-
return <div className={mx(textPadding, classNames)}>{str}</div>;
|
|
377
|
-
} catch (err) {
|
|
378
|
-
log.info('formatError', { value });
|
|
379
|
-
return null;
|
|
380
|
-
}
|
|
381
|
-
},
|
|
382
|
-
...props,
|
|
383
|
-
meta: { ...props.meta, cell: { ...props.meta?.cell, classNames } },
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* PublicKey with tooltip.
|
|
389
|
-
*/
|
|
390
|
-
key({ label, tooltip, classNames, ...props }: KeyColumnOptions<TData> = {}): Partial<ColumnDef<TData, PublicKey>> {
|
|
391
|
-
return {
|
|
392
|
-
size: 94,
|
|
393
|
-
minSize: 94,
|
|
394
|
-
header: (cell) => label ?? cell.header.id,
|
|
395
|
-
cell: (cell) => {
|
|
396
|
-
const value = cell.getValue();
|
|
397
|
-
if (!value) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// TODO(burdon): Factor out styles.
|
|
402
|
-
const element = value.truncate();
|
|
403
|
-
if (!tooltip) {
|
|
404
|
-
return element;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return (
|
|
408
|
-
<Tooltip.Provider>
|
|
409
|
-
<Tooltip.Root>
|
|
410
|
-
<Tooltip.Trigger>{element}</Tooltip.Trigger>
|
|
411
|
-
<Tooltip.Portal>
|
|
412
|
-
<Tooltip.Content side='right'>
|
|
413
|
-
<Tooltip.Arrow />
|
|
414
|
-
<ClipboardText
|
|
415
|
-
onClick={(ev) => {
|
|
416
|
-
ev.stopPropagation(); // Prevent select row.
|
|
417
|
-
void navigator.clipboard.writeText(value.toHex());
|
|
418
|
-
}}
|
|
419
|
-
/>
|
|
420
|
-
</Tooltip.Content>
|
|
421
|
-
</Tooltip.Portal>
|
|
422
|
-
</Tooltip.Root>
|
|
423
|
-
</Tooltip.Provider>
|
|
424
|
-
);
|
|
425
|
-
},
|
|
426
|
-
...props,
|
|
427
|
-
meta: { ...props.meta, cell: { ...props.meta?.cell, classNames: ['font-mono', textPadding, classNames] } },
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Row selector
|
|
433
|
-
*/
|
|
434
|
-
selectRow({ classNames, onUpdate, id = 'selectRow' }: SelectRowColumnOptions<TData> = {}): Parameters<
|
|
435
|
-
ColumnHelper<TData>['display']
|
|
436
|
-
>[0] {
|
|
437
|
-
return {
|
|
438
|
-
id,
|
|
439
|
-
size: defaultSizeRow,
|
|
440
|
-
enableResizing: false,
|
|
441
|
-
meta: { onUpdate, cell: { classNames } },
|
|
442
|
-
header: ({ table }) => {
|
|
443
|
-
const { rowsSelectable } = useTableContext();
|
|
444
|
-
const checked = table.getIsSomeRowsSelected() ? 'indeterminate' : table.getIsAllRowsSelected();
|
|
445
|
-
|
|
446
|
-
return rowsSelectable === 'multi' ? (
|
|
447
|
-
<div className='flex justify-center w-full h-full' role='presentation'>
|
|
448
|
-
<Input.Root>
|
|
449
|
-
<Input.Checkbox
|
|
450
|
-
size={4}
|
|
451
|
-
classNames={['mli-auto', classNames]}
|
|
452
|
-
checked={checked}
|
|
453
|
-
onCheckedChange={() => table.toggleAllRowsSelected()}
|
|
454
|
-
/>
|
|
455
|
-
</Input.Root>
|
|
456
|
-
</div>
|
|
457
|
-
) : null;
|
|
458
|
-
},
|
|
459
|
-
cell: RowSelectorBuilderCell,
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Switch
|
|
465
|
-
*/
|
|
466
|
-
switch({ label, classNames, onUpdate, ...props }: SwitchColumnOptions<TData> = {}): Partial<
|
|
467
|
-
ColumnDef<TData, boolean>
|
|
468
|
-
> {
|
|
469
|
-
return {
|
|
470
|
-
size: 50,
|
|
471
|
-
minSize: 50,
|
|
472
|
-
header: (column) => label ?? column.header.id,
|
|
473
|
-
// TODO(zan): Implement sort algorithm.
|
|
474
|
-
enableSorting: true,
|
|
475
|
-
cell: SwitchBuilderCell,
|
|
476
|
-
...props,
|
|
477
|
-
meta: { ...props.meta, onUpdate, cell: { ...props.meta?.cell, classNames: [textPadding, classNames] } },
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Icon based on boolean value.
|
|
483
|
-
*/
|
|
484
|
-
icon({ label, size, on, off, ...props }: IconColumnOptions<TData> = {}): Partial<ColumnDef<TData, boolean>> {
|
|
485
|
-
const IconOn = on?.Icon ?? Check;
|
|
486
|
-
const IconOff = off?.Icon ?? X;
|
|
487
|
-
return {
|
|
488
|
-
size: size ?? defaultSizeRow,
|
|
489
|
-
// TODO(zan): Implement sort algorithm.
|
|
490
|
-
enableSorting: false,
|
|
491
|
-
header: (column) => <div className={'justify-center'}>{label ?? column.header.id}</div>,
|
|
492
|
-
cell: (cell) => {
|
|
493
|
-
const value = cell.getValue();
|
|
494
|
-
if (value) {
|
|
495
|
-
return <IconOn className={mx('block mli-auto', getSize(6), on?.className ?? 'text-green-700')} />;
|
|
496
|
-
} else if (value === false) {
|
|
497
|
-
return <IconOff className={mx('block mli-auto', getSize(6), off?.className ?? 'text-red-700')} />;
|
|
498
|
-
} else {
|
|
499
|
-
return null;
|
|
500
|
-
}
|
|
501
|
-
},
|
|
502
|
-
...props,
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* This display column type is for nested/unhandled data to appear as JSON.
|
|
508
|
-
*/
|
|
509
|
-
json({ label, classNames, ...props }: KeyColumnOptions<TData> = {}): Partial<ColumnDef<TData, PublicKey>> {
|
|
510
|
-
return {
|
|
511
|
-
size: 120,
|
|
512
|
-
minSize: 120,
|
|
513
|
-
header: (cell) => label ?? cell.header.id,
|
|
514
|
-
cell: (cell) => {
|
|
515
|
-
const value = cell.getValue();
|
|
516
|
-
return (
|
|
517
|
-
<div className='overflow-scroll'>
|
|
518
|
-
<code className='text-xs'>{JSON.stringify(value)}</code>
|
|
519
|
-
</div>
|
|
520
|
-
);
|
|
521
|
-
},
|
|
522
|
-
...props,
|
|
523
|
-
meta: { ...props.meta, cell: { ...props.meta?.cell, classNames: ['font-mono', textPadding, classNames] } },
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type ColumnSizingInfoState, type ColumnSizingState } from '@tanstack/react-table';
|
|
6
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
7
|
-
|
|
8
|
-
import { useOnTransition } from '@dxos/react-ui';
|
|
9
|
-
|
|
10
|
-
import { type TableColumnDef } from '../types';
|
|
11
|
-
|
|
12
|
-
export const useColumnResizing = ({
|
|
13
|
-
columns,
|
|
14
|
-
onColumnResize,
|
|
15
|
-
}: {
|
|
16
|
-
columns: TableColumnDef<any>[];
|
|
17
|
-
onColumnResize: ((state: Record<string, number>) => void) | undefined;
|
|
18
|
-
}) => {
|
|
19
|
-
const [columnsInitialised, setColumnsInitialised] = useState(false);
|
|
20
|
-
const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({});
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (columnsInitialised) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
setColumnSizing(
|
|
28
|
-
columns
|
|
29
|
-
.filter((column) => !!column.size && (column as any).prop !== undefined)
|
|
30
|
-
.reduce<ColumnSizingState>((state, column) => {
|
|
31
|
-
state[(column as any).prop] = column.size!;
|
|
32
|
-
return state;
|
|
33
|
-
}, {}),
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
setColumnsInitialised(true);
|
|
37
|
-
}, [columns, setColumnSizing]);
|
|
38
|
-
|
|
39
|
-
const [columnSizingInfo, setColumnSizingInfo] = useState<ColumnSizingInfoState>({} as ColumnSizingInfoState);
|
|
40
|
-
|
|
41
|
-
// Notify on column resize.
|
|
42
|
-
const notifyColumnResize = useCallback(() => onColumnResize?.(columnSizing), [onColumnResize, columnSizing]);
|
|
43
|
-
useOnTransition(columnSizingInfo.isResizingColumn, (v) => typeof v === 'string', false, notifyColumnResize);
|
|
44
|
-
|
|
45
|
-
return { columnSizing, columnSizingInfo, setColumnSizing, setColumnSizingInfo };
|
|
46
|
-
};
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type SortDirection, type Column, type ColumnSort } from '@tanstack/react-table';
|
|
6
|
-
import { useState } from 'react';
|
|
7
|
-
|
|
8
|
-
import { useTableContext } from '../components/Table/TableContext';
|
|
9
|
-
|
|
10
|
-
export const useColumnSorting = () => {
|
|
11
|
-
const [columnSorting, setColumnSorting] = useState<ColumnSort[]>([]);
|
|
12
|
-
|
|
13
|
-
const sortColumn = (columnId: string, sortDirection: SortDirection) => {
|
|
14
|
-
setColumnSorting([{ id: columnId, desc: sortDirection === 'desc' }]);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const clearColumnSorting = () => {
|
|
18
|
-
setColumnSorting([]);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
return { sorting: columnSorting, sortColumn, clearColumnSorting };
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export type ColumnSorting = ReturnType<typeof useColumnSorting>;
|
|
25
|
-
|
|
26
|
-
export const useSortColumn = (column: Column<any>) => {
|
|
27
|
-
const { sorting, sortColumn, clearColumnSorting } = useTableContext();
|
|
28
|
-
const [initialSortDirection, setInitialSortDirection] = useState<SortDirection | undefined>();
|
|
29
|
-
|
|
30
|
-
const columnSort = sorting.find((s) => s.id === column.id);
|
|
31
|
-
const sortDirection = columnSort ? (columnSort.desc ? ('desc' as const) : ('asc' as const)) : undefined;
|
|
32
|
-
|
|
33
|
-
const canSort = column.getCanSort();
|
|
34
|
-
|
|
35
|
-
const updateColumnSort = (direction: SortDirection) => {
|
|
36
|
-
sortColumn(column.id, direction);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Whichever sort is explicitly set first, will be the first sort direction
|
|
40
|
-
// When toggling, we always go to the other direction, and then to unsorted.
|
|
41
|
-
const onToggleSort = () => {
|
|
42
|
-
if (sortDirection === undefined) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (sortDirection === initialSortDirection) {
|
|
47
|
-
updateColumnSort(initialSortDirection === 'asc' ? 'desc' : 'asc');
|
|
48
|
-
} else {
|
|
49
|
-
clearColumnSorting();
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const onSelectSort = (direction: SortDirection) => {
|
|
54
|
-
clearColumnSorting();
|
|
55
|
-
setInitialSortDirection(direction);
|
|
56
|
-
updateColumnSort(direction);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const onClearSort = () => {
|
|
60
|
-
clearColumnSorting();
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return { canSort, sortDirection, onSelectSort, onToggleSort, onClearSort };
|
|
64
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type Row, type Table } from '@tanstack/react-table';
|
|
6
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
7
|
-
|
|
8
|
-
export const usePinLastRow = (pinLastRow: boolean | undefined, table: Table<any>, data: any[]) => {
|
|
9
|
-
const [pinnedRowKey, setPinnedRowKey] = useState<string>();
|
|
10
|
-
|
|
11
|
-
const pinRow = useCallback(
|
|
12
|
-
(rowToPin: Row<any>) => {
|
|
13
|
-
table.resetRowPinning();
|
|
14
|
-
rowToPin.pin('bottom');
|
|
15
|
-
setPinnedRowKey(rowToPin.id);
|
|
16
|
-
},
|
|
17
|
-
[table],
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
const clearRowPinning = useCallback(() => {
|
|
21
|
-
table.resetRowPinning();
|
|
22
|
-
setPinnedRowKey(undefined);
|
|
23
|
-
}, [table]);
|
|
24
|
-
|
|
25
|
-
// Define the logic for pinning the last row in a callback.
|
|
26
|
-
const pinLastRowCallback = useCallback(() => {
|
|
27
|
-
const rows = table.getRowModel().rows;
|
|
28
|
-
|
|
29
|
-
if (rows.length === 0) {
|
|
30
|
-
return clearRowPinning();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const lastRow = rows[rows.length - 1];
|
|
34
|
-
if (lastRow.id === pinnedRowKey) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
pinRow(lastRow);
|
|
39
|
-
}, [table, pinnedRowKey]);
|
|
40
|
-
|
|
41
|
-
// Effect to handle pinning logic when data changes.
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
if (pinLastRow) {
|
|
44
|
-
pinLastRowCallback();
|
|
45
|
-
}
|
|
46
|
-
}, [data, pinLastRow, pinLastRowCallback]);
|
|
47
|
-
};
|