@crispy-seed/data-table 0.1.1 → 0.1.2
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/index.cjs +4563 -2
- package/dist/index.js +4547 -1
- package/package.json +1 -1
- package/dist/DataTable-12s-D02v6Qj5.js +0 -1523
- package/dist/DataTable-12s-Gpv6I4J8.cjs +0 -1574
- package/dist/DataTable-12s-Zml1x9Kr-12s-B-mwMBhn.cjs +0 -161
- package/dist/DataTable-12s-Zml1x9Kr-12s-BR-yHfob.js +0 -153
- package/dist/Menu-12s-A4lEc__n.cjs +0 -103
- package/dist/Menu-12s-v9vnaq8F.js +0 -77
- package/dist/Select-12s-CE3SMzFp.js +0 -218
- package/dist/Select-12s-CNQC9z8t.cjs +0 -249
- package/dist/body-cells-12s-2sTwdliH.cjs +0 -461
- package/dist/body-cells-12s-Ba2uF4T-.js +0 -452
- package/dist/column-calc-12s-C1-I2KdV.js +0 -129
- package/dist/column-calc-12s-CJ26VuDJ.cjs +0 -149
- package/dist/column-layout-12s-BhQmNTJG.js +0 -99
- package/dist/column-layout-12s-k2fZYeKl.cjs +0 -120
- package/dist/column-menu-12s-6Yvu4SZ0.js +0 -406
- package/dist/column-menu-12s-BnknuXGh.cjs +0 -426
- package/dist/editors-12s-C0RxmTcI.cjs +0 -554
- package/dist/editors-12s-COixUnI2.js +0 -524
- package/dist/resize-12s-CajyNXFB.js +0 -58
- package/dist/resize-12s-ChLpxb4i.cjs +0 -58
- package/dist/states-12s-BB0PT_bq.cjs +0 -125
- package/dist/states-12s-m5mBR90e.js +0 -122
- package/dist/toolbar-12s-B1xiS-Zu.js +0 -68
- package/dist/toolbar-12s-DzLbghpK.cjs +0 -70
- package/dist/useDataTable-12s-BHiDUubw-12s-CBeCwTe7.js +0 -61
- package/dist/useDataTable-12s-BHiDUubw-12s-Dgvt7XDk.cjs +0 -61
- package/dist/useDataTableColumnCalc-12s-DTQQTtEJ-12s-CvD14JYo.cjs +0 -207
- package/dist/useDataTableColumnCalc-12s-DTQQTtEJ-12s-DsEse3uq.js +0 -183
- package/dist/useDataTableColumns-12s-Cn2ZAzFL-12s-CD6goR59.js +0 -289
- package/dist/useDataTableColumns-12s-Cn2ZAzFL-12s-CUk_CpYT.cjs +0 -292
- package/dist/useDataTableEdit-12s-9Wb_UCrN-12s-BoOHq3GB.js +0 -98
- package/dist/useDataTableEdit-12s-9Wb_UCrN-12s-De6YHBba.cjs +0 -98
- package/dist/useDataTableFilter-12s-ZzbmWMin-12s-CWyBeFna.js +0 -74
- package/dist/useDataTableFilter-12s-ZzbmWMin-12s-lpjzZY3_.cjs +0 -74
- package/dist/useDataTableInfiniteScroll-12s-8ZG31URd-12s-BexjP6iO.js +0 -104
- package/dist/useDataTableInfiniteScroll-12s-8ZG31URd-12s-Bt8gojr9.cjs +0 -104
- package/dist/useDataTableRow-12s-CPYaDa1p-12s-4qkGoz-j.js +0 -30
- package/dist/useDataTableRow-12s-CPYaDa1p-12s-DG64uYjn.cjs +0 -30
- package/dist/useDataTableScroll-12s-BKDCr0en-12s-C7f2vHeG.js +0 -61
- package/dist/useDataTableScroll-12s-BKDCr0en-12s-CUvUYMtt.cjs +0 -61
- package/dist/useDataTableSearch-12s-Ck3iWcpX-12s-B-65V6gH.js +0 -37
- package/dist/useDataTableSearch-12s-Ck3iWcpX-12s-DhVfN2Hq.cjs +0 -37
- package/dist/useDataTableSelection-12s-BIDtiRQq-12s-IS__VAnU.cjs +0 -71
- package/dist/useDataTableSelection-12s-BIDtiRQq-12s-O6M_BhrH.js +0 -71
- package/dist/useDataTableSort-12s-DvJYtmeS-12s-C5VGnsq4.cjs +0 -78
- package/dist/useDataTableSort-12s-DvJYtmeS-12s-DABSNt6U.js +0 -78
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
function __insertCSS(code) {
|
|
3
|
-
if (!code || typeof document == 'undefined') return
|
|
4
|
-
let head = document.head || document.getElementsByTagName('head')[0]
|
|
5
|
-
let style = document.createElement('style')
|
|
6
|
-
style.type = 'text/css'
|
|
7
|
-
head.appendChild(style)
|
|
8
|
-
;style.styleSheet ? (style.styleSheet.cssText = code) : style.appendChild(document.createTextNode(code))
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
var useDataTableColumnCalc12sDTQQTtEJ12s = require('./useDataTableColumnCalc-12s-DTQQTtEJ-12s-CvD14JYo.cjs');
|
|
12
|
-
var domUtils = require('@seed-design/dom-utils');
|
|
13
|
-
var React = require('react');
|
|
14
|
-
|
|
15
|
-
// Select's `dom.ts` reads state off REAL rendered elements (aria-disabled, data-value)
|
|
16
|
-
// because its options register asynchronously through a floating-ui list and the DOM
|
|
17
|
-
// is the one thing always in sync with `elementsRef`. DataTable's selection has no
|
|
18
|
-
// such registry -- it is two plain id arrays (`rowIds`, `selectedIds`) the root already
|
|
19
|
-
// holds -- so there is nothing to inspect on an element. What's isolated here instead is
|
|
20
|
-
// the same KIND of thing Select isolates: small pure functions the state hooks would
|
|
21
|
-
// otherwise inline, kept out of the hooks so they can be unit-tested (and mutation-
|
|
22
|
-
// tested) on their own.
|
|
23
|
-
/**
|
|
24
|
-
* Tri-state selection summary of `selectedIds` against the CURRENTLY RENDERED
|
|
25
|
-
* `rowIds` -- never against `selectedIds` alone, so a stale id that scrolled out of a
|
|
26
|
-
* filtered/sorted view can't quietly count toward "all" or "some".
|
|
27
|
-
*/ function computeSelectionState(rowIds, selectedIds) {
|
|
28
|
-
if (rowIds.length === 0) return "none";
|
|
29
|
-
const selectedIdSet = new Set(selectedIds);
|
|
30
|
-
const selectedRowCount = rowIds.filter((id)=>selectedIdSet.has(id)).length;
|
|
31
|
-
if (selectedRowCount === 0) return "none";
|
|
32
|
-
return selectedRowCount === rowIds.length ? "all" : "some";
|
|
33
|
-
}
|
|
34
|
-
/** Adds `id` if absent, removes it if present. Never mutates `ids`. */ function toggleMembership(ids, id) {
|
|
35
|
-
return ids.includes(id) ? ids.filter((existing)=>existing !== id) : [
|
|
36
|
-
...ids,
|
|
37
|
-
id
|
|
38
|
-
];
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Reconciles a persisted/controlled column ORDER against the table's current column
|
|
42
|
-
* KEYS -- used by useDataTableColumns so a consumer's `columnOrder` never silently drops
|
|
43
|
-
* a column the table actually renders (a key added to `columns` after the order was
|
|
44
|
-
* first captured) nor keeps a ghost entry for one that was removed. Known keys keep
|
|
45
|
-
* their position from `order`; any key in `keys` missing from `order` is appended, in
|
|
46
|
-
* `keys`' own order; any entry in `order` no longer in `keys` is dropped.
|
|
47
|
-
*/ function reconcileColumnOrder(order, keys) {
|
|
48
|
-
const keySet = new Set(keys);
|
|
49
|
-
const known = order.filter((key)=>keySet.has(key));
|
|
50
|
-
const knownSet = new Set(known);
|
|
51
|
-
const added = keys.filter((key)=>!knownSet.has(key));
|
|
52
|
-
return [
|
|
53
|
-
...known,
|
|
54
|
-
...added
|
|
55
|
-
];
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Moves `key` one step toward `direction` in `order` -- a no-op (same array, well,
|
|
59
|
-
* an equal-valued copy) at the edge it would otherwise walk off. Column-menu's
|
|
60
|
-
* "Move left"/"Move right" (DATATABLE-ATTIO-SPEC.md's column menu) is one call of
|
|
61
|
-
* this per click; drag-to-reorder is `reorderColumn` below instead, which can jump
|
|
62
|
-
* more than one position in a single move.
|
|
63
|
-
*/ function moveColumnKey(order, key, direction) {
|
|
64
|
-
const index = order.indexOf(key);
|
|
65
|
-
if (index === -1) return [
|
|
66
|
-
...order
|
|
67
|
-
];
|
|
68
|
-
const targetIndex = direction === "left" ? index - 1 : index + 1;
|
|
69
|
-
if (targetIndex < 0 || targetIndex >= order.length) return [
|
|
70
|
-
...order
|
|
71
|
-
];
|
|
72
|
-
const next = [
|
|
73
|
-
...order
|
|
74
|
-
];
|
|
75
|
-
[next[index], next[targetIndex]] = [
|
|
76
|
-
next[targetIndex],
|
|
77
|
-
next[index]
|
|
78
|
-
];
|
|
79
|
-
return next;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Drag-to-reorder: removes `dragKey` from `order` and reinserts it immediately before
|
|
83
|
-
* `dropKey`'s CURRENT position (i.e. its position after the removal, so dropping a
|
|
84
|
-
* column just after its own old slot doesn't appear to do nothing). A no-op (an
|
|
85
|
-
* equal-valued copy) when either key is missing or they're the same key.
|
|
86
|
-
*/ function reorderColumnKey(order, dragKey, dropKey) {
|
|
87
|
-
if (dragKey === dropKey || !order.includes(dragKey) || !order.includes(dropKey)) {
|
|
88
|
-
return [
|
|
89
|
-
...order
|
|
90
|
-
];
|
|
91
|
-
}
|
|
92
|
-
const withoutDrag = order.filter((key)=>key !== dragKey);
|
|
93
|
-
const dropIndex = withoutDrag.indexOf(dropKey);
|
|
94
|
-
return [
|
|
95
|
-
...withoutDrag.slice(0, dropIndex),
|
|
96
|
-
dragKey,
|
|
97
|
-
...withoutDrag.slice(dropIndex)
|
|
98
|
-
];
|
|
99
|
-
}
|
|
100
|
-
/** Clamps a drag-resized column width to a sane range -- crisp's own datatable.tsx
|
|
101
|
-
* resize handler clamps the same way (a column can neither collapse to unreadable
|
|
102
|
-
* nor balloon past a sane cap from one fast mouse move). */ function clampColumnWidth(width, min = 80, max = 640) {
|
|
103
|
-
return Math.min(max, Math.max(min, width));
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Infinite scroll's own gate: fire `onLoadMore` only when the sentinel is ACTUALLY
|
|
107
|
-
* intersecting (not e.g. an observer's initial `false` callback, which fires once on
|
|
108
|
-
* `observe()` before any real intersection), there IS a next page (`hasMore`), and no
|
|
109
|
-
* fetch is already in flight (`loadingMore`) -- either of the latter two alone must
|
|
110
|
-
* suppress a trigger, which is why this is a pure `&&` rather than three separate
|
|
111
|
-
* call sites that could each drift. Isolated the same way `computeSelectionState`/
|
|
112
|
-
* `toggleMembership` are: the real IntersectionObserver callback (useDataTable
|
|
113
|
-
* InfiniteScroll.ts) is unit-testable only through a live browser API, but the
|
|
114
|
-
* DECISION it makes on every callback is plain data in, boolean out.
|
|
115
|
-
*/ function shouldTriggerLoadMore(isIntersecting, hasMore, loadingMore) {
|
|
116
|
-
return hasMore && !loadingMore;
|
|
117
|
-
}
|
|
118
|
-
const EMPTY_STRINGS = [];
|
|
119
|
-
const EMPTY_RECORD = {};
|
|
120
|
-
/**
|
|
121
|
-
* Owns everything DATATABLE-ATTIO-SPEC.md's column menu + reorder + resize tranche
|
|
122
|
-
* needs -- order, visibility, a per-column label override, and a per-column width --
|
|
123
|
-
* the way useDataTableSelection owns the one selected-id SET rather than one hook per
|
|
124
|
-
* row. All four are "one value per column key" maps/lists a consumer may want to
|
|
125
|
-
* persist (a saved view), so they share this hook instead of splitting into four
|
|
126
|
-
* separate ones; drag-to-reorder and drag-to-resize (below) are the two INTERACTIONS
|
|
127
|
-
* built on top of the order/width state this hook already owns, not independent state
|
|
128
|
-
* of their own.
|
|
129
|
-
*/ function useDataTableColumns(props) {
|
|
130
|
-
const { columnKeys = EMPTY_STRINGS, columnOrder: columnOrderProp, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys: hiddenProp, defaultHiddenColumnKeys = EMPTY_STRINGS, onHiddenColumnKeysChange, columnWidths: widthsProp, defaultColumnWidths = EMPTY_RECORD, onColumnWidthsChange, columnLabels: labelsProp, defaultColumnLabels = EMPTY_RECORD, onColumnLabelsChange } = props;
|
|
131
|
-
const [rawOrder, setRawOrder] = useDataTableColumnCalc12sDTQQTtEJ12s.useControllableState({
|
|
132
|
-
prop: columnOrderProp,
|
|
133
|
-
defaultProp: defaultColumnOrder ?? columnKeys,
|
|
134
|
-
onChange: onColumnOrderChange
|
|
135
|
-
});
|
|
136
|
-
// Reconciled EVERY render against the table's current `columnKeys` (dom.ts's
|
|
137
|
-
// `reconcileColumnOrder`), not just once at mount -- a controlled `columnOrder` a
|
|
138
|
-
// consumer persisted before a new column existed must still show that new column
|
|
139
|
-
// (appended), and one holding a column that got removed from `columns` must not
|
|
140
|
-
// render a ghost header for it.
|
|
141
|
-
const columnOrder = React.useMemo(()=>reconcileColumnOrder(rawOrder ?? columnKeys, columnKeys), [
|
|
142
|
-
rawOrder,
|
|
143
|
-
columnKeys
|
|
144
|
-
]);
|
|
145
|
-
const [hiddenColumnKeys = EMPTY_STRINGS, setHiddenColumnKeys] = useDataTableColumnCalc12sDTQQTtEJ12s.useControllableState({
|
|
146
|
-
prop: hiddenProp,
|
|
147
|
-
defaultProp: defaultHiddenColumnKeys,
|
|
148
|
-
onChange: onHiddenColumnKeysChange
|
|
149
|
-
});
|
|
150
|
-
const hiddenSet = React.useMemo(()=>new Set(hiddenColumnKeys), [
|
|
151
|
-
hiddenColumnKeys
|
|
152
|
-
]);
|
|
153
|
-
const [columnWidths = EMPTY_RECORD, setColumnWidths] = useDataTableColumnCalc12sDTQQTtEJ12s.useControllableState({
|
|
154
|
-
prop: widthsProp,
|
|
155
|
-
defaultProp: defaultColumnWidths,
|
|
156
|
-
onChange: onColumnWidthsChange
|
|
157
|
-
});
|
|
158
|
-
const [columnLabels = EMPTY_RECORD, setColumnLabels] = useDataTableColumnCalc12sDTQQTtEJ12s.useControllableState({
|
|
159
|
-
prop: labelsProp,
|
|
160
|
-
defaultProp: defaultColumnLabels,
|
|
161
|
-
onChange: onColumnLabelsChange
|
|
162
|
-
});
|
|
163
|
-
const visibleColumnOrder = React.useMemo(()=>columnOrder.filter((key)=>!hiddenSet.has(key)), [
|
|
164
|
-
columnOrder,
|
|
165
|
-
hiddenSet
|
|
166
|
-
]);
|
|
167
|
-
const isColumnHidden = React.useCallback((key)=>hiddenSet.has(key), [
|
|
168
|
-
hiddenSet
|
|
169
|
-
]);
|
|
170
|
-
const hideColumn = React.useCallback((key)=>setHiddenColumnKeys((current = EMPTY_STRINGS)=>[
|
|
171
|
-
...current,
|
|
172
|
-
key
|
|
173
|
-
]), [
|
|
174
|
-
setHiddenColumnKeys
|
|
175
|
-
]);
|
|
176
|
-
const showColumn = React.useCallback((key)=>setHiddenColumnKeys((current = EMPTY_STRINGS)=>current.filter((existing)=>existing !== key)), [
|
|
177
|
-
setHiddenColumnKeys
|
|
178
|
-
]);
|
|
179
|
-
const toggleColumnVisibility = React.useCallback((key)=>isColumnHidden(key) ? showColumn(key) : hideColumn(key), [
|
|
180
|
-
isColumnHidden,
|
|
181
|
-
showColumn,
|
|
182
|
-
hideColumn
|
|
183
|
-
]);
|
|
184
|
-
const getColumnLabel = React.useCallback((key, fallback)=>columnLabels[key] ?? fallback, [
|
|
185
|
-
columnLabels
|
|
186
|
-
]);
|
|
187
|
-
const renameColumn = React.useCallback((key, label)=>setColumnLabels((current = EMPTY_RECORD)=>({
|
|
188
|
-
...current,
|
|
189
|
-
[key]: label
|
|
190
|
-
})), [
|
|
191
|
-
setColumnLabels
|
|
192
|
-
]);
|
|
193
|
-
const getColumnWidth = React.useCallback((key)=>columnWidths[key], [
|
|
194
|
-
columnWidths
|
|
195
|
-
]);
|
|
196
|
-
const setColumnWidth = React.useCallback((key, width)=>setColumnWidths((current = EMPTY_RECORD)=>({
|
|
197
|
-
...current,
|
|
198
|
-
[key]: clampColumnWidth(width)
|
|
199
|
-
})), [
|
|
200
|
-
setColumnWidths
|
|
201
|
-
]);
|
|
202
|
-
const moveColumn = React.useCallback((key, direction)=>setRawOrder((current)=>moveColumnKey(current ?? columnKeys, key, direction)), [
|
|
203
|
-
setRawOrder,
|
|
204
|
-
columnKeys
|
|
205
|
-
]);
|
|
206
|
-
const reorderColumn = React.useCallback((dragKey, dropKey)=>setRawOrder((current)=>reorderColumnKey(current ?? columnKeys, dragKey, dropKey)), [
|
|
207
|
-
setRawOrder,
|
|
208
|
-
columnKeys
|
|
209
|
-
]);
|
|
210
|
-
// -- drag-to-reorder ---------------------------------------------------------------
|
|
211
|
-
// Live state only (which column is currently being dragged) -- the styled layer
|
|
212
|
-
// drives it by calling `dragOverColumn` as the pointer crosses OTHER header cells
|
|
213
|
-
// (via `document.elementFromPoint`, since a captured pointer stops native
|
|
214
|
-
// `pointerenter` from firing on siblings), which reorders immediately rather than
|
|
215
|
-
// waiting for a drop. That is exactly what Attio's own header drag does (the column
|
|
216
|
-
// being passed visibly swaps live), and it means `endColumnDrag` never has to also
|
|
217
|
-
// commit a move -- there is nothing left to commit.
|
|
218
|
-
const [draggingColumnKey, setDraggingColumnKey] = React.useState(null);
|
|
219
|
-
const beginColumnDrag = React.useCallback((key)=>setDraggingColumnKey(key), []);
|
|
220
|
-
const dragOverColumn = React.useCallback((hoverKey)=>{
|
|
221
|
-
setDraggingColumnKey((current)=>{
|
|
222
|
-
if (!current || current === hoverKey) return current;
|
|
223
|
-
reorderColumn(current, hoverKey);
|
|
224
|
-
return current;
|
|
225
|
-
});
|
|
226
|
-
}, [
|
|
227
|
-
reorderColumn
|
|
228
|
-
]);
|
|
229
|
-
const endColumnDrag = React.useCallback(()=>setDraggingColumnKey(null), []);
|
|
230
|
-
// -- drag-to-resize ------------------------------------------------------------------
|
|
231
|
-
// `resizeStartRef` holds the ONE thing that must survive across pointermove events
|
|
232
|
-
// without triggering a re-render on every pixel (the drag's origin) -- state
|
|
233
|
-
// (`resizingColumnKey`) is only for what the render actually needs: which column's
|
|
234
|
-
// handle should show its active/dragging look.
|
|
235
|
-
const resizeStartRef = React.useRef(null);
|
|
236
|
-
const [resizingColumnKey, setResizingColumnKey] = React.useState(null);
|
|
237
|
-
const beginColumnResize = React.useCallback((key, clientX, currentWidth)=>{
|
|
238
|
-
resizeStartRef.current = {
|
|
239
|
-
key,
|
|
240
|
-
startX: clientX,
|
|
241
|
-
startWidth: currentWidth
|
|
242
|
-
};
|
|
243
|
-
setResizingColumnKey(key);
|
|
244
|
-
}, []);
|
|
245
|
-
const updateColumnResize = React.useCallback((clientX)=>{
|
|
246
|
-
const start = resizeStartRef.current;
|
|
247
|
-
if (!start) return;
|
|
248
|
-
setColumnWidth(start.key, start.startWidth + (clientX - start.startX));
|
|
249
|
-
}, [
|
|
250
|
-
setColumnWidth
|
|
251
|
-
]);
|
|
252
|
-
const endColumnResize = React.useCallback(()=>{
|
|
253
|
-
resizeStartRef.current = null;
|
|
254
|
-
setResizingColumnKey(null);
|
|
255
|
-
}, []);
|
|
256
|
-
return {
|
|
257
|
-
columnOrder,
|
|
258
|
-
visibleColumnOrder,
|
|
259
|
-
hiddenColumnKeys,
|
|
260
|
-
columnWidths,
|
|
261
|
-
columnLabels,
|
|
262
|
-
isColumnHidden,
|
|
263
|
-
hideColumn,
|
|
264
|
-
showColumn,
|
|
265
|
-
toggleColumnVisibility,
|
|
266
|
-
getColumnLabel,
|
|
267
|
-
renameColumn,
|
|
268
|
-
getColumnWidth,
|
|
269
|
-
setColumnWidth,
|
|
270
|
-
moveColumn,
|
|
271
|
-
reorderColumn,
|
|
272
|
-
draggingColumnKey,
|
|
273
|
-
beginColumnDrag,
|
|
274
|
-
dragOverColumn,
|
|
275
|
-
endColumnDrag,
|
|
276
|
-
resizingColumnKey,
|
|
277
|
-
beginColumnResize,
|
|
278
|
-
updateColumnResize,
|
|
279
|
-
endColumnResize,
|
|
280
|
-
// Exposed for the styled layer's header cell -- `data-dragging`/`data-resizing`
|
|
281
|
-
// read directly off state above already cover most of it; `dataAttr` re-exported
|
|
282
|
-
// via this hook's own module keeps every other sub-hook's habit of building its
|
|
283
|
-
// own data-attribute values rather than the styled layer re-deriving booleans.
|
|
284
|
-
isColumnDragging: (key)=>domUtils.dataAttr(draggingColumnKey === key),
|
|
285
|
-
isColumnResizing: (key)=>domUtils.dataAttr(resizingColumnKey === key)
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
exports.computeSelectionState = computeSelectionState;
|
|
290
|
-
exports.shouldTriggerLoadMore = shouldTriggerLoadMore;
|
|
291
|
-
exports.toggleMembership = toggleMembership;
|
|
292
|
-
exports.useDataTableColumns = useDataTableColumns;
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
function __insertCSS(code) {
|
|
3
|
-
if (!code || typeof document == 'undefined') return
|
|
4
|
-
let head = document.head || document.getElementsByTagName('head')[0]
|
|
5
|
-
let style = document.createElement('style')
|
|
6
|
-
style.type = 'text/css'
|
|
7
|
-
head.appendChild(style)
|
|
8
|
-
;style.styleSheet ? (style.styleSheet.cssText = code) : style.appendChild(document.createTextNode(code))
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
import { useState, useCallback } from 'react';
|
|
12
|
-
|
|
13
|
-
function sameCell(a, id, key) {
|
|
14
|
-
return a !== null && a.id === id && a.key === key;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Owns which single cell is mid-edit, which one (if any) has a commit in flight, and
|
|
18
|
-
* which one last failed -- the way useDataTableColumnCalc owns which op is active per
|
|
19
|
-
* column. This hook never touches `TRow` or renders an editor itself; it only tracks
|
|
20
|
-
* WHICH cell is in which of those three states and orchestrates the async commit
|
|
21
|
-
* (crisp's own `commitEdit`, `datatable.tsx`) -- the styled layer (react/DataTable's
|
|
22
|
-
* `editors.tsx`) reads `isEditing`/`isPending`/`getEditError` to decide what to render
|
|
23
|
-
* for a given `(id, key)` and calls `startEdit`/`cancelEdit`/`commitEdit` in response
|
|
24
|
-
* to a double-click, Escape, Enter/blur, or an always-live widget's own change event.
|
|
25
|
-
*
|
|
26
|
-
* Only one cell can be mid-edit at a time (`editingCell`, not a set) -- matching
|
|
27
|
-
* crisp's own single `editing` state and this table's spec (no multi-cell/range
|
|
28
|
-
* editing is in scope here).
|
|
29
|
-
*/ function useDataTableEdit(props) {
|
|
30
|
-
const { onEdit } = props;
|
|
31
|
-
const [editingCell, setEditingCell] = useState(null);
|
|
32
|
-
const [pendingCell, setPendingCell] = useState(null);
|
|
33
|
-
const [editError, setEditError] = useState(null);
|
|
34
|
-
const isEditing = useCallback((id, key)=>sameCell(editingCell, id, key), [
|
|
35
|
-
editingCell
|
|
36
|
-
]);
|
|
37
|
-
const isPending = useCallback((id, key)=>sameCell(pendingCell, id, key), [
|
|
38
|
-
pendingCell
|
|
39
|
-
]);
|
|
40
|
-
const getEditError = useCallback((id, key)=>editError && editError.id === id && editError.key === key ? editError.message : null, [
|
|
41
|
-
editError
|
|
42
|
-
]);
|
|
43
|
-
const startEdit = useCallback((id, key)=>{
|
|
44
|
-
// Opening a cell's editor also clears any stale error left over from a PREVIOUS
|
|
45
|
-
// failed commit on it (crisp/#385 comment) -- otherwise a rejection from three
|
|
46
|
-
// edits ago would still read under a freshly-reopened editor.
|
|
47
|
-
setEditError(null);
|
|
48
|
-
setEditingCell({
|
|
49
|
-
id,
|
|
50
|
-
key
|
|
51
|
-
});
|
|
52
|
-
}, []);
|
|
53
|
-
const cancelEdit = useCallback(()=>setEditingCell(null), []);
|
|
54
|
-
// Async-aware (crisp/#385): a sync `onEdit` (returns undefined) commits exactly as
|
|
55
|
-
// before -- close the editor immediately. A Promise-returning `onEdit` keeps the
|
|
56
|
-
// editor open with a pending state while it settles, then either closes it
|
|
57
|
-
// (resolve) or closes it AND reverts to the last-known-good value while showing the
|
|
58
|
-
// rejection's message beside the cell (reject). The revert needs no extra code:
|
|
59
|
-
// neither this hook nor the styled layer ever mutates the caller's own row data, so
|
|
60
|
-
// once `editingCell` clears, the cell simply shows that data again.
|
|
61
|
-
const commitEdit = useCallback((id, key, value)=>{
|
|
62
|
-
setEditError(null);
|
|
63
|
-
const result = onEdit?.(id, key, value);
|
|
64
|
-
if (result && typeof result.then === "function") {
|
|
65
|
-
setPendingCell({
|
|
66
|
-
id,
|
|
67
|
-
key
|
|
68
|
-
});
|
|
69
|
-
result.then(()=>{
|
|
70
|
-
setPendingCell(null);
|
|
71
|
-
setEditingCell(null);
|
|
72
|
-
}, (err)=>{
|
|
73
|
-
setPendingCell(null);
|
|
74
|
-
setEditingCell(null);
|
|
75
|
-
setEditError({
|
|
76
|
-
id,
|
|
77
|
-
key,
|
|
78
|
-
message: err instanceof Error ? err.message : typeof err === "string" ? err : "Could not save"
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
setEditingCell(null);
|
|
84
|
-
}, [
|
|
85
|
-
onEdit
|
|
86
|
-
]);
|
|
87
|
-
return {
|
|
88
|
-
editingCell,
|
|
89
|
-
isEditing,
|
|
90
|
-
isPending,
|
|
91
|
-
getEditError,
|
|
92
|
-
startEdit,
|
|
93
|
-
cancelEdit,
|
|
94
|
-
commitEdit
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export { useDataTableEdit as u };
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
function __insertCSS(code) {
|
|
3
|
-
if (!code || typeof document == 'undefined') return
|
|
4
|
-
let head = document.head || document.getElementsByTagName('head')[0]
|
|
5
|
-
let style = document.createElement('style')
|
|
6
|
-
style.type = 'text/css'
|
|
7
|
-
head.appendChild(style)
|
|
8
|
-
;style.styleSheet ? (style.styleSheet.cssText = code) : style.appendChild(document.createTextNode(code))
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
var React = require('react');
|
|
12
|
-
|
|
13
|
-
function sameCell(a, id, key) {
|
|
14
|
-
return a !== null && a.id === id && a.key === key;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Owns which single cell is mid-edit, which one (if any) has a commit in flight, and
|
|
18
|
-
* which one last failed -- the way useDataTableColumnCalc owns which op is active per
|
|
19
|
-
* column. This hook never touches `TRow` or renders an editor itself; it only tracks
|
|
20
|
-
* WHICH cell is in which of those three states and orchestrates the async commit
|
|
21
|
-
* (crisp's own `commitEdit`, `datatable.tsx`) -- the styled layer (react/DataTable's
|
|
22
|
-
* `editors.tsx`) reads `isEditing`/`isPending`/`getEditError` to decide what to render
|
|
23
|
-
* for a given `(id, key)` and calls `startEdit`/`cancelEdit`/`commitEdit` in response
|
|
24
|
-
* to a double-click, Escape, Enter/blur, or an always-live widget's own change event.
|
|
25
|
-
*
|
|
26
|
-
* Only one cell can be mid-edit at a time (`editingCell`, not a set) -- matching
|
|
27
|
-
* crisp's own single `editing` state and this table's spec (no multi-cell/range
|
|
28
|
-
* editing is in scope here).
|
|
29
|
-
*/ function useDataTableEdit(props) {
|
|
30
|
-
const { onEdit } = props;
|
|
31
|
-
const [editingCell, setEditingCell] = React.useState(null);
|
|
32
|
-
const [pendingCell, setPendingCell] = React.useState(null);
|
|
33
|
-
const [editError, setEditError] = React.useState(null);
|
|
34
|
-
const isEditing = React.useCallback((id, key)=>sameCell(editingCell, id, key), [
|
|
35
|
-
editingCell
|
|
36
|
-
]);
|
|
37
|
-
const isPending = React.useCallback((id, key)=>sameCell(pendingCell, id, key), [
|
|
38
|
-
pendingCell
|
|
39
|
-
]);
|
|
40
|
-
const getEditError = React.useCallback((id, key)=>editError && editError.id === id && editError.key === key ? editError.message : null, [
|
|
41
|
-
editError
|
|
42
|
-
]);
|
|
43
|
-
const startEdit = React.useCallback((id, key)=>{
|
|
44
|
-
// Opening a cell's editor also clears any stale error left over from a PREVIOUS
|
|
45
|
-
// failed commit on it (crisp/#385 comment) -- otherwise a rejection from three
|
|
46
|
-
// edits ago would still read under a freshly-reopened editor.
|
|
47
|
-
setEditError(null);
|
|
48
|
-
setEditingCell({
|
|
49
|
-
id,
|
|
50
|
-
key
|
|
51
|
-
});
|
|
52
|
-
}, []);
|
|
53
|
-
const cancelEdit = React.useCallback(()=>setEditingCell(null), []);
|
|
54
|
-
// Async-aware (crisp/#385): a sync `onEdit` (returns undefined) commits exactly as
|
|
55
|
-
// before -- close the editor immediately. A Promise-returning `onEdit` keeps the
|
|
56
|
-
// editor open with a pending state while it settles, then either closes it
|
|
57
|
-
// (resolve) or closes it AND reverts to the last-known-good value while showing the
|
|
58
|
-
// rejection's message beside the cell (reject). The revert needs no extra code:
|
|
59
|
-
// neither this hook nor the styled layer ever mutates the caller's own row data, so
|
|
60
|
-
// once `editingCell` clears, the cell simply shows that data again.
|
|
61
|
-
const commitEdit = React.useCallback((id, key, value)=>{
|
|
62
|
-
setEditError(null);
|
|
63
|
-
const result = onEdit?.(id, key, value);
|
|
64
|
-
if (result && typeof result.then === "function") {
|
|
65
|
-
setPendingCell({
|
|
66
|
-
id,
|
|
67
|
-
key
|
|
68
|
-
});
|
|
69
|
-
result.then(()=>{
|
|
70
|
-
setPendingCell(null);
|
|
71
|
-
setEditingCell(null);
|
|
72
|
-
}, (err)=>{
|
|
73
|
-
setPendingCell(null);
|
|
74
|
-
setEditingCell(null);
|
|
75
|
-
setEditError({
|
|
76
|
-
id,
|
|
77
|
-
key,
|
|
78
|
-
message: err instanceof Error ? err.message : typeof err === "string" ? err : "Could not save"
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
setEditingCell(null);
|
|
84
|
-
}, [
|
|
85
|
-
onEdit
|
|
86
|
-
]);
|
|
87
|
-
return {
|
|
88
|
-
editingCell,
|
|
89
|
-
isEditing,
|
|
90
|
-
isPending,
|
|
91
|
-
getEditError,
|
|
92
|
-
startEdit,
|
|
93
|
-
cancelEdit,
|
|
94
|
-
commitEdit
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
exports.useDataTableEdit = useDataTableEdit;
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
function __insertCSS(code) {
|
|
3
|
-
if (!code || typeof document == 'undefined') return
|
|
4
|
-
let head = document.head || document.getElementsByTagName('head')[0]
|
|
5
|
-
let style = document.createElement('style')
|
|
6
|
-
style.type = 'text/css'
|
|
7
|
-
head.appendChild(style)
|
|
8
|
-
;style.styleSheet ? (style.styleSheet.cssText = code) : style.appendChild(document.createTextNode(code))
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
import { d as useControllableState } from './useDataTableColumnCalc-12s-DTQQTtEJ-12s-DsEse3uq.js';
|
|
12
|
-
import { useCallback } from 'react';
|
|
13
|
-
import { t as toggleMembership } from './useDataTableColumns-12s-Cn2ZAzFL-12s-CD6goR59.js';
|
|
14
|
-
|
|
15
|
-
const EMPTY_FILTERS = {};
|
|
16
|
-
// Owns one filter per column key -- the way useDataTableSelection owns one selected-id
|
|
17
|
-
// SET rather than one boolean per row. Applying a column's filter to `data` needs
|
|
18
|
-
// `TRow` (a type this headless package never sees), so -- same split as search/sort --
|
|
19
|
-
// this hook only tracks which mode/values are checked per column; the styled layer
|
|
20
|
-
// (DataTable.tsx's `getVisibleRows`) reads it to actually narrow rows.
|
|
21
|
-
function useDataTableFilter(props) {
|
|
22
|
-
const { filters: filtersProp, defaultFilters = EMPTY_FILTERS, onFiltersChange } = props;
|
|
23
|
-
const [filters = EMPTY_FILTERS, setFilters] = useControllableState({
|
|
24
|
-
prop: filtersProp,
|
|
25
|
-
defaultProp: defaultFilters,
|
|
26
|
-
onChange: onFiltersChange
|
|
27
|
-
});
|
|
28
|
-
const setFilterMode = useCallback((columnKey, mode)=>{
|
|
29
|
-
setFilters((current = EMPTY_FILTERS)=>({
|
|
30
|
-
...current,
|
|
31
|
-
[columnKey]: {
|
|
32
|
-
mode,
|
|
33
|
-
values: current[columnKey]?.values ?? []
|
|
34
|
-
}
|
|
35
|
-
}));
|
|
36
|
-
}, [
|
|
37
|
-
setFilters
|
|
38
|
-
]);
|
|
39
|
-
const toggleFilterValue = useCallback((columnKey, value)=>{
|
|
40
|
-
setFilters((current = EMPTY_FILTERS)=>({
|
|
41
|
-
...current,
|
|
42
|
-
[columnKey]: {
|
|
43
|
-
mode: current[columnKey]?.mode ?? "is",
|
|
44
|
-
values: toggleMembership(current[columnKey]?.values ?? [], value)
|
|
45
|
-
}
|
|
46
|
-
}));
|
|
47
|
-
}, [
|
|
48
|
-
setFilters
|
|
49
|
-
]);
|
|
50
|
-
const clearFilter = useCallback((columnKey)=>{
|
|
51
|
-
setFilters((current = EMPTY_FILTERS)=>{
|
|
52
|
-
if (!(columnKey in current)) return current;
|
|
53
|
-
const next = {
|
|
54
|
-
...current
|
|
55
|
-
};
|
|
56
|
-
delete next[columnKey];
|
|
57
|
-
return next;
|
|
58
|
-
});
|
|
59
|
-
}, [
|
|
60
|
-
setFilters
|
|
61
|
-
]);
|
|
62
|
-
const isFilterActive = useCallback((columnKey)=>(filters[columnKey]?.values.length ?? 0) > 0, [
|
|
63
|
-
filters
|
|
64
|
-
]);
|
|
65
|
-
return {
|
|
66
|
-
filters,
|
|
67
|
-
setFilterMode,
|
|
68
|
-
toggleFilterValue,
|
|
69
|
-
clearFilter,
|
|
70
|
-
isFilterActive
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export { useDataTableFilter as u };
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
function __insertCSS(code) {
|
|
3
|
-
if (!code || typeof document == 'undefined') return
|
|
4
|
-
let head = document.head || document.getElementsByTagName('head')[0]
|
|
5
|
-
let style = document.createElement('style')
|
|
6
|
-
style.type = 'text/css'
|
|
7
|
-
head.appendChild(style)
|
|
8
|
-
;style.styleSheet ? (style.styleSheet.cssText = code) : style.appendChild(document.createTextNode(code))
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
var useDataTableColumnCalc12sDTQQTtEJ12s = require('./useDataTableColumnCalc-12s-DTQQTtEJ-12s-CvD14JYo.cjs');
|
|
12
|
-
var React = require('react');
|
|
13
|
-
var useDataTableColumns12sCn2ZAzFL12s = require('./useDataTableColumns-12s-Cn2ZAzFL-12s-CUk_CpYT.cjs');
|
|
14
|
-
|
|
15
|
-
const EMPTY_FILTERS = {};
|
|
16
|
-
// Owns one filter per column key -- the way useDataTableSelection owns one selected-id
|
|
17
|
-
// SET rather than one boolean per row. Applying a column's filter to `data` needs
|
|
18
|
-
// `TRow` (a type this headless package never sees), so -- same split as search/sort --
|
|
19
|
-
// this hook only tracks which mode/values are checked per column; the styled layer
|
|
20
|
-
// (DataTable.tsx's `getVisibleRows`) reads it to actually narrow rows.
|
|
21
|
-
function useDataTableFilter(props) {
|
|
22
|
-
const { filters: filtersProp, defaultFilters = EMPTY_FILTERS, onFiltersChange } = props;
|
|
23
|
-
const [filters = EMPTY_FILTERS, setFilters] = useDataTableColumnCalc12sDTQQTtEJ12s.useControllableState({
|
|
24
|
-
prop: filtersProp,
|
|
25
|
-
defaultProp: defaultFilters,
|
|
26
|
-
onChange: onFiltersChange
|
|
27
|
-
});
|
|
28
|
-
const setFilterMode = React.useCallback((columnKey, mode)=>{
|
|
29
|
-
setFilters((current = EMPTY_FILTERS)=>({
|
|
30
|
-
...current,
|
|
31
|
-
[columnKey]: {
|
|
32
|
-
mode,
|
|
33
|
-
values: current[columnKey]?.values ?? []
|
|
34
|
-
}
|
|
35
|
-
}));
|
|
36
|
-
}, [
|
|
37
|
-
setFilters
|
|
38
|
-
]);
|
|
39
|
-
const toggleFilterValue = React.useCallback((columnKey, value)=>{
|
|
40
|
-
setFilters((current = EMPTY_FILTERS)=>({
|
|
41
|
-
...current,
|
|
42
|
-
[columnKey]: {
|
|
43
|
-
mode: current[columnKey]?.mode ?? "is",
|
|
44
|
-
values: useDataTableColumns12sCn2ZAzFL12s.toggleMembership(current[columnKey]?.values ?? [], value)
|
|
45
|
-
}
|
|
46
|
-
}));
|
|
47
|
-
}, [
|
|
48
|
-
setFilters
|
|
49
|
-
]);
|
|
50
|
-
const clearFilter = React.useCallback((columnKey)=>{
|
|
51
|
-
setFilters((current = EMPTY_FILTERS)=>{
|
|
52
|
-
if (!(columnKey in current)) return current;
|
|
53
|
-
const next = {
|
|
54
|
-
...current
|
|
55
|
-
};
|
|
56
|
-
delete next[columnKey];
|
|
57
|
-
return next;
|
|
58
|
-
});
|
|
59
|
-
}, [
|
|
60
|
-
setFilters
|
|
61
|
-
]);
|
|
62
|
-
const isFilterActive = React.useCallback((columnKey)=>(filters[columnKey]?.values.length ?? 0) > 0, [
|
|
63
|
-
filters
|
|
64
|
-
]);
|
|
65
|
-
return {
|
|
66
|
-
filters,
|
|
67
|
-
setFilterMode,
|
|
68
|
-
toggleFilterValue,
|
|
69
|
-
clearFilter,
|
|
70
|
-
isFilterActive
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
exports.useDataTableFilter = useDataTableFilter;
|