@crispy-seed/data-table 0.12.0 → 0.12.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/dist/index.cjs +44 -13
- package/dist/index.js +44 -13
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1340,13 +1340,15 @@ const EMPTY_RECORD = {};
|
|
|
1340
1340
|
})), [
|
|
1341
1341
|
setColumnWidths
|
|
1342
1342
|
]);
|
|
1343
|
-
const moveColumn = React.useCallback((key, direction)=>setRawOrder((current)=>moveColumnKey(current ?? columnKeys, key, direction)), [
|
|
1343
|
+
const moveColumn = React.useCallback((key, direction)=>setRawOrder((current)=>moveColumnKey(reconcileColumnOrder(current ?? columnKeys, columnKeys, actionsColumnKey), key, direction)), [
|
|
1344
1344
|
setRawOrder,
|
|
1345
|
-
columnKeys
|
|
1345
|
+
columnKeys,
|
|
1346
|
+
actionsColumnKey
|
|
1346
1347
|
]);
|
|
1347
|
-
const reorderColumn = React.useCallback((dragKey, dropKey)=>setRawOrder((current)=>reorderColumnKey(current ?? columnKeys, dragKey, dropKey)), [
|
|
1348
|
+
const reorderColumn = React.useCallback((dragKey, dropKey)=>setRawOrder((current)=>reorderColumnKey(reconcileColumnOrder(current ?? columnKeys, columnKeys, actionsColumnKey), dragKey, dropKey)), [
|
|
1348
1349
|
setRawOrder,
|
|
1349
|
-
columnKeys
|
|
1350
|
+
columnKeys,
|
|
1351
|
+
actionsColumnKey
|
|
1350
1352
|
]);
|
|
1351
1353
|
// -- drag-to-reorder ---------------------------------------------------------------
|
|
1352
1354
|
// Live state only (which column is currently being dragged) -- the styled layer's
|
|
@@ -1514,11 +1516,11 @@ function sameCell(a, id, key) {
|
|
|
1514
1516
|
key
|
|
1515
1517
|
});
|
|
1516
1518
|
result.then(()=>{
|
|
1517
|
-
setPendingCell(null);
|
|
1518
|
-
setEditingCell(null);
|
|
1519
|
+
setPendingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1520
|
+
setEditingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1519
1521
|
}, (err)=>{
|
|
1520
|
-
setPendingCell(null);
|
|
1521
|
-
setEditingCell(null);
|
|
1522
|
+
setPendingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1523
|
+
setEditingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1522
1524
|
setEditError({
|
|
1523
1525
|
id,
|
|
1524
1526
|
key,
|
|
@@ -2444,9 +2446,20 @@ DataTableCell$1.displayName = "DataTableCell";
|
|
|
2444
2446
|
|
|
2445
2447
|
const EMPTY_VIEWS = [];
|
|
2446
2448
|
function readStoredViews(storageKey) {
|
|
2447
|
-
if (!storageKey || typeof window === "undefined") return
|
|
2449
|
+
if (!storageKey || typeof window === "undefined") return null;
|
|
2448
2450
|
try {
|
|
2449
|
-
|
|
2451
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
2452
|
+
if (raw === null) return null;
|
|
2453
|
+
// Only a well-formed array counts as "stored" -- `[]` is a real answer (the user
|
|
2454
|
+
// deleted every view), whereas garbage/non-array JSON is treated as absent so the
|
|
2455
|
+
// defaults still seed.
|
|
2456
|
+
let parsed;
|
|
2457
|
+
try {
|
|
2458
|
+
parsed = JSON.parse(raw);
|
|
2459
|
+
} catch {
|
|
2460
|
+
return null;
|
|
2461
|
+
}
|
|
2462
|
+
return Array.isArray(parsed) ? deserializeDataTableViews(raw) : null;
|
|
2450
2463
|
} catch {
|
|
2451
2464
|
// A private-browsing tab / blocked storage throws on access, not just on quota --
|
|
2452
2465
|
// this hook degrades to in-memory-only rather than crash the table over it.
|
|
@@ -2484,7 +2497,7 @@ function readStoredViews(storageKey) {
|
|
|
2484
2497
|
// Nothing in storage yet (first run, or no `storageKey` at all) -- seed from
|
|
2485
2498
|
// `defaultViews` instead of an empty list, matching every other hook's own
|
|
2486
2499
|
// `defaultProp` semantics.
|
|
2487
|
-
initialViewsRef.current = stored
|
|
2500
|
+
initialViewsRef.current = stored !== null ? stored : defaultViews;
|
|
2488
2501
|
}
|
|
2489
2502
|
}
|
|
2490
2503
|
const [views = EMPTY_VIEWS, setViews] = useControllableState$1({
|
|
@@ -4480,6 +4493,10 @@ const { ClassNamesProvider, withContext: withContext$1, useClassNames } = create
|
|
|
4480
4493
|
});
|
|
4481
4494
|
}
|
|
4482
4495
|
|
|
4496
|
+
/** Attribute on the floating-ui-portaled option list of the `select`/`reference`/`actor`
|
|
4497
|
+
* editors. The portal lands in `document.body`, outside the cell and its expand overlay,
|
|
4498
|
+
* so `body-cells.tsx`'s outside-click detector checks for this marker to avoid reading an
|
|
4499
|
+
* option click as "outside" and cancelling the edit before it commits. */ const EDITOR_PORTAL_ATTR = "data-datatable-editor-portal";
|
|
4483
4500
|
/** The raw value a live editor reads, distinct from `DataTableColumn.value` (the
|
|
4484
4501
|
* accessor sort/search/filter/export share): `editValue` returns whatever TYPE the
|
|
4485
4502
|
* editor itself expects -- a real `boolean` for `editor: "switch"`/`type:
|
|
@@ -4628,6 +4645,7 @@ function SelectEditor({ column, value, pending, onCommit, onCancel }) {
|
|
|
4628
4645
|
]
|
|
4629
4646
|
}),
|
|
4630
4647
|
/*#__PURE__*/ jsxRuntime.jsx(SelectPositioner, {
|
|
4648
|
+
[EDITOR_PORTAL_ATTR]: "",
|
|
4631
4649
|
children: /*#__PURE__*/ jsxRuntime.jsxs(SelectContent, {
|
|
4632
4650
|
children: [
|
|
4633
4651
|
searchable && /*#__PURE__*/ jsxRuntime.jsx(SelectSearchField, {
|
|
@@ -4703,6 +4721,7 @@ function ReferenceEditor({ column, value, pending, onCommit, onCancel }) {
|
|
|
4703
4721
|
]
|
|
4704
4722
|
}),
|
|
4705
4723
|
/*#__PURE__*/ jsxRuntime.jsx(SelectPositioner, {
|
|
4724
|
+
[EDITOR_PORTAL_ATTR]: "",
|
|
4706
4725
|
children: /*#__PURE__*/ jsxRuntime.jsxs(SelectContent, {
|
|
4707
4726
|
children: [
|
|
4708
4727
|
/*#__PURE__*/ jsxRuntime.jsx(SelectSearchField, {
|
|
@@ -5318,8 +5337,14 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
5318
5337
|
function isInside(target) {
|
|
5319
5338
|
return (cellRef.current?.contains(target) ?? false) || (popoverRef.current?.contains(target) ?? false) || (expandOverlayRef.current?.contains(target) ?? false);
|
|
5320
5339
|
}
|
|
5340
|
+
// The select/reference/actor editor's option list is portaled to `document.body` by
|
|
5341
|
+
// floating-ui, outside both `cellRef` and `expandOverlayRef`; `editors.tsx` marks its
|
|
5342
|
+
// positioner with `EDITOR_PORTAL_ATTR`, so a click on an option is not an outside click.
|
|
5343
|
+
function isInsideEditorPortal(target) {
|
|
5344
|
+
return target instanceof Element && target.closest(`[${EDITOR_PORTAL_ATTR}]`) != null;
|
|
5345
|
+
}
|
|
5321
5346
|
function handlePointerDown(event) {
|
|
5322
|
-
if (!isInside(event.target)) {
|
|
5347
|
+
if (!isInside(event.target) && !isInsideEditorPortal(event.target)) {
|
|
5323
5348
|
setOverlayOpen(false);
|
|
5324
5349
|
setPopoverStyle(null);
|
|
5325
5350
|
closePeek();
|
|
@@ -11193,7 +11218,13 @@ const toDateOrNull = (v)=>{
|
|
|
11193
11218
|
return f.op === "before" ? d < cd : d > cd;
|
|
11194
11219
|
}
|
|
11195
11220
|
const t = asText(raw).toLowerCase();
|
|
11196
|
-
if (f.op === "isanyof")
|
|
11221
|
+
if (f.op === "isanyof") {
|
|
11222
|
+
const wanted = (f.values ?? []).map((v)=>v.toLowerCase());
|
|
11223
|
+
const cells = Array.isArray(raw) ? raw.map((x)=>asText(x).toLowerCase()) : [
|
|
11224
|
+
t
|
|
11225
|
+
];
|
|
11226
|
+
return cells.some((c)=>wanted.includes(c));
|
|
11227
|
+
}
|
|
11197
11228
|
const v = f.value.trim().toLowerCase();
|
|
11198
11229
|
if (f.op === "contains") return t.includes(v);
|
|
11199
11230
|
if (f.op === "doesnotcontain") return !t.includes(v);
|
package/dist/index.js
CHANGED
|
@@ -1321,13 +1321,15 @@ const EMPTY_RECORD = {};
|
|
|
1321
1321
|
})), [
|
|
1322
1322
|
setColumnWidths
|
|
1323
1323
|
]);
|
|
1324
|
-
const moveColumn = useCallback((key, direction)=>setRawOrder((current)=>moveColumnKey(current ?? columnKeys, key, direction)), [
|
|
1324
|
+
const moveColumn = useCallback((key, direction)=>setRawOrder((current)=>moveColumnKey(reconcileColumnOrder(current ?? columnKeys, columnKeys, actionsColumnKey), key, direction)), [
|
|
1325
1325
|
setRawOrder,
|
|
1326
|
-
columnKeys
|
|
1326
|
+
columnKeys,
|
|
1327
|
+
actionsColumnKey
|
|
1327
1328
|
]);
|
|
1328
|
-
const reorderColumn = useCallback((dragKey, dropKey)=>setRawOrder((current)=>reorderColumnKey(current ?? columnKeys, dragKey, dropKey)), [
|
|
1329
|
+
const reorderColumn = useCallback((dragKey, dropKey)=>setRawOrder((current)=>reorderColumnKey(reconcileColumnOrder(current ?? columnKeys, columnKeys, actionsColumnKey), dragKey, dropKey)), [
|
|
1329
1330
|
setRawOrder,
|
|
1330
|
-
columnKeys
|
|
1331
|
+
columnKeys,
|
|
1332
|
+
actionsColumnKey
|
|
1331
1333
|
]);
|
|
1332
1334
|
// -- drag-to-reorder ---------------------------------------------------------------
|
|
1333
1335
|
// Live state only (which column is currently being dragged) -- the styled layer's
|
|
@@ -1495,11 +1497,11 @@ function sameCell(a, id, key) {
|
|
|
1495
1497
|
key
|
|
1496
1498
|
});
|
|
1497
1499
|
result.then(()=>{
|
|
1498
|
-
setPendingCell(null);
|
|
1499
|
-
setEditingCell(null);
|
|
1500
|
+
setPendingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1501
|
+
setEditingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1500
1502
|
}, (err)=>{
|
|
1501
|
-
setPendingCell(null);
|
|
1502
|
-
setEditingCell(null);
|
|
1503
|
+
setPendingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1504
|
+
setEditingCell((c)=>sameCell(c, id, key) ? null : c);
|
|
1503
1505
|
setEditError({
|
|
1504
1506
|
id,
|
|
1505
1507
|
key,
|
|
@@ -2425,9 +2427,20 @@ DataTableCell$1.displayName = "DataTableCell";
|
|
|
2425
2427
|
|
|
2426
2428
|
const EMPTY_VIEWS = [];
|
|
2427
2429
|
function readStoredViews(storageKey) {
|
|
2428
|
-
if (!storageKey || typeof window === "undefined") return
|
|
2430
|
+
if (!storageKey || typeof window === "undefined") return null;
|
|
2429
2431
|
try {
|
|
2430
|
-
|
|
2432
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
2433
|
+
if (raw === null) return null;
|
|
2434
|
+
// Only a well-formed array counts as "stored" -- `[]` is a real answer (the user
|
|
2435
|
+
// deleted every view), whereas garbage/non-array JSON is treated as absent so the
|
|
2436
|
+
// defaults still seed.
|
|
2437
|
+
let parsed;
|
|
2438
|
+
try {
|
|
2439
|
+
parsed = JSON.parse(raw);
|
|
2440
|
+
} catch {
|
|
2441
|
+
return null;
|
|
2442
|
+
}
|
|
2443
|
+
return Array.isArray(parsed) ? deserializeDataTableViews(raw) : null;
|
|
2431
2444
|
} catch {
|
|
2432
2445
|
// A private-browsing tab / blocked storage throws on access, not just on quota --
|
|
2433
2446
|
// this hook degrades to in-memory-only rather than crash the table over it.
|
|
@@ -2465,7 +2478,7 @@ function readStoredViews(storageKey) {
|
|
|
2465
2478
|
// Nothing in storage yet (first run, or no `storageKey` at all) -- seed from
|
|
2466
2479
|
// `defaultViews` instead of an empty list, matching every other hook's own
|
|
2467
2480
|
// `defaultProp` semantics.
|
|
2468
|
-
initialViewsRef.current = stored
|
|
2481
|
+
initialViewsRef.current = stored !== null ? stored : defaultViews;
|
|
2469
2482
|
}
|
|
2470
2483
|
}
|
|
2471
2484
|
const [views = EMPTY_VIEWS, setViews] = useControllableState$1({
|
|
@@ -4461,6 +4474,10 @@ const { ClassNamesProvider, withContext: withContext$1, useClassNames } = create
|
|
|
4461
4474
|
});
|
|
4462
4475
|
}
|
|
4463
4476
|
|
|
4477
|
+
/** Attribute on the floating-ui-portaled option list of the `select`/`reference`/`actor`
|
|
4478
|
+
* editors. The portal lands in `document.body`, outside the cell and its expand overlay,
|
|
4479
|
+
* so `body-cells.tsx`'s outside-click detector checks for this marker to avoid reading an
|
|
4480
|
+
* option click as "outside" and cancelling the edit before it commits. */ const EDITOR_PORTAL_ATTR = "data-datatable-editor-portal";
|
|
4464
4481
|
/** The raw value a live editor reads, distinct from `DataTableColumn.value` (the
|
|
4465
4482
|
* accessor sort/search/filter/export share): `editValue` returns whatever TYPE the
|
|
4466
4483
|
* editor itself expects -- a real `boolean` for `editor: "switch"`/`type:
|
|
@@ -4609,6 +4626,7 @@ function SelectEditor({ column, value, pending, onCommit, onCancel }) {
|
|
|
4609
4626
|
]
|
|
4610
4627
|
}),
|
|
4611
4628
|
/*#__PURE__*/ jsx(SelectPositioner, {
|
|
4629
|
+
[EDITOR_PORTAL_ATTR]: "",
|
|
4612
4630
|
children: /*#__PURE__*/ jsxs(SelectContent, {
|
|
4613
4631
|
children: [
|
|
4614
4632
|
searchable && /*#__PURE__*/ jsx(SelectSearchField, {
|
|
@@ -4684,6 +4702,7 @@ function ReferenceEditor({ column, value, pending, onCommit, onCancel }) {
|
|
|
4684
4702
|
]
|
|
4685
4703
|
}),
|
|
4686
4704
|
/*#__PURE__*/ jsx(SelectPositioner, {
|
|
4705
|
+
[EDITOR_PORTAL_ATTR]: "",
|
|
4687
4706
|
children: /*#__PURE__*/ jsxs(SelectContent, {
|
|
4688
4707
|
children: [
|
|
4689
4708
|
/*#__PURE__*/ jsx(SelectSearchField, {
|
|
@@ -5299,8 +5318,14 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
5299
5318
|
function isInside(target) {
|
|
5300
5319
|
return (cellRef.current?.contains(target) ?? false) || (popoverRef.current?.contains(target) ?? false) || (expandOverlayRef.current?.contains(target) ?? false);
|
|
5301
5320
|
}
|
|
5321
|
+
// The select/reference/actor editor's option list is portaled to `document.body` by
|
|
5322
|
+
// floating-ui, outside both `cellRef` and `expandOverlayRef`; `editors.tsx` marks its
|
|
5323
|
+
// positioner with `EDITOR_PORTAL_ATTR`, so a click on an option is not an outside click.
|
|
5324
|
+
function isInsideEditorPortal(target) {
|
|
5325
|
+
return target instanceof Element && target.closest(`[${EDITOR_PORTAL_ATTR}]`) != null;
|
|
5326
|
+
}
|
|
5302
5327
|
function handlePointerDown(event) {
|
|
5303
|
-
if (!isInside(event.target)) {
|
|
5328
|
+
if (!isInside(event.target) && !isInsideEditorPortal(event.target)) {
|
|
5304
5329
|
setOverlayOpen(false);
|
|
5305
5330
|
setPopoverStyle(null);
|
|
5306
5331
|
closePeek();
|
|
@@ -11174,7 +11199,13 @@ const toDateOrNull = (v)=>{
|
|
|
11174
11199
|
return f.op === "before" ? d < cd : d > cd;
|
|
11175
11200
|
}
|
|
11176
11201
|
const t = asText(raw).toLowerCase();
|
|
11177
|
-
if (f.op === "isanyof")
|
|
11202
|
+
if (f.op === "isanyof") {
|
|
11203
|
+
const wanted = (f.values ?? []).map((v)=>v.toLowerCase());
|
|
11204
|
+
const cells = Array.isArray(raw) ? raw.map((x)=>asText(x).toLowerCase()) : [
|
|
11205
|
+
t
|
|
11206
|
+
];
|
|
11207
|
+
return cells.some((c)=>wanted.includes(c));
|
|
11208
|
+
}
|
|
11178
11209
|
const v = f.value.trim().toLowerCase();
|
|
11179
11210
|
if (f.op === "contains") return t.includes(v);
|
|
11180
11211
|
if (f.op === "doesnotcontain") return !t.includes(v);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crispy-seed/data-table",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Self-contained, publishable build of seed-design's Attio-measured DataTable, ResizablePanel and RecordPreview — one install, one CSS import.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|