react-glide-table 1.1.9 → 1.3.0
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 +114 -47
- package/dist/compound.cjs +236 -15
- package/dist/compound.d.cts +3 -3
- package/dist/compound.d.ts +3 -3
- package/dist/compound.js +236 -15
- package/dist/core.cjs +163 -4
- package/dist/core.d.cts +20 -5
- package/dist/core.d.ts +20 -5
- package/dist/core.js +158 -4
- package/dist/index.cjs +246 -15
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +241 -15
- package/dist/{types-xxzMLUwM.d.cts → types-B4uHdkrY.d.cts} +95 -3
- package/dist/{types-xxzMLUwM.d.ts → types-B4uHdkrY.d.ts} +95 -3
- package/package.json +23 -1
package/README.md
CHANGED
|
@@ -18,24 +18,24 @@ Peer dependencies: `react` and `react-dom` (`^18` or `^19`).
|
|
|
18
18
|
|
|
19
19
|
The package is marked `"sideEffects": false` for tree-shaking. Prefer subpath imports when you only need one surface:
|
|
20
20
|
|
|
21
|
-
| Import
|
|
22
|
-
|
|
|
23
|
-
| `react-glide-table`
|
|
24
|
-
| `react-glide-table/compound` | `createTable` / `Table` / `DataTable` + related types
|
|
25
|
-
| `react-glide-table/core`
|
|
21
|
+
| Import | Contents |
|
|
22
|
+
| ---------------------------- | -------------------------------------------------------- |
|
|
23
|
+
| `react-glide-table` | Full barrel (compound + core) |
|
|
24
|
+
| `react-glide-table/compound` | `createTable` / `Table` / `DataTable` + related types |
|
|
25
|
+
| `react-glide-table/core` | `useGlideTable` + feature hooks/helpers (no compound UI) |
|
|
26
26
|
|
|
27
27
|
## Quick start (compound)
|
|
28
28
|
|
|
29
29
|
```tsx
|
|
30
|
-
import { createTable } from "react-glide-table/compound"
|
|
31
|
-
import { useState } from "react"
|
|
30
|
+
import { createTable } from "react-glide-table/compound";
|
|
31
|
+
import { useState } from "react";
|
|
32
32
|
|
|
33
|
-
type Product = { id: string; name: string; qty: number }
|
|
33
|
+
type Product = { id: string; name: string; qty: number };
|
|
34
34
|
|
|
35
|
-
const ProductTable = createTable<Product>()
|
|
35
|
+
const ProductTable = createTable<Product>();
|
|
36
36
|
|
|
37
37
|
export function Products({ data }: { data: Product[] }) {
|
|
38
|
-
const [page, setPage] = useState(1)
|
|
38
|
+
const [page, setPage] = useState(1);
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
41
|
<ProductTable
|
|
@@ -59,26 +59,26 @@ export function Products({ data }: { data: Product[] }) {
|
|
|
59
59
|
</ProductTable.Header>
|
|
60
60
|
<ProductTable.Pagination page={page} pageSize={10} onChange={setPage} />
|
|
61
61
|
</ProductTable>
|
|
62
|
-
)
|
|
62
|
+
);
|
|
63
63
|
}
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
### Customization surface
|
|
67
67
|
|
|
68
|
-
| Slot / prop
|
|
69
|
-
|
|
|
70
|
-
| `classNames`
|
|
71
|
-
| `slots.Toolbar`
|
|
72
|
-
| `slots.Row`
|
|
73
|
-
| `slots.Pending` / `slots.Empty`
|
|
74
|
-
| `className` / column `className` / `headerClassName` | Extra class hooks
|
|
75
|
-
| `labels` / `summary` / `toolbar`
|
|
76
|
-
| `Column.render`
|
|
68
|
+
| Slot / prop | Role |
|
|
69
|
+
| ---------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
70
|
+
| `classNames` | Per-part Tailwind/utility classes (`root`, `scroll`, `row`, `cell`, `toolbar`, …) |
|
|
71
|
+
| `slots.Toolbar` | Top summary / actions region |
|
|
72
|
+
| `slots.Row` | Full row replacement (cells, selection, edit UI) |
|
|
73
|
+
| `slots.Pending` / `slots.Empty` | Loading and empty states |
|
|
74
|
+
| `className` / column `className` / `headerClassName` | Extra class hooks |
|
|
75
|
+
| `labels` / `summary` / `toolbar` | Copy and slot nodes |
|
|
76
|
+
| `Column.render` | Cell content custom render |
|
|
77
77
|
|
|
78
78
|
Row/cell **state** is exposed as `data-*` attributes for Tailwind variants:
|
|
79
79
|
|
|
80
80
|
- row: `data-selected`, `data-hovered`, `data-expandable`, `data-expanded`
|
|
81
|
-
- cell: `data-merged`, `data-selection-fill`, `data-editable`, `data-editing`, …
|
|
81
|
+
- cell: `data-merged`, `data-selection-fill`, `data-editable`, `data-editing`, `data-frozen`, …
|
|
82
82
|
|
|
83
83
|
Example: `row: "data-[selected]:bg-blue-600"`.
|
|
84
84
|
|
|
@@ -87,16 +87,16 @@ Row-level UI → `slots.Row`. Cell content → `Column.render`. Header/Cell are
|
|
|
87
87
|
## Escape hatch (`useGlideTable`)
|
|
88
88
|
|
|
89
89
|
```tsx
|
|
90
|
-
import { flexRender } from "@tanstack/react-table"
|
|
91
|
-
import { useGlideTable } from "react-glide-table/core"
|
|
92
|
-
import type { ColumnDef } from "react-glide-table/core"
|
|
90
|
+
import { flexRender } from "@tanstack/react-table";
|
|
91
|
+
import { useGlideTable } from "react-glide-table/core";
|
|
92
|
+
import type { ColumnDef } from "react-glide-table/core";
|
|
93
93
|
|
|
94
|
-
type Product = { id: string; name: string; qty: number }
|
|
94
|
+
type Product = { id: string; name: string; qty: number };
|
|
95
95
|
|
|
96
96
|
const columns: ColumnDef<Product, unknown>[] = [
|
|
97
97
|
{ accessorKey: "name", header: "Name" },
|
|
98
98
|
{ accessorKey: "qty", header: "Qty" },
|
|
99
|
-
]
|
|
99
|
+
];
|
|
100
100
|
|
|
101
101
|
export function ProductTable({ data }: { data: Product[] }) {
|
|
102
102
|
const { table, rows, scrollRef } = useGlideTable({
|
|
@@ -104,7 +104,7 @@ export function ProductTable({ data }: { data: Product[] }) {
|
|
|
104
104
|
columns,
|
|
105
105
|
getRowId: (row) => row.id,
|
|
106
106
|
rowSelectionMode: "multi",
|
|
107
|
-
})
|
|
107
|
+
});
|
|
108
108
|
|
|
109
109
|
return (
|
|
110
110
|
<div ref={scrollRef}>
|
|
@@ -116,7 +116,10 @@ export function ProductTable({ data }: { data: Product[] }) {
|
|
|
116
116
|
<th key={header.id}>
|
|
117
117
|
{header.isPlaceholder
|
|
118
118
|
? null
|
|
119
|
-
: flexRender(
|
|
119
|
+
: flexRender(
|
|
120
|
+
header.column.columnDef.header,
|
|
121
|
+
header.getContext(),
|
|
122
|
+
)}
|
|
120
123
|
</th>
|
|
121
124
|
))}
|
|
122
125
|
</tr>
|
|
@@ -135,7 +138,7 @@ export function ProductTable({ data }: { data: Product[] }) {
|
|
|
135
138
|
</tbody>
|
|
136
139
|
</table>
|
|
137
140
|
</div>
|
|
138
|
-
)
|
|
141
|
+
);
|
|
139
142
|
}
|
|
140
143
|
```
|
|
141
144
|
|
|
@@ -145,17 +148,17 @@ Wire `rowContextValue` into your own row/cell components for edit, selection, ex
|
|
|
145
148
|
|
|
146
149
|
Cell selection ships with clipboard shortcuts. The table parses TSV and emits structured payloads; **your app applies domain conversion and updates data**.
|
|
147
150
|
|
|
148
|
-
| Shortcut
|
|
149
|
-
|
|
|
150
|
-
| Ctrl/Cmd+C
|
|
151
|
-
| Ctrl/Cmd+Shift+C | Copy including collapsed tree descendants (`enableSubtreeCopy`)
|
|
152
|
-
| Ctrl/Cmd+V
|
|
151
|
+
| Shortcut | Behavior |
|
|
152
|
+
| ---------------- | -------------------------------------------------------------------------------------- |
|
|
153
|
+
| Ctrl/Cmd+C | Copy the active selection (visible rows) |
|
|
154
|
+
| Ctrl/Cmd+Shift+C | Copy including collapsed tree descendants (`enableSubtreeCopy`) |
|
|
155
|
+
| Ctrl/Cmd+V | Paste **overwrite** into the selection (`onRowsPaste`, `mode: "overwrite"`) |
|
|
153
156
|
| Ctrl/Cmd+Shift+V | Paste **insert** rows after the selection (`mode: "insert"`, when `enableInsertPaste`) |
|
|
154
157
|
|
|
155
158
|
Subtree copy encodes relative tree depth as leading tabs in the TSV so paste can rebuild parent/child nesting via `payload.depths`. Depth is only inferred when the clipboard looks like subtree indentation (first row unindented, at least one later row indented). Otherwise leading empty cells are kept as real values (e.g. Excel/Sheets blank first column) and `depths` stay `0`.
|
|
156
159
|
|
|
157
160
|
```tsx
|
|
158
|
-
import type { RowsPastePayload } from "react-glide-table/compound"
|
|
161
|
+
import type { RowsPastePayload } from "react-glide-table/compound";
|
|
159
162
|
|
|
160
163
|
<ProductTable
|
|
161
164
|
data={data}
|
|
@@ -164,27 +167,91 @@ import type { RowsPastePayload } from "react-glide-table/compound"
|
|
|
164
167
|
onRowsPaste={(payload: RowsPastePayload) => {
|
|
165
168
|
// overwrite: update cells from startRow using payload.values / columnIds
|
|
166
169
|
// insert: create rows after payload.endRow (or payload.anchorRowId for trees)
|
|
167
|
-
setData((prev) => applyMyPaste(prev, payload))
|
|
170
|
+
setData((prev) => applyMyPaste(prev, payload));
|
|
168
171
|
}}
|
|
169
172
|
>
|
|
170
173
|
{/* columns… */}
|
|
171
|
-
</ProductTable
|
|
174
|
+
</ProductTable>;
|
|
172
175
|
```
|
|
173
176
|
|
|
174
177
|
Related props: `onRowsPaste`, `enableInsertPaste`, `enableSubtreeCopy`, `onCopyActionsReady`.
|
|
175
178
|
Helpers (`/core`): `buildRowsPastePayload`, `parseClipboardTSV`, `parseClipboardTSVWithDepths`, `serializeSelectionToTSV`, …
|
|
176
179
|
|
|
180
|
+
## Column resize
|
|
181
|
+
|
|
182
|
+
Opt in with `enableColumnResize`. Drag the handle on the right edge of a header cell; double-click resets to the column’s default `width` / `size`.
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
<ProductTable
|
|
186
|
+
data={data}
|
|
187
|
+
enableColumnResize
|
|
188
|
+
// optional controlled sizing
|
|
189
|
+
// columnSizing={sizing}
|
|
190
|
+
// onColumnSizingChange={setSizing}
|
|
191
|
+
>
|
|
192
|
+
<ProductTable.Header>
|
|
193
|
+
<ProductTable.Column field="name" width={200} minWidth={80} maxWidth={480}>
|
|
194
|
+
Name
|
|
195
|
+
</ProductTable.Column>
|
|
196
|
+
<ProductTable.Column field="sku" resizable={false}>
|
|
197
|
+
SKU
|
|
198
|
+
</ProductTable.Column>
|
|
199
|
+
</ProductTable.Header>
|
|
200
|
+
</ProductTable>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
| Prop | Role |
|
|
204
|
+
| ---------------------------------------- | -------------------------------------------- |
|
|
205
|
+
| `enableColumnResize` | Turn on header drag resize (default `false`) |
|
|
206
|
+
| `columnSizing` / `onColumnSizingChange` | Controlled width map `{ [columnId]: px }` |
|
|
207
|
+
| `columnResizeMode` | `"onChange"` (live) or `"onEnd"` |
|
|
208
|
+
| `Column.width` / `minWidth` / `maxWidth` | Default / clamp sizes |
|
|
209
|
+
| `Column.resizable={false}` | Disable resize for one column |
|
|
210
|
+
| `classNames.resizeHandle` | Style hook for the drag handle |
|
|
211
|
+
|
|
212
|
+
## Column freeze
|
|
213
|
+
|
|
214
|
+
Opt in with `enableColumnFreeze`. Mark columns with `frozen` — sticky insets are stacked so frozen cells never overlap, and **column order is unchanged** (middle columns may also freeze).
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
<ProductTable data={data} enableColumnFreeze>
|
|
218
|
+
<ProductTable.Header>
|
|
219
|
+
<ProductTable.Column field="name" frozen width={200}>
|
|
220
|
+
Name
|
|
221
|
+
</ProductTable.Column>
|
|
222
|
+
<ProductTable.Column field="sku">SKU</ProductTable.Column>
|
|
223
|
+
<ProductTable.Column field="qty" frozen="left">
|
|
224
|
+
Qty
|
|
225
|
+
</ProductTable.Column>
|
|
226
|
+
<ProductTable.Column field="status" frozen="right">
|
|
227
|
+
Status
|
|
228
|
+
</ProductTable.Column>
|
|
229
|
+
</ProductTable.Header>
|
|
230
|
+
</ProductTable>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
| Prop | Role |
|
|
234
|
+
| ---------------------------------- | --------------------------------------- |
|
|
235
|
+
| `enableColumnFreeze` | Turn on sticky freeze (default `false`) |
|
|
236
|
+
| `Column.frozen` / `meta.frozen` | `true` / `"left"` or `"right"` |
|
|
237
|
+
| `data-frozen` | `"left"` / `"right"` on frozen cells |
|
|
238
|
+
| `data-freeze-edge` | `"left"` / `"right"` / `"both"` on island boundaries |
|
|
239
|
+
|
|
240
|
+
Helpers (`/core`): `buildColumnFreezeOffsets`, `getColumnFreezeEdgeAttr`, `getColumnFreezeStyle`, `resolveColumnFreezeSide`.
|
|
241
|
+
|
|
242
|
+
Contiguous same-side freezes share one island (shadow only on the outer boundary). A gap between frozen columns creates separate islands, so both sides of the gap get an edge shadow.
|
|
243
|
+
|
|
177
244
|
## Public API
|
|
178
245
|
|
|
179
|
-
| Export
|
|
180
|
-
|
|
|
181
|
-
| `createTable` / `Table`
|
|
182
|
-
| `DataTable`
|
|
183
|
-
| `useGlideTable`
|
|
184
|
-
| `useCellEdit` / `useCellSelection` / `useConvertTreeData`
|
|
185
|
-
| `applyCellEdit`, `applyFillData`, `buildRowsPastePayload`, `buildColumnRowSpanMap`, … | `/core`
|
|
186
|
-
| `DEFAULT_DATA_TABLE_LABELS` / `resolveDataTableLabels`
|
|
187
|
-
| Tree field defaults
|
|
246
|
+
| Export | Path | Role |
|
|
247
|
+
| ------------------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------- |
|
|
248
|
+
| `createTable` / `Table` | `/compound` | Compound column DSL (`Header` / `Column` / `Body` / `Pagination`) |
|
|
249
|
+
| `DataTable` | `/compound` | Unstyled default renderer (semantic HTML + slots/props) |
|
|
250
|
+
| `useGlideTable` | `/core` | Headless engine escape hatch |
|
|
251
|
+
| `useCellEdit` / `useCellSelection` / `useConvertTreeData` | `/core` | Feature hooks |
|
|
252
|
+
| `applyCellEdit`, `applyFillData`, `buildRowsPastePayload`, `buildColumnRowSpanMap`, … | `/core` | Pure helpers |
|
|
253
|
+
| `DEFAULT_DATA_TABLE_LABELS` / `resolveDataTableLabels` | `/core` | Optional English UI copy helpers |
|
|
254
|
+
| Tree field defaults | `/core` | `id` / `parentId` / `children` / `qty` |
|
|
188
255
|
|
|
189
256
|
Root `react-glide-table` re-exports both surfaces. Related types: `TableProps`, `TableColumnProps`, `DataTableProps`, `DataTableSlots`, `TableCompoundComponent`, `ColumnDef`, `RowsPastePayload`, `PasteMode`, …
|
|
190
257
|
|
|
@@ -192,7 +259,7 @@ Root `react-glide-table` re-exports both surfaces. Related types: `TableProps`,
|
|
|
192
259
|
|
|
193
260
|
- **Row span + virtualization**: when `enableRowSpan` is on, virtualization is forced off (HTML `<table>` + `rowspan` cannot safely share a virtual window).
|
|
194
261
|
- **Paste is app-owned**: the library does not mutate `data` on paste — handle `onRowsPaste` (coerce types, ids, tree shape, row-span keys).
|
|
195
|
-
- **Flat tree parent order**: `useConvertTreeData` attaches each child to the nearest
|
|
262
|
+
- **Flat tree parent order**: `useConvertTreeData` attaches each child to the nearest _preceding_ row whose toggle key matches `parentId` (duplicate keys after paste resolve this way). Flat inputs must list parents before their children; a child whose parent appears later becomes a root. Nested `children` arrays are flattened parent-before-child automatically.
|
|
196
263
|
- **No shipped CSS**: the default renderer emits class hooks only. Bring your own styles (see playground for a CSS-skinned example).
|
|
197
264
|
|
|
198
265
|
## Local playground
|