@crispy-seed/data-table 0.1.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/LICENSE +201 -0
- package/NOTICE +30 -0
- package/README.md +103 -0
- package/dist/DataTable-12s-8LMBtS2u.cjs +1532 -0
- package/dist/DataTable-12s-Bd20OuMs.js +1482 -0
- package/dist/DataTable-12s-Zml1x9Kr-12s-CTRzgvMT.cjs +161 -0
- package/dist/DataTable-12s-Zml1x9Kr-12s-Coi-3lUa.js +153 -0
- package/dist/Menu-12s-Db_zr1AP.cjs +104 -0
- package/dist/Menu-12s-Di5JADW4.js +78 -0
- package/dist/Select-12s-1Uh7XbkG.js +219 -0
- package/dist/Select-12s-D8DdKT-U.cjs +250 -0
- package/dist/body-cells-12s-BnOVUTKN.js +453 -0
- package/dist/body-cells-12s-BoOTcg-l.cjs +462 -0
- package/dist/column-calc-12s-C6IPSOaF.js +129 -0
- package/dist/column-calc-12s-CKuSpe-l.cjs +149 -0
- package/dist/column-layout-12s-CTu5yT_D.cjs +120 -0
- package/dist/column-layout-12s-s7wnxkMN.js +99 -0
- package/dist/column-menu-12s-BPE9N1gs.cjs +427 -0
- package/dist/column-menu-12s-mRBk-4oa.js +407 -0
- package/dist/data-table-recipe.css +442 -0
- package/dist/data-table-recipe.layered.css +505 -0
- package/dist/editors-12s-BO9Mp034.js +525 -0
- package/dist/editors-12s-DO8TZkYV.cjs +555 -0
- package/dist/index.cjs +14 -0
- package/dist/index.d.ts +323 -0
- package/dist/index.js +10 -0
- package/dist/resize-12s-jQY-PX67.cjs +58 -0
- package/dist/resize-12s-nsMvrmLt.js +58 -0
- package/dist/states-12s-CLO_uVue.cjs +125 -0
- package/dist/states-12s-DEFSxJCO.js +122 -0
- package/dist/styles.css +14660 -0
- package/dist/toolbar-12s-AVU-sbDW.js +69 -0
- package/dist/toolbar-12s-CaLgJrDo.cjs +71 -0
- package/dist/useDataTable-12s-BHiDUubw-12s-CBeCwTe7.js +61 -0
- package/dist/useDataTable-12s-BHiDUubw-12s-Dgvt7XDk.cjs +61 -0
- package/dist/useDataTableColumnCalc-12s-DTQQTtEJ-12s-CvD14JYo.cjs +207 -0
- package/dist/useDataTableColumnCalc-12s-DTQQTtEJ-12s-DsEse3uq.js +183 -0
- package/dist/useDataTableColumns-12s-Cn2ZAzFL-12s-CD6goR59.js +289 -0
- package/dist/useDataTableColumns-12s-Cn2ZAzFL-12s-CUk_CpYT.cjs +292 -0
- package/dist/useDataTableEdit-12s-9Wb_UCrN-12s-BoOHq3GB.js +98 -0
- package/dist/useDataTableEdit-12s-9Wb_UCrN-12s-De6YHBba.cjs +98 -0
- package/dist/useDataTableFilter-12s-ZzbmWMin-12s-CWyBeFna.js +74 -0
- package/dist/useDataTableFilter-12s-ZzbmWMin-12s-lpjzZY3_.cjs +74 -0
- package/dist/useDataTableInfiniteScroll-12s-8ZG31URd-12s-BexjP6iO.js +104 -0
- package/dist/useDataTableInfiniteScroll-12s-8ZG31URd-12s-Bt8gojr9.cjs +104 -0
- package/dist/useDataTableRow-12s-CPYaDa1p-12s-BmUSAnPe.js +30 -0
- package/dist/useDataTableRow-12s-CPYaDa1p-12s-D-DRjwAe.cjs +30 -0
- package/dist/useDataTableScroll-12s-BKDCr0en-12s-C7f2vHeG.js +61 -0
- package/dist/useDataTableScroll-12s-BKDCr0en-12s-CUvUYMtt.cjs +61 -0
- package/dist/useDataTableSearch-12s-Ck3iWcpX-12s-B-65V6gH.js +37 -0
- package/dist/useDataTableSearch-12s-Ck3iWcpX-12s-DhVfN2Hq.cjs +37 -0
- package/dist/useDataTableSelection-12s-BIDtiRQq-12s-IS__VAnU.cjs +71 -0
- package/dist/useDataTableSelection-12s-BIDtiRQq-12s-O6M_BhrH.js +71 -0
- package/dist/useDataTableSort-12s-DvJYtmeS-12s-C5VGnsq4.cjs +78 -0
- package/dist/useDataTableSort-12s-DvJYtmeS-12s-DABSNt6U.js +78 -0
- package/package.json +78 -0
|
@@ -0,0 +1,69 @@
|
|
|
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 { jsxs, jsx } from 'react/jsx-runtime';
|
|
12
|
+
import 'react';
|
|
13
|
+
import { z as withContext, A as dataTable, B as IconMagnifyingglassLine_default } from './DataTable-12s-Bd20OuMs.js';
|
|
14
|
+
import { Primitive } from '@seed-design/react-primitive';
|
|
15
|
+
import { c as TextFieldRoot, d as TextFieldPrefixIcon, e as TextFieldInput } from './editors-12s-BO9Mp034.js';
|
|
16
|
+
import { u as useDataTableContext } from './DataTable-12s-Zml1x9Kr-12s-Coi-3lUa.js';
|
|
17
|
+
|
|
18
|
+
const DataTableToolbar = withContext(Primitive.div, "toolbar");
|
|
19
|
+
const DataTableCount = withContext(Primitive.span, "count");
|
|
20
|
+
/**
|
|
21
|
+
* Fix (recurring bug): the search box is seed's own DOCUMENTED `TextField`
|
|
22
|
+
* composition -- `TextFieldRoot` (`variant="outline" size="medium"`) +
|
|
23
|
+
* `TextFieldPrefixIcon` + `TextFieldInput`, exactly `docs/examples/react/
|
|
24
|
+
* text-field-input/prefix.tsx` -- not that same trio fought with a custom
|
|
25
|
+
* `classNames.search` overriding its height/padding/icon position with `!important`.
|
|
26
|
+
* That override (this file's own previous state) is what kept mis-placing the icon:
|
|
27
|
+
* every fix landed on ANOTHER property the override was still fighting (the icon's own
|
|
28
|
+
* intrinsic SVG size, its inherited margin, the root's own min-height beating a plain
|
|
29
|
+
* `height` override) because the override was never the right layer to fix it at.
|
|
30
|
+
* `size="medium"`'s built-in prefix-icon spacing (a flex `gap` + edge margins, not
|
|
31
|
+
* absolute positioning) is what `text-input.ts`'s own variant CSS already gets right,
|
|
32
|
+
* so it needs no help from this component at all -- `search` (recipe.ts) is now just
|
|
33
|
+
* this box's own layout constraint (`flex`, `max-width`) within the toolbar row, not
|
|
34
|
+
* its internal chrome.
|
|
35
|
+
*/ function SearchBox({ placeholder, label }) {
|
|
36
|
+
const { query, setQuery } = useDataTableContext();
|
|
37
|
+
const classNames = dataTable();
|
|
38
|
+
return /*#__PURE__*/ jsxs(TextFieldRoot, {
|
|
39
|
+
variant: "outline",
|
|
40
|
+
size: "medium",
|
|
41
|
+
className: classNames.search,
|
|
42
|
+
children: [
|
|
43
|
+
/*#__PURE__*/ jsx(TextFieldPrefixIcon, {
|
|
44
|
+
svg: /*#__PURE__*/ jsx(IconMagnifyingglassLine_default, {})
|
|
45
|
+
}),
|
|
46
|
+
/*#__PURE__*/ jsx(TextFieldInput, {
|
|
47
|
+
type: "text",
|
|
48
|
+
value: query,
|
|
49
|
+
onChange: (event)=>setQuery(event.target.value),
|
|
50
|
+
placeholder: placeholder,
|
|
51
|
+
"aria-label": label
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** crisp's own count format (`datatable.tsx`'s `resolvedCountLabel`): unfiltered reads
|
|
57
|
+
* "N rows" ("N row" for exactly one), filtered/searched reads "N of M" with no
|
|
58
|
+
* trailing word at all -- reproduced literally rather than reinvented, since this is
|
|
59
|
+
* the one piece of copy DATATABLE-ATTIO-SPEC.md calls out by example. */ function defaultCountLabel(shown, total) {
|
|
60
|
+
if (shown === total) return `${total} ${total === 1 ? "row" : "rows"}`;
|
|
61
|
+
return `${shown} of ${total}`;
|
|
62
|
+
}
|
|
63
|
+
function RowCount({ shown, total, countLabel }) {
|
|
64
|
+
return /*#__PURE__*/ jsx(DataTableCount, {
|
|
65
|
+
children: (countLabel ?? defaultCountLabel)(shown, total)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { DataTableToolbar as D, RowCount as R, SearchBox as S };
|
|
@@ -0,0 +1,71 @@
|
|
|
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 jsxRuntime = require('react/jsx-runtime');
|
|
12
|
+
require('react');
|
|
13
|
+
var DataTable12s = require('./DataTable-12s-8LMBtS2u.cjs');
|
|
14
|
+
var reactPrimitive = require('@seed-design/react-primitive');
|
|
15
|
+
var editors12s = require('./editors-12s-DO8TZkYV.cjs');
|
|
16
|
+
var DataTable12sZml1x9Kr12s = require('./DataTable-12s-Zml1x9Kr-12s-CTRzgvMT.cjs');
|
|
17
|
+
|
|
18
|
+
const DataTableToolbar = DataTable12s.withContext(reactPrimitive.Primitive.div, "toolbar");
|
|
19
|
+
const DataTableCount = DataTable12s.withContext(reactPrimitive.Primitive.span, "count");
|
|
20
|
+
/**
|
|
21
|
+
* Fix (recurring bug): the search box is seed's own DOCUMENTED `TextField`
|
|
22
|
+
* composition -- `TextFieldRoot` (`variant="outline" size="medium"`) +
|
|
23
|
+
* `TextFieldPrefixIcon` + `TextFieldInput`, exactly `docs/examples/react/
|
|
24
|
+
* text-field-input/prefix.tsx` -- not that same trio fought with a custom
|
|
25
|
+
* `classNames.search` overriding its height/padding/icon position with `!important`.
|
|
26
|
+
* That override (this file's own previous state) is what kept mis-placing the icon:
|
|
27
|
+
* every fix landed on ANOTHER property the override was still fighting (the icon's own
|
|
28
|
+
* intrinsic SVG size, its inherited margin, the root's own min-height beating a plain
|
|
29
|
+
* `height` override) because the override was never the right layer to fix it at.
|
|
30
|
+
* `size="medium"`'s built-in prefix-icon spacing (a flex `gap` + edge margins, not
|
|
31
|
+
* absolute positioning) is what `text-input.ts`'s own variant CSS already gets right,
|
|
32
|
+
* so it needs no help from this component at all -- `search` (recipe.ts) is now just
|
|
33
|
+
* this box's own layout constraint (`flex`, `max-width`) within the toolbar row, not
|
|
34
|
+
* its internal chrome.
|
|
35
|
+
*/ function SearchBox({ placeholder, label }) {
|
|
36
|
+
const { query, setQuery } = DataTable12sZml1x9Kr12s.useDataTableContext();
|
|
37
|
+
const classNames = DataTable12s.dataTable();
|
|
38
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(editors12s.TextFieldRoot, {
|
|
39
|
+
variant: "outline",
|
|
40
|
+
size: "medium",
|
|
41
|
+
className: classNames.search,
|
|
42
|
+
children: [
|
|
43
|
+
/*#__PURE__*/ jsxRuntime.jsx(editors12s.TextFieldPrefixIcon, {
|
|
44
|
+
svg: /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.IconMagnifyingglassLine_default, {})
|
|
45
|
+
}),
|
|
46
|
+
/*#__PURE__*/ jsxRuntime.jsx(editors12s.TextFieldInput, {
|
|
47
|
+
type: "text",
|
|
48
|
+
value: query,
|
|
49
|
+
onChange: (event)=>setQuery(event.target.value),
|
|
50
|
+
placeholder: placeholder,
|
|
51
|
+
"aria-label": label
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** crisp's own count format (`datatable.tsx`'s `resolvedCountLabel`): unfiltered reads
|
|
57
|
+
* "N rows" ("N row" for exactly one), filtered/searched reads "N of M" with no
|
|
58
|
+
* trailing word at all -- reproduced literally rather than reinvented, since this is
|
|
59
|
+
* the one piece of copy DATATABLE-ATTIO-SPEC.md calls out by example. */ function defaultCountLabel(shown, total) {
|
|
60
|
+
if (shown === total) return `${total} ${total === 1 ? "row" : "rows"}`;
|
|
61
|
+
return `${shown} of ${total}`;
|
|
62
|
+
}
|
|
63
|
+
function RowCount({ shown, total, countLabel }) {
|
|
64
|
+
return /*#__PURE__*/ jsxRuntime.jsx(DataTableCount, {
|
|
65
|
+
children: (countLabel ?? defaultCountLabel)(shown, total)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.DataTableToolbar = DataTableToolbar;
|
|
70
|
+
exports.RowCount = RowCount;
|
|
71
|
+
exports.SearchBox = SearchBox;
|
|
@@ -0,0 +1,61 @@
|
|
|
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 { elementProps } from '@seed-design/dom-utils';
|
|
12
|
+
import { u as useDataTableColumnCalc } from './useDataTableColumnCalc-12s-DTQQTtEJ-12s-DsEse3uq.js';
|
|
13
|
+
import { u as useDataTableColumns } from './useDataTableColumns-12s-Cn2ZAzFL-12s-CD6goR59.js';
|
|
14
|
+
import { u as useDataTableEdit } from './useDataTableEdit-12s-9Wb_UCrN-12s-BoOHq3GB.js';
|
|
15
|
+
import { u as useDataTableFilter } from './useDataTableFilter-12s-ZzbmWMin-12s-CWyBeFna.js';
|
|
16
|
+
import { u as useDataTableInfiniteScroll } from './useDataTableInfiniteScroll-12s-8ZG31URd-12s-BexjP6iO.js';
|
|
17
|
+
import { u as useDataTableScroll } from './useDataTableScroll-12s-BKDCr0en-12s-C7f2vHeG.js';
|
|
18
|
+
import { u as useDataTableSearch } from './useDataTableSearch-12s-Ck3iWcpX-12s-B-65V6gH.js';
|
|
19
|
+
import { u as useDataTableSelection } from './useDataTableSelection-12s-BIDtiRQq-12s-O6M_BhrH.js';
|
|
20
|
+
import { u as useDataTableSort } from './useDataTableSort-12s-DvJYtmeS-12s-DABSNt6U.js';
|
|
21
|
+
|
|
22
|
+
// Composes the eight independent concerns a table root owns -- which column is
|
|
23
|
+
// sorted, which rows are selected, the toolbar's free-text query, each column's own
|
|
24
|
+
// filter, column order/visibility/width/label, each column's ColumnCalc footer op, the
|
|
25
|
+
// horizontal scroll-shadow edge state, and which single cell is mid-edit/pending/
|
|
26
|
+
// erroring -- the way useSelect composes useSelectHighlight + useSelectOptions. No
|
|
27
|
+
// sub-hook knows about any other; a future concern (row grouping) is a ninth sibling
|
|
28
|
+
// call here, not a branch inside an existing one.
|
|
29
|
+
function useDataTable(props) {
|
|
30
|
+
const sort = useDataTableSort(props);
|
|
31
|
+
const selection = useDataTableSelection(props);
|
|
32
|
+
const search = useDataTableSearch(props);
|
|
33
|
+
const filter = useDataTableFilter(props);
|
|
34
|
+
const columns = useDataTableColumns(props);
|
|
35
|
+
const columnCalc = useDataTableColumnCalc(props);
|
|
36
|
+
const scroll = useDataTableScroll();
|
|
37
|
+
const edit = useDataTableEdit(props);
|
|
38
|
+
// Wired to `scroll`'s own scroll-container ref (not a fresh one of its own) so a
|
|
39
|
+
// BOUNDED table's auto-load triggers off its own internal scroll, not the
|
|
40
|
+
// browsing viewport -- see useDataTableInfiniteScroll.ts's own doc comment.
|
|
41
|
+
const infiniteScroll = useDataTableInfiniteScroll({
|
|
42
|
+
...props,
|
|
43
|
+
scrollRootRef: scroll.elementRef
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
...sort,
|
|
47
|
+
...selection,
|
|
48
|
+
...search,
|
|
49
|
+
...filter,
|
|
50
|
+
...columns,
|
|
51
|
+
...columnCalc,
|
|
52
|
+
...scroll,
|
|
53
|
+
...edit,
|
|
54
|
+
...infiniteScroll,
|
|
55
|
+
rootProps: elementProps({
|
|
56
|
+
role: "table"
|
|
57
|
+
})
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { useDataTable as u };
|
|
@@ -0,0 +1,61 @@
|
|
|
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 domUtils = require('@seed-design/dom-utils');
|
|
12
|
+
var useDataTableColumnCalc12sDTQQTtEJ12s = require('./useDataTableColumnCalc-12s-DTQQTtEJ-12s-CvD14JYo.cjs');
|
|
13
|
+
var useDataTableColumns12sCn2ZAzFL12s = require('./useDataTableColumns-12s-Cn2ZAzFL-12s-CUk_CpYT.cjs');
|
|
14
|
+
var useDataTableEdit12s9Wb_UCrN12s = require('./useDataTableEdit-12s-9Wb_UCrN-12s-De6YHBba.cjs');
|
|
15
|
+
var useDataTableFilter12sZzbmWMin12s = require('./useDataTableFilter-12s-ZzbmWMin-12s-lpjzZY3_.cjs');
|
|
16
|
+
var useDataTableInfiniteScroll12s8ZG31URd12s = require('./useDataTableInfiniteScroll-12s-8ZG31URd-12s-Bt8gojr9.cjs');
|
|
17
|
+
var useDataTableScroll12sBKDCr0en12s = require('./useDataTableScroll-12s-BKDCr0en-12s-CUvUYMtt.cjs');
|
|
18
|
+
var useDataTableSearch12sCk3iWcpX12s = require('./useDataTableSearch-12s-Ck3iWcpX-12s-DhVfN2Hq.cjs');
|
|
19
|
+
var useDataTableSelection12sBIDtiRQq12s = require('./useDataTableSelection-12s-BIDtiRQq-12s-IS__VAnU.cjs');
|
|
20
|
+
var useDataTableSort12sDvJYtmeS12s = require('./useDataTableSort-12s-DvJYtmeS-12s-C5VGnsq4.cjs');
|
|
21
|
+
|
|
22
|
+
// Composes the eight independent concerns a table root owns -- which column is
|
|
23
|
+
// sorted, which rows are selected, the toolbar's free-text query, each column's own
|
|
24
|
+
// filter, column order/visibility/width/label, each column's ColumnCalc footer op, the
|
|
25
|
+
// horizontal scroll-shadow edge state, and which single cell is mid-edit/pending/
|
|
26
|
+
// erroring -- the way useSelect composes useSelectHighlight + useSelectOptions. No
|
|
27
|
+
// sub-hook knows about any other; a future concern (row grouping) is a ninth sibling
|
|
28
|
+
// call here, not a branch inside an existing one.
|
|
29
|
+
function useDataTable(props) {
|
|
30
|
+
const sort = useDataTableSort12sDvJYtmeS12s.useDataTableSort(props);
|
|
31
|
+
const selection = useDataTableSelection12sBIDtiRQq12s.useDataTableSelection(props);
|
|
32
|
+
const search = useDataTableSearch12sCk3iWcpX12s.useDataTableSearch(props);
|
|
33
|
+
const filter = useDataTableFilter12sZzbmWMin12s.useDataTableFilter(props);
|
|
34
|
+
const columns = useDataTableColumns12sCn2ZAzFL12s.useDataTableColumns(props);
|
|
35
|
+
const columnCalc = useDataTableColumnCalc12sDTQQTtEJ12s.useDataTableColumnCalc(props);
|
|
36
|
+
const scroll = useDataTableScroll12sBKDCr0en12s.useDataTableScroll();
|
|
37
|
+
const edit = useDataTableEdit12s9Wb_UCrN12s.useDataTableEdit(props);
|
|
38
|
+
// Wired to `scroll`'s own scroll-container ref (not a fresh one of its own) so a
|
|
39
|
+
// BOUNDED table's auto-load triggers off its own internal scroll, not the
|
|
40
|
+
// browsing viewport -- see useDataTableInfiniteScroll.ts's own doc comment.
|
|
41
|
+
const infiniteScroll = useDataTableInfiniteScroll12s8ZG31URd12s.useDataTableInfiniteScroll({
|
|
42
|
+
...props,
|
|
43
|
+
scrollRootRef: scroll.elementRef
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
...sort,
|
|
47
|
+
...selection,
|
|
48
|
+
...search,
|
|
49
|
+
...filter,
|
|
50
|
+
...columns,
|
|
51
|
+
...columnCalc,
|
|
52
|
+
...scroll,
|
|
53
|
+
...edit,
|
|
54
|
+
...infiniteScroll,
|
|
55
|
+
rootProps: domUtils.elementProps({
|
|
56
|
+
role: "table"
|
|
57
|
+
})
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
exports.useDataTable = useDataTable;
|
|
@@ -0,0 +1,207 @@
|
|
|
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 _interopNamespace(e) {
|
|
14
|
+
if (e && e.__esModule) return e;
|
|
15
|
+
var n = Object.create(null);
|
|
16
|
+
if (e) {
|
|
17
|
+
Object.keys(e).forEach(function (k) {
|
|
18
|
+
if (k !== 'default') {
|
|
19
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return e[k]; }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return n;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
32
|
+
|
|
33
|
+
// packages/react/use-layout-effect/src/use-layout-effect.tsx
|
|
34
|
+
var useLayoutEffect2 = globalThis?.document ? React__namespace.useLayoutEffect : ()=>{};
|
|
35
|
+
|
|
36
|
+
// src/use-controllable-state.tsx
|
|
37
|
+
var useInsertionEffect = React__namespace[" useInsertionEffect ".trim().toString()] || useLayoutEffect2;
|
|
38
|
+
function useControllableState({ prop, defaultProp, onChange = ()=>{}, caller }) {
|
|
39
|
+
const [uncontrolledProp, setUncontrolledProp, onChangeRef] = useUncontrolledState({
|
|
40
|
+
defaultProp,
|
|
41
|
+
onChange
|
|
42
|
+
});
|
|
43
|
+
const isControlled = prop !== void 0;
|
|
44
|
+
const value = isControlled ? prop : uncontrolledProp;
|
|
45
|
+
{
|
|
46
|
+
const isControlledRef = React__namespace.useRef(prop !== void 0);
|
|
47
|
+
React__namespace.useEffect(()=>{
|
|
48
|
+
const wasControlled = isControlledRef.current;
|
|
49
|
+
if (wasControlled !== isControlled) {
|
|
50
|
+
const from = wasControlled ? "controlled" : "uncontrolled";
|
|
51
|
+
const to = isControlled ? "controlled" : "uncontrolled";
|
|
52
|
+
console.warn(`${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`);
|
|
53
|
+
}
|
|
54
|
+
isControlledRef.current = isControlled;
|
|
55
|
+
}, [
|
|
56
|
+
isControlled,
|
|
57
|
+
caller
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
const setValue = React__namespace.useCallback((nextValue)=>{
|
|
61
|
+
if (isControlled) {
|
|
62
|
+
const value2 = isFunction(nextValue) ? nextValue(prop) : nextValue;
|
|
63
|
+
if (value2 !== prop) {
|
|
64
|
+
onChangeRef.current?.(value2);
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
setUncontrolledProp(nextValue);
|
|
68
|
+
}
|
|
69
|
+
}, [
|
|
70
|
+
isControlled,
|
|
71
|
+
prop,
|
|
72
|
+
setUncontrolledProp,
|
|
73
|
+
onChangeRef
|
|
74
|
+
]);
|
|
75
|
+
return [
|
|
76
|
+
value,
|
|
77
|
+
setValue
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
function useUncontrolledState({ defaultProp, onChange }) {
|
|
81
|
+
const [value, setValue] = React__namespace.useState(defaultProp);
|
|
82
|
+
const prevValueRef = React__namespace.useRef(value);
|
|
83
|
+
const onChangeRef = React__namespace.useRef(onChange);
|
|
84
|
+
useInsertionEffect(()=>{
|
|
85
|
+
onChangeRef.current = onChange;
|
|
86
|
+
}, [
|
|
87
|
+
onChange
|
|
88
|
+
]);
|
|
89
|
+
React__namespace.useEffect(()=>{
|
|
90
|
+
if (prevValueRef.current !== value) {
|
|
91
|
+
onChangeRef.current?.(value);
|
|
92
|
+
prevValueRef.current = value;
|
|
93
|
+
}
|
|
94
|
+
}, [
|
|
95
|
+
value,
|
|
96
|
+
prevValueRef
|
|
97
|
+
]);
|
|
98
|
+
return [
|
|
99
|
+
value,
|
|
100
|
+
setValue,
|
|
101
|
+
onChangeRef
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
function isFunction(value) {
|
|
105
|
+
return typeof value === "function";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const DATA_TABLE_UNIVERSAL_CALC_OPS = [
|
|
109
|
+
"count",
|
|
110
|
+
"countFilled"
|
|
111
|
+
];
|
|
112
|
+
const DATA_TABLE_NUMERIC_CALC_OPS = [
|
|
113
|
+
"sum",
|
|
114
|
+
"average",
|
|
115
|
+
"min",
|
|
116
|
+
"max"
|
|
117
|
+
];
|
|
118
|
+
const DATA_TABLE_CALC_LABEL = {
|
|
119
|
+
count: "Count",
|
|
120
|
+
countFilled: "Count filled",
|
|
121
|
+
sum: "Sum",
|
|
122
|
+
average: "Average",
|
|
123
|
+
min: "Min",
|
|
124
|
+
max: "Max"
|
|
125
|
+
};
|
|
126
|
+
/** A value counts as empty when it is null/undefined, an empty string, or an empty
|
|
127
|
+
* array -- crisp's own `isEmptyValue` (columncalc.tsx), reused verbatim. */ function isEmptyValueForCalc(value) {
|
|
128
|
+
if (value == null) return true;
|
|
129
|
+
if (typeof value === "string") return value.trim() === "";
|
|
130
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Pure so the arithmetic is independently (and mutation-) testable without rendering a
|
|
135
|
+
* table at all. `sum`/`average`/`min`/`max` skip empty values and non-numeric ones
|
|
136
|
+
* (coerced via `Number`, dropping `NaN`); they return `null` -- render nothing, not a
|
|
137
|
+
* misleading 0 -- when there is nothing numeric left to reduce over.
|
|
138
|
+
*/ function computeColumnCalc(values, op) {
|
|
139
|
+
switch(op){
|
|
140
|
+
case "count":
|
|
141
|
+
return values.length;
|
|
142
|
+
case "countFilled":
|
|
143
|
+
return values.filter((value)=>!isEmptyValueForCalc(value)).length;
|
|
144
|
+
}
|
|
145
|
+
const numbers = values.filter((value)=>!isEmptyValueForCalc(value)).map((value)=>typeof value === "number" ? value : Number(value)).filter((value)=>Number.isFinite(value));
|
|
146
|
+
if (numbers.length === 0) return null;
|
|
147
|
+
switch(op){
|
|
148
|
+
case "sum":
|
|
149
|
+
return numbers.reduce((total, value)=>total + value, 0);
|
|
150
|
+
case "average":
|
|
151
|
+
return numbers.reduce((total, value)=>total + value, 0) / numbers.length;
|
|
152
|
+
case "min":
|
|
153
|
+
return Math.min(...numbers);
|
|
154
|
+
case "max":
|
|
155
|
+
return Math.max(...numbers);
|
|
156
|
+
default:
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const EMPTY_OPS = {};
|
|
161
|
+
// Owns which aggregation (if any) each column's ColumnCalc footer cell currently
|
|
162
|
+
// shows -- the way useDataTableFilter owns one filter per column key. The actual
|
|
163
|
+
// REDUCE over row values needs `TRow` (a type this headless package never sees), so
|
|
164
|
+
// -- same split as sort/search/filter -- this hook only tracks WHICH op is active per
|
|
165
|
+
// column; the styled layer (DataTable.tsx's `ColumnCalcCell`) calls `computeColumnCalc`
|
|
166
|
+
// with the column's own resolved values.
|
|
167
|
+
function useDataTableColumnCalc(props) {
|
|
168
|
+
const { columnCalcOps: opsProp, defaultColumnCalcOps = EMPTY_OPS, onColumnCalcOpsChange } = props;
|
|
169
|
+
const [columnCalcOps = EMPTY_OPS, setColumnCalcOps] = useControllableState({
|
|
170
|
+
prop: opsProp,
|
|
171
|
+
defaultProp: defaultColumnCalcOps,
|
|
172
|
+
onChange: onColumnCalcOpsChange
|
|
173
|
+
});
|
|
174
|
+
const getColumnCalcOp = React.useCallback((columnKey)=>columnCalcOps[columnKey], [
|
|
175
|
+
columnCalcOps
|
|
176
|
+
]);
|
|
177
|
+
const setColumnCalcOp = React.useCallback((columnKey, op)=>{
|
|
178
|
+
setColumnCalcOps((current = EMPTY_OPS)=>{
|
|
179
|
+
if (op === undefined) {
|
|
180
|
+
if (!(columnKey in current)) return current;
|
|
181
|
+
const next = {
|
|
182
|
+
...current
|
|
183
|
+
};
|
|
184
|
+
delete next[columnKey];
|
|
185
|
+
return next;
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
...current,
|
|
189
|
+
[columnKey]: op
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}, [
|
|
193
|
+
setColumnCalcOps
|
|
194
|
+
]);
|
|
195
|
+
return {
|
|
196
|
+
columnCalcOps,
|
|
197
|
+
getColumnCalcOp,
|
|
198
|
+
setColumnCalcOp
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
exports.DATA_TABLE_CALC_LABEL = DATA_TABLE_CALC_LABEL;
|
|
203
|
+
exports.DATA_TABLE_NUMERIC_CALC_OPS = DATA_TABLE_NUMERIC_CALC_OPS;
|
|
204
|
+
exports.DATA_TABLE_UNIVERSAL_CALC_OPS = DATA_TABLE_UNIVERSAL_CALC_OPS;
|
|
205
|
+
exports.computeColumnCalc = computeColumnCalc;
|
|
206
|
+
exports.useControllableState = useControllableState;
|
|
207
|
+
exports.useDataTableColumnCalc = useDataTableColumnCalc;
|
|
@@ -0,0 +1,183 @@
|
|
|
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 * as React from 'react';
|
|
12
|
+
import { useCallback } from 'react';
|
|
13
|
+
|
|
14
|
+
// packages/react/use-layout-effect/src/use-layout-effect.tsx
|
|
15
|
+
var useLayoutEffect2 = globalThis?.document ? React.useLayoutEffect : ()=>{};
|
|
16
|
+
|
|
17
|
+
// src/use-controllable-state.tsx
|
|
18
|
+
var useInsertionEffect = React[" useInsertionEffect ".trim().toString()] || useLayoutEffect2;
|
|
19
|
+
function useControllableState({ prop, defaultProp, onChange = ()=>{}, caller }) {
|
|
20
|
+
const [uncontrolledProp, setUncontrolledProp, onChangeRef] = useUncontrolledState({
|
|
21
|
+
defaultProp,
|
|
22
|
+
onChange
|
|
23
|
+
});
|
|
24
|
+
const isControlled = prop !== void 0;
|
|
25
|
+
const value = isControlled ? prop : uncontrolledProp;
|
|
26
|
+
{
|
|
27
|
+
const isControlledRef = React.useRef(prop !== void 0);
|
|
28
|
+
React.useEffect(()=>{
|
|
29
|
+
const wasControlled = isControlledRef.current;
|
|
30
|
+
if (wasControlled !== isControlled) {
|
|
31
|
+
const from = wasControlled ? "controlled" : "uncontrolled";
|
|
32
|
+
const to = isControlled ? "controlled" : "uncontrolled";
|
|
33
|
+
console.warn(`${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`);
|
|
34
|
+
}
|
|
35
|
+
isControlledRef.current = isControlled;
|
|
36
|
+
}, [
|
|
37
|
+
isControlled,
|
|
38
|
+
caller
|
|
39
|
+
]);
|
|
40
|
+
}
|
|
41
|
+
const setValue = React.useCallback((nextValue)=>{
|
|
42
|
+
if (isControlled) {
|
|
43
|
+
const value2 = isFunction(nextValue) ? nextValue(prop) : nextValue;
|
|
44
|
+
if (value2 !== prop) {
|
|
45
|
+
onChangeRef.current?.(value2);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
setUncontrolledProp(nextValue);
|
|
49
|
+
}
|
|
50
|
+
}, [
|
|
51
|
+
isControlled,
|
|
52
|
+
prop,
|
|
53
|
+
setUncontrolledProp,
|
|
54
|
+
onChangeRef
|
|
55
|
+
]);
|
|
56
|
+
return [
|
|
57
|
+
value,
|
|
58
|
+
setValue
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
function useUncontrolledState({ defaultProp, onChange }) {
|
|
62
|
+
const [value, setValue] = React.useState(defaultProp);
|
|
63
|
+
const prevValueRef = React.useRef(value);
|
|
64
|
+
const onChangeRef = React.useRef(onChange);
|
|
65
|
+
useInsertionEffect(()=>{
|
|
66
|
+
onChangeRef.current = onChange;
|
|
67
|
+
}, [
|
|
68
|
+
onChange
|
|
69
|
+
]);
|
|
70
|
+
React.useEffect(()=>{
|
|
71
|
+
if (prevValueRef.current !== value) {
|
|
72
|
+
onChangeRef.current?.(value);
|
|
73
|
+
prevValueRef.current = value;
|
|
74
|
+
}
|
|
75
|
+
}, [
|
|
76
|
+
value,
|
|
77
|
+
prevValueRef
|
|
78
|
+
]);
|
|
79
|
+
return [
|
|
80
|
+
value,
|
|
81
|
+
setValue,
|
|
82
|
+
onChangeRef
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
function isFunction(value) {
|
|
86
|
+
return typeof value === "function";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const DATA_TABLE_UNIVERSAL_CALC_OPS = [
|
|
90
|
+
"count",
|
|
91
|
+
"countFilled"
|
|
92
|
+
];
|
|
93
|
+
const DATA_TABLE_NUMERIC_CALC_OPS = [
|
|
94
|
+
"sum",
|
|
95
|
+
"average",
|
|
96
|
+
"min",
|
|
97
|
+
"max"
|
|
98
|
+
];
|
|
99
|
+
const DATA_TABLE_CALC_LABEL = {
|
|
100
|
+
count: "Count",
|
|
101
|
+
countFilled: "Count filled",
|
|
102
|
+
sum: "Sum",
|
|
103
|
+
average: "Average",
|
|
104
|
+
min: "Min",
|
|
105
|
+
max: "Max"
|
|
106
|
+
};
|
|
107
|
+
/** A value counts as empty when it is null/undefined, an empty string, or an empty
|
|
108
|
+
* array -- crisp's own `isEmptyValue` (columncalc.tsx), reused verbatim. */ function isEmptyValueForCalc(value) {
|
|
109
|
+
if (value == null) return true;
|
|
110
|
+
if (typeof value === "string") return value.trim() === "";
|
|
111
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Pure so the arithmetic is independently (and mutation-) testable without rendering a
|
|
116
|
+
* table at all. `sum`/`average`/`min`/`max` skip empty values and non-numeric ones
|
|
117
|
+
* (coerced via `Number`, dropping `NaN`); they return `null` -- render nothing, not a
|
|
118
|
+
* misleading 0 -- when there is nothing numeric left to reduce over.
|
|
119
|
+
*/ function computeColumnCalc(values, op) {
|
|
120
|
+
switch(op){
|
|
121
|
+
case "count":
|
|
122
|
+
return values.length;
|
|
123
|
+
case "countFilled":
|
|
124
|
+
return values.filter((value)=>!isEmptyValueForCalc(value)).length;
|
|
125
|
+
}
|
|
126
|
+
const numbers = values.filter((value)=>!isEmptyValueForCalc(value)).map((value)=>typeof value === "number" ? value : Number(value)).filter((value)=>Number.isFinite(value));
|
|
127
|
+
if (numbers.length === 0) return null;
|
|
128
|
+
switch(op){
|
|
129
|
+
case "sum":
|
|
130
|
+
return numbers.reduce((total, value)=>total + value, 0);
|
|
131
|
+
case "average":
|
|
132
|
+
return numbers.reduce((total, value)=>total + value, 0) / numbers.length;
|
|
133
|
+
case "min":
|
|
134
|
+
return Math.min(...numbers);
|
|
135
|
+
case "max":
|
|
136
|
+
return Math.max(...numbers);
|
|
137
|
+
default:
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const EMPTY_OPS = {};
|
|
142
|
+
// Owns which aggregation (if any) each column's ColumnCalc footer cell currently
|
|
143
|
+
// shows -- the way useDataTableFilter owns one filter per column key. The actual
|
|
144
|
+
// REDUCE over row values needs `TRow` (a type this headless package never sees), so
|
|
145
|
+
// -- same split as sort/search/filter -- this hook only tracks WHICH op is active per
|
|
146
|
+
// column; the styled layer (DataTable.tsx's `ColumnCalcCell`) calls `computeColumnCalc`
|
|
147
|
+
// with the column's own resolved values.
|
|
148
|
+
function useDataTableColumnCalc(props) {
|
|
149
|
+
const { columnCalcOps: opsProp, defaultColumnCalcOps = EMPTY_OPS, onColumnCalcOpsChange } = props;
|
|
150
|
+
const [columnCalcOps = EMPTY_OPS, setColumnCalcOps] = useControllableState({
|
|
151
|
+
prop: opsProp,
|
|
152
|
+
defaultProp: defaultColumnCalcOps,
|
|
153
|
+
onChange: onColumnCalcOpsChange
|
|
154
|
+
});
|
|
155
|
+
const getColumnCalcOp = useCallback((columnKey)=>columnCalcOps[columnKey], [
|
|
156
|
+
columnCalcOps
|
|
157
|
+
]);
|
|
158
|
+
const setColumnCalcOp = useCallback((columnKey, op)=>{
|
|
159
|
+
setColumnCalcOps((current = EMPTY_OPS)=>{
|
|
160
|
+
if (op === undefined) {
|
|
161
|
+
if (!(columnKey in current)) return current;
|
|
162
|
+
const next = {
|
|
163
|
+
...current
|
|
164
|
+
};
|
|
165
|
+
delete next[columnKey];
|
|
166
|
+
return next;
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
...current,
|
|
170
|
+
[columnKey]: op
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
}, [
|
|
174
|
+
setColumnCalcOps
|
|
175
|
+
]);
|
|
176
|
+
return {
|
|
177
|
+
columnCalcOps,
|
|
178
|
+
getColumnCalcOp,
|
|
179
|
+
setColumnCalcOp
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export { DATA_TABLE_CALC_LABEL as D, DATA_TABLE_UNIVERSAL_CALC_OPS as a, DATA_TABLE_NUMERIC_CALC_OPS as b, computeColumnCalc as c, useControllableState as d, useDataTableColumnCalc as u };
|