@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,427 @@
|
|
|
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
|
+
var React = require('react');
|
|
13
|
+
var DataTable12s = require('./DataTable-12s-8LMBtS2u.cjs');
|
|
14
|
+
var domUtils = require('@seed-design/dom-utils');
|
|
15
|
+
var Menu12s = require('./Menu-12s-Db_zr1AP.cjs');
|
|
16
|
+
var segmentedControl = require('@seed-design/css/recipes/segmented-control');
|
|
17
|
+
var reactPrimitive = require('@seed-design/react-primitive');
|
|
18
|
+
var reactSegmentedControl = require('@seed-design/react-segmented-control');
|
|
19
|
+
var columnLayout12s = require('./column-layout-12s-CTu5yT_D.cjs');
|
|
20
|
+
var resize12s = require('./resize-12s-jQY-PX67.cjs');
|
|
21
|
+
var DataTable12sZml1x9Kr12s = require('./DataTable-12s-Zml1x9Kr-12s-CTRzgvMT.cjs');
|
|
22
|
+
|
|
23
|
+
function _interopNamespace(e) {
|
|
24
|
+
if (e && e.__esModule) return e;
|
|
25
|
+
var n = Object.create(null);
|
|
26
|
+
if (e) {
|
|
27
|
+
Object.keys(e).forEach(function (k) {
|
|
28
|
+
if (k !== 'default') {
|
|
29
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
30
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () { return e[k]; }
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
n.default = e;
|
|
38
|
+
return n;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
42
|
+
|
|
43
|
+
const { withProvider, withContext } = DataTable12s.createSlotRecipeContext(segmentedControl.segmentedControl);
|
|
44
|
+
const SegmentedControlRoot = withProvider(reactSegmentedControl.SegmentedControl.Root, "root");
|
|
45
|
+
const SegmentedControlIndicator = withContext(reactPrimitive.Primitive.div, "indicator");
|
|
46
|
+
const SegmentedControlItem = withContext(reactSegmentedControl.SegmentedControl.Item, "item");
|
|
47
|
+
const SegmentedControlItemHiddenInput = reactSegmentedControl.SegmentedControl.ItemHiddenInput;
|
|
48
|
+
|
|
49
|
+
// Same fix as cells.tsx's `CheckboxCell`/editors.tsx's `CheckboxEditor` -- seed's
|
|
50
|
+
// `CheckboxIndicator` needs a real icon for its `checked` prop (it renders exactly
|
|
51
|
+
// what's passed there, nothing automatically); `checked={null}` here used to render an
|
|
52
|
+
// empty box even once a value was actually checked. 12px, matching the row-selection
|
|
53
|
+
// checkbox's own already-correct icon size (`DataTable.tsx`'s `SELECTION_ICON_SIZE`).
|
|
54
|
+
const FILTER_CHECKED_ICON = /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.IconCheckmarkLine_default, {
|
|
55
|
+
size: 12
|
|
56
|
+
});
|
|
57
|
+
// Fix (bug report): karrot icons default to a 24px intrinsic `width`/`height`
|
|
58
|
+
// SVG ATTRIBUTE (not CSS) -- inside a fixed 16px `headerCellIcon` box (a flex
|
|
59
|
+
// item), flexbox only auto-shrinks the MAIN axis (width) to fit, leaving the
|
|
60
|
+
// CROSS axis (height) at its full 24px intrinsic size, so the glyph rendered
|
|
61
|
+
// visibly oversized/non-square and spilled out of its slot (measured live:
|
|
62
|
+
// 16×24, not 16×16). Passing `size` sets both attributes directly, sidestepping
|
|
63
|
+
// the mismatch entirely rather than fighting it with more CSS. Matches crisp's
|
|
64
|
+
// own measured `.crisp-datatable-chevron` size (14px).
|
|
65
|
+
const SORT_ICON_SIZE = 14;
|
|
66
|
+
const DEFAULT_SORT_ICON = {
|
|
67
|
+
idle: /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.IconChevronDownLine_default, {
|
|
68
|
+
size: SORT_ICON_SIZE
|
|
69
|
+
}),
|
|
70
|
+
asc: /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.IconChevronUpLine_default, {
|
|
71
|
+
size: SORT_ICON_SIZE
|
|
72
|
+
}),
|
|
73
|
+
desc: /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.IconChevronDownLine_default, {
|
|
74
|
+
size: SORT_ICON_SIZE
|
|
75
|
+
})
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Rendered for EVERY sortable column, sorted or not -- unlike a naive "only show the
|
|
79
|
+
* active column's arrow", Attio reveals a neutral chevron on ANY sortable header on
|
|
80
|
+
* hover (`data-chevron`'s own CSS in `data-table.ts` owns the opacity: 0 at rest, 0.6
|
|
81
|
+
* on header hover, 1 + full foreground once sorted). Conditionally rendering only the
|
|
82
|
+
* sorted state, the way this component used to, has nothing for that hover state to
|
|
83
|
+
* reveal.
|
|
84
|
+
*/ function SortIndicator({ columnKey, icon }) {
|
|
85
|
+
const { sort } = DataTable12sZml1x9Kr12s.useDataTableContext();
|
|
86
|
+
const isSorted = sort?.key === columnKey;
|
|
87
|
+
const resolved = isSorted ? sort?.dir === "asc" ? icon?.asc ?? DEFAULT_SORT_ICON.asc : icon?.desc ?? DEFAULT_SORT_ICON.desc : icon?.idle ?? DEFAULT_SORT_ICON.idle;
|
|
88
|
+
return /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.DataTableHeaderCellIcon, {
|
|
89
|
+
"aria-hidden": true,
|
|
90
|
+
"data-chevron": "",
|
|
91
|
+
draggable: false,
|
|
92
|
+
children: resolved
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/** Attio's own condition word: "Is"/"Is not" alone with zero or one value checked,
|
|
96
|
+
* "Is any of"/"Is not any of" once a second value joins the set -- the underlying
|
|
97
|
+
* predicate never changes (`useDataTableFilter.ts`'s own comment: membership in a
|
|
98
|
+
* set of one IS "is X"), only the word describing it does. */ function filterConditionLabel(mode, hasMultipleValues) {
|
|
99
|
+
if (mode === "isnot") return hasMultipleValues ? "Is not any of" : "Is not";
|
|
100
|
+
return hasMultipleValues ? "Is any of" : "Is";
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A column's "is / is not / is any of" checkbox filter picker (DATATABLE-ATTIO-
|
|
104
|
+
* SPEC.md's Feature contract), Attio's own chrome: a two-way condition control above a
|
|
105
|
+
* checkbox value list, both built from seed's own documented components -- `Menu` for
|
|
106
|
+
* the popover shell (`MenuRoot`/`Trigger`/`Positioner`/`Content`, unchanged), seed's
|
|
107
|
+
* `SegmentedControl` (docs/content/react/components/segmented-control.mdx) for the
|
|
108
|
+
* is/is-not toggle in place of the two hand-styled buttons (hardcoded hex, no seed
|
|
109
|
+
* token) this used to be, and plain `<label>` + `CheckboxRoot` rows for the value
|
|
110
|
+
* list -- NOT `MenuItem` there either: `MenuItem`'s own `getItemProps` (`useMenu.ts`)
|
|
111
|
+
* closes the menu unconditionally after every click, which is correct for a normal
|
|
112
|
+
* command menu but would close this ENTIRE popover after a single condition pick or a
|
|
113
|
+
* single checked value -- exactly wrong for a control meant to stay open while the
|
|
114
|
+
* condition changes and several boxes get checked. `SegmentedControl` has no such
|
|
115
|
+
* auto-close (it's a plain controlled radio group, not a menu), which is exactly why
|
|
116
|
+
* it -- not `MenuItem` -- is the documented component that fits here.
|
|
117
|
+
*/ function FilterMenu({ column }) {
|
|
118
|
+
const { filters, toggleFilterValue, setFilterMode } = DataTable12sZml1x9Kr12s.useDataTableContext();
|
|
119
|
+
const values = column.filterValues ?? [];
|
|
120
|
+
const current = filters[column.key];
|
|
121
|
+
const mode = current?.mode ?? "is";
|
|
122
|
+
const checkedValues = current?.values ?? [];
|
|
123
|
+
const hasMultipleValues = checkedValues.length > 1;
|
|
124
|
+
const columnLabel = typeof column.header === "string" ? column.header : column.key;
|
|
125
|
+
// A filter trigger lives INSIDE a (possibly sortable) header cell, whose own
|
|
126
|
+
// onClick/onKeyDown toggle sort -- stop the event here so opening the filter
|
|
127
|
+
// picker never also reorders the rows out from under it.
|
|
128
|
+
const stopPropagation = (event)=>event.stopPropagation();
|
|
129
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(Menu12s.MenuRoot, {
|
|
130
|
+
children: [
|
|
131
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTable12s.DataTableHeaderCellIcon, {
|
|
132
|
+
asChild: true,
|
|
133
|
+
onClick: stopPropagation,
|
|
134
|
+
onKeyDown: stopPropagation,
|
|
135
|
+
draggable: false,
|
|
136
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuTrigger, {
|
|
137
|
+
"aria-label": `Filter ${columnLabel}`,
|
|
138
|
+
"data-active": domUtils.dataAttr(checkedValues.length > 0),
|
|
139
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.IconSlider2HorizontalLine_default, {
|
|
140
|
+
size: 16
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
}),
|
|
144
|
+
/*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuPositioner, {
|
|
145
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuContent, {
|
|
146
|
+
style: {
|
|
147
|
+
minWidth: 180
|
|
148
|
+
},
|
|
149
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs(Menu12s.MenuScrollArea, {
|
|
150
|
+
children: [
|
|
151
|
+
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
152
|
+
style: {
|
|
153
|
+
padding: "0 8px"
|
|
154
|
+
},
|
|
155
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs(SegmentedControlRoot, {
|
|
156
|
+
"aria-label": `${columnLabel} filter condition`,
|
|
157
|
+
value: mode,
|
|
158
|
+
onValueChange: (next)=>setFilterMode(column.key, next),
|
|
159
|
+
style: {
|
|
160
|
+
width: "100%"
|
|
161
|
+
},
|
|
162
|
+
children: [
|
|
163
|
+
/*#__PURE__*/ jsxRuntime.jsxs(SegmentedControlItem, {
|
|
164
|
+
value: "is",
|
|
165
|
+
children: [
|
|
166
|
+
/*#__PURE__*/ jsxRuntime.jsx(SegmentedControlItemHiddenInput, {}),
|
|
167
|
+
filterConditionLabel("is", hasMultipleValues)
|
|
168
|
+
]
|
|
169
|
+
}),
|
|
170
|
+
/*#__PURE__*/ jsxRuntime.jsxs(SegmentedControlItem, {
|
|
171
|
+
value: "isnot",
|
|
172
|
+
children: [
|
|
173
|
+
/*#__PURE__*/ jsxRuntime.jsx(SegmentedControlItemHiddenInput, {}),
|
|
174
|
+
filterConditionLabel("isnot", hasMultipleValues)
|
|
175
|
+
]
|
|
176
|
+
}),
|
|
177
|
+
/*#__PURE__*/ jsxRuntime.jsx(SegmentedControlIndicator, {})
|
|
178
|
+
]
|
|
179
|
+
})
|
|
180
|
+
}),
|
|
181
|
+
values.map((value)=>// `CheckboxRoot` is ALREADY a `<label>` (`Checkbox.tsx`'s own
|
|
182
|
+
// `Primitive.label`) wrapping the hidden input + `CheckboxLabel` text --
|
|
183
|
+
// wrapping it in a SECOND `<label>` here used to nest one label inside
|
|
184
|
+
// another, which is invalid HTML and made a click on the row's own text
|
|
185
|
+
// reach the checkbox's native activation twice (once via each label),
|
|
186
|
+
// toggling it on then immediately back off. `CheckboxRoot` takes the
|
|
187
|
+
// row's own layout via `style` directly instead.
|
|
188
|
+
/*#__PURE__*/ jsxRuntime.jsxs(DataTable12s.CheckboxRoot, {
|
|
189
|
+
checked: checkedValues.includes(value),
|
|
190
|
+
onCheckedChange: ()=>toggleFilterValue(column.key, value),
|
|
191
|
+
style: {
|
|
192
|
+
display: "flex",
|
|
193
|
+
alignItems: "center",
|
|
194
|
+
gap: 8,
|
|
195
|
+
padding: "4px 8px",
|
|
196
|
+
cursor: "pointer"
|
|
197
|
+
},
|
|
198
|
+
children: [
|
|
199
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTable12s.CheckboxControl, {
|
|
200
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.CheckboxIndicator, {
|
|
201
|
+
checked: FILTER_CHECKED_ICON
|
|
202
|
+
})
|
|
203
|
+
}),
|
|
204
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTable12s.CheckboxLabel, {
|
|
205
|
+
children: value
|
|
206
|
+
}),
|
|
207
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTable12s.CheckboxHiddenInput, {
|
|
208
|
+
"aria-label": value
|
|
209
|
+
})
|
|
210
|
+
]
|
|
211
|
+
}, value))
|
|
212
|
+
]
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
]
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/** Every header cell, in the effective (ordered, visible) order -- a standalone
|
|
220
|
+
* component (not inlined in `DataTableInner`'s render) so it alone re-renders when
|
|
221
|
+
* `visibleColumnOrder`/labels/widths change, without also re-deriving `sortedData`'s
|
|
222
|
+
* render above it. */ function ColumnHeaderCells({ columns, columnMenu, reorderable, resizable, sortIcon, selectable, stickyFirst, stickyLast }) {
|
|
223
|
+
const { draggingColumnKey, beginColumnDrag, dragOverColumn, endColumnDrag } = DataTable12sZml1x9Kr12s.useDataTableContext();
|
|
224
|
+
const effective = columnLayout12s.useEffectiveColumns(columns);
|
|
225
|
+
const [renamingKey, setRenamingKey] = React__namespace.useState(null);
|
|
226
|
+
return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
227
|
+
children: effective.map(({ column, label, width }, index)=>{
|
|
228
|
+
const isFirst = index === 0;
|
|
229
|
+
const isLast = index === effective.length - 1;
|
|
230
|
+
const sticky = columnLayout12s.stickyProps({
|
|
231
|
+
selectable,
|
|
232
|
+
stickyFirst,
|
|
233
|
+
stickyLast,
|
|
234
|
+
isSelectionCell: false,
|
|
235
|
+
isFirst,
|
|
236
|
+
isLast
|
|
237
|
+
});
|
|
238
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(DataTable12s.DataTableHeaderCell, {
|
|
239
|
+
columnKey: column.key,
|
|
240
|
+
sortable: column.sortable,
|
|
241
|
+
"data-column-key": column.key,
|
|
242
|
+
draggable: reorderable && renamingKey !== column.key,
|
|
243
|
+
onDragStart: (event)=>{
|
|
244
|
+
event.dataTransfer.effectAllowed = "move";
|
|
245
|
+
beginColumnDrag(column.key);
|
|
246
|
+
},
|
|
247
|
+
onDragOver: (event)=>{
|
|
248
|
+
event.preventDefault();
|
|
249
|
+
if (draggingColumnKey && draggingColumnKey !== column.key) dragOverColumn(column.key);
|
|
250
|
+
},
|
|
251
|
+
onDrop: (event)=>event.preventDefault(),
|
|
252
|
+
onDragEnd: endColumnDrag,
|
|
253
|
+
"data-dragging": domUtils.dataAttr(draggingColumnKey === column.key),
|
|
254
|
+
style: sticky.style,
|
|
255
|
+
"data-sticky": sticky["data-sticky"],
|
|
256
|
+
"data-sticky-edge": sticky["data-sticky-edge"],
|
|
257
|
+
"data-sticky-edge-end": sticky["data-sticky-edge-end"],
|
|
258
|
+
children: [
|
|
259
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTable12s.DataTableHeaderCellInner, {
|
|
260
|
+
children: renamingKey === column.key ? /*#__PURE__*/ jsxRuntime.jsx(ColumnRenameInput, {
|
|
261
|
+
column: column,
|
|
262
|
+
initialLabel: typeof label === "string" ? label : column.key,
|
|
263
|
+
onDone: ()=>setRenamingKey(null)
|
|
264
|
+
}) : /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
265
|
+
children: [
|
|
266
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTable12s.DataTableHeaderCellLabel, {
|
|
267
|
+
children: label
|
|
268
|
+
}),
|
|
269
|
+
column.filterValues && column.filterValues.length > 0 && /*#__PURE__*/ jsxRuntime.jsx(FilterMenu, {
|
|
270
|
+
column: column
|
|
271
|
+
}),
|
|
272
|
+
column.sortable && /*#__PURE__*/ jsxRuntime.jsx(SortIndicator, {
|
|
273
|
+
columnKey: column.key,
|
|
274
|
+
icon: sortIcon
|
|
275
|
+
}),
|
|
276
|
+
columnMenu && /*#__PURE__*/ jsxRuntime.jsx(ColumnMenu, {
|
|
277
|
+
column: column,
|
|
278
|
+
onRename: ()=>setRenamingKey(column.key)
|
|
279
|
+
})
|
|
280
|
+
]
|
|
281
|
+
})
|
|
282
|
+
}),
|
|
283
|
+
resizable && column.resizable !== false && /*#__PURE__*/ jsxRuntime.jsx(resize12s.ColumnResizeHandle, {
|
|
284
|
+
columnKey: column.key,
|
|
285
|
+
width: width
|
|
286
|
+
})
|
|
287
|
+
]
|
|
288
|
+
}, column.key);
|
|
289
|
+
})
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
function ColumnRenameInput({ column, initialLabel, onDone }) {
|
|
293
|
+
const { renameColumn } = DataTable12sZml1x9Kr12s.useDataTableContext();
|
|
294
|
+
const [value, setValue] = React__namespace.useState(initialLabel);
|
|
295
|
+
// Opening this input is ITSELF the result of clicking a `MenuItem` -- the menu's own
|
|
296
|
+
// close (which happens on that same click) restores focus to its trigger a beat
|
|
297
|
+
// later, and that focus move fires as a `blur` on this input the instant it mounts
|
|
298
|
+
// with `autoFocus`. Committing on THAT blur would silently re-close the editor
|
|
299
|
+
// before anyone saw it (found writing this file's own rename test, which failed
|
|
300
|
+
// with the header reverting to its plain label with no visible input in between).
|
|
301
|
+
// `ready` flips true one frame after mount, so only a blur after that -- an actual
|
|
302
|
+
// click/tab away -- commits.
|
|
303
|
+
const readyRef = React__namespace.useRef(false);
|
|
304
|
+
const inputRef = React__namespace.useRef(null);
|
|
305
|
+
React__namespace.useEffect(()=>{
|
|
306
|
+
// The menu's close restores focus to its trigger one frame after this input
|
|
307
|
+
// mounts, stealing focus from `autoFocus`. Re-grab it in the SAME frame (after
|
|
308
|
+
// the restore) and select the text, so the user can type/replace immediately.
|
|
309
|
+
const frame = requestAnimationFrame(()=>{
|
|
310
|
+
readyRef.current = true;
|
|
311
|
+
inputRef.current?.focus();
|
|
312
|
+
inputRef.current?.select();
|
|
313
|
+
});
|
|
314
|
+
return ()=>cancelAnimationFrame(frame);
|
|
315
|
+
}, []);
|
|
316
|
+
const commit = ()=>{
|
|
317
|
+
if (value.trim()) renameColumn(column.key, value.trim());
|
|
318
|
+
onDone();
|
|
319
|
+
};
|
|
320
|
+
return(// A bare, minimal input -- NOT seed's `TextField` (its labeled root measures
|
|
321
|
+
// ~52px tall, per DATATABLE-ATTIO-SPEC.md's own note; this has to fit a 40px
|
|
322
|
+
// header cell with no label/description chrome of its own). Seed has no lighter
|
|
323
|
+
// input primitive at this level, so this follows crisp's own measured
|
|
324
|
+
// `.crisp-datatable-th-rename` (`datatable.recipe.ts`) instead: full-width,
|
|
325
|
+
// header-row height, a small inset, no border (an inset brand-solid box-shadow
|
|
326
|
+
// stands in for a focus ring), the header's own font weight/size inherited
|
|
327
|
+
// rather than a new size introduced for one input.
|
|
328
|
+
/*#__PURE__*/ jsxRuntime.jsx("input", {
|
|
329
|
+
ref: inputRef,
|
|
330
|
+
// biome-ignore lint/a11y/noAutofocus: opening this input IS the user's own click a moment earlier (crisp's `.crisp-datatable-th-rename` does the same), not an unannounced page-load autofocus.
|
|
331
|
+
autoFocus: true,
|
|
332
|
+
"aria-label": `Rename ${initialLabel}`,
|
|
333
|
+
value: value,
|
|
334
|
+
onClick: (event)=>event.stopPropagation(),
|
|
335
|
+
onChange: (event)=>setValue(event.target.value),
|
|
336
|
+
onBlur: ()=>{
|
|
337
|
+
if (readyRef.current) commit();
|
|
338
|
+
},
|
|
339
|
+
onKeyDown: (event)=>{
|
|
340
|
+
event.stopPropagation();
|
|
341
|
+
if (event.key === "Enter") commit();
|
|
342
|
+
if (event.key === "Escape") onDone();
|
|
343
|
+
},
|
|
344
|
+
// Bare inline input: no border/ring/background/radius -- it reads as the
|
|
345
|
+
// header label made editable in place, not a boxed field.
|
|
346
|
+
style: {
|
|
347
|
+
width: "100%",
|
|
348
|
+
minWidth: 0,
|
|
349
|
+
height: "100%",
|
|
350
|
+
margin: 0,
|
|
351
|
+
padding: 0,
|
|
352
|
+
border: "none",
|
|
353
|
+
borderRadius: 0,
|
|
354
|
+
background: "transparent",
|
|
355
|
+
boxShadow: "none",
|
|
356
|
+
font: "inherit",
|
|
357
|
+
fontWeight: "var(--seed-font-weight-medium)",
|
|
358
|
+
color: "var(--seed-color-fg-neutral)",
|
|
359
|
+
outline: "none"
|
|
360
|
+
}
|
|
361
|
+
}));
|
|
362
|
+
}
|
|
363
|
+
/** The per-column header menu (rename / hide / move left / move right) -- seed
|
|
364
|
+
* `Menu`, opened from the same `headerCellIcon` slot the filter trigger and sort
|
|
365
|
+
* chevron already share. Hover/focus-reveal (`data-column-menu`'s own CSS in
|
|
366
|
+
* `data-table.ts`) -- crisp's own header shows the trigger only on hover, not
|
|
367
|
+
* permanently, so this one carries its own marker attribute distinct from that
|
|
368
|
+
* slot's OTHER occupants (the sort chevron, the filter trigger), which stay visible
|
|
369
|
+
* under their own separate rules regardless of hover. */ function ColumnMenu({ column, onRename }) {
|
|
370
|
+
const { moveColumn, hideColumn } = DataTable12sZml1x9Kr12s.useDataTableContext();
|
|
371
|
+
const columnLabel = typeof column.header === "string" ? column.header : column.key;
|
|
372
|
+
const stopPropagation = (event)=>event.stopPropagation();
|
|
373
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(Menu12s.MenuRoot, {
|
|
374
|
+
children: [
|
|
375
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTable12s.DataTableHeaderCellIcon, {
|
|
376
|
+
asChild: true,
|
|
377
|
+
"data-column-menu": "",
|
|
378
|
+
onClick: stopPropagation,
|
|
379
|
+
onKeyDown: stopPropagation,
|
|
380
|
+
draggable: false,
|
|
381
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuTrigger, {
|
|
382
|
+
"aria-label": `${columnLabel} column menu`,
|
|
383
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(DataTable12s.IconDot3HorizontalLine_default, {
|
|
384
|
+
size: 16
|
|
385
|
+
})
|
|
386
|
+
})
|
|
387
|
+
}),
|
|
388
|
+
/*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuPositioner, {
|
|
389
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuContent, {
|
|
390
|
+
style: {
|
|
391
|
+
minWidth: 160
|
|
392
|
+
},
|
|
393
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs(Menu12s.MenuScrollArea, {
|
|
394
|
+
children: [
|
|
395
|
+
/*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItem, {
|
|
396
|
+
onClick: onRename,
|
|
397
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItemLabel, {
|
|
398
|
+
children: "Rename"
|
|
399
|
+
})
|
|
400
|
+
}),
|
|
401
|
+
/*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItem, {
|
|
402
|
+
onClick: ()=>moveColumn(column.key, "left"),
|
|
403
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItemLabel, {
|
|
404
|
+
children: "Move left"
|
|
405
|
+
})
|
|
406
|
+
}),
|
|
407
|
+
/*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItem, {
|
|
408
|
+
onClick: ()=>moveColumn(column.key, "right"),
|
|
409
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItemLabel, {
|
|
410
|
+
children: "Move right"
|
|
411
|
+
})
|
|
412
|
+
}),
|
|
413
|
+
/*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItem, {
|
|
414
|
+
onClick: ()=>hideColumn(column.key),
|
|
415
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(Menu12s.MenuItemLabel, {
|
|
416
|
+
children: "Hide column"
|
|
417
|
+
})
|
|
418
|
+
})
|
|
419
|
+
]
|
|
420
|
+
})
|
|
421
|
+
})
|
|
422
|
+
})
|
|
423
|
+
]
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
exports.ColumnHeaderCells = ColumnHeaderCells;
|