@adapttable/unstyled 0.1.0 → 0.2.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/dist/index.js CHANGED
@@ -1,2401 +1,1878 @@
1
- import { resolveLabels, useSavedViews, useTableData, isDeclarativeFilters, useTableChrome, useFilterTriggerToggle, useChromeScrollReset, useChromeBodyData, RANGE_SUFFIXES, useColumnDragState, columnMenuRows, pageSizeOptions, useBulkActionRunner, resolveDisabledReason, ACTIONS_COLUMN_KEY, readRangeWidget, RANGE_OP_LABEL_KEYS, RANGE_OPS, filterLabel, useFilterOptions, GripIcon, columnReorderKeyProps, nextPinSide, pinActionLabel, resolveVirtualRows, rowClickProps, tableRenderModel, useHorizontalOverflow, PIN_Z, tableMinWidth, headerGroupRow, columnResizeHandleProps, writeRangeWidget, EyeIcon, PinIcon, edgePinStyle, pinnedColumnWidth, runRowAction, pinnedCellStyle } from '@adapttable/core';
2
- export { FILTER_TYPES, createHistoryAdapter, createMemoryAdapter, defaultConfirm, defaultLabels, deriveSortByOptions, filterLabel, filterStateKeys, getHistoryAdapter, useBackendData, useDataTable, useFrontendData, useSavedViews, useServerData, useTableData, useTableUrlState } from '@adapttable/core';
3
- import { useRef, useEffect, useState, useCallback, useMemo, memo } from 'react';
4
- import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
5
- import { createPortal } from 'react-dom';
6
-
7
- // src/components/AutoFilterForm.tsx
8
- var FIELD_PART = "filter-field";
9
- var LABEL_PART = "filter-label";
1
+ import { ACTIONS_COLUMN_KEY, EyeIcon, FILTER_TYPES, GripIcon, PIN_Z, PinIcon, RANGE_OPS, RANGE_OP_LABEL_KEYS, RANGE_SUFFIXES, columnMenuRows, columnReorderKeyProps, columnResizeHandleProps, createHistoryAdapter, createMemoryAdapter, defaultConfirm, defaultLabels, deriveSortByOptions, edgePinStyle, filterLabel, filterLabel as filterLabel$1, filterStateKeys, getHistoryAdapter, headerGroupRow, isDeclarativeFilters, nextPinSide, pageSizeOptions, pinActionLabel, pinnedCellStyle, pinnedColumnWidth, readRangeWidget, resolveDisabledReason, resolveLabels, resolveVirtualRows, rowClickProps, runRowAction, tableMinWidth, tableRenderModel, useBackendData, useBulkActionRunner, useChromeBodyData, useChromeScrollReset, useColumnDragState, useDataTable, useFilterOptions, useFilterTriggerToggle, useFrontendData, useHorizontalOverflow, useSavedViews, useSavedViews as useSavedViews$1, useServerData, useTableChrome, useTableData, useTableData as useTableData$1, useTableUrlState, writeRangeWidget } from "@adapttable/core";
2
+ import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { createPortal } from "react-dom";
5
+ //#region src/components/AutoFilterForm.tsx
6
+ const FIELD_PART = "filter-field";
7
+ const LABEL_PART = "filter-label";
8
+ /** A filter-bag value as input text (`undefined` renders empty). */
10
9
  function asText(value) {
11
- return String(value ?? "");
10
+ return String(value ?? "");
12
11
  }
12
+ /** A `multiSelect` bag value as an array, tolerating a scalar from the URL. */
13
13
  function selectedValues(value) {
14
- if (Array.isArray(value)) return value;
15
- if (value == null || value === "") return [];
16
- return [String(value)];
14
+ if (Array.isArray(value)) return value;
15
+ if (value == null || value === "") return [];
16
+ return [String(value)];
17
17
  }
18
- function GroupField({
19
- caption,
20
- classNames,
21
- children
22
- }) {
23
- return /* @__PURE__ */ jsxs(
24
- "fieldset",
25
- {
26
- "data-adapttable-part": FIELD_PART,
27
- className: classNames.filterField,
28
- children: [
29
- /* @__PURE__ */ jsx(
30
- "legend",
31
- {
32
- "data-adapttable-part": LABEL_PART,
33
- className: classNames.filterLabel,
34
- children: caption
35
- }
36
- ),
37
- children
38
- ]
39
- }
40
- );
18
+ /** `<fieldset>` + `<legend>` wrapper for multi-control fields. */
19
+ function GroupField({ caption, classNames, children }) {
20
+ return /* @__PURE__ */ jsxs("fieldset", {
21
+ "data-adapttable-part": FIELD_PART,
22
+ className: classNames.filterField,
23
+ children: [/* @__PURE__ */ jsx("legend", {
24
+ "data-adapttable-part": LABEL_PART,
25
+ className: classNames.filterLabel,
26
+ children: caption
27
+ }), children]
28
+ });
41
29
  }
42
- function BagInput({
43
- source,
44
- stateKey,
45
- type,
46
- placeholder,
47
- classNames
48
- }) {
49
- return /* @__PURE__ */ jsx(
50
- "input",
51
- {
52
- type,
53
- placeholder,
54
- "data-adapttable-part": "filter-input",
55
- className: classNames.filterInput,
56
- value: asText(source.extra[stateKey]),
57
- onChange: (e) => source.setExtra(stateKey, e.currentTarget.value)
58
- }
59
- );
30
+ /** One input bound to a filter-bag state key (empty text clears it). */
31
+ function BagInput({ source, stateKey, type, placeholder, classNames }) {
32
+ return /* @__PURE__ */ jsx("input", {
33
+ type,
34
+ placeholder,
35
+ "data-adapttable-part": "filter-input",
36
+ className: classNames.filterInput,
37
+ value: asText(source.extra[stateKey]),
38
+ onChange: (e) => source.setExtra(stateKey, e.currentTarget.value)
39
+ });
60
40
  }
61
- function TextField({
62
- def,
63
- source,
64
- classNames
65
- }) {
66
- return /* @__PURE__ */ jsxs("label", { "data-adapttable-part": FIELD_PART, className: classNames.filterField, children: [
67
- /* @__PURE__ */ jsx(
68
- "span",
69
- {
70
- "data-adapttable-part": LABEL_PART,
71
- className: classNames.filterLabel,
72
- children: filterLabel(def)
73
- }
74
- ),
75
- " ",
76
- /* @__PURE__ */ jsx(
77
- BagInput,
78
- {
79
- source,
80
- stateKey: def.key,
81
- type: "text",
82
- placeholder: def.placeholder,
83
- classNames
84
- }
85
- )
86
- ] });
41
+ function TextField({ def, source, classNames }) {
42
+ return /* @__PURE__ */ jsxs("label", {
43
+ "data-adapttable-part": FIELD_PART,
44
+ className: classNames.filterField,
45
+ children: [
46
+ /* @__PURE__ */ jsx("span", {
47
+ "data-adapttable-part": LABEL_PART,
48
+ className: classNames.filterLabel,
49
+ children: filterLabel$1(def)
50
+ }),
51
+ " ",
52
+ /* @__PURE__ */ jsx(BagInput, {
53
+ source,
54
+ stateKey: def.key,
55
+ type: "text",
56
+ placeholder: def.placeholder,
57
+ classNames
58
+ })
59
+ ]
60
+ });
87
61
  }
88
- function SelectField({
89
- def,
90
- source,
91
- classNames
92
- }) {
93
- const { options, loading } = useFilterOptions(def);
94
- return /* @__PURE__ */ jsxs("label", { "data-adapttable-part": FIELD_PART, className: classNames.filterField, children: [
95
- /* @__PURE__ */ jsx(
96
- "span",
97
- {
98
- "data-adapttable-part": LABEL_PART,
99
- className: classNames.filterLabel,
100
- children: filterLabel(def)
101
- }
102
- ),
103
- " ",
104
- /* @__PURE__ */ jsx(
105
- "select",
106
- {
107
- "data-adapttable-part": "filter-select",
108
- className: classNames.filterSelect,
109
- value: asText(source.extra[def.key]),
110
- onChange: (e) => source.setExtra(def.key, e.currentTarget.value),
111
- children: loading ? /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "\u2026" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
112
- /* @__PURE__ */ jsx("option", { value: "", children: "All" }),
113
- options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
114
- ] })
115
- }
116
- )
117
- ] });
62
+ function SelectField({ def, source, classNames }) {
63
+ const { options, loading } = useFilterOptions(def);
64
+ return /* @__PURE__ */ jsxs("label", {
65
+ "data-adapttable-part": FIELD_PART,
66
+ className: classNames.filterField,
67
+ children: [
68
+ /* @__PURE__ */ jsx("span", {
69
+ "data-adapttable-part": LABEL_PART,
70
+ className: classNames.filterLabel,
71
+ children: filterLabel$1(def)
72
+ }),
73
+ " ",
74
+ /* @__PURE__ */ jsx("select", {
75
+ "data-adapttable-part": "filter-select",
76
+ className: classNames.filterSelect,
77
+ value: asText(source.extra[def.key]),
78
+ onChange: (e) => source.setExtra(def.key, e.currentTarget.value),
79
+ children: loading ? /* @__PURE__ */ jsx("option", {
80
+ value: "",
81
+ disabled: true,
82
+ children: "…"
83
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("option", {
84
+ value: "",
85
+ children: "All"
86
+ }), options.map((option) => /* @__PURE__ */ jsx("option", {
87
+ value: option.value,
88
+ children: option.label
89
+ }, option.value))] })
90
+ })
91
+ ]
92
+ });
118
93
  }
119
- function MultiSelectField({
120
- def,
121
- source,
122
- classNames
123
- }) {
124
- const selected = selectedValues(source.extra[def.key]);
125
- const { options, loading } = useFilterOptions(def);
126
- return /* @__PURE__ */ jsx(GroupField, { caption: filterLabel(def), classNames, children: /* @__PURE__ */ jsx(
127
- "div",
128
- {
129
- "data-adapttable-part": "filter-checkbox-group",
130
- className: classNames.filterCheckboxGroup,
131
- children: loading ? /* @__PURE__ */ jsx(
132
- "span",
133
- {
134
- "data-adapttable-part": "filter-options-loading",
135
- className: classNames.filterOptionsLoading,
136
- children: "\u2026"
137
- }
138
- ) : options.map((option) => /* @__PURE__ */ jsxs(
139
- "label",
140
- {
141
- "data-adapttable-part": "filter-checkbox",
142
- className: classNames.filterCheckbox,
143
- children: [
144
- /* @__PURE__ */ jsx(
145
- "input",
146
- {
147
- type: "checkbox",
148
- checked: selected.includes(option.value),
149
- onChange: (e) => source.setExtra(
150
- def.key,
151
- e.currentTarget.checked ? [...selected, option.value] : selected.filter((v) => v !== option.value)
152
- )
153
- }
154
- ),
155
- " ",
156
- option.label
157
- ]
158
- },
159
- option.value
160
- ))
161
- }
162
- ) });
94
+ function MultiSelectField({ def, source, classNames }) {
95
+ const selected = selectedValues(source.extra[def.key]);
96
+ const { options, loading } = useFilterOptions(def);
97
+ return /* @__PURE__ */ jsx(GroupField, {
98
+ caption: filterLabel$1(def),
99
+ classNames,
100
+ children: /* @__PURE__ */ jsx("div", {
101
+ "data-adapttable-part": "filter-checkbox-group",
102
+ className: classNames.filterCheckboxGroup,
103
+ children: loading ? /* @__PURE__ */ jsx("span", {
104
+ "data-adapttable-part": "filter-options-loading",
105
+ className: classNames.filterOptionsLoading,
106
+ children: "…"
107
+ }) : options.map((option) => /* @__PURE__ */ jsxs("label", {
108
+ "data-adapttable-part": "filter-checkbox",
109
+ className: classNames.filterCheckbox,
110
+ children: [
111
+ /* @__PURE__ */ jsx("input", {
112
+ type: "checkbox",
113
+ checked: selected.includes(option.value),
114
+ onChange: (e) => source.setExtra(def.key, e.currentTarget.checked ? [...selected, option.value] : selected.filter((v) => v !== option.value))
115
+ }),
116
+ " ",
117
+ option.label
118
+ ]
119
+ }, option.value))
120
+ })
121
+ });
163
122
  }
164
- function RangeValueInput({
165
- type,
166
- label,
167
- value,
168
- onValue,
169
- classNames
170
- }) {
171
- return /* @__PURE__ */ jsx(
172
- "input",
173
- {
174
- type,
175
- style: { flex: "1 1 7rem", minWidth: "7rem" },
176
- placeholder: label,
177
- "aria-label": label,
178
- "data-adapttable-part": "filter-input",
179
- className: classNames.filterInput,
180
- value,
181
- onChange: (e) => onValue(e.currentTarget.value)
182
- }
183
- );
123
+ /** One bound of a range widget; the parent owns the write-through. */
124
+ function RangeValueInput({ type, label, value, onValue, classNames }) {
125
+ return /* @__PURE__ */ jsx("input", {
126
+ type,
127
+ style: {
128
+ flex: "1 1 7rem",
129
+ minWidth: "7rem"
130
+ },
131
+ placeholder: label,
132
+ "aria-label": label,
133
+ "data-adapttable-part": "filter-input",
134
+ className: classNames.filterInput,
135
+ value,
136
+ onChange: (e) => onValue(e.currentTarget.value)
137
+ });
184
138
  }
185
- function RangeField({
186
- def,
187
- source,
188
- classNames,
189
- inputType,
190
- suffixes,
191
- labels
192
- }) {
193
- const lowKey = def.key + suffixes.start;
194
- const highKey = def.key + suffixes.end;
195
- const [op, setOp] = useState(
196
- () => readRangeWidget(source.extra, lowKey, highKey).op
197
- );
198
- const a = asText(source.extra[op === "lte" ? highKey : lowKey]);
199
- const b = asText(source.extra[highKey]);
200
- const write = (nextOp, nextA, nextB) => source.setExtras(writeRangeWidget(nextOp, nextA, nextB, lowKey, highKey));
201
- const opLabelKeys = RANGE_OP_LABEL_KEYS[inputType];
202
- return /* @__PURE__ */ jsx(GroupField, { caption: filterLabel(def), classNames, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: [
203
- /* @__PURE__ */ jsxs(
204
- "select",
205
- {
206
- style: { flex: "0 0 8.5rem", width: "8.5rem" },
207
- "aria-label": labels.operator,
208
- "data-adapttable-part": "filter-operator",
209
- className: classNames.filterOperator,
210
- value: op ?? "",
211
- onChange: (e) => {
212
- const next = RANGE_OPS.find((o) => o === e.currentTarget.value);
213
- setOp(next);
214
- write(next, a, b);
215
- },
216
- children: [
217
- /* @__PURE__ */ jsx("option", { value: "", children: labels.operator }),
218
- RANGE_OPS.map((o) => /* @__PURE__ */ jsx("option", { value: o, children: labels[opLabelKeys[o]] }, o))
219
- ]
220
- }
221
- ),
222
- op === "between" && /* @__PURE__ */ jsxs(Fragment, { children: [
223
- /* @__PURE__ */ jsx(
224
- RangeValueInput,
225
- {
226
- type: inputType,
227
- label: labels.from,
228
- value: a,
229
- onValue: (next) => write(op, next, b),
230
- classNames
231
- }
232
- ),
233
- /* @__PURE__ */ jsx(
234
- RangeValueInput,
235
- {
236
- type: inputType,
237
- label: labels.to,
238
- value: b,
239
- onValue: (next) => write(op, a, next),
240
- classNames
241
- }
242
- )
243
- ] }),
244
- op !== void 0 && op !== "between" && /* @__PURE__ */ jsx(
245
- RangeValueInput,
246
- {
247
- type: inputType,
248
- label: labels.value,
249
- value: a,
250
- onValue: (next) => write(op, next, ""),
251
- classNames
252
- }
253
- )
254
- ] }) });
139
+ /**
140
+ * Operator-first range field: a comparison `<select>` (its placeholder
141
+ * option clears the pair), then ONE value input — or a labeled From/To
142
+ * pair for `between`. The persisted state stays the inclusive
143
+ * `<key><start>` / `<key><end>` pair, written through `setExtras`.
144
+ */
145
+ function RangeField({ def, source, classNames, inputType, suffixes, labels }) {
146
+ const lowKey = def.key + suffixes.start;
147
+ const highKey = def.key + suffixes.end;
148
+ const [op, setOp] = useState(() => readRangeWidget(source.extra, lowKey, highKey).op);
149
+ const a = asText(source.extra[op === "lte" ? highKey : lowKey]);
150
+ const b = asText(source.extra[highKey]);
151
+ const write = (nextOp, nextA, nextB) => source.setExtras(writeRangeWidget(nextOp, nextA, nextB, lowKey, highKey));
152
+ const opLabelKeys = RANGE_OP_LABEL_KEYS[inputType];
153
+ return /* @__PURE__ */ jsx(GroupField, {
154
+ caption: filterLabel$1(def),
155
+ classNames,
156
+ children: /* @__PURE__ */ jsxs("div", {
157
+ style: {
158
+ display: "flex",
159
+ flexWrap: "wrap",
160
+ gap: 8
161
+ },
162
+ children: [
163
+ /* @__PURE__ */ jsxs("select", {
164
+ style: {
165
+ flex: "0 0 8.5rem",
166
+ width: "8.5rem"
167
+ },
168
+ "aria-label": labels.operator,
169
+ "data-adapttable-part": "filter-operator",
170
+ className: classNames.filterOperator,
171
+ value: op ?? "",
172
+ onChange: (e) => {
173
+ const next = RANGE_OPS.find((o) => o === e.currentTarget.value);
174
+ setOp(next);
175
+ write(next, a, b);
176
+ },
177
+ children: [/* @__PURE__ */ jsx("option", {
178
+ value: "",
179
+ children: labels.operator
180
+ }), RANGE_OPS.map((o) => /* @__PURE__ */ jsx("option", {
181
+ value: o,
182
+ children: labels[opLabelKeys[o]]
183
+ }, o))]
184
+ }),
185
+ op === "between" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(RangeValueInput, {
186
+ type: inputType,
187
+ label: labels.from,
188
+ value: a,
189
+ onValue: (next) => write(op, next, b),
190
+ classNames
191
+ }), /* @__PURE__ */ jsx(RangeValueInput, {
192
+ type: inputType,
193
+ label: labels.to,
194
+ value: b,
195
+ onValue: (next) => write(op, a, next),
196
+ classNames
197
+ })] }),
198
+ op !== void 0 && op !== "between" && /* @__PURE__ */ jsx(RangeValueInput, {
199
+ type: inputType,
200
+ label: labels.value,
201
+ value: a,
202
+ onValue: (next) => write(op, next, ""),
203
+ classNames
204
+ })
205
+ ]
206
+ })
207
+ });
255
208
  }
256
- function FilterField({
257
- def,
258
- source,
259
- classNames,
260
- labels
261
- }) {
262
- switch (def.type) {
263
- case "text":
264
- return /* @__PURE__ */ jsx(TextField, { def, source, classNames });
265
- case "select":
266
- return /* @__PURE__ */ jsx(SelectField, { def, source, classNames });
267
- case "multiSelect":
268
- return /* @__PURE__ */ jsx(MultiSelectField, { def, source, classNames });
269
- case "dateRange":
270
- return /* @__PURE__ */ jsx(
271
- RangeField,
272
- {
273
- def,
274
- source,
275
- classNames,
276
- inputType: "date",
277
- suffixes: RANGE_SUFFIXES.dateRange,
278
- labels
279
- }
280
- );
281
- case "numberRange":
282
- return /* @__PURE__ */ jsx(
283
- RangeField,
284
- {
285
- def,
286
- source,
287
- classNames,
288
- inputType: "number",
289
- suffixes: RANGE_SUFFIXES.numberRange,
290
- labels
291
- }
292
- );
293
- }
209
+ function FilterField({ def, source, classNames, labels }) {
210
+ switch (def.type) {
211
+ case "text": return /* @__PURE__ */ jsx(TextField, {
212
+ def,
213
+ source,
214
+ classNames
215
+ });
216
+ case "select": return /* @__PURE__ */ jsx(SelectField, {
217
+ def,
218
+ source,
219
+ classNames
220
+ });
221
+ case "multiSelect": return /* @__PURE__ */ jsx(MultiSelectField, {
222
+ def,
223
+ source,
224
+ classNames
225
+ });
226
+ case "dateRange": return /* @__PURE__ */ jsx(RangeField, {
227
+ def,
228
+ source,
229
+ classNames,
230
+ inputType: "date",
231
+ suffixes: RANGE_SUFFIXES.dateRange,
232
+ labels
233
+ });
234
+ case "numberRange": return /* @__PURE__ */ jsx(RangeField, {
235
+ def,
236
+ source,
237
+ classNames,
238
+ inputType: "number",
239
+ suffixes: RANGE_SUFFIXES.numberRange,
240
+ labels
241
+ });
242
+ }
294
243
  }
295
- function AutoFilterForm({
296
- defs,
297
- source,
298
- classNames = {},
299
- labels
300
- }) {
301
- const resolvedLabels = resolveLabels(labels);
302
- return /* @__PURE__ */ jsx(Fragment, { children: defs.map((def) => /* @__PURE__ */ jsx(
303
- FilterField,
304
- {
305
- def,
306
- source,
307
- classNames,
308
- labels: resolvedLabels
309
- },
310
- def.key
311
- )) });
244
+ /**
245
+ * The auto-built filter form for the declarative `filters` array: one
246
+ * semantic field per definition (`text` input, `select` with an "All"
247
+ * option, `multiSelect` checkbox list, operator-first `dateRange` /
248
+ * `numberRange` widgets), each carrying `data-adapttable-part` hooks and
249
+ * `classNames` overrides. Controls read `source.extra` and write through
250
+ * `source.setExtra` / `source.setExtras` — an empty value clears its key.
251
+ *
252
+ * @typeParam TRow - The row type.
253
+ */
254
+ function AutoFilterForm({ defs, source, classNames = {}, labels }) {
255
+ const resolvedLabels = resolveLabels(labels);
256
+ return /* @__PURE__ */ jsx(Fragment, { children: defs.map((def) => /* @__PURE__ */ jsx(FilterField, {
257
+ def,
258
+ source,
259
+ classNames,
260
+ labels: resolvedLabels
261
+ }, def.key)) });
312
262
  }
313
-
314
- // src/cx.ts
263
+ //#endregion
264
+ //#region src/cx.ts
265
+ /**
266
+ * Join class-name parts, dropping falsy values. Tiny `clsx`-style helper
267
+ * so the unstyled adapter has no runtime dependencies.
268
+ *
269
+ * @param parts - Class names or falsy values.
270
+ * @returns The space-joined class string.
271
+ */
315
272
  function cx(...parts) {
316
- return parts.filter(Boolean).join(" ");
273
+ return parts.filter(Boolean).join(" ");
317
274
  }
318
- function FilterPanel({
319
- open,
320
- onClose,
321
- filters,
322
- activeFilterCount,
323
- onClearFilters,
324
- labels,
325
- dir = "ltr",
326
- classNames
327
- }) {
328
- const panelRef = useRef(null);
329
- const onCloseRef = useRef(onClose);
330
- onCloseRef.current = onClose;
331
- useEffect(() => {
332
- if (!open) return;
333
- const trigger = document.activeElement;
334
- panelRef.current?.focus();
335
- const onKeyDown = (event) => {
336
- if (event.key === "Escape") onCloseRef.current();
337
- };
338
- document.addEventListener("keydown", onKeyDown);
339
- return () => {
340
- document.removeEventListener("keydown", onKeyDown);
341
- trigger?.focus?.();
342
- };
343
- }, [open]);
344
- if (!open) return null;
345
- return createPortal(
346
- /* @__PURE__ */ jsxs(Fragment, { children: [
347
- /* @__PURE__ */ jsx(
348
- "button",
349
- {
350
- type: "button",
351
- "aria-label": labels.cancel,
352
- "data-adapttable-part": "filters-backdrop",
353
- className: cx(
354
- "adapttable-filters-backdrop",
355
- classNames.filtersBackdrop
356
- ),
357
- onClick: onClose
358
- }
359
- ),
360
- /* @__PURE__ */ jsxs(
361
- "dialog",
362
- {
363
- ref: panelRef,
364
- open: true,
365
- tabIndex: -1,
366
- "aria-modal": "true",
367
- "aria-label": labels.filters,
368
- "data-adapttable-part": "filters-panel",
369
- dir,
370
- "data-dir": dir,
371
- className: cx("adapttable-filters-panel", classNames.filtersPanel),
372
- style: {
373
- position: "fixed",
374
- insetBlock: 0,
375
- insetInlineEnd: 0,
376
- insetInlineStart: "auto",
377
- margin: 0,
378
- maxHeight: "none",
379
- maxWidth: "none",
380
- height: "100%",
381
- zIndex: 200
382
- },
383
- children: [
384
- /* @__PURE__ */ jsxs(
385
- "header",
386
- {
387
- "data-adapttable-part": "filters-header",
388
- className: classNames.filtersHeader,
389
- children: [
390
- /* @__PURE__ */ jsxs(
391
- "h3",
392
- {
393
- "data-adapttable-part": "filters-title",
394
- className: classNames.filtersTitle,
395
- children: [
396
- labels.filters,
397
- activeFilterCount > 0 ? ` (${activeFilterCount})` : ""
398
- ]
399
- }
400
- ),
401
- /* @__PURE__ */ jsx(
402
- "button",
403
- {
404
- type: "button",
405
- "aria-label": labels.cancel,
406
- "data-adapttable-part": "filters-close",
407
- className: classNames.filtersClose,
408
- onClick: onClose,
409
- children: "\xD7"
410
- }
411
- )
412
- ]
413
- }
414
- ),
415
- /* @__PURE__ */ jsx(
416
- "div",
417
- {
418
- "data-adapttable-part": "filters-body",
419
- className: classNames.filtersBody,
420
- children: filters
421
- }
422
- ),
423
- /* @__PURE__ */ jsxs(
424
- "footer",
425
- {
426
- "data-adapttable-part": "filters-footer",
427
- className: classNames.filtersFooter,
428
- children: [
429
- /* @__PURE__ */ jsx(
430
- "button",
431
- {
432
- type: "button",
433
- onClick: () => onClearFilters?.(),
434
- disabled: activeFilterCount === 0,
435
- "data-adapttable-part": "filters-clear",
436
- className: classNames.filtersClear,
437
- children: labels.clearAll
438
- }
439
- ),
440
- /* @__PURE__ */ jsx(
441
- "button",
442
- {
443
- type: "button",
444
- onClick: onClose,
445
- "data-adapttable-part": "filters-done",
446
- className: classNames.filtersDone,
447
- children: labels.applyFilters
448
- }
449
- )
450
- ]
451
- }
452
- )
453
- ]
454
- }
455
- )
456
- ] }),
457
- document.body
458
- );
275
+ //#endregion
276
+ //#region src/components/FilterPanel.tsx
277
+ /** Backdrop + side drawer for caller-provided filter widgets. */
278
+ function FilterPanel({ open, onClose, filters, activeFilterCount, onClearFilters, labels, dir = "ltr", classNames }) {
279
+ const panelRef = useRef(null);
280
+ const onCloseRef = useRef(onClose);
281
+ onCloseRef.current = onClose;
282
+ useEffect(() => {
283
+ if (!open) return;
284
+ const trigger = document.activeElement;
285
+ panelRef.current?.focus();
286
+ const onKeyDown = (event) => {
287
+ if (event.key === "Escape") onCloseRef.current();
288
+ };
289
+ document.addEventListener("keydown", onKeyDown);
290
+ return () => {
291
+ document.removeEventListener("keydown", onKeyDown);
292
+ trigger?.focus?.();
293
+ };
294
+ }, [open]);
295
+ if (!open) return null;
296
+ return createPortal(/* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
297
+ type: "button",
298
+ "aria-label": labels.cancel,
299
+ "data-adapttable-part": "filters-backdrop",
300
+ className: cx("adapttable-filters-backdrop", classNames.filtersBackdrop),
301
+ onClick: onClose
302
+ }), /* @__PURE__ */ jsxs("dialog", {
303
+ ref: panelRef,
304
+ open: true,
305
+ tabIndex: -1,
306
+ "aria-modal": "true",
307
+ "aria-label": labels.filters,
308
+ "data-adapttable-part": "filters-panel",
309
+ dir,
310
+ "data-dir": dir,
311
+ className: cx("adapttable-filters-panel", classNames.filtersPanel),
312
+ style: {
313
+ position: "fixed",
314
+ insetBlock: 0,
315
+ insetInlineEnd: 0,
316
+ insetInlineStart: "auto",
317
+ margin: 0,
318
+ maxHeight: "none",
319
+ maxWidth: "none",
320
+ height: "100%",
321
+ zIndex: 200
322
+ },
323
+ children: [
324
+ /* @__PURE__ */ jsxs("header", {
325
+ "data-adapttable-part": "filters-header",
326
+ className: classNames.filtersHeader,
327
+ children: [/* @__PURE__ */ jsxs("h3", {
328
+ "data-adapttable-part": "filters-title",
329
+ className: classNames.filtersTitle,
330
+ children: [labels.filters, activeFilterCount > 0 ? ` (${activeFilterCount})` : ""]
331
+ }), /* @__PURE__ */ jsx("button", {
332
+ type: "button",
333
+ "aria-label": labels.cancel,
334
+ "data-adapttable-part": "filters-close",
335
+ className: classNames.filtersClose,
336
+ onClick: onClose,
337
+ children: "×"
338
+ })]
339
+ }),
340
+ /* @__PURE__ */ jsx("div", {
341
+ "data-adapttable-part": "filters-body",
342
+ className: classNames.filtersBody,
343
+ children: filters
344
+ }),
345
+ /* @__PURE__ */ jsxs("footer", {
346
+ "data-adapttable-part": "filters-footer",
347
+ className: classNames.filtersFooter,
348
+ children: [/* @__PURE__ */ jsx("button", {
349
+ type: "button",
350
+ onClick: () => onClearFilters?.(),
351
+ disabled: activeFilterCount === 0,
352
+ "data-adapttable-part": "filters-clear",
353
+ className: classNames.filtersClear,
354
+ children: labels.clearAll
355
+ }), /* @__PURE__ */ jsx("button", {
356
+ type: "button",
357
+ onClick: onClose,
358
+ "data-adapttable-part": "filters-done",
359
+ className: classNames.filtersDone,
360
+ children: labels.applyFilters
361
+ })]
362
+ })
363
+ ]
364
+ })] }), document.body);
459
365
  }
460
- function FilterPopover({
461
- open,
462
- onClose,
463
- filters,
464
- activeFilterCount,
465
- onClearFilters,
466
- labels,
467
- dir = "ltr",
468
- classNames,
469
- children
470
- }) {
471
- const onCloseRef = useRef(onClose);
472
- onCloseRef.current = onClose;
473
- const rootRef = useRef(null);
474
- const cardRef = useRef(null);
475
- useEffect(() => {
476
- if (!open) return;
477
- const onClick = (event) => {
478
- const root = rootRef.current;
479
- if (root.contains(event.target)) return;
480
- if (cardRef.current?.contains(document.activeElement)) return;
481
- onCloseRef.current();
482
- };
483
- const onKeyDown = (event) => {
484
- if (event.key !== "Escape") return;
485
- onCloseRef.current();
486
- rootRef.current?.querySelector("button")?.focus();
487
- };
488
- document.addEventListener("click", onClick);
489
- document.addEventListener("keydown", onKeyDown);
490
- return () => {
491
- document.removeEventListener("click", onClick);
492
- document.removeEventListener("keydown", onKeyDown);
493
- };
494
- }, [open]);
495
- const side = dir === "rtl" ? { left: 0 } : { right: 0 };
496
- return /* @__PURE__ */ jsxs(
497
- "span",
498
- {
499
- ref: rootRef,
500
- "data-adapttable-part": "filters-anchor",
501
- className: cx("adapttable-filters-anchor", classNames.filtersAnchor),
502
- style: { position: "relative", display: "inline-flex" },
503
- children: [
504
- children,
505
- open && /* @__PURE__ */ jsxs(
506
- "div",
507
- {
508
- ref: cardRef,
509
- "data-adapttable-part": "filters-popover",
510
- "data-dir": dir,
511
- className: cx(
512
- "adapttable-filters-popover",
513
- classNames.filtersPopover
514
- ),
515
- style: { position: "absolute", top: "100%", zIndex: 200, ...side },
516
- children: [
517
- /* @__PURE__ */ jsxs(
518
- "header",
519
- {
520
- "data-adapttable-part": "filters-header",
521
- className: classNames.filtersHeader,
522
- children: [
523
- /* @__PURE__ */ jsxs(
524
- "h3",
525
- {
526
- "data-adapttable-part": "filters-title",
527
- className: classNames.filtersTitle,
528
- children: [
529
- labels.filters,
530
- activeFilterCount > 0 ? ` (${activeFilterCount})` : ""
531
- ]
532
- }
533
- ),
534
- /* @__PURE__ */ jsx(
535
- "button",
536
- {
537
- type: "button",
538
- onClick: () => onClearFilters?.(),
539
- disabled: activeFilterCount === 0,
540
- "data-adapttable-part": "filters-clear",
541
- className: classNames.filtersClear,
542
- children: labels.clearAll
543
- }
544
- )
545
- ]
546
- }
547
- ),
548
- /* @__PURE__ */ jsx(
549
- "div",
550
- {
551
- "data-adapttable-part": "filters-body",
552
- className: classNames.filtersBody,
553
- children: filters
554
- }
555
- )
556
- ]
557
- }
558
- )
559
- ]
560
- }
561
- );
366
+ //#endregion
367
+ //#region src/components/FilterPopover.tsx
368
+ /**
369
+ * Anchored filter card (the default filter container). Opens beneath the
370
+ * Filters button with NO backdrop — the background stays visible and
371
+ * interactive; clicking outside the popover/anchor or pressing Escape closes
372
+ * it. This is the plain-DOM mirror of the Mantine reference; pair with
373
+ * `filtersMode="drawer"` for the slide-in panel (`FilterPanel`) instead.
374
+ */
375
+ function FilterPopover({ open, onClose, filters, activeFilterCount, onClearFilters, labels, dir = "ltr", classNames, children }) {
376
+ const onCloseRef = useRef(onClose);
377
+ onCloseRef.current = onClose;
378
+ const rootRef = useRef(null);
379
+ const cardRef = useRef(null);
380
+ useEffect(() => {
381
+ if (!open) return;
382
+ const onClick = (event) => {
383
+ if (rootRef.current.contains(event.target)) return;
384
+ if (cardRef.current?.contains(document.activeElement)) return;
385
+ onCloseRef.current();
386
+ };
387
+ const onKeyDown = (event) => {
388
+ if (event.key !== "Escape") return;
389
+ onCloseRef.current();
390
+ rootRef.current?.querySelector("button")?.focus();
391
+ };
392
+ document.addEventListener("click", onClick);
393
+ document.addEventListener("keydown", onKeyDown);
394
+ return () => {
395
+ document.removeEventListener("click", onClick);
396
+ document.removeEventListener("keydown", onKeyDown);
397
+ };
398
+ }, [open]);
399
+ const side = dir === "rtl" ? { left: 0 } : { right: 0 };
400
+ return /* @__PURE__ */ jsxs("span", {
401
+ ref: rootRef,
402
+ "data-adapttable-part": "filters-anchor",
403
+ className: cx("adapttable-filters-anchor", classNames.filtersAnchor),
404
+ style: {
405
+ position: "relative",
406
+ display: "inline-flex"
407
+ },
408
+ children: [children, open && /* @__PURE__ */ jsxs("div", {
409
+ ref: cardRef,
410
+ "data-adapttable-part": "filters-popover",
411
+ "data-dir": dir,
412
+ className: cx("adapttable-filters-popover", classNames.filtersPopover),
413
+ style: {
414
+ position: "absolute",
415
+ top: "100%",
416
+ zIndex: 200,
417
+ ...side
418
+ },
419
+ children: [/* @__PURE__ */ jsxs("header", {
420
+ "data-adapttable-part": "filters-header",
421
+ className: classNames.filtersHeader,
422
+ children: [/* @__PURE__ */ jsxs("h3", {
423
+ "data-adapttable-part": "filters-title",
424
+ className: classNames.filtersTitle,
425
+ children: [labels.filters, activeFilterCount > 0 ? ` (${activeFilterCount})` : ""]
426
+ }), /* @__PURE__ */ jsx("button", {
427
+ type: "button",
428
+ onClick: () => onClearFilters?.(),
429
+ disabled: activeFilterCount === 0,
430
+ "data-adapttable-part": "filters-clear",
431
+ className: classNames.filtersClear,
432
+ children: labels.clearAll
433
+ })]
434
+ }), /* @__PURE__ */ jsx("div", {
435
+ "data-adapttable-part": "filters-body",
436
+ className: classNames.filtersBody,
437
+ children: filters
438
+ })]
439
+ })]
440
+ });
562
441
  }
563
- function Svg({
564
- size = 16,
565
- className,
566
- children
567
- }) {
568
- return /* @__PURE__ */ jsx(
569
- "svg",
570
- {
571
- width: size,
572
- height: size,
573
- viewBox: "0 0 24 24",
574
- fill: "none",
575
- stroke: "currentColor",
576
- strokeWidth: 2,
577
- strokeLinecap: "round",
578
- strokeLinejoin: "round",
579
- className,
580
- "aria-hidden": "true",
581
- focusable: "false",
582
- children
583
- }
584
- );
442
+ //#endregion
443
+ //#region src/components/icons.tsx
444
+ function Svg({ size = 16, className, children }) {
445
+ return /* @__PURE__ */ jsx("svg", {
446
+ width: size,
447
+ height: size,
448
+ viewBox: "0 0 24 24",
449
+ fill: "none",
450
+ stroke: "currentColor",
451
+ strokeWidth: 2,
452
+ strokeLinecap: "round",
453
+ strokeLinejoin: "round",
454
+ className,
455
+ "aria-hidden": "true",
456
+ focusable: "false",
457
+ children
458
+ });
585
459
  }
586
- var SearchIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
587
- /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
588
- /* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })
589
- ] });
590
- var FiltersIcon = (p) => /* @__PURE__ */ jsx(Svg, { ...p, children: /* @__PURE__ */ jsx("path", { d: "M3 4h18l-7 8v6l-4 2v-8L3 4Z" }) });
591
- var ChevronIcon = (p) => /* @__PURE__ */ jsx(Svg, { ...p, children: /* @__PURE__ */ jsx("path", { d: "m9 6 6 6-6 6" }) });
592
- var MENU_PANEL_STYLE = {
593
- position: "absolute",
594
- zIndex: 200,
595
- insetInlineEnd: 0,
596
- margin: 0,
597
- border: 0,
598
- padding: 0,
599
- minInlineSize: 0
460
+ /** Magnifying-glass search glyph (inline SVG, `currentColor`). */
461
+ const SearchIcon = (p) => /* @__PURE__ */ jsxs(Svg, {
462
+ ...p,
463
+ children: [/* @__PURE__ */ jsx("circle", {
464
+ cx: "11",
465
+ cy: "11",
466
+ r: "7"
467
+ }), /* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })]
468
+ });
469
+ /** Funnel glyph for the Filters button (inline SVG, `currentColor`). */
470
+ const FiltersIcon = (p) => /* @__PURE__ */ jsx(Svg, {
471
+ ...p,
472
+ children: /* @__PURE__ */ jsx("path", { d: "M3 4h18l-7 8v6l-4 2v-8L3 4Z" })
473
+ });
474
+ /**
475
+ * Right-pointing chevron (▸) for the expand-row button. The button carries a
476
+ * `data-expanded` attribute so consumers rotate the glyph with their own CSS
477
+ * (e.g. `[data-expanded] svg { transform: rotate(90deg) }`).
478
+ */
479
+ const ChevronIcon = (p) => /* @__PURE__ */ jsx(Svg, {
480
+ ...p,
481
+ children: /* @__PURE__ */ jsx("path", { d: "m9 6 6 6-6 6" })
482
+ });
483
+ //#endregion
484
+ //#region src/components/menuPopover.ts
485
+ /**
486
+ * Inline style for an absolutely-positioned toolbar menu panel. The extra
487
+ * `margin`/`border`/`padding`/`minInlineSize` zeros neutralise `<fieldset>`
488
+ * defaults so the same style works for any panel element.
489
+ */
490
+ const MENU_PANEL_STYLE = {
491
+ position: "absolute",
492
+ zIndex: 200,
493
+ insetInlineEnd: 0,
494
+ margin: 0,
495
+ border: 0,
496
+ padding: 0,
497
+ minInlineSize: 0
600
498
  };
499
+ /**
500
+ * Disclosure behaviour for the toolbar menus (ColumnMenu, SavedViewsMenu):
501
+ * open/close state that also closes on outside mousedown or Escape, with
502
+ * Escape restoring focus to the trigger.
503
+ */
601
504
  function useMenuPopover() {
602
- const [open, setOpen] = useState(false);
603
- const rootRef = useRef(null);
604
- const triggerRef = useRef(null);
605
- useEffect(() => {
606
- if (!open) return;
607
- const onDown = (event) => {
608
- if (!rootRef.current?.contains(event.target)) setOpen(false);
609
- };
610
- const onKey = (event) => {
611
- if (event.key !== "Escape") return;
612
- setOpen(false);
613
- triggerRef.current?.focus();
614
- };
615
- document.addEventListener("mousedown", onDown);
616
- document.addEventListener("keydown", onKey);
617
- return () => {
618
- document.removeEventListener("mousedown", onDown);
619
- document.removeEventListener("keydown", onKey);
620
- };
621
- }, [open]);
622
- return { open, setOpen, rootRef, triggerRef };
505
+ const [open, setOpen] = useState(false);
506
+ const rootRef = useRef(null);
507
+ const triggerRef = useRef(null);
508
+ useEffect(() => {
509
+ if (!open) return;
510
+ const onDown = (event) => {
511
+ if (!rootRef.current?.contains(event.target)) setOpen(false);
512
+ };
513
+ const onKey = (event) => {
514
+ if (event.key !== "Escape") return;
515
+ setOpen(false);
516
+ triggerRef.current?.focus();
517
+ };
518
+ document.addEventListener("mousedown", onDown);
519
+ document.addEventListener("keydown", onKey);
520
+ return () => {
521
+ document.removeEventListener("mousedown", onDown);
522
+ document.removeEventListener("keydown", onKey);
523
+ };
524
+ }, [open]);
525
+ return {
526
+ open,
527
+ setOpen,
528
+ rootRef,
529
+ triggerRef
530
+ };
623
531
  }
624
- function SavedViewsMenu({
625
- options,
626
- labels,
627
- classNames
628
- }) {
629
- const { views, save, apply, remove } = useSavedViews(options);
630
- const { open, setOpen, rootRef, triggerRef } = useMenuPopover();
631
- const [name, setName] = useState("");
632
- const trimmed = name.trim();
633
- return /* @__PURE__ */ jsxs(
634
- "div",
635
- {
636
- ref: rootRef,
637
- "data-adapttable-part": "views-menu",
638
- style: { position: "relative" },
639
- children: [
640
- /* @__PURE__ */ jsx(
641
- "button",
642
- {
643
- ref: triggerRef,
644
- type: "button",
645
- "aria-expanded": open,
646
- "aria-haspopup": "true",
647
- "data-adapttable-part": "views-button",
648
- "data-active": open || void 0,
649
- className: classNames.viewsButton,
650
- style: { flexShrink: 0, whiteSpace: "nowrap" },
651
- onClick: () => setOpen((v) => !v),
652
- children: labels.savedViews
653
- }
654
- ),
655
- open && /* @__PURE__ */ jsxs(
656
- "div",
657
- {
658
- "data-adapttable-part": "views-panel",
659
- className: classNames.viewsPanel,
660
- style: MENU_PANEL_STYLE,
661
- children: [
662
- views.map((view) => /* @__PURE__ */ jsxs(
663
- "div",
664
- {
665
- style: { display: "flex", alignItems: "center" },
666
- children: [
667
- /* @__PURE__ */ jsx(
668
- "button",
669
- {
670
- type: "button",
671
- "data-adapttable-part": "views-item",
672
- className: classNames.viewsItem,
673
- onClick: () => {
674
- apply(view.name);
675
- setOpen(false);
676
- },
677
- children: view.name
678
- }
679
- ),
680
- /* @__PURE__ */ jsx(
681
- "button",
682
- {
683
- type: "button",
684
- "aria-label": `${labels.deleteView}: ${view.name}`,
685
- "data-adapttable-part": "views-delete",
686
- className: classNames.viewsDelete,
687
- onClick: () => remove(view.name),
688
- children: "\xD7"
689
- }
690
- )
691
- ]
692
- },
693
- view.name
694
- )),
695
- /* @__PURE__ */ jsx("hr", { "data-adapttable-part": "views-divider" }),
696
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
697
- /* @__PURE__ */ jsx(
698
- "input",
699
- {
700
- "aria-label": labels.viewName,
701
- placeholder: labels.viewName,
702
- "data-adapttable-part": "views-input",
703
- className: classNames.viewsInput,
704
- value: name,
705
- onChange: (e) => setName(e.currentTarget.value)
706
- }
707
- ),
708
- /* @__PURE__ */ jsx(
709
- "button",
710
- {
711
- type: "button",
712
- disabled: trimmed === "",
713
- "data-adapttable-part": "views-save",
714
- className: classNames.viewsSave,
715
- onClick: () => {
716
- save(trimmed);
717
- setName("");
718
- },
719
- children: labels.saveView
720
- }
721
- )
722
- ] })
723
- ]
724
- }
725
- )
726
- ]
727
- }
728
- );
532
+ //#endregion
533
+ //#region src/components/SavedViewsMenu.tsx
534
+ /**
535
+ * Saved-views popover: a disclosure button + a panel listing the saved views
536
+ * (click applies one; each has a delete button) above a save row that
537
+ * captures the table's CURRENT state under a typed name. Built on core's
538
+ * `useSavedViews`; closes on outside-click or Escape. Ships no styles —
539
+ * target the `data-adapttable-part` hooks or the `views*` className slots.
540
+ */
541
+ function SavedViewsMenu({ options, labels, classNames }) {
542
+ const { views, save, apply, remove } = useSavedViews$1(options);
543
+ const { open, setOpen, rootRef, triggerRef } = useMenuPopover();
544
+ const [name, setName] = useState("");
545
+ const trimmed = name.trim();
546
+ return /* @__PURE__ */ jsxs("div", {
547
+ ref: rootRef,
548
+ "data-adapttable-part": "views-menu",
549
+ style: { position: "relative" },
550
+ children: [/* @__PURE__ */ jsx("button", {
551
+ ref: triggerRef,
552
+ type: "button",
553
+ "aria-expanded": open,
554
+ "aria-haspopup": "true",
555
+ "data-adapttable-part": "views-button",
556
+ "data-active": open || void 0,
557
+ className: classNames.viewsButton,
558
+ style: {
559
+ flexShrink: 0,
560
+ whiteSpace: "nowrap"
561
+ },
562
+ onClick: () => setOpen((v) => !v),
563
+ children: labels.savedViews
564
+ }), open && /* @__PURE__ */ jsxs("div", {
565
+ "data-adapttable-part": "views-panel",
566
+ className: classNames.viewsPanel,
567
+ style: MENU_PANEL_STYLE,
568
+ children: [
569
+ views.map((view) => /* @__PURE__ */ jsxs("div", {
570
+ style: {
571
+ display: "flex",
572
+ alignItems: "center"
573
+ },
574
+ children: [/* @__PURE__ */ jsx("button", {
575
+ type: "button",
576
+ "data-adapttable-part": "views-item",
577
+ className: classNames.viewsItem,
578
+ onClick: () => {
579
+ apply(view.name);
580
+ setOpen(false);
581
+ },
582
+ children: view.name
583
+ }), /* @__PURE__ */ jsx("button", {
584
+ type: "button",
585
+ "aria-label": `${labels.deleteView}: ${view.name}`,
586
+ "data-adapttable-part": "views-delete",
587
+ className: classNames.viewsDelete,
588
+ onClick: () => remove(view.name),
589
+ children: "×"
590
+ })]
591
+ }, view.name)),
592
+ /* @__PURE__ */ jsx("hr", { "data-adapttable-part": "views-divider" }),
593
+ /* @__PURE__ */ jsxs("div", {
594
+ style: {
595
+ display: "flex",
596
+ alignItems: "center"
597
+ },
598
+ children: [/* @__PURE__ */ jsx("input", {
599
+ "aria-label": labels.viewName,
600
+ placeholder: labels.viewName,
601
+ "data-adapttable-part": "views-input",
602
+ className: classNames.viewsInput,
603
+ value: name,
604
+ onChange: (e) => setName(e.currentTarget.value)
605
+ }), /* @__PURE__ */ jsx("button", {
606
+ type: "button",
607
+ disabled: trimmed === "",
608
+ "data-adapttable-part": "views-save",
609
+ className: classNames.viewsSave,
610
+ onClick: () => {
611
+ save(trimmed);
612
+ setName("");
613
+ },
614
+ children: labels.saveView
615
+ })]
616
+ })
617
+ ]
618
+ })]
619
+ });
729
620
  }
730
- function Chips({
731
- chips,
732
- onClearAll,
733
- labels,
734
- classNames
735
- }) {
736
- if (chips.length === 0) return null;
737
- return /* @__PURE__ */ jsxs(
738
- "ul",
739
- {
740
- "aria-label": labels.filters,
741
- "data-adapttable-part": "chips",
742
- className: classNames.chips,
743
- children: [
744
- chips.map((chip) => /* @__PURE__ */ jsxs(
745
- "li",
746
- {
747
- "data-adapttable-part": "chip",
748
- className: classNames.chip,
749
- children: [
750
- chip.label,
751
- /* @__PURE__ */ jsx(
752
- "button",
753
- {
754
- type: "button",
755
- "aria-label": `${labels.clearAll}: ${chip.label}`,
756
- "data-adapttable-part": "chip-remove",
757
- className: classNames.chipRemove,
758
- onClick: chip.onRemove,
759
- children: "\xD7"
760
- }
761
- )
762
- ]
763
- },
764
- chip.key
765
- )),
766
- /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
767
- "button",
768
- {
769
- type: "button",
770
- onClick: onClearAll,
771
- className: classNames.chipRemove,
772
- children: labels.clearAll
773
- }
774
- ) })
775
- ]
776
- }
777
- );
621
+ //#endregion
622
+ //#region src/components/chrome.tsx
623
+ /** Removable filter-chip strip. Renders nothing when empty. */
624
+ function Chips({ chips, onClearAll, labels, classNames }) {
625
+ if (chips.length === 0) return null;
626
+ return /* @__PURE__ */ jsxs("ul", {
627
+ "aria-label": labels.filters,
628
+ "data-adapttable-part": "chips",
629
+ className: classNames.chips,
630
+ children: [chips.map((chip) => /* @__PURE__ */ jsxs("li", {
631
+ "data-adapttable-part": "chip",
632
+ className: classNames.chip,
633
+ children: [chip.label, /* @__PURE__ */ jsx("button", {
634
+ type: "button",
635
+ "aria-label": `${labels.clearAll}: ${chip.label}`,
636
+ "data-adapttable-part": "chip-remove",
637
+ className: classNames.chipRemove,
638
+ onClick: chip.onRemove,
639
+ children: "×"
640
+ })]
641
+ }, chip.key)), /* @__PURE__ */ jsx("li", {
642
+ "data-adapttable-part": "chip",
643
+ className: classNames.chip,
644
+ children: /* @__PURE__ */ jsx("button", {
645
+ type: "button",
646
+ "data-adapttable-part": "chip-remove",
647
+ className: classNames.chipRemove,
648
+ onClick: onClearAll,
649
+ children: labels.clearAll
650
+ })
651
+ })]
652
+ });
778
653
  }
779
- function BulkBar({
780
- selection,
781
- total,
782
- bulkActions,
783
- confirm,
784
- labels,
785
- classNames
786
- }) {
787
- const {
788
- selectedIds,
789
- selectedCount,
790
- clear,
791
- headerState,
792
- visibleIds,
793
- allMatching,
794
- selectAllMatching
795
- } = selection;
796
- const { pending, run } = useBulkActionRunner({
797
- confirm,
798
- cancelLabel: labels.cancel,
799
- onComplete: clear
800
- });
801
- if (selectedCount === 0) return null;
802
- const ids = [...selectedIds];
803
- const showBanner = headerState === "all" && total > visibleIds.length;
804
- const scope = allMatching ? { allMatching: true, total } : void 0;
805
- return /* @__PURE__ */ jsxs("div", { "data-adapttable-part": "bulk-bar", className: classNames.bulkBar, children: [
806
- /* @__PURE__ */ jsx("span", { children: labels.selectedCount(selectedCount) }),
807
- showBanner && /* @__PURE__ */ jsxs(
808
- "div",
809
- {
810
- "data-adapttable-part": "select-all-banner",
811
- className: classNames.selectAllBanner,
812
- children: [
813
- /* @__PURE__ */ jsx(
814
- "span",
815
- {
816
- "data-adapttable-part": "select-all-text",
817
- className: classNames.selectAllText,
818
- children: allMatching ? labels.allMatchingSelected(total) : labels.pageSelected(visibleIds.length)
819
- }
820
- ),
821
- /* @__PURE__ */ jsx(
822
- "button",
823
- {
824
- type: "button",
825
- "data-adapttable-part": "select-all-button",
826
- className: classNames.selectAllButton,
827
- onClick: allMatching ? clear : selectAllMatching,
828
- children: allMatching ? labels.clearAll : labels.selectAllMatching(total)
829
- }
830
- )
831
- ]
832
- }
833
- ),
834
- /* @__PURE__ */ jsx("button", { type: "button", onClick: clear, disabled: pending !== null, children: labels.clearAll }),
835
- bulkActions.map((action) => {
836
- const reason = resolveDisabledReason(action.disabledReason?.(ids));
837
- return /* @__PURE__ */ jsxs(
838
- "button",
839
- {
840
- type: "button",
841
- title: reason,
842
- disabled: reason !== void 0 || pending !== null,
843
- "data-adapttable-part": "bulk-button",
844
- "data-color": action.color,
845
- className: classNames.bulkButton,
846
- onClick: () => run(action, ids, scope),
847
- children: [
848
- action.icon,
849
- action.label
850
- ]
851
- },
852
- action.key
853
- );
854
- })
855
- ] });
654
+ /** Selection toolbar with bulk-action buttons. */
655
+ function BulkBar({ selection, total, bulkActions, confirm, labels, classNames }) {
656
+ const { selectedIds, selectedCount, clear, headerState, visibleIds, allMatching, selectAllMatching } = selection;
657
+ const { pending, run } = useBulkActionRunner({
658
+ confirm,
659
+ cancelLabel: labels.cancel,
660
+ onComplete: clear
661
+ });
662
+ if (selectedCount === 0) return null;
663
+ const ids = [...selectedIds];
664
+ const showBanner = headerState === "all" && total > visibleIds.length;
665
+ const scope = allMatching ? {
666
+ allMatching: true,
667
+ total
668
+ } : void 0;
669
+ return /* @__PURE__ */ jsxs("div", {
670
+ "data-adapttable-part": "bulk-bar",
671
+ className: classNames.bulkBar,
672
+ children: [
673
+ /* @__PURE__ */ jsx("span", { children: labels.selectedCount(selectedCount) }),
674
+ showBanner && /* @__PURE__ */ jsxs("div", {
675
+ "data-adapttable-part": "select-all-banner",
676
+ className: classNames.selectAllBanner,
677
+ children: [/* @__PURE__ */ jsx("span", {
678
+ "data-adapttable-part": "select-all-text",
679
+ className: classNames.selectAllText,
680
+ children: allMatching ? labels.allMatchingSelected(total) : labels.pageSelected(visibleIds.length)
681
+ }), /* @__PURE__ */ jsx("button", {
682
+ type: "button",
683
+ "data-adapttable-part": "select-all-button",
684
+ className: classNames.selectAllButton,
685
+ onClick: allMatching ? clear : selectAllMatching,
686
+ children: allMatching ? labels.clearAll : labels.selectAllMatching(total)
687
+ })]
688
+ }),
689
+ /* @__PURE__ */ jsx("button", {
690
+ type: "button",
691
+ onClick: clear,
692
+ disabled: pending !== null,
693
+ children: labels.clearAll
694
+ }),
695
+ bulkActions.map((action) => {
696
+ const reason = resolveDisabledReason(action.disabledReason?.(ids));
697
+ return /* @__PURE__ */ jsxs("button", {
698
+ type: "button",
699
+ title: reason,
700
+ disabled: reason !== void 0 || pending !== null,
701
+ "data-adapttable-part": "bulk-button",
702
+ "data-color": action.color,
703
+ className: classNames.bulkButton,
704
+ onClick: () => run(action, ids, scope),
705
+ children: [action.icon, action.label]
706
+ }, action.key);
707
+ })
708
+ ]
709
+ });
856
710
  }
857
- function RowsPerPageSelect({
858
- source,
859
- labels,
860
- classNames
861
- }) {
862
- return /* @__PURE__ */ jsxs("label", { children: [
863
- labels.rowsPerPage,
864
- " ",
865
- /* @__PURE__ */ jsx(
866
- "select",
867
- {
868
- "aria-label": labels.rowsPerPage,
869
- "data-adapttable-part": "rows-per-page",
870
- className: classNames.rowsPerPageSelect,
871
- value: source.limit,
872
- onChange: (e) => source.setLimit(Number(e.currentTarget.value)),
873
- children: pageSizeOptions(source.limit).map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n))
874
- }
875
- )
876
- ] });
711
+ /** The rows-per-page selector shared by the toolbar (infinite) and footer. */
712
+ function RowsPerPageSelect({ source, labels, classNames }) {
713
+ return /* @__PURE__ */ jsxs("label", { children: [
714
+ labels.rowsPerPage,
715
+ " ",
716
+ /* @__PURE__ */ jsx("select", {
717
+ "aria-label": labels.rowsPerPage,
718
+ "data-adapttable-part": "rows-per-page",
719
+ className: classNames.rowsPerPageSelect,
720
+ value: source.limit,
721
+ onChange: (e) => source.setLimit(Number(e.currentTarget.value)),
722
+ children: pageSizeOptions(source.limit).map((n) => /* @__PURE__ */ jsx("option", {
723
+ value: n,
724
+ children: n
725
+ }, n))
726
+ })
727
+ ] });
877
728
  }
878
- function Footer({
879
- pagination,
880
- source,
881
- labels,
882
- classNames
883
- }) {
884
- const { safePage, totalPages, fromIndex, toIndex } = pagination;
885
- return /* @__PURE__ */ jsxs("div", { "data-adapttable-part": "footer", className: classNames.footer, children: [
886
- /* @__PURE__ */ jsx(
887
- RowsPerPageSelect,
888
- {
889
- source,
890
- labels,
891
- classNames
892
- }
893
- ),
894
- source.total > 0 && /* @__PURE__ */ jsx("span", { children: labels.showing({
895
- from: fromIndex,
896
- to: toIndex,
897
- total: source.total
898
- }) }),
899
- /* @__PURE__ */ jsx("span", { children: labels.pageOf({ page: safePage, total: totalPages }) }),
900
- /* @__PURE__ */ jsx(
901
- "button",
902
- {
903
- type: "button",
904
- "aria-label": labels.previousPage,
905
- "data-adapttable-part": "page-prev",
906
- className: classNames.pageButton,
907
- disabled: safePage <= 1,
908
- onClick: () => source.setPage(safePage - 1),
909
- children: "\u2039"
910
- }
911
- ),
912
- /* @__PURE__ */ jsx(
913
- "button",
914
- {
915
- type: "button",
916
- "aria-label": labels.nextPage,
917
- "data-adapttable-part": "page-next",
918
- className: classNames.pageButton,
919
- disabled: safePage >= totalPages,
920
- onClick: () => source.setPage(safePage + 1),
921
- children: "\u203A"
922
- }
923
- )
924
- ] });
729
+ /** Prev/next pager with a rows-per-page select. */
730
+ function Footer({ pagination, source, labels, classNames }) {
731
+ const { safePage, totalPages, fromIndex, toIndex } = pagination;
732
+ return /* @__PURE__ */ jsxs("div", {
733
+ "data-adapttable-part": "footer",
734
+ className: classNames.footer,
735
+ children: [
736
+ /* @__PURE__ */ jsx(RowsPerPageSelect, {
737
+ source,
738
+ labels,
739
+ classNames
740
+ }),
741
+ source.total > 0 && /* @__PURE__ */ jsx("span", { children: labels.showing({
742
+ from: fromIndex,
743
+ to: toIndex,
744
+ total: source.total
745
+ }) }),
746
+ /* @__PURE__ */ jsx("span", { children: labels.pageOf({
747
+ page: safePage,
748
+ total: totalPages
749
+ }) }),
750
+ /* @__PURE__ */ jsx("button", {
751
+ type: "button",
752
+ "aria-label": labels.previousPage,
753
+ "data-adapttable-part": "page-prev",
754
+ className: classNames.pageButton,
755
+ disabled: safePage <= 1,
756
+ onClick: () => source.setPage(safePage - 1),
757
+ children: "‹"
758
+ }),
759
+ /* @__PURE__ */ jsx("button", {
760
+ type: "button",
761
+ "aria-label": labels.nextPage,
762
+ "data-adapttable-part": "page-next",
763
+ className: classNames.pageButton,
764
+ disabled: safePage >= totalPages,
765
+ onClick: () => source.setPage(safePage + 1),
766
+ children: ""
767
+ })
768
+ ]
769
+ });
925
770
  }
926
- function ErrorState({
927
- error,
928
- labels,
929
- onRetry,
930
- classNames
931
- }) {
932
- return /* @__PURE__ */ jsxs("div", { role: "alert", "data-adapttable-part": "error", className: classNames.error, children: [
933
- /* @__PURE__ */ jsx("strong", { children: labels.errorTitle }),
934
- /* @__PURE__ */ jsx("p", { children: labels.errorMessage }),
935
- /* @__PURE__ */ jsx("small", { children: error.message }),
936
- onRetry && /* @__PURE__ */ jsx(
937
- "button",
938
- {
939
- type: "button",
940
- onClick: onRetry,
941
- "data-adapttable-part": "retry",
942
- className: classNames.retryButton,
943
- children: labels.retry
944
- }
945
- )
946
- ] });
771
+ /** Inline error with optional retry. */
772
+ function ErrorState({ error, labels, onRetry, classNames }) {
773
+ return /* @__PURE__ */ jsxs("div", {
774
+ role: "alert",
775
+ "data-adapttable-part": "error",
776
+ className: classNames.error,
777
+ children: [
778
+ /* @__PURE__ */ jsx("strong", { children: labels.errorTitle }),
779
+ /* @__PURE__ */ jsx("p", { children: labels.errorMessage }),
780
+ /* @__PURE__ */ jsx("small", { children: error.message }),
781
+ onRetry && /* @__PURE__ */ jsx("button", {
782
+ type: "button",
783
+ onClick: onRetry,
784
+ "data-adapttable-part": "retry",
785
+ className: classNames.retryButton,
786
+ children: labels.retry
787
+ })
788
+ ]
789
+ });
947
790
  }
948
791
  function loadingLineWidth(column, total) {
949
- if (column === 0) return "70%";
950
- if (column === total - 1) return "42%";
951
- return "55%";
792
+ if (column === 0) return "70%";
793
+ if (column === total - 1) return "42%";
794
+ return "55%";
952
795
  }
953
- function LoadingState({
954
- rows,
955
- columns,
956
- variant,
957
- labels,
958
- classNames,
959
- hasActions = false
960
- }) {
961
- const rowKeys = Array.from({ length: rows }, (_, i) => i);
962
- const dataColumns = Math.max(columns, 1);
963
- const columnCount = dataColumns + (hasActions ? 1 : 0);
964
- const columnKeys = Array.from({ length: columnCount }, (_, i) => i);
965
- return /* @__PURE__ */ jsxs(
966
- "div",
967
- {
968
- role: "status",
969
- "aria-busy": "true",
970
- "aria-live": "polite",
971
- "data-adapttable-part": "loading",
972
- className: cx(classNames.loading),
973
- children: [
974
- variant === "table" ? /* @__PURE__ */ jsxs("table", { "data-adapttable-part": "loading-table", children: [
975
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { "data-adapttable-part": "loading-header-row", children: columnKeys.map((column) => /* @__PURE__ */ jsx("th", { "data-adapttable-part": "loading-header-cell", children: /* @__PURE__ */ jsx(
976
- "span",
977
- {
978
- "data-adapttable-part": "loading-line",
979
- style: { width: loadingLineWidth(column, columnCount) }
980
- }
981
- ) }, column)) }) }),
982
- /* @__PURE__ */ jsx("tbody", { children: rowKeys.map((row) => /* @__PURE__ */ jsx("tr", { "data-adapttable-part": "loading-row", children: columnKeys.map((column) => /* @__PURE__ */ jsx("td", { "data-adapttable-part": "loading-cell", children: /* @__PURE__ */ jsx(
983
- "span",
984
- {
985
- "data-adapttable-part": "loading-line",
986
- style: {
987
- width: loadingLineWidth(column, columnCount)
988
- }
989
- }
990
- ) }, column)) }, row)) })
991
- ] }) : /* @__PURE__ */ jsx("div", { "data-adapttable-part": "loading-cards", children: rowKeys.map((row) => /* @__PURE__ */ jsx("div", { "data-adapttable-part": "loading-card", children: columnKeys.slice(0, Math.min(4, columnKeys.length)).map((column) => /* @__PURE__ */ jsx(
992
- "span",
993
- {
994
- "data-adapttable-part": "loading-line",
995
- style: {
996
- width: loadingLineWidth(column, columnKeys.length)
997
- }
998
- },
999
- column
1000
- )) }, row)) }),
1001
- /* @__PURE__ */ jsx("span", { className: "adapttable-sr-only", children: labels.loading })
1002
- ]
1003
- }
1004
- );
796
+ /** Skeleton-ish loading placeholder (semantic, unstyled). */
797
+ function LoadingState({ rows, columns, variant, labels, classNames, hasActions = false }) {
798
+ const rowKeys = Array.from({ length: rows }, (_, i) => i);
799
+ const columnCount = Math.max(columns, 1) + (hasActions ? 1 : 0);
800
+ const columnKeys = Array.from({ length: columnCount }, (_, i) => i);
801
+ return /* @__PURE__ */ jsxs("div", {
802
+ role: "status",
803
+ "aria-busy": "true",
804
+ "aria-live": "polite",
805
+ "data-adapttable-part": "loading",
806
+ className: cx(classNames.loading),
807
+ children: [variant === "table" ? /* @__PURE__ */ jsxs("table", {
808
+ "data-adapttable-part": "loading-table",
809
+ children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", {
810
+ "data-adapttable-part": "loading-header-row",
811
+ children: columnKeys.map((column) => /* @__PURE__ */ jsx("th", {
812
+ "data-adapttable-part": "loading-header-cell",
813
+ children: /* @__PURE__ */ jsx("span", {
814
+ "data-adapttable-part": "loading-line",
815
+ style: { width: loadingLineWidth(column, columnCount) }
816
+ })
817
+ }, column))
818
+ }) }), /* @__PURE__ */ jsx("tbody", { children: rowKeys.map((row) => /* @__PURE__ */ jsx("tr", {
819
+ "data-adapttable-part": "loading-row",
820
+ children: columnKeys.map((column) => /* @__PURE__ */ jsx("td", {
821
+ "data-adapttable-part": "loading-cell",
822
+ children: /* @__PURE__ */ jsx("span", {
823
+ "data-adapttable-part": "loading-line",
824
+ style: { width: loadingLineWidth(column, columnCount) }
825
+ })
826
+ }, column))
827
+ }, row)) })]
828
+ }) : /* @__PURE__ */ jsx("div", {
829
+ "data-adapttable-part": "loading-cards",
830
+ children: rowKeys.map((row) => /* @__PURE__ */ jsx("div", {
831
+ "data-adapttable-part": "loading-card",
832
+ children: columnKeys.slice(0, Math.min(4, columnKeys.length)).map((column) => /* @__PURE__ */ jsx("span", {
833
+ "data-adapttable-part": "loading-line",
834
+ style: { width: loadingLineWidth(column, columnKeys.length) }
835
+ }, column))
836
+ }, row))
837
+ }), /* @__PURE__ */ jsx("span", {
838
+ className: "adapttable-sr-only",
839
+ children: labels.loading
840
+ })]
841
+ });
1005
842
  }
1006
- function VisibilityToggle({
1007
- hidden,
1008
- name,
1009
- labels,
1010
- classNames,
1011
- onToggle
1012
- }) {
1013
- return /* @__PURE__ */ jsx(
1014
- "button",
1015
- {
1016
- type: "button",
1017
- "data-adapttable-part": "column-menu-visibility",
1018
- "data-active": !hidden || void 0,
1019
- "aria-pressed": !hidden,
1020
- "aria-label": `${hidden ? labels.showColumn : labels.hideColumn}: ${name}`,
1021
- className: classNames.columnMenuVisibility,
1022
- onClick: onToggle,
1023
- children: /* @__PURE__ */ jsx(EyeIcon, { off: hidden })
1024
- }
1025
- );
843
+ //#endregion
844
+ //#region src/components/ColumnMenu.tsx
845
+ /** The eye toggle shared by data-column rows and the actions row. */
846
+ function VisibilityToggle({ hidden, name, labels, classNames, onToggle }) {
847
+ return /* @__PURE__ */ jsx("button", {
848
+ type: "button",
849
+ "data-adapttable-part": "column-menu-visibility",
850
+ "data-active": !hidden || void 0,
851
+ "aria-pressed": !hidden,
852
+ "aria-label": `${hidden ? labels.showColumn : labels.hideColumn}: ${name}`,
853
+ className: classNames.columnMenuVisibility,
854
+ onClick: onToggle,
855
+ children: /* @__PURE__ */ jsx(EyeIcon, { off: hidden })
856
+ });
1026
857
  }
1027
- function RowName({
1028
- hidden,
1029
- name,
1030
- classNames
1031
- }) {
1032
- return /* @__PURE__ */ jsx(
1033
- "span",
1034
- {
1035
- "data-adapttable-part": "column-menu-label",
1036
- "data-hidden": hidden || void 0,
1037
- className: classNames.columnMenuLabel,
1038
- children: name
1039
- }
1040
- );
858
+ /** The row's name caption, shared by data-column rows and the actions row. */
859
+ function RowName({ hidden, name, classNames }) {
860
+ return /* @__PURE__ */ jsx("span", {
861
+ "data-adapttable-part": "column-menu-label",
862
+ "data-hidden": hidden || void 0,
863
+ className: classNames.columnMenuLabel,
864
+ children: name
865
+ });
1041
866
  }
1042
- function PinToggle({
1043
- active,
1044
- actionLabel,
1045
- classNames,
1046
- onClick
1047
- }) {
1048
- return /* @__PURE__ */ jsx(
1049
- "button",
1050
- {
1051
- type: "button",
1052
- "data-adapttable-part": "column-menu-pin",
1053
- "data-active": active || void 0,
1054
- "aria-pressed": active,
1055
- "aria-label": actionLabel,
1056
- className: classNames.columnMenuPin,
1057
- onClick,
1058
- children: /* @__PURE__ */ jsx(PinIcon, {})
1059
- }
1060
- );
867
+ /** The pin toggle shared by data-column rows and the actions row. */
868
+ function PinToggle({ active, actionLabel, classNames, onClick }) {
869
+ return /* @__PURE__ */ jsx("button", {
870
+ type: "button",
871
+ "data-adapttable-part": "column-menu-pin",
872
+ "data-active": active || void 0,
873
+ "aria-pressed": active,
874
+ "aria-label": actionLabel,
875
+ className: classNames.columnMenuPin,
876
+ onClick,
877
+ children: /* @__PURE__ */ jsx(PinIcon, {})
878
+ });
1061
879
  }
1062
- function ColumnMenuRowItem({
1063
- row,
1064
- layout,
1065
- labels,
1066
- classNames,
1067
- drag
1068
- }) {
1069
- const { key, name, hidden, pinned, index } = row;
1070
- return /* @__PURE__ */ jsxs(
1071
- "div",
1072
- {
1073
- "data-adapttable-part": "column-menu-item",
1074
- "data-hidden": hidden || void 0,
1075
- "data-pinned": pinned,
1076
- className: classNames.columnMenuItem,
1077
- style: { cursor: "grab" },
1078
- ...drag.rowDragProps(key, index),
1079
- ...drag.dropProps(index, layout.move),
1080
- ...drag.rowAttrs(key, index),
1081
- children: [
1082
- /* @__PURE__ */ jsx(
1083
- "span",
1084
- {
1085
- "data-adapttable-part": "column-menu-grip",
1086
- className: classNames.columnMenuGrip,
1087
- ...columnReorderKeyProps(
1088
- key,
1089
- index,
1090
- layout.move,
1091
- `${labels.moveLeft} / ${labels.moveRight}: ${name}`
1092
- ),
1093
- children: /* @__PURE__ */ jsx(GripIcon, {})
1094
- }
1095
- ),
1096
- /* @__PURE__ */ jsx(
1097
- VisibilityToggle,
1098
- {
1099
- hidden,
1100
- name,
1101
- labels,
1102
- classNames,
1103
- onToggle: () => layout.toggleVisible(key)
1104
- }
1105
- ),
1106
- /* @__PURE__ */ jsx(RowName, { hidden, name, classNames }),
1107
- /* @__PURE__ */ jsx(
1108
- PinToggle,
1109
- {
1110
- active: pinned !== void 0,
1111
- actionLabel: `${pinActionLabel(pinned, labels)}: ${name}`,
1112
- classNames,
1113
- onClick: () => layout.setPinned(key, nextPinSide(pinned))
1114
- }
1115
- )
1116
- ]
1117
- }
1118
- );
880
+ function ColumnMenuRowItem({ row, layout, labels, classNames, drag }) {
881
+ const { key, name, hidden, pinned, index } = row;
882
+ return /* @__PURE__ */ jsxs("div", {
883
+ "data-adapttable-part": "column-menu-item",
884
+ "data-hidden": hidden || void 0,
885
+ "data-pinned": pinned,
886
+ className: classNames.columnMenuItem,
887
+ style: { cursor: "grab" },
888
+ ...drag.rowDragProps(key, index),
889
+ ...drag.dropProps(index, layout.move),
890
+ ...drag.rowAttrs(key, index),
891
+ children: [
892
+ /* @__PURE__ */ jsx("span", {
893
+ "data-adapttable-part": "column-menu-grip",
894
+ className: classNames.columnMenuGrip,
895
+ ...columnReorderKeyProps(key, index, layout.move, `${labels.moveLeft} / ${labels.moveRight}: ${name}`),
896
+ children: /* @__PURE__ */ jsx(GripIcon, {})
897
+ }),
898
+ /* @__PURE__ */ jsx(VisibilityToggle, {
899
+ hidden,
900
+ name,
901
+ labels,
902
+ classNames,
903
+ onToggle: () => layout.toggleVisible(key)
904
+ }),
905
+ /* @__PURE__ */ jsx(RowName, {
906
+ hidden,
907
+ name,
908
+ classNames
909
+ }),
910
+ /* @__PURE__ */ jsx(PinToggle, {
911
+ active: pinned !== void 0,
912
+ actionLabel: `${pinActionLabel(pinned, labels)}: ${name}`,
913
+ classNames,
914
+ onClick: () => layout.setPinned(key, nextPinSide(pinned))
915
+ })
916
+ ]
917
+ });
1119
918
  }
1120
- function ActionsMenuRowItem({
1121
- layout,
1122
- labels,
1123
- classNames
1124
- }) {
1125
- const hidden = layout.isHidden(ACTIONS_COLUMN_KEY);
1126
- const pinned = layout.state.pinned[ACTIONS_COLUMN_KEY] !== void 0;
1127
- const name = labels.actions;
1128
- return /* @__PURE__ */ jsxs(
1129
- "div",
1130
- {
1131
- "data-adapttable-part": "column-menu-item",
1132
- "data-actions": "",
1133
- "data-hidden": hidden || void 0,
1134
- "data-pinned": pinned ? "right" : void 0,
1135
- className: classNames.columnMenuItem,
1136
- children: [
1137
- /* @__PURE__ */ jsx(
1138
- VisibilityToggle,
1139
- {
1140
- hidden,
1141
- name,
1142
- labels,
1143
- classNames,
1144
- onToggle: () => layout.toggleVisible(ACTIONS_COLUMN_KEY)
1145
- }
1146
- ),
1147
- /* @__PURE__ */ jsx(RowName, { hidden, name, classNames }),
1148
- /* @__PURE__ */ jsx(
1149
- PinToggle,
1150
- {
1151
- active: pinned,
1152
- actionLabel: `${pinned ? labels.unpin : labels.pinRight}: ${name}`,
1153
- classNames,
1154
- onClick: () => layout.setPinned(ACTIONS_COLUMN_KEY, pinned ? void 0 : "right")
1155
- }
1156
- )
1157
- ]
1158
- }
1159
- );
919
+ /**
920
+ * The injected row-actions column as a first-class menu row: the same eye
921
+ * toggle as a data column plus a ONE-CLICK end-pin toggle (right ↔ unpinned).
922
+ * The column always trails, so there is no left pin and no reorder grip.
923
+ */
924
+ function ActionsMenuRowItem({ layout, labels, classNames }) {
925
+ const hidden = layout.isHidden(ACTIONS_COLUMN_KEY);
926
+ const pinned = layout.state.pinned[ACTIONS_COLUMN_KEY] !== void 0;
927
+ const name = labels.actions;
928
+ return /* @__PURE__ */ jsxs("div", {
929
+ "data-adapttable-part": "column-menu-item",
930
+ "data-actions": "",
931
+ "data-hidden": hidden || void 0,
932
+ "data-pinned": pinned ? "right" : void 0,
933
+ className: classNames.columnMenuItem,
934
+ children: [
935
+ /* @__PURE__ */ jsx(VisibilityToggle, {
936
+ hidden,
937
+ name,
938
+ labels,
939
+ classNames,
940
+ onToggle: () => layout.toggleVisible(ACTIONS_COLUMN_KEY)
941
+ }),
942
+ /* @__PURE__ */ jsx(RowName, {
943
+ hidden,
944
+ name,
945
+ classNames
946
+ }),
947
+ /* @__PURE__ */ jsx(PinToggle, {
948
+ active: pinned,
949
+ actionLabel: `${pinned ? labels.unpin : labels.pinRight}: ${name}`,
950
+ classNames,
951
+ onClick: () => layout.setPinned(ACTIONS_COLUMN_KEY, pinned ? void 0 : "right")
952
+ })
953
+ ]
954
+ });
1160
955
  }
1161
- function ColumnMenu({
1162
- allColumns,
1163
- layout,
1164
- labels,
1165
- classNames,
1166
- hasRowActions
1167
- }) {
1168
- const drag = useColumnDragState();
1169
- const { open, setOpen, rootRef, triggerRef } = useMenuPopover();
1170
- return /* @__PURE__ */ jsxs(
1171
- "div",
1172
- {
1173
- ref: rootRef,
1174
- "data-adapttable-part": "column-menu",
1175
- className: classNames.columnMenu,
1176
- style: { position: "relative" },
1177
- children: [
1178
- /* @__PURE__ */ jsx(
1179
- "button",
1180
- {
1181
- ref: triggerRef,
1182
- type: "button",
1183
- "aria-expanded": open,
1184
- "aria-haspopup": "true",
1185
- "data-adapttable-part": "column-menu-button",
1186
- "data-active": open || void 0,
1187
- className: classNames.columnMenuButton,
1188
- style: { flexShrink: 0, whiteSpace: "nowrap" },
1189
- onClick: () => setOpen((v) => !v),
1190
- children: labels.columns
1191
- }
1192
- ),
1193
- open && /* @__PURE__ */ jsxs(
1194
- "fieldset",
1195
- {
1196
- "aria-label": labels.columns,
1197
- "data-adapttable-part": "column-menu-panel",
1198
- className: classNames.columnMenuPanel,
1199
- style: MENU_PANEL_STYLE,
1200
- children: [
1201
- /* @__PURE__ */ jsx(
1202
- "div",
1203
- {
1204
- "data-adapttable-part": "column-menu-header",
1205
- className: classNames.columnMenuHeader,
1206
- children: /* @__PURE__ */ jsx(
1207
- "span",
1208
- {
1209
- "data-adapttable-part": "column-menu-title",
1210
- className: classNames.columnMenuTitle,
1211
- children: labels.columns
1212
- }
1213
- )
1214
- }
1215
- ),
1216
- columnMenuRows(allColumns, layout).map((row) => /* @__PURE__ */ jsx(
1217
- ColumnMenuRowItem,
1218
- {
1219
- row,
1220
- layout,
1221
- labels,
1222
- classNames,
1223
- drag
1224
- },
1225
- row.key
1226
- )),
1227
- hasRowActions && /* @__PURE__ */ jsxs(Fragment, { children: [
1228
- /* @__PURE__ */ jsx(
1229
- "hr",
1230
- {
1231
- "data-adapttable-part": "column-menu-separator",
1232
- className: classNames.columnMenuSeparator
1233
- }
1234
- ),
1235
- /* @__PURE__ */ jsx(
1236
- ActionsMenuRowItem,
1237
- {
1238
- layout,
1239
- labels,
1240
- classNames
1241
- }
1242
- )
1243
- ] }),
1244
- /* @__PURE__ */ jsx(
1245
- "button",
1246
- {
1247
- type: "button",
1248
- "data-adapttable-part": "column-menu-reset",
1249
- className: cx(classNames.columnMenuReset),
1250
- onClick: () => layout.reset(),
1251
- children: labels.resetColumns
1252
- }
1253
- )
1254
- ]
1255
- }
1256
- )
1257
- ]
1258
- }
1259
- );
956
+ /**
957
+ * Column-management popover: a disclosure button + a panel where each column
958
+ * has a drag grip (reorder), an eye toggle (show/hide), and a pin toggle.
959
+ * Closes on outside-click or Escape. Ships no styles — target the
960
+ * `data-adapttable-part` hooks or the `columnMenu*` className slots.
961
+ */
962
+ function ColumnMenu({ allColumns, layout, labels, classNames, hasRowActions }) {
963
+ const drag = useColumnDragState();
964
+ const { open, setOpen, rootRef, triggerRef } = useMenuPopover();
965
+ return /* @__PURE__ */ jsxs("div", {
966
+ ref: rootRef,
967
+ "data-adapttable-part": "column-menu",
968
+ className: classNames.columnMenu,
969
+ style: { position: "relative" },
970
+ children: [/* @__PURE__ */ jsx("button", {
971
+ ref: triggerRef,
972
+ type: "button",
973
+ "aria-expanded": open,
974
+ "aria-haspopup": "true",
975
+ "data-adapttable-part": "column-menu-button",
976
+ "data-active": open || void 0,
977
+ className: classNames.columnMenuButton,
978
+ style: {
979
+ flexShrink: 0,
980
+ whiteSpace: "nowrap"
981
+ },
982
+ onClick: () => setOpen((v) => !v),
983
+ children: labels.columns
984
+ }), open && /* @__PURE__ */ jsxs("fieldset", {
985
+ "aria-label": labels.columns,
986
+ "data-adapttable-part": "column-menu-panel",
987
+ className: classNames.columnMenuPanel,
988
+ style: MENU_PANEL_STYLE,
989
+ children: [
990
+ /* @__PURE__ */ jsx("div", {
991
+ "data-adapttable-part": "column-menu-header",
992
+ className: classNames.columnMenuHeader,
993
+ children: /* @__PURE__ */ jsx("span", {
994
+ "data-adapttable-part": "column-menu-title",
995
+ className: classNames.columnMenuTitle,
996
+ children: labels.columns
997
+ })
998
+ }),
999
+ columnMenuRows(allColumns, layout).map((row) => /* @__PURE__ */ jsx(ColumnMenuRowItem, {
1000
+ row,
1001
+ layout,
1002
+ labels,
1003
+ classNames,
1004
+ drag
1005
+ }, row.key)),
1006
+ hasRowActions && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("hr", {
1007
+ "data-adapttable-part": "column-menu-separator",
1008
+ className: classNames.columnMenuSeparator
1009
+ }), /* @__PURE__ */ jsx(ActionsMenuRowItem, {
1010
+ layout,
1011
+ labels,
1012
+ classNames
1013
+ })] }),
1014
+ /* @__PURE__ */ jsx("button", {
1015
+ type: "button",
1016
+ "data-adapttable-part": "column-menu-reset",
1017
+ className: cx(classNames.columnMenuReset),
1018
+ onClick: () => layout.reset(),
1019
+ children: labels.resetColumns
1020
+ })
1021
+ ]
1022
+ })]
1023
+ });
1260
1024
  }
1261
- var RESIZE_HANDLE_STYLE = {
1262
- position: "absolute",
1263
- insetInlineEnd: 0,
1264
- top: 0,
1265
- height: "100%",
1266
- width: 8,
1267
- cursor: "col-resize",
1268
- touchAction: "none",
1269
- userSelect: "none"
1025
+ //#endregion
1026
+ //#region src/components/tables.tsx
1027
+ /** Inline style for an absolutely-positioned column-resize handle. */
1028
+ const RESIZE_HANDLE_STYLE = {
1029
+ position: "absolute",
1030
+ insetInlineEnd: 0,
1031
+ top: 0,
1032
+ height: "100%",
1033
+ width: 8,
1034
+ cursor: "col-resize",
1035
+ touchAction: "none",
1036
+ userSelect: "none"
1270
1037
  };
1271
- var SELECTION_WIDTH = 44;
1272
- var ACTIONS_WIDTH = 120;
1038
+ const SELECTION_WIDTH = 44;
1039
+ const ACTIONS_WIDTH = 120;
1040
+ /**
1041
+ * Scroll-box style: a `maxHeight`-bounded box scrolls on both axes; otherwise
1042
+ * the wrapper scrolls sideways only when something needs it (a pinned column,
1043
+ * or measured horizontal overflow). When the table fits, the wrapper carries
1044
+ * NO overflow style — `overflow-x: auto` makes `overflow-y` compute to `auto`
1045
+ * too, which would trap a page-scroll sticky header inside the box.
1046
+ */
1273
1047
  function scrollBoxStyle(maxHeight, scrollX) {
1274
- if (maxHeight != null) {
1275
- return { maxHeight, overflowX: "auto", overflowY: "auto" };
1276
- }
1277
- return scrollX ? { overflowX: "auto" } : void 0;
1048
+ if (maxHeight != null) return {
1049
+ maxHeight,
1050
+ overflowX: "auto",
1051
+ overflowY: "auto"
1052
+ };
1053
+ return scrollX ? { overflowX: "auto" } : void 0;
1278
1054
  }
1279
- function RowActionButtons({
1280
- row,
1281
- actions,
1282
- confirm,
1283
- cancelLabel,
1284
- classNames
1285
- }) {
1286
- return /* @__PURE__ */ jsx(Fragment, { children: actions.map((action) => {
1287
- if (action.isHidden?.(row)) return null;
1288
- const reason = resolveDisabledReason(action.disabledReason?.(row));
1289
- const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
1290
- const handleClick = disabled ? void 0 : (e) => {
1291
- e.stopPropagation();
1292
- runRowAction(action, row, confirm, cancelLabel);
1293
- };
1294
- return /* @__PURE__ */ jsx(
1295
- "button",
1296
- {
1297
- type: "button",
1298
- disabled,
1299
- title: reason,
1300
- "aria-label": action.label,
1301
- "data-adapttable-part": "action-button",
1302
- "data-color": action.color,
1303
- className: classNames.actionButton,
1304
- onClick: handleClick,
1305
- children: action.icon ?? action.label
1306
- },
1307
- action.key
1308
- );
1309
- }) });
1055
+ function RowActionButtons({ row, actions, confirm, cancelLabel, classNames }) {
1056
+ return /* @__PURE__ */ jsx(Fragment, { children: actions.map((action) => {
1057
+ if (action.isHidden?.(row)) return null;
1058
+ const reason = resolveDisabledReason(action.disabledReason?.(row));
1059
+ const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
1060
+ const handleClick = disabled ? void 0 : (e) => {
1061
+ e.stopPropagation();
1062
+ runRowAction(action, row, confirm, cancelLabel);
1063
+ };
1064
+ return /* @__PURE__ */ jsx("button", {
1065
+ type: "button",
1066
+ disabled,
1067
+ title: reason,
1068
+ "aria-label": action.label,
1069
+ "data-adapttable-part": "action-button",
1070
+ "data-color": action.color,
1071
+ className: classNames.actionButton,
1072
+ onClick: handleClick,
1073
+ children: action.icon ?? action.label
1074
+ }, action.key);
1075
+ }) });
1310
1076
  }
1311
- function ExpandButton({
1312
- expanded,
1313
- labels,
1314
- classNames,
1315
- onToggle
1316
- }) {
1317
- return /* @__PURE__ */ jsx(
1318
- "button",
1319
- {
1320
- type: "button",
1321
- "data-adapttable-part": "expand-button",
1322
- "data-expanded": expanded ? "" : void 0,
1323
- className: classNames.expandButton,
1324
- "aria-expanded": expanded,
1325
- "aria-label": expanded ? labels.collapseRow : labels.expandRow,
1326
- onClick: onToggle,
1327
- children: /* @__PURE__ */ jsx(ChevronIcon, { size: 14 })
1328
- }
1329
- );
1077
+ /**
1078
+ * The expand/collapse chevron, shared by desktop rows and mobile cards. The
1079
+ * `data-expanded` attribute is the styling hook for rotating the glyph
1080
+ * (`rowClickProps`' interactive-child guard keeps the click off the row).
1081
+ */
1082
+ function ExpandButton({ expanded, labels, classNames, onToggle }) {
1083
+ return /* @__PURE__ */ jsx("button", {
1084
+ type: "button",
1085
+ "data-adapttable-part": "expand-button",
1086
+ "data-expanded": expanded ? "" : void 0,
1087
+ className: classNames.expandButton,
1088
+ "aria-expanded": expanded,
1089
+ "aria-label": expanded ? labels.collapseRow : labels.expandRow,
1090
+ onClick: onToggle,
1091
+ children: /* @__PURE__ */ jsx(ChevronIcon, { size: 14 })
1092
+ });
1330
1093
  }
1094
+ /**
1095
+ * `React.memo` comparator: re-render a row only when one of its VISUAL
1096
+ * inputs changes. A search keystroke or another row's checkbox re-renders
1097
+ * the table shell, but every unchanged row bails out here (accessors and
1098
+ * Cell render-props are not re-invoked).
1099
+ */
1331
1100
  function desktopRowPropsEqual(prev, next) {
1332
- return prev.row === next.row && prev.index === next.index && prev.id === next.id && prev.selected === next.selected && prev.expanded === next.expanded && prev.columns === next.columns && prev.labels === next.labels && prev.classNames === next.classNames && prev.showActions === next.showActions && prev.rowActions === next.rowActions && prev.columnSpan === next.columnSpan && prev.columnWidths === next.columnWidths && prev.pinSignature === next.pinSignature && prev.hasLeftPin === next.hasLeftPin && prev.hasRightPin === next.hasRightPin && prev.actionsPinned === next.actionsPinned && prev.rowClass === next.rowClass && prev.clickable === next.clickable && prev.hasPrefetch === next.hasPrefetch;
1101
+ return prev.row === next.row && prev.index === next.index && prev.id === next.id && prev.selected === next.selected && prev.expanded === next.expanded && prev.columns === next.columns && prev.labels === next.labels && prev.classNames === next.classNames && prev.showActions === next.showActions && prev.rowActions === next.rowActions && prev.columnSpan === next.columnSpan && prev.columnWidths === next.columnWidths && prev.pinSignature === next.pinSignature && prev.hasLeftPin === next.hasLeftPin && prev.hasRightPin === next.hasRightPin && prev.actionsPinned === next.actionsPinned && prev.rowClass === next.rowClass && prev.clickable === next.clickable && prev.hasPrefetch === next.hasPrefetch;
1333
1102
  }
1334
1103
  function DesktopRowBase(props) {
1335
- const {
1336
- row,
1337
- index,
1338
- id,
1339
- table,
1340
- columns,
1341
- labels,
1342
- classNames,
1343
- selected,
1344
- expanded,
1345
- showActions,
1346
- rowActions,
1347
- confirm,
1348
- columnSpan,
1349
- pinOffset,
1350
- hasLeftPin,
1351
- hasRightPin,
1352
- actionsPinned,
1353
- rowClass,
1354
- clickable,
1355
- hasPrefetch,
1356
- onRowClick,
1357
- onPrefetch,
1358
- onToggleSelect,
1359
- onToggleExpand,
1360
- renderDetail,
1361
- measureElement
1362
- } = props;
1363
- const expandable = expanded !== void 0;
1364
- const leads = {
1365
- left: selected === void 0 ? 0 : SELECTION_WIDTH,
1366
- right: showActions ? ACTIONS_WIDTH : 0
1367
- };
1368
- const bodyPinStyle = (key) => pinnedCellStyle(pinOffset?.(key), PIN_Z.body, leads);
1369
- const rowProps = { ...table.getRowProps(row, index) };
1370
- delete rowProps.key;
1371
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1372
- /* @__PURE__ */ jsxs(
1373
- "tr",
1374
- {
1375
- ...rowProps,
1376
- ...rowClickProps(row, clickable ? onRowClick : void 0),
1377
- ref: measureElement,
1378
- "data-adapttable-part": "row",
1379
- "data-selected": selected ? "" : void 0,
1380
- "data-clickable": clickable ? "" : void 0,
1381
- className: cx(classNames.row, rowClass),
1382
- onMouseEnter: hasPrefetch ? () => onPrefetch(row) : void 0,
1383
- children: [
1384
- expandable && /* @__PURE__ */ jsx(
1385
- "td",
1386
- {
1387
- "data-adapttable-part": "expand-cell",
1388
- className: classNames.expandCell,
1389
- children: /* @__PURE__ */ jsx(
1390
- ExpandButton,
1391
- {
1392
- expanded,
1393
- labels,
1394
- classNames,
1395
- onToggle: () => onToggleExpand(id)
1396
- }
1397
- )
1398
- }
1399
- ),
1400
- selected !== void 0 && /* @__PURE__ */ jsx(
1401
- "td",
1402
- {
1403
- "data-adapttable-part": "selection-cell",
1404
- "data-pinned": hasLeftPin ? "left" : void 0,
1405
- style: edgePinStyle("left", hasLeftPin, PIN_Z.body),
1406
- className: cx(classNames.cell, classNames.selectionCell),
1407
- children: /* @__PURE__ */ jsx(
1408
- "input",
1409
- {
1410
- type: "checkbox",
1411
- "aria-label": labels.selectRow,
1412
- checked: selected,
1413
- onChange: () => onToggleSelect(id),
1414
- className: classNames.checkbox
1415
- }
1416
- )
1417
- }
1418
- ),
1419
- columns.map((column) => {
1420
- const pinStyle = bodyPinStyle(column.key);
1421
- return /* @__PURE__ */ jsx(
1422
- "td",
1423
- {
1424
- ...table.getCellProps(column, pinStyle && { style: pinStyle }),
1425
- "data-adapttable-part": "cell",
1426
- "data-pinned": pinOffset?.(column.key)?.side,
1427
- className: classNames.cell,
1428
- children: column.Cell ? /* @__PURE__ */ jsx(column.Cell, { row, rowIndex: index }) : column.accessor?.(row)
1429
- },
1430
- column.key
1431
- );
1432
- }),
1433
- showActions && /* @__PURE__ */ jsx(
1434
- "td",
1435
- {
1436
- "data-adapttable-part": "actions-cell",
1437
- "data-pinned": hasRightPin || actionsPinned ? "right" : void 0,
1438
- style: edgePinStyle(
1439
- "right",
1440
- hasRightPin || actionsPinned,
1441
- PIN_Z.body
1442
- ),
1443
- className: cx(classNames.cell, classNames.actionsCell),
1444
- children: /* @__PURE__ */ jsx(
1445
- RowActionButtons,
1446
- {
1447
- row,
1448
- actions: rowActions,
1449
- confirm,
1450
- cancelLabel: labels.cancel,
1451
- classNames
1452
- }
1453
- )
1454
- }
1455
- )
1456
- ]
1457
- }
1458
- ),
1459
- expandable && expanded && /* @__PURE__ */ jsx("tr", { "data-adapttable-part": "detail-row", className: classNames.detailRow, children: /* @__PURE__ */ jsx(
1460
- "td",
1461
- {
1462
- colSpan: columnSpan,
1463
- "data-adapttable-part": "detail-cell",
1464
- className: classNames.detailCell,
1465
- children: renderDetail(row)
1466
- }
1467
- ) })
1468
- ] });
1104
+ const { row, index, id, table, columns, labels, classNames, selected, expanded, showActions, rowActions, confirm, columnSpan, pinOffset, hasLeftPin, hasRightPin, actionsPinned, rowClass, clickable, hasPrefetch, onRowClick, onPrefetch, onToggleSelect, onToggleExpand, renderDetail, measureElement } = props;
1105
+ const expandable = expanded !== void 0;
1106
+ const leads = {
1107
+ left: selected === void 0 ? 0 : SELECTION_WIDTH,
1108
+ right: showActions ? ACTIONS_WIDTH : 0
1109
+ };
1110
+ const bodyPinStyle = (key) => pinnedCellStyle(pinOffset?.(key), PIN_Z.body, leads);
1111
+ const rowProps = { ...table.getRowProps(row, index) };
1112
+ delete rowProps.key;
1113
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("tr", {
1114
+ ...rowProps,
1115
+ ...rowClickProps(row, clickable ? onRowClick : void 0),
1116
+ ref: measureElement,
1117
+ "data-adapttable-part": "row",
1118
+ "data-selected": selected ? "" : void 0,
1119
+ "data-clickable": clickable ? "" : void 0,
1120
+ className: cx(classNames.row, rowClass),
1121
+ onMouseEnter: hasPrefetch ? () => onPrefetch(row) : void 0,
1122
+ children: [
1123
+ expandable && /* @__PURE__ */ jsx("td", {
1124
+ "data-adapttable-part": "expand-cell",
1125
+ className: classNames.expandCell,
1126
+ children: /* @__PURE__ */ jsx(ExpandButton, {
1127
+ expanded,
1128
+ labels,
1129
+ classNames,
1130
+ onToggle: () => onToggleExpand(id)
1131
+ })
1132
+ }),
1133
+ selected !== void 0 && /* @__PURE__ */ jsx("td", {
1134
+ "data-adapttable-part": "selection-cell",
1135
+ "data-pinned": hasLeftPin ? "left" : void 0,
1136
+ style: edgePinStyle("left", hasLeftPin, PIN_Z.body),
1137
+ className: cx(classNames.cell, classNames.selectionCell),
1138
+ children: /* @__PURE__ */ jsx("input", {
1139
+ type: "checkbox",
1140
+ "aria-label": labels.selectRow,
1141
+ checked: selected,
1142
+ onChange: () => onToggleSelect(id),
1143
+ className: classNames.checkbox
1144
+ })
1145
+ }),
1146
+ columns.map((column) => {
1147
+ const pinStyle = bodyPinStyle(column.key);
1148
+ return /* @__PURE__ */ jsx("td", {
1149
+ ...table.getCellProps(column, pinStyle && { style: pinStyle }),
1150
+ "data-adapttable-part": "cell",
1151
+ "data-pinned": pinOffset?.(column.key)?.side,
1152
+ className: classNames.cell,
1153
+ children: column.Cell ? /* @__PURE__ */ jsx(column.Cell, {
1154
+ row,
1155
+ rowIndex: index
1156
+ }) : column.accessor?.(row)
1157
+ }, column.key);
1158
+ }),
1159
+ showActions && /* @__PURE__ */ jsx("td", {
1160
+ "data-adapttable-part": "actions-cell",
1161
+ "data-pinned": hasRightPin || actionsPinned ? "right" : void 0,
1162
+ style: edgePinStyle("right", hasRightPin || actionsPinned, PIN_Z.body),
1163
+ className: cx(classNames.cell, classNames.actionsCell),
1164
+ children: /* @__PURE__ */ jsx(RowActionButtons, {
1165
+ row,
1166
+ actions: rowActions,
1167
+ confirm,
1168
+ cancelLabel: labels.cancel,
1169
+ classNames
1170
+ })
1171
+ })
1172
+ ]
1173
+ }), expandable && expanded && /* @__PURE__ */ jsx("tr", {
1174
+ "data-adapttable-part": "detail-row",
1175
+ className: classNames.detailRow,
1176
+ children: /* @__PURE__ */ jsx("td", {
1177
+ colSpan: columnSpan,
1178
+ "data-adapttable-part": "detail-cell",
1179
+ className: classNames.detailCell,
1180
+ children: renderDetail(row)
1181
+ })
1182
+ })] });
1469
1183
  }
1184
+ /**
1185
+ * One memoized row component per `DesktopTable` instantiation. A factory
1186
+ * (called once through `useMemo`) instead of a module-level `memo(...)`
1187
+ * because `React.memo` erases a generic component's type parameter — the
1188
+ * factory keeps `TRow` without a type cast.
1189
+ */
1470
1190
  function createDesktopRow() {
1471
- return memo(DesktopRowBase, desktopRowPropsEqual);
1191
+ return memo(DesktopRowBase, desktopRowPropsEqual);
1472
1192
  }
1473
- function DesktopTable({
1474
- table,
1475
- rows,
1476
- rowActions,
1477
- confirm,
1478
- getRowId,
1479
- classNames,
1480
- prefetch,
1481
- onRowClick,
1482
- rowClassName,
1483
- renderRowDetail,
1484
- summaryRow,
1485
- expansion,
1486
- rowEntries,
1487
- paddingTop = 0,
1488
- paddingBottom = 0,
1489
- measureElement,
1490
- stickyHeader = false,
1491
- stickyTop = 0,
1492
- pinOffset,
1493
- maxHeight,
1494
- virtualScrollRef,
1495
- setWidth,
1496
- columnWidths,
1497
- resizeLabel = "Resize column",
1498
- actionsPinned = false
1499
- }) {
1500
- const { columns, selection, labels, showActions, entries, columnSpan } = tableRenderModel({
1501
- table,
1502
- rows,
1503
- rowActions,
1504
- getRowId,
1505
- rowEntries,
1506
- renderRowDetail,
1507
- expansion
1508
- });
1509
- const stickActions = showActions && actionsPinned;
1510
- const expansionState = renderRowDetail ? expansion : void 0;
1511
- const expandable = expansionState !== void 0;
1512
- const live = useRef({
1513
- selection,
1514
- expansion: expansionState,
1515
- onRowClick,
1516
- prefetch,
1517
- renderRowDetail
1518
- });
1519
- live.current = {
1520
- selection,
1521
- expansion: expansionState,
1522
- onRowClick,
1523
- prefetch,
1524
- renderRowDetail
1525
- };
1526
- const onToggleSelect = useCallback(
1527
- (id) => live.current.selection?.toggle(id),
1528
- []
1529
- );
1530
- const onToggleExpand = useCallback(
1531
- (id) => live.current.expansion?.toggle(id),
1532
- []
1533
- );
1534
- const handleRowClick = useCallback(
1535
- (row) => live.current.onRowClick?.(row),
1536
- []
1537
- );
1538
- const handlePrefetch = useCallback(
1539
- (row) => live.current.prefetch?.(row),
1540
- []
1541
- );
1542
- const renderDetail = useCallback(
1543
- (row) => live.current.renderRowDetail?.(row),
1544
- []
1545
- );
1546
- const Row = useMemo(() => createDesktopRow(), []);
1547
- const { ref: overflowRef, overflowing } = useHorizontalOverflow();
1548
- const hasPinned = columns.some((c) => pinOffset?.(c.key) != null) || stickActions;
1549
- const inScrollBox = maxHeight != null || hasPinned || overflowing;
1550
- const stickyStyle = stickyHeader ? {
1551
- position: "sticky",
1552
- top: inScrollBox ? 0 : stickyTop,
1553
- zIndex: PIN_Z.header
1554
- } : void 0;
1555
- const stickyAttr = stickyHeader || void 0;
1556
- const leads = {
1557
- left: selection ? SELECTION_WIDTH : 0,
1558
- right: showActions ? ACTIONS_WIDTH : 0
1559
- };
1560
- const hasLeftPin = columns.some((c) => pinOffset?.(c.key)?.side === "left");
1561
- const hasRightPin = columns.some((c) => pinOffset?.(c.key)?.side === "right");
1562
- const pinSignature = columns.map((c) => {
1563
- const pin = pinOffset?.(c.key);
1564
- return pin ? `${c.key}:${pin.side}:${pin.inset}` : "";
1565
- }).join("|");
1566
- const headPinStyle = (key) => pinnedCellStyle(pinOffset?.(key), PIN_Z.headerPinned, leads);
1567
- const headStyle = (column) => {
1568
- const key = column.key;
1569
- const pin = headPinStyle(key);
1570
- const width = pin ? pinnedColumnWidth(column, columnWidths) : columnWidths?.[key];
1571
- if (!stickyStyle && !pin && width == null && !setWidth) return void 0;
1572
- const merged = {
1573
- ...stickyStyle,
1574
- ...pin,
1575
- ...width != null && { width }
1576
- };
1577
- if (setWidth && !merged.position) merged.position = "relative";
1578
- return merged;
1579
- };
1580
- const edgeHeadStyle = (side, active) => {
1581
- const edge = edgePinStyle(side, active, PIN_Z.headerPinned);
1582
- if (!stickyStyle && !edge) return void 0;
1583
- return { ...stickyStyle, ...edge };
1584
- };
1585
- const columnName = (column) => typeof column.header === "string" ? column.header : column.key;
1586
- const minWidth = tableMinWidth(columns, {
1587
- widths: columnWidths,
1588
- extra: (selection ? SELECTION_WIDTH : 0) + (showActions ? ACTIONS_WIDTH : 0)
1589
- });
1590
- const groups = headerGroupRow(columns);
1591
- const summary = summaryRow?.(rows);
1592
- const groupPad = /* @__PURE__ */ jsx("th", { "data-adapttable-part": "group-cell", className: classNames.groupCell });
1593
- const summaryPad = /* @__PURE__ */ jsx(
1594
- "td",
1595
- {
1596
- "data-adapttable-part": "summary-cell",
1597
- className: classNames.summaryCell
1598
- }
1599
- );
1600
- const tableEl = /* @__PURE__ */ jsxs(
1601
- "table",
1602
- {
1603
- ...table.getTableProps(),
1604
- "data-adapttable-part": "table",
1605
- className: classNames.table,
1606
- style: minWidth > 0 ? { minWidth } : void 0,
1607
- children: [
1608
- /* @__PURE__ */ jsxs("thead", { "data-adapttable-part": "thead", className: classNames.thead, children: [
1609
- groups && /* @__PURE__ */ jsxs("tr", { "data-adapttable-part": "group-row", className: classNames.groupRow, children: [
1610
- expandable && groupPad,
1611
- selection && groupPad,
1612
- groups.map((group) => /* @__PURE__ */ jsx(
1613
- "th",
1614
- {
1615
- colSpan: group.span,
1616
- "data-adapttable-part": "group-cell",
1617
- className: classNames.groupCell,
1618
- children: group.label
1619
- },
1620
- group.key
1621
- )),
1622
- showActions && groupPad
1623
- ] }),
1624
- /* @__PURE__ */ jsxs(
1625
- "tr",
1626
- {
1627
- ...table.getHeaderRowProps(),
1628
- "data-adapttable-part": "header-row",
1629
- className: classNames.headerRow,
1630
- children: [
1631
- expandable && /* @__PURE__ */ jsx(
1632
- "th",
1633
- {
1634
- "aria-label": labels.expandRow,
1635
- "data-adapttable-part": "expand-header",
1636
- "data-sticky": stickyAttr,
1637
- style: stickyStyle,
1638
- className: cx(classNames.headerCell, classNames.expandHeader)
1639
- }
1640
- ),
1641
- selection && /* @__PURE__ */ jsx(
1642
- "th",
1643
- {
1644
- "data-adapttable-part": "selection-header",
1645
- "data-sticky": stickyAttr,
1646
- "data-pinned": hasLeftPin ? "left" : void 0,
1647
- style: edgeHeadStyle("left", hasLeftPin),
1648
- className: cx(classNames.headerCell, classNames.selectionCell),
1649
- children: /* @__PURE__ */ jsx(
1650
- "input",
1651
- {
1652
- type: "checkbox",
1653
- "aria-label": labels.selectAll,
1654
- checked: selection.headerState === "all",
1655
- ref: (el) => {
1656
- if (el) el.indeterminate = selection.headerState === "some";
1657
- },
1658
- onChange: selection.toggleAll,
1659
- className: classNames.checkbox
1660
- }
1661
- )
1662
- }
1663
- ),
1664
- columns.map((column) => {
1665
- const localStyle = headStyle(column);
1666
- const headerProps = table.getHeaderCellProps(
1667
- column,
1668
- localStyle && { style: localStyle }
1669
- );
1670
- const active = table.sortBy === column.key;
1671
- const sortButtonProps = table.getSortButtonProps(column);
1672
- const sortIndex = sortButtonProps["data-sort-index"];
1673
- return /* @__PURE__ */ jsxs(
1674
- "th",
1675
- {
1676
- ...headerProps,
1677
- "data-adapttable-part": "header-cell",
1678
- "data-sorted": active ? table.sortDir : void 0,
1679
- "data-sticky": stickyAttr,
1680
- "data-pinned": pinOffset?.(column.key)?.side,
1681
- className: classNames.headerCell,
1682
- children: [
1683
- column.sortable ? /* @__PURE__ */ jsxs(
1684
- "button",
1685
- {
1686
- ...sortButtonProps,
1687
- "data-adapttable-part": "sort-button",
1688
- className: classNames.sortButton,
1689
- children: [
1690
- column.header,
1691
- typeof sortIndex === "number" && /* @__PURE__ */ jsx(
1692
- "span",
1693
- {
1694
- "data-adapttable-part": "sort-index",
1695
- className: classNames.sortIndex,
1696
- children: sortIndex
1697
- }
1698
- ),
1699
- /* @__PURE__ */ jsxs("span", { "aria-hidden": true, children: [
1700
- " ",
1701
- sortGlyph(active, table.sortDir)
1702
- ] })
1703
- ]
1704
- }
1705
- ) : column.header,
1706
- setWidth && /* @__PURE__ */ jsx(
1707
- "span",
1708
- {
1709
- ...columnResizeHandleProps(
1710
- column.key,
1711
- setWidth,
1712
- `${resizeLabel}: ${columnName(column)}`
1713
- ),
1714
- "data-adapttable-part": "resize-handle",
1715
- className: classNames.resizeHandle,
1716
- style: RESIZE_HANDLE_STYLE
1717
- }
1718
- )
1719
- ]
1720
- },
1721
- column.key
1722
- );
1723
- }),
1724
- showActions && /* @__PURE__ */ jsx(
1725
- "th",
1726
- {
1727
- "data-adapttable-part": "actions-header",
1728
- "data-sticky": stickyAttr,
1729
- "data-pinned": hasRightPin || stickActions ? "right" : void 0,
1730
- style: edgeHeadStyle("right", hasRightPin || stickActions),
1731
- className: cx(classNames.headerCell, classNames.actionsCell),
1732
- children: labels.actions
1733
- }
1734
- )
1735
- ]
1736
- }
1737
- )
1738
- ] }),
1739
- /* @__PURE__ */ jsxs("tbody", { "data-adapttable-part": "tbody", className: classNames.tbody, children: [
1740
- paddingTop > 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
1741
- "td",
1742
- {
1743
- colSpan: columnSpan,
1744
- style: { height: paddingTop, padding: 0 }
1745
- }
1746
- ) }),
1747
- entries.map(({ row, index, key }) => {
1748
- const id = getRowId(row);
1749
- return /* @__PURE__ */ jsx(
1750
- Row,
1751
- {
1752
- row,
1753
- index,
1754
- id,
1755
- table,
1756
- columns,
1757
- labels,
1758
- classNames,
1759
- selected: selection ? selection.isSelected(id) : void 0,
1760
- expanded: expansionState ? expansionState.isExpanded(id) : void 0,
1761
- showActions,
1762
- rowActions,
1763
- confirm,
1764
- columnSpan,
1765
- columnWidths,
1766
- pinOffset,
1767
- pinSignature,
1768
- hasLeftPin,
1769
- hasRightPin,
1770
- actionsPinned: stickActions,
1771
- rowClass: rowClassName?.(row, index),
1772
- clickable: Boolean(onRowClick),
1773
- hasPrefetch: Boolean(prefetch),
1774
- onRowClick: handleRowClick,
1775
- onPrefetch: handlePrefetch,
1776
- onToggleSelect,
1777
- onToggleExpand,
1778
- renderDetail,
1779
- measureElement
1780
- },
1781
- key
1782
- );
1783
- }),
1784
- paddingBottom > 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
1785
- "td",
1786
- {
1787
- colSpan: columnSpan,
1788
- style: { height: paddingBottom, padding: 0 }
1789
- }
1790
- ) })
1791
- ] }),
1792
- summary && /* @__PURE__ */ jsx("tfoot", { "data-adapttable-part": "summary", className: classNames.summary, children: /* @__PURE__ */ jsxs(
1793
- "tr",
1794
- {
1795
- "data-adapttable-part": "summary-row",
1796
- className: classNames.summaryRow,
1797
- children: [
1798
- expandable && summaryPad,
1799
- selection && summaryPad,
1800
- columns.map((column) => /* @__PURE__ */ jsx(
1801
- "td",
1802
- {
1803
- "data-adapttable-part": "summary-cell",
1804
- className: classNames.summaryCell,
1805
- children: summary[column.key]
1806
- },
1807
- column.key
1808
- )),
1809
- showActions && summaryPad
1810
- ]
1811
- }
1812
- ) })
1813
- ]
1814
- }
1815
- );
1816
- return /* @__PURE__ */ jsx(
1817
- "div",
1818
- {
1819
- ref: (node) => {
1820
- overflowRef(node);
1821
- virtualScrollRef?.(node);
1822
- },
1823
- "data-adapttable-part": "scroll-box",
1824
- style: scrollBoxStyle(maxHeight, hasPinned || overflowing),
1825
- children: tableEl
1826
- }
1827
- );
1193
+ /** Desktop semantic `<table>` rendering. */
1194
+ function DesktopTable({ table, rows, rowActions, confirm, getRowId, classNames, prefetch, onRowClick, rowClassName, renderRowDetail, summaryRow, expansion, rowEntries, paddingTop = 0, paddingBottom = 0, measureElement, stickyHeader = false, stickyTop = 0, pinOffset, maxHeight, virtualScrollRef, setWidth, columnWidths, resizeLabel = "Resize column", actionsPinned = false }) {
1195
+ const { columns, selection, labels, showActions, entries, columnSpan } = tableRenderModel({
1196
+ table,
1197
+ rows,
1198
+ rowActions,
1199
+ getRowId,
1200
+ rowEntries,
1201
+ renderRowDetail,
1202
+ expansion
1203
+ });
1204
+ const stickActions = showActions && actionsPinned;
1205
+ const expansionState = renderRowDetail ? expansion : void 0;
1206
+ const expandable = expansionState !== void 0;
1207
+ const live = useRef({
1208
+ selection,
1209
+ expansion: expansionState,
1210
+ onRowClick,
1211
+ prefetch,
1212
+ renderRowDetail
1213
+ });
1214
+ live.current = {
1215
+ selection,
1216
+ expansion: expansionState,
1217
+ onRowClick,
1218
+ prefetch,
1219
+ renderRowDetail
1220
+ };
1221
+ const onToggleSelect = useCallback((id) => live.current.selection?.toggle(id), []);
1222
+ const onToggleExpand = useCallback((id) => live.current.expansion?.toggle(id), []);
1223
+ const handleRowClick = useCallback((row) => live.current.onRowClick?.(row), []);
1224
+ const handlePrefetch = useCallback((row) => live.current.prefetch?.(row), []);
1225
+ const renderDetail = useCallback((row) => live.current.renderRowDetail?.(row), []);
1226
+ const Row = useMemo(() => createDesktopRow(), []);
1227
+ const { ref: overflowRef, overflowing } = useHorizontalOverflow();
1228
+ const hasPinned = columns.some((c) => pinOffset?.(c.key) != null) || stickActions;
1229
+ const stickyStyle = stickyHeader ? {
1230
+ position: "sticky",
1231
+ top: maxHeight != null || hasPinned || overflowing ? 0 : stickyTop,
1232
+ zIndex: PIN_Z.header
1233
+ } : void 0;
1234
+ const stickyAttr = stickyHeader || void 0;
1235
+ const leads = {
1236
+ left: selection ? SELECTION_WIDTH : 0,
1237
+ right: showActions ? ACTIONS_WIDTH : 0
1238
+ };
1239
+ const hasLeftPin = columns.some((c) => pinOffset?.(c.key)?.side === "left");
1240
+ const hasRightPin = columns.some((c) => pinOffset?.(c.key)?.side === "right");
1241
+ const pinSignature = columns.map((c) => {
1242
+ const pin = pinOffset?.(c.key);
1243
+ return pin ? `${c.key}:${pin.side}:${pin.inset}` : "";
1244
+ }).join("|");
1245
+ const headPinStyle = (key) => pinnedCellStyle(pinOffset?.(key), PIN_Z.headerPinned, leads);
1246
+ const headStyle = (column) => {
1247
+ const key = column.key;
1248
+ const pin = headPinStyle(key);
1249
+ const width = pin ? pinnedColumnWidth(column, columnWidths) : columnWidths?.[key];
1250
+ if (!stickyStyle && !pin && width == null && !setWidth) return void 0;
1251
+ const merged = {
1252
+ ...stickyStyle,
1253
+ ...pin,
1254
+ ...width != null && { width }
1255
+ };
1256
+ if (setWidth && !merged.position) merged.position = "relative";
1257
+ return merged;
1258
+ };
1259
+ const edgeHeadStyle = (side, active) => {
1260
+ const edge = edgePinStyle(side, active, PIN_Z.headerPinned);
1261
+ if (!stickyStyle && !edge) return void 0;
1262
+ return {
1263
+ ...stickyStyle,
1264
+ ...edge
1265
+ };
1266
+ };
1267
+ const columnName = (column) => typeof column.header === "string" ? column.header : column.key;
1268
+ const minWidth = tableMinWidth(columns, {
1269
+ widths: columnWidths,
1270
+ extra: (selection ? SELECTION_WIDTH : 0) + (showActions ? ACTIONS_WIDTH : 0)
1271
+ });
1272
+ const groups = headerGroupRow(columns);
1273
+ const summary = summaryRow?.(rows);
1274
+ const groupPad = /* @__PURE__ */ jsx("th", {
1275
+ "data-adapttable-part": "group-cell",
1276
+ className: classNames.groupCell
1277
+ });
1278
+ const summaryPad = /* @__PURE__ */ jsx("td", {
1279
+ "data-adapttable-part": "summary-cell",
1280
+ className: classNames.summaryCell
1281
+ });
1282
+ const tableEl = /* @__PURE__ */ jsxs("table", {
1283
+ ...table.getTableProps(),
1284
+ "data-adapttable-part": "table",
1285
+ className: classNames.table,
1286
+ style: minWidth > 0 ? { minWidth } : void 0,
1287
+ children: [
1288
+ /* @__PURE__ */ jsxs("thead", {
1289
+ "data-adapttable-part": "thead",
1290
+ className: classNames.thead,
1291
+ children: [groups && /* @__PURE__ */ jsxs("tr", {
1292
+ "data-adapttable-part": "group-row",
1293
+ className: classNames.groupRow,
1294
+ children: [
1295
+ expandable && groupPad,
1296
+ selection && groupPad,
1297
+ groups.map((group) => /* @__PURE__ */ jsx("th", {
1298
+ colSpan: group.span,
1299
+ "data-adapttable-part": "group-cell",
1300
+ className: classNames.groupCell,
1301
+ children: group.label
1302
+ }, group.key)),
1303
+ showActions && groupPad
1304
+ ]
1305
+ }), /* @__PURE__ */ jsxs("tr", {
1306
+ ...table.getHeaderRowProps(),
1307
+ "data-adapttable-part": "header-row",
1308
+ className: classNames.headerRow,
1309
+ children: [
1310
+ expandable && /* @__PURE__ */ jsx("th", {
1311
+ "aria-label": labels.expandRow,
1312
+ "data-adapttable-part": "expand-header",
1313
+ "data-sticky": stickyAttr,
1314
+ style: stickyStyle,
1315
+ className: cx(classNames.headerCell, classNames.expandHeader)
1316
+ }),
1317
+ selection && /* @__PURE__ */ jsx("th", {
1318
+ "data-adapttable-part": "selection-header",
1319
+ "data-sticky": stickyAttr,
1320
+ "data-pinned": hasLeftPin ? "left" : void 0,
1321
+ style: edgeHeadStyle("left", hasLeftPin),
1322
+ className: cx(classNames.headerCell, classNames.selectionCell),
1323
+ children: /* @__PURE__ */ jsx("input", {
1324
+ type: "checkbox",
1325
+ "aria-label": labels.selectAll,
1326
+ checked: selection.headerState === "all",
1327
+ ref: (el) => {
1328
+ if (el) el.indeterminate = selection.headerState === "some";
1329
+ },
1330
+ onChange: selection.toggleAll,
1331
+ className: classNames.checkbox
1332
+ })
1333
+ }),
1334
+ columns.map((column) => {
1335
+ const localStyle = headStyle(column);
1336
+ const headerProps = table.getHeaderCellProps(column, localStyle && { style: localStyle });
1337
+ const active = table.sortBy === column.key;
1338
+ const sortButtonProps = table.getSortButtonProps(column);
1339
+ const sortIndex = sortButtonProps["data-sort-index"];
1340
+ return /* @__PURE__ */ jsxs("th", {
1341
+ ...headerProps,
1342
+ "data-adapttable-part": "header-cell",
1343
+ "data-sorted": active ? table.sortDir : void 0,
1344
+ "data-sticky": stickyAttr,
1345
+ "data-pinned": pinOffset?.(column.key)?.side,
1346
+ className: classNames.headerCell,
1347
+ children: [column.sortable ? /* @__PURE__ */ jsxs("button", {
1348
+ ...sortButtonProps,
1349
+ "data-adapttable-part": "sort-button",
1350
+ className: classNames.sortButton,
1351
+ children: [
1352
+ column.header,
1353
+ typeof sortIndex === "number" && /* @__PURE__ */ jsx("span", {
1354
+ "data-adapttable-part": "sort-index",
1355
+ className: classNames.sortIndex,
1356
+ children: sortIndex
1357
+ }),
1358
+ /* @__PURE__ */ jsxs("span", {
1359
+ "aria-hidden": true,
1360
+ children: [" ", sortGlyph(active, table.sortDir)]
1361
+ })
1362
+ ]
1363
+ }) : column.header, setWidth && /* @__PURE__ */ jsx("span", {
1364
+ ...columnResizeHandleProps(column.key, setWidth, `${resizeLabel}: ${columnName(column)}`),
1365
+ "data-adapttable-part": "resize-handle",
1366
+ className: classNames.resizeHandle,
1367
+ style: RESIZE_HANDLE_STYLE
1368
+ })]
1369
+ }, column.key);
1370
+ }),
1371
+ showActions && /* @__PURE__ */ jsx("th", {
1372
+ "data-adapttable-part": "actions-header",
1373
+ "data-sticky": stickyAttr,
1374
+ "data-pinned": hasRightPin || stickActions ? "right" : void 0,
1375
+ style: edgeHeadStyle("right", hasRightPin || stickActions),
1376
+ className: cx(classNames.headerCell, classNames.actionsCell),
1377
+ children: labels.actions
1378
+ })
1379
+ ]
1380
+ })]
1381
+ }),
1382
+ /* @__PURE__ */ jsxs("tbody", {
1383
+ "data-adapttable-part": "tbody",
1384
+ className: classNames.tbody,
1385
+ children: [
1386
+ paddingTop > 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
1387
+ colSpan: columnSpan,
1388
+ style: {
1389
+ height: paddingTop,
1390
+ padding: 0
1391
+ }
1392
+ }) }),
1393
+ entries.map(({ row, index, key }) => {
1394
+ const id = getRowId(row);
1395
+ return /* @__PURE__ */ jsx(Row, {
1396
+ row,
1397
+ index,
1398
+ id,
1399
+ table,
1400
+ columns,
1401
+ labels,
1402
+ classNames,
1403
+ selected: selection ? selection.isSelected(id) : void 0,
1404
+ expanded: expansionState ? expansionState.isExpanded(id) : void 0,
1405
+ showActions,
1406
+ rowActions,
1407
+ confirm,
1408
+ columnSpan,
1409
+ columnWidths,
1410
+ pinOffset,
1411
+ pinSignature,
1412
+ hasLeftPin,
1413
+ hasRightPin,
1414
+ actionsPinned: stickActions,
1415
+ rowClass: rowClassName?.(row, index),
1416
+ clickable: Boolean(onRowClick),
1417
+ hasPrefetch: Boolean(prefetch),
1418
+ onRowClick: handleRowClick,
1419
+ onPrefetch: handlePrefetch,
1420
+ onToggleSelect,
1421
+ onToggleExpand,
1422
+ renderDetail,
1423
+ measureElement
1424
+ }, key);
1425
+ }),
1426
+ paddingBottom > 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
1427
+ colSpan: columnSpan,
1428
+ style: {
1429
+ height: paddingBottom,
1430
+ padding: 0
1431
+ }
1432
+ }) })
1433
+ ]
1434
+ }),
1435
+ summary && /* @__PURE__ */ jsx("tfoot", {
1436
+ "data-adapttable-part": "summary",
1437
+ className: classNames.summary,
1438
+ children: /* @__PURE__ */ jsxs("tr", {
1439
+ "data-adapttable-part": "summary-row",
1440
+ className: classNames.summaryRow,
1441
+ children: [
1442
+ expandable && summaryPad,
1443
+ selection && summaryPad,
1444
+ columns.map((column) => /* @__PURE__ */ jsx("td", {
1445
+ "data-adapttable-part": "summary-cell",
1446
+ className: classNames.summaryCell,
1447
+ children: summary[column.key]
1448
+ }, column.key)),
1449
+ showActions && summaryPad
1450
+ ]
1451
+ })
1452
+ })
1453
+ ]
1454
+ });
1455
+ return /* @__PURE__ */ jsx("div", {
1456
+ ref: (node) => {
1457
+ overflowRef(node);
1458
+ virtualScrollRef?.(node);
1459
+ },
1460
+ "data-adapttable-part": "scroll-box",
1461
+ style: scrollBoxStyle(maxHeight, hasPinned || overflowing),
1462
+ children: tableEl
1463
+ });
1828
1464
  }
1829
- function MobileCards({
1830
- table,
1831
- rows,
1832
- rowActions,
1833
- confirm,
1834
- getRowId,
1835
- classNames,
1836
- onRowClick,
1837
- rowClassName,
1838
- renderRowDetail,
1839
- summaryRow,
1840
- expansion,
1841
- rowEntries,
1842
- paddingTop = 0,
1843
- paddingBottom = 0,
1844
- measureElement
1845
- }) {
1846
- const { columns, selection, labels } = table;
1847
- const entries = resolveVirtualRows(rows, getRowId, rowEntries);
1848
- const expansionState = renderRowDetail ? expansion : void 0;
1849
- const summary = summaryRow?.(rows);
1850
- return /* @__PURE__ */ jsxs(
1851
- "ul",
1852
- {
1853
- ...table.getTableProps({ role: void 0 }),
1854
- "data-adapttable-part": "cards",
1855
- className: classNames.cards,
1856
- style: { listStyle: "none", margin: 0, padding: 0 },
1857
- children: [
1858
- paddingTop > 0 && /* @__PURE__ */ jsx(
1859
- "li",
1860
- {
1861
- "aria-hidden": true,
1862
- "data-adapttable-part": "virtual-spacer",
1863
- style: { height: paddingTop }
1864
- }
1865
- ),
1866
- entries.map(({ row, index, key }) => {
1867
- const id = getRowId(row);
1868
- const expanded = expansionState?.isExpanded(id) ?? false;
1869
- return /* @__PURE__ */ jsxs(
1870
- "li",
1871
- {
1872
- ...rowClickProps(row, onRowClick),
1873
- ref: measureElement,
1874
- "data-index": index,
1875
- "data-adapttable-part": "card",
1876
- "data-selected": selection?.isSelected(id) ? "" : void 0,
1877
- "data-clickable": onRowClick ? "" : void 0,
1878
- className: cx(classNames.card, rowClassName?.(row, index)),
1879
- children: [
1880
- selection && /* @__PURE__ */ jsx(
1881
- "input",
1882
- {
1883
- type: "checkbox",
1884
- "aria-label": labels.selectRow,
1885
- checked: selection.isSelected(id),
1886
- onChange: () => selection.toggle(id),
1887
- className: classNames.checkbox
1888
- }
1889
- ),
1890
- expansionState && /* @__PURE__ */ jsx(
1891
- ExpandButton,
1892
- {
1893
- expanded,
1894
- labels,
1895
- classNames,
1896
- onToggle: () => expansionState.toggle(id)
1897
- }
1898
- ),
1899
- columns.map((column) => /* @__PURE__ */ jsxs(
1900
- "div",
1901
- {
1902
- "data-adapttable-part": "card-row",
1903
- className: classNames.cardRow,
1904
- children: [
1905
- /* @__PURE__ */ jsx(
1906
- "span",
1907
- {
1908
- "data-adapttable-part": "card-label",
1909
- className: classNames.cardLabel,
1910
- children: cardLabel(column)
1911
- }
1912
- ),
1913
- /* @__PURE__ */ jsx(
1914
- "span",
1915
- {
1916
- "data-adapttable-part": "card-value",
1917
- className: classNames.cardValue,
1918
- children: column.Cell ? /* @__PURE__ */ jsx(column.Cell, { row, rowIndex: index }) : column.accessor?.(row)
1919
- }
1920
- )
1921
- ]
1922
- },
1923
- column.key
1924
- )),
1925
- rowActions && rowActions.length > 0 && /* @__PURE__ */ jsx(
1926
- "div",
1927
- {
1928
- "data-adapttable-part": "card-actions",
1929
- className: classNames.actionsCell,
1930
- children: /* @__PURE__ */ jsx(
1931
- RowActionButtons,
1932
- {
1933
- row,
1934
- actions: rowActions,
1935
- confirm,
1936
- cancelLabel: labels.cancel,
1937
- classNames
1938
- }
1939
- )
1940
- }
1941
- ),
1942
- expanded && // Inside the measured card `<li>`, so the virtualizer's size
1943
- // measurement tracks the open detail panel.
1944
- /* @__PURE__ */ jsx(
1945
- "div",
1946
- {
1947
- "data-adapttable-part": "card-detail",
1948
- className: classNames.cardDetail,
1949
- children: renderRowDetail(row)
1950
- }
1951
- )
1952
- ]
1953
- },
1954
- key
1955
- );
1956
- }),
1957
- paddingBottom > 0 && /* @__PURE__ */ jsx(
1958
- "li",
1959
- {
1960
- "aria-hidden": true,
1961
- "data-adapttable-part": "virtual-spacer",
1962
- style: { height: paddingBottom }
1963
- }
1964
- ),
1965
- summary && /* @__PURE__ */ jsx(
1966
- "li",
1967
- {
1968
- "data-adapttable-part": "summary-card",
1969
- className: classNames.summaryCard,
1970
- children: columns.filter((column) => summary[column.key] !== void 0).map((column) => /* @__PURE__ */ jsxs(
1971
- "div",
1972
- {
1973
- "data-adapttable-part": "card-row",
1974
- className: classNames.cardRow,
1975
- children: [
1976
- /* @__PURE__ */ jsx(
1977
- "span",
1978
- {
1979
- "data-adapttable-part": "card-label",
1980
- className: classNames.cardLabel,
1981
- children: cardLabel(column)
1982
- }
1983
- ),
1984
- /* @__PURE__ */ jsx(
1985
- "span",
1986
- {
1987
- "data-adapttable-part": "card-value",
1988
- className: classNames.cardValue,
1989
- children: summary[column.key]
1990
- }
1991
- )
1992
- ]
1993
- },
1994
- column.key
1995
- ))
1996
- }
1997
- )
1998
- ]
1999
- }
2000
- );
1465
+ /** Mobile card-list rendering. */
1466
+ function MobileCards({ table, rows, rowActions, confirm, getRowId, classNames, onRowClick, rowClassName, renderRowDetail, summaryRow, expansion, rowEntries, paddingTop = 0, paddingBottom = 0, measureElement }) {
1467
+ const { columns, selection, labels } = table;
1468
+ const entries = resolveVirtualRows(rows, getRowId, rowEntries);
1469
+ const expansionState = renderRowDetail ? expansion : void 0;
1470
+ const summary = summaryRow?.(rows);
1471
+ return /* @__PURE__ */ jsxs("ul", {
1472
+ ...table.getTableProps({ role: void 0 }),
1473
+ "data-adapttable-part": "cards",
1474
+ className: classNames.cards,
1475
+ style: {
1476
+ listStyle: "none",
1477
+ margin: 0,
1478
+ padding: 0
1479
+ },
1480
+ children: [
1481
+ paddingTop > 0 && /* @__PURE__ */ jsx("li", {
1482
+ "aria-hidden": true,
1483
+ "data-adapttable-part": "virtual-spacer",
1484
+ style: { height: paddingTop }
1485
+ }),
1486
+ entries.map(({ row, index, key }) => {
1487
+ const id = getRowId(row);
1488
+ const expanded = expansionState?.isExpanded(id) ?? false;
1489
+ return /* @__PURE__ */ jsxs("li", {
1490
+ ...rowClickProps(row, onRowClick),
1491
+ ref: measureElement,
1492
+ "data-index": index,
1493
+ "data-adapttable-part": "card",
1494
+ "data-selected": selection?.isSelected(id) ? "" : void 0,
1495
+ "data-clickable": onRowClick ? "" : void 0,
1496
+ className: cx(classNames.card, rowClassName?.(row, index)),
1497
+ children: [
1498
+ selection && /* @__PURE__ */ jsx("input", {
1499
+ type: "checkbox",
1500
+ "aria-label": labels.selectRow,
1501
+ checked: selection.isSelected(id),
1502
+ onChange: () => selection.toggle(id),
1503
+ className: classNames.checkbox
1504
+ }),
1505
+ expansionState && /* @__PURE__ */ jsx(ExpandButton, {
1506
+ expanded,
1507
+ labels,
1508
+ classNames,
1509
+ onToggle: () => expansionState.toggle(id)
1510
+ }),
1511
+ columns.map((column) => /* @__PURE__ */ jsxs("div", {
1512
+ "data-adapttable-part": "card-row",
1513
+ className: classNames.cardRow,
1514
+ children: [/* @__PURE__ */ jsx("span", {
1515
+ "data-adapttable-part": "card-label",
1516
+ className: classNames.cardLabel,
1517
+ children: cardLabel(column)
1518
+ }), /* @__PURE__ */ jsx("span", {
1519
+ "data-adapttable-part": "card-value",
1520
+ className: classNames.cardValue,
1521
+ children: column.Cell ? /* @__PURE__ */ jsx(column.Cell, {
1522
+ row,
1523
+ rowIndex: index
1524
+ }) : column.accessor?.(row)
1525
+ })]
1526
+ }, column.key)),
1527
+ rowActions && rowActions.length > 0 && /* @__PURE__ */ jsx("div", {
1528
+ "data-adapttable-part": "card-actions",
1529
+ className: classNames.actionsCell,
1530
+ children: /* @__PURE__ */ jsx(RowActionButtons, {
1531
+ row,
1532
+ actions: rowActions,
1533
+ confirm,
1534
+ cancelLabel: labels.cancel,
1535
+ classNames
1536
+ })
1537
+ }),
1538
+ expanded && /* @__PURE__ */ jsx("div", {
1539
+ "data-adapttable-part": "card-detail",
1540
+ className: classNames.cardDetail,
1541
+ children: renderRowDetail(row)
1542
+ })
1543
+ ]
1544
+ }, key);
1545
+ }),
1546
+ paddingBottom > 0 && /* @__PURE__ */ jsx("li", {
1547
+ "aria-hidden": true,
1548
+ "data-adapttable-part": "virtual-spacer",
1549
+ style: { height: paddingBottom }
1550
+ }),
1551
+ summary && /* @__PURE__ */ jsx("li", {
1552
+ "data-adapttable-part": "summary-card",
1553
+ className: classNames.summaryCard,
1554
+ children: columns.filter((column) => summary[column.key] !== void 0).map((column) => /* @__PURE__ */ jsxs("div", {
1555
+ "data-adapttable-part": "card-row",
1556
+ className: classNames.cardRow,
1557
+ children: [/* @__PURE__ */ jsx("span", {
1558
+ "data-adapttable-part": "card-label",
1559
+ className: classNames.cardLabel,
1560
+ children: cardLabel(column)
1561
+ }), /* @__PURE__ */ jsx("span", {
1562
+ "data-adapttable-part": "card-value",
1563
+ className: classNames.cardValue,
1564
+ children: summary[column.key]
1565
+ })]
1566
+ }, column.key))
1567
+ })
1568
+ ]
1569
+ });
2001
1570
  }
2002
1571
  function sortGlyph(active, dir) {
2003
- if (!active) return "\u2195";
2004
- return dir === "asc" ? "\u2191" : "\u2193";
1572
+ if (!active) return "";
1573
+ return dir === "asc" ? "" : "";
2005
1574
  }
2006
1575
  function cardLabel(column) {
2007
- return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
1576
+ return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
2008
1577
  }
2009
- var NO_CLASSNAMES = {};
2010
- function DataTableBody({
2011
- chrome,
2012
- props,
2013
- classNames,
2014
- confirm,
2015
- getRowId,
2016
- virtualization,
2017
- virtualScrollRef,
2018
- labels
2019
- }) {
2020
- const rowActions = chrome.columnLayout.isHidden(ACTIONS_COLUMN_KEY) ? void 0 : props.rowActions;
2021
- const actionsPinned = (rowActions?.length ?? 0) > 0 && chrome.columnLayout.state.pinned[ACTIONS_COLUMN_KEY] !== void 0;
2022
- if (chrome.body === "skeleton") {
2023
- return /* @__PURE__ */ jsx(Fragment, { children: props.slots?.skeleton ?? props.loadingState ?? /* @__PURE__ */ jsx(
2024
- LoadingState,
2025
- {
2026
- rows: props.skeletonRows ?? props.source.limit,
2027
- columns: chrome.table.columns.length,
2028
- variant: chrome.isMobile ? "cards" : "table",
2029
- labels,
2030
- classNames,
2031
- hasActions: (rowActions?.length ?? 0) > 0
2032
- }
2033
- ) });
2034
- }
2035
- if (chrome.body === "empty") {
2036
- const noResults = chrome.emptyVariant === "noResults";
2037
- return /* @__PURE__ */ jsx(Fragment, { children: props.slots?.empty ?? props.emptyState ?? /* @__PURE__ */ jsxs("output", { "data-adapttable-part": "empty", className: classNames.empty, children: [
2038
- noResults ? labels.noResults : labels.noData,
2039
- noResults && /* @__PURE__ */ jsx(
2040
- "button",
2041
- {
2042
- type: "button",
2043
- "data-adapttable-part": "empty-clear",
2044
- className: classNames.emptyClear,
2045
- onClick: chrome.clearFilters,
2046
- children: labels.clearAll
2047
- }
2048
- )
2049
- ] }) });
2050
- }
2051
- const Renderer = chrome.isMobile ? MobileCards : DesktopTable;
2052
- return /* @__PURE__ */ jsx(
2053
- Renderer,
2054
- {
2055
- table: chrome.table,
2056
- rows: props.source.rows,
2057
- rowActions,
2058
- actionsPinned,
2059
- confirm,
2060
- getRowId,
2061
- classNames,
2062
- prefetch: props.prefetch,
2063
- onRowClick: props.onRowClick,
2064
- rowClassName: props.rowClassName,
2065
- renderRowDetail: props.renderRowDetail,
2066
- summaryRow: props.summaryRow,
2067
- expansion: chrome.detail?.expansion,
2068
- rowEntries: virtualization.enabled ? virtualization.rows : void 0,
2069
- paddingTop: virtualization.paddingTop,
2070
- paddingBottom: virtualization.paddingBottom,
2071
- measureElement: virtualization.measureElement,
2072
- stickyHeader: props.stickyHeader,
2073
- stickyTop: props.stickyTop,
2074
- pinOffset: chrome.columnLayout.pinOffset,
2075
- maxHeight: props.maxHeight,
2076
- virtualScrollRef,
2077
- setWidth: props.resizableColumns ? chrome.columnLayout.setWidth : void 0,
2078
- columnWidths: chrome.columnLayout.state.widths,
2079
- resizeLabel: labels.resizeColumn
2080
- }
2081
- );
1578
+ //#endregion
1579
+ //#region src/DataTable.tsx
1580
+ const NO_CLASSNAMES = {};
1581
+ function DataTableBody({ chrome, props, classNames, confirm, getRowId, virtualization, virtualScrollRef, labels }) {
1582
+ const rowActions = chrome.columnLayout.isHidden(ACTIONS_COLUMN_KEY) ? void 0 : props.rowActions;
1583
+ const actionsPinned = (rowActions?.length ?? 0) > 0 && chrome.columnLayout.state.pinned[ACTIONS_COLUMN_KEY] !== void 0;
1584
+ if (chrome.body === "skeleton") return /* @__PURE__ */ jsx(Fragment, { children: props.slots?.skeleton ?? props.loadingState ?? /* @__PURE__ */ jsx(LoadingState, {
1585
+ rows: props.skeletonRows ?? props.source.limit,
1586
+ columns: chrome.table.columns.length,
1587
+ variant: chrome.isMobile ? "cards" : "table",
1588
+ labels,
1589
+ classNames,
1590
+ hasActions: (rowActions?.length ?? 0) > 0
1591
+ }) });
1592
+ if (chrome.body === "empty") {
1593
+ const noResults = chrome.emptyVariant === "noResults";
1594
+ return /* @__PURE__ */ jsx(Fragment, { children: props.slots?.empty ?? props.emptyState ?? /* @__PURE__ */ jsxs("output", {
1595
+ "data-adapttable-part": "empty",
1596
+ className: classNames.empty,
1597
+ children: [noResults ? labels.noResults : labels.noData, noResults && /* @__PURE__ */ jsx("button", {
1598
+ type: "button",
1599
+ "data-adapttable-part": "empty-clear",
1600
+ className: classNames.emptyClear,
1601
+ onClick: chrome.clearFilters,
1602
+ children: labels.clearAll
1603
+ })]
1604
+ }) });
1605
+ }
1606
+ return /* @__PURE__ */ jsx(chrome.isMobile ? MobileCards : DesktopTable, {
1607
+ table: chrome.table,
1608
+ rows: props.source.rows,
1609
+ rowActions,
1610
+ actionsPinned,
1611
+ confirm,
1612
+ getRowId,
1613
+ classNames,
1614
+ prefetch: props.prefetch,
1615
+ onRowClick: props.onRowClick,
1616
+ rowClassName: props.rowClassName,
1617
+ renderRowDetail: props.renderRowDetail,
1618
+ summaryRow: props.summaryRow,
1619
+ expansion: chrome.detail?.expansion,
1620
+ rowEntries: virtualization.enabled ? virtualization.rows : void 0,
1621
+ paddingTop: virtualization.paddingTop,
1622
+ paddingBottom: virtualization.paddingBottom,
1623
+ measureElement: virtualization.measureElement,
1624
+ stickyHeader: props.stickyHeader,
1625
+ stickyTop: props.stickyTop,
1626
+ pinOffset: chrome.columnLayout.pinOffset,
1627
+ maxHeight: props.maxHeight,
1628
+ virtualScrollRef,
1629
+ setWidth: props.resizableColumns ? chrome.columnLayout.setWidth : void 0,
1630
+ columnWidths: chrome.columnLayout.state.widths,
1631
+ resizeLabel: labels.resizeColumn
1632
+ });
2082
1633
  }
1634
+ /**
1635
+ * Headless, unstyled AdaptTable for Tailwind / shadcn / custom CSS. Renders
1636
+ * semantic HTML with `data-adapttable-part` hooks and `className` overrides;
1637
+ * ships no styles of its own. Built on the `@adapttable/core` prop-getters.
1638
+ *
1639
+ * @typeParam TRow - The row type.
1640
+ */
2083
1641
  function DataTable(props) {
2084
- const {
2085
- data,
2086
- total,
2087
- loading,
2088
- onQueryChange,
2089
- urlAdapter,
2090
- urlKey,
2091
- searchPlaceholder,
2092
- sortByOptions,
2093
- dir,
2094
- hideSearch,
2095
- filtersMode = "popover",
2096
- bulkActions,
2097
- classNames = NO_CLASSNAMES,
2098
- toolbar: customToolbar
2099
- } = props;
2100
- const density = props.density ?? "comfortable";
2101
- const { source, runtime } = useTableData({
2102
- locale: props.locale,
2103
- source: props.source,
2104
- data,
2105
- total,
2106
- loading,
2107
- onQueryChange,
2108
- adapter: props.urlSync === false ? void 0 : urlAdapter,
2109
- enabled: props.urlSync,
2110
- urlKey,
2111
- columns: props.columns,
2112
- filters: props.filters
2113
- });
2114
- const autoForm = runtime.defs.length > 0 ? /* @__PURE__ */ jsx(
2115
- AutoFilterForm,
2116
- {
2117
- defs: runtime.defs,
2118
- source,
2119
- classNames,
2120
- labels: props.labels
2121
- }
2122
- ) : void 0;
2123
- const filters = isDeclarativeFilters(props.filters) || props.filters === void 0 ? autoForm : props.filters;
2124
- const chromeProps = {
2125
- ...props,
2126
- source,
2127
- filters,
2128
- filterLabels: { ...runtime.filterLabels, ...props.filterLabels }
2129
- };
2130
- const chrome = useTableChrome(chromeProps);
2131
- const { table, confirm, getRowId } = chrome;
2132
- const { labels } = table;
2133
- const [filtersOpen, setFiltersOpen] = useState(false);
2134
- const filtersTrigger = useFilterTriggerToggle(filtersOpen, setFiltersOpen);
2135
- const rootRef = useRef(null);
2136
- useChromeScrollReset(rootRef, chrome, chromeProps);
2137
- const bodyData = useChromeBodyData(chrome, chromeProps);
2138
- const { virtualization, canLoadMore } = bodyData;
2139
- const loadMoreRef = bodyData.loadMoreRef;
2140
- const searchProps = table.getSearchInputProps(
2141
- searchPlaceholder ? { placeholder: searchPlaceholder } : void 0
2142
- );
2143
- const sortOptions = sortByOptions ?? (chrome.isMobile ? table.sortByOptions : void 0);
2144
- const filtersButton = /* @__PURE__ */ jsxs(
2145
- "button",
2146
- {
2147
- type: "button",
2148
- "aria-expanded": filtersMode === "popover" ? filtersOpen : void 0,
2149
- "data-active": filtersOpen || void 0,
2150
- "data-adapttable-part": "filters-button",
2151
- className: classNames.filtersButton,
2152
- style: { flexShrink: 0, whiteSpace: "nowrap" },
2153
- onPointerDown: filtersTrigger.onPointerDown,
2154
- onClick: filtersTrigger.onClick,
2155
- children: [
2156
- /* @__PURE__ */ jsx(
2157
- "span",
2158
- {
2159
- "data-adapttable-part": "filters-icon",
2160
- className: classNames.filtersIcon,
2161
- style: { display: "inline-flex" },
2162
- children: /* @__PURE__ */ jsx(FiltersIcon, {})
2163
- }
2164
- ),
2165
- labels.filters,
2166
- chrome.activeFilterCount > 0 && /* @__PURE__ */ jsx(
2167
- "span",
2168
- {
2169
- "data-adapttable-part": "filters-count",
2170
- className: classNames.filtersCount,
2171
- children: chrome.activeFilterCount
2172
- }
2173
- )
2174
- ]
2175
- }
2176
- );
2177
- return /* @__PURE__ */ jsxs(
2178
- "div",
2179
- {
2180
- ref: rootRef,
2181
- dir,
2182
- "data-adapttable-part": "root",
2183
- "data-mobile": chrome.isMobile || void 0,
2184
- "data-density": density,
2185
- "data-refreshing": chrome.isRefreshing || void 0,
2186
- "aria-busy": chrome.isRefreshing || void 0,
2187
- className: cx("adapttable", classNames.root),
2188
- children: [
2189
- /* @__PURE__ */ jsxs(
2190
- "div",
2191
- {
2192
- "data-adapttable-part": "toolbar",
2193
- className: classNames.toolbar,
2194
- style: {
2195
- display: "flex",
2196
- flexWrap: "wrap",
2197
- alignItems: "center",
2198
- rowGap: 8
2199
- },
2200
- children: [
2201
- !hideSearch && /* @__PURE__ */ jsxs(
2202
- "span",
2203
- {
2204
- "data-adapttable-part": "search-field",
2205
- className: classNames.searchField,
2206
- style: {
2207
- flex: 1,
2208
- minWidth: 0,
2209
- display: "inline-flex",
2210
- alignItems: "center"
2211
- },
2212
- children: [
2213
- /* @__PURE__ */ jsx(
2214
- "span",
2215
- {
2216
- "data-adapttable-part": "search-icon",
2217
- className: classNames.searchIcon,
2218
- style: { display: "inline-flex" },
2219
- children: /* @__PURE__ */ jsx(SearchIcon, { size: 14 })
2220
- }
2221
- ),
2222
- /* @__PURE__ */ jsx(
2223
- "input",
2224
- {
2225
- ...searchProps,
2226
- "data-adapttable-part": "search",
2227
- className: classNames.search,
2228
- style: { flex: 1, minWidth: 0 }
2229
- }
2230
- )
2231
- ]
2232
- }
2233
- ),
2234
- sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxs("label", { children: [
2235
- labels.sortBy,
2236
- " ",
2237
- /* @__PURE__ */ jsxs(
2238
- "select",
2239
- {
2240
- "aria-label": labels.sortBy,
2241
- "data-adapttable-part": "sort-select",
2242
- className: classNames.sortSelect,
2243
- value: source.sortBy ?? "",
2244
- onChange: (e) => source.setSort(
2245
- e.currentTarget.value || void 0,
2246
- source.sortDir ?? "asc"
2247
- ),
2248
- children: [
2249
- /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
2250
- sortOptions.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
2251
- ]
2252
- }
2253
- )
2254
- ] }),
2255
- customToolbar,
2256
- filters && (filtersMode === "popover" ? /* @__PURE__ */ jsx(
2257
- FilterPopover,
2258
- {
2259
- open: filtersOpen,
2260
- onClose: () => setFiltersOpen(false),
2261
- filters,
2262
- activeFilterCount: chrome.activeFilterCount,
2263
- onClearFilters: chrome.clearFilters,
2264
- labels,
2265
- dir,
2266
- classNames,
2267
- children: filtersButton
2268
- }
2269
- ) : filtersButton),
2270
- props.enableColumnMenu && !chrome.isMobile && /* @__PURE__ */ jsx(
2271
- ColumnMenu,
2272
- {
2273
- allColumns: chrome.allColumns,
2274
- layout: chrome.columnLayout,
2275
- labels,
2276
- classNames,
2277
- hasRowActions: (props.rowActions?.length ?? 0) > 0
2278
- }
2279
- ),
2280
- props.savedViews && // The menu must capture/apply through the SAME URL backend and
2281
- // namespace the table reads, so those default from the table's
2282
- // own props (explicit option values still win).
2283
- /* @__PURE__ */ jsx(
2284
- SavedViewsMenu,
2285
- {
2286
- options: { adapter: urlAdapter, urlKey, ...props.savedViews },
2287
- labels,
2288
- classNames
2289
- }
2290
- ),
2291
- canLoadMore && /* @__PURE__ */ jsx(
2292
- RowsPerPageSelect,
2293
- {
2294
- source,
2295
- labels,
2296
- classNames
2297
- }
2298
- )
2299
- ]
2300
- }
2301
- ),
2302
- filters && filtersMode === "drawer" && /* @__PURE__ */ jsx(
2303
- FilterPanel,
2304
- {
2305
- open: filtersOpen,
2306
- onClose: () => setFiltersOpen(false),
2307
- filters,
2308
- activeFilterCount: chrome.activeFilterCount,
2309
- onClearFilters: chrome.clearFilters,
2310
- labels,
2311
- dir,
2312
- classNames
2313
- }
2314
- ),
2315
- /* @__PURE__ */ jsx(
2316
- Chips,
2317
- {
2318
- chips: chrome.mergedChips,
2319
- onClearAll: chrome.clearFilters,
2320
- labels,
2321
- classNames
2322
- }
2323
- ),
2324
- table.selection && bulkActions && /* @__PURE__ */ jsx(
2325
- BulkBar,
2326
- {
2327
- selection: table.selection,
2328
- total: source.total,
2329
- bulkActions,
2330
- confirm,
2331
- labels,
2332
- classNames
2333
- }
2334
- ),
2335
- chrome.isRefreshing && // Native indeterminate progress (no `value`) — implicit progressbar
2336
- // role with correct semantics on every device.
2337
- /* @__PURE__ */ jsx(
2338
- "progress",
2339
- {
2340
- "aria-label": labels.loading,
2341
- "data-adapttable-part": "refresh-indicator",
2342
- className: classNames.refreshIndicator
2343
- }
2344
- ),
2345
- source.error ? /* @__PURE__ */ jsx(
2346
- ErrorState,
2347
- {
2348
- error: source.error,
2349
- labels,
2350
- onRetry: source.refetch ? () => void source.refetch?.() : void 0,
2351
- classNames
2352
- }
2353
- ) : /* @__PURE__ */ jsx(
2354
- DataTableBody,
2355
- {
2356
- chrome,
2357
- props: chromeProps,
2358
- classNames,
2359
- confirm,
2360
- getRowId,
2361
- virtualization,
2362
- virtualScrollRef: bodyData.virtualScrollRef,
2363
- labels
2364
- }
2365
- ),
2366
- canLoadMore && source.hasNextPage && /* @__PURE__ */ jsx(
2367
- "div",
2368
- {
2369
- ref: loadMoreRef,
2370
- "data-adapttable-part": "load-more",
2371
- className: classNames.loadMore,
2372
- children: /* @__PURE__ */ jsx(
2373
- "button",
2374
- {
2375
- type: "button",
2376
- disabled: source.isFetchingNextPage,
2377
- "data-adapttable-part": "load-more-button",
2378
- className: classNames.loadMoreButton,
2379
- onClick: () => source.fetchNextPage(),
2380
- children: labels.loadMore
2381
- }
2382
- )
2383
- }
2384
- ),
2385
- chrome.showFooter && /* @__PURE__ */ jsx(
2386
- Footer,
2387
- {
2388
- pagination: table.pagination,
2389
- source,
2390
- labels,
2391
- classNames
2392
- }
2393
- )
2394
- ]
2395
- }
2396
- );
1642
+ const { data, total, loading, onQueryChange, urlAdapter, urlKey, searchPlaceholder, sortByOptions, dir, hideSearch, filtersMode = "popover", bulkActions, classNames = NO_CLASSNAMES, toolbar: customToolbar } = props;
1643
+ const density = props.density ?? "comfortable";
1644
+ const { source, runtime } = useTableData$1({
1645
+ locale: props.locale,
1646
+ source: props.source,
1647
+ data,
1648
+ total,
1649
+ loading,
1650
+ onQueryChange,
1651
+ adapter: props.urlSync === false ? void 0 : urlAdapter,
1652
+ enabled: props.urlSync,
1653
+ urlKey,
1654
+ columns: props.columns,
1655
+ filters: props.filters
1656
+ });
1657
+ const autoForm = runtime.defs.length > 0 ? /* @__PURE__ */ jsx(AutoFilterForm, {
1658
+ defs: runtime.defs,
1659
+ source,
1660
+ classNames,
1661
+ labels: props.labels
1662
+ }) : void 0;
1663
+ const filters = isDeclarativeFilters(props.filters) || props.filters === void 0 ? autoForm : props.filters;
1664
+ const chromeProps = {
1665
+ ...props,
1666
+ source,
1667
+ filters,
1668
+ filterLabels: {
1669
+ ...runtime.filterLabels,
1670
+ ...props.filterLabels
1671
+ }
1672
+ };
1673
+ const chrome = useTableChrome(chromeProps);
1674
+ const { table, confirm, getRowId } = chrome;
1675
+ const { labels } = table;
1676
+ const [filtersOpen, setFiltersOpen] = useState(false);
1677
+ const filtersTrigger = useFilterTriggerToggle(filtersOpen, setFiltersOpen);
1678
+ const rootRef = useRef(null);
1679
+ useChromeScrollReset(rootRef, chrome, chromeProps);
1680
+ const bodyData = useChromeBodyData(chrome, chromeProps);
1681
+ const { virtualization, canLoadMore } = bodyData;
1682
+ const loadMoreRef = bodyData.loadMoreRef;
1683
+ const searchProps = table.getSearchInputProps(searchPlaceholder ? { placeholder: searchPlaceholder } : void 0);
1684
+ const sortOptions = sortByOptions ?? (chrome.isMobile ? table.sortByOptions : void 0);
1685
+ const filtersButton = /* @__PURE__ */ jsxs("button", {
1686
+ type: "button",
1687
+ "aria-expanded": filtersMode === "popover" ? filtersOpen : void 0,
1688
+ "data-active": filtersOpen || void 0,
1689
+ "data-adapttable-part": "filters-button",
1690
+ className: classNames.filtersButton,
1691
+ style: {
1692
+ flexShrink: 0,
1693
+ whiteSpace: "nowrap"
1694
+ },
1695
+ onPointerDown: filtersTrigger.onPointerDown,
1696
+ onClick: filtersTrigger.onClick,
1697
+ children: [
1698
+ /* @__PURE__ */ jsx("span", {
1699
+ "data-adapttable-part": "filters-icon",
1700
+ className: classNames.filtersIcon,
1701
+ style: { display: "inline-flex" },
1702
+ children: /* @__PURE__ */ jsx(FiltersIcon, {})
1703
+ }),
1704
+ labels.filters,
1705
+ chrome.activeFilterCount > 0 && /* @__PURE__ */ jsx("span", {
1706
+ "data-adapttable-part": "filters-count",
1707
+ className: classNames.filtersCount,
1708
+ children: chrome.activeFilterCount
1709
+ })
1710
+ ]
1711
+ });
1712
+ return /* @__PURE__ */ jsxs("div", {
1713
+ ref: rootRef,
1714
+ dir,
1715
+ "data-adapttable-part": "root",
1716
+ "data-mobile": chrome.isMobile || void 0,
1717
+ "data-density": density,
1718
+ "data-refreshing": chrome.isRefreshing || void 0,
1719
+ "aria-busy": chrome.isRefreshing || void 0,
1720
+ className: cx("adapttable", classNames.root),
1721
+ children: [
1722
+ /* @__PURE__ */ jsxs("div", {
1723
+ "data-adapttable-part": "toolbar",
1724
+ className: classNames.toolbar,
1725
+ style: {
1726
+ display: "flex",
1727
+ flexWrap: "wrap",
1728
+ alignItems: "center",
1729
+ rowGap: 8
1730
+ },
1731
+ children: [
1732
+ !hideSearch && /* @__PURE__ */ jsxs("span", {
1733
+ "data-adapttable-part": "search-field",
1734
+ className: classNames.searchField,
1735
+ style: {
1736
+ flex: 1,
1737
+ minWidth: 0,
1738
+ display: "inline-flex",
1739
+ alignItems: "center"
1740
+ },
1741
+ children: [/* @__PURE__ */ jsx("span", {
1742
+ "data-adapttable-part": "search-icon",
1743
+ className: classNames.searchIcon,
1744
+ style: { display: "inline-flex" },
1745
+ children: /* @__PURE__ */ jsx(SearchIcon, { size: 14 })
1746
+ }), /* @__PURE__ */ jsx("input", {
1747
+ ...searchProps,
1748
+ "data-adapttable-part": "search",
1749
+ className: classNames.search,
1750
+ style: {
1751
+ flex: 1,
1752
+ minWidth: 0
1753
+ }
1754
+ })]
1755
+ }),
1756
+ sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxs("label", { children: [
1757
+ labels.sortBy,
1758
+ " ",
1759
+ /* @__PURE__ */ jsxs("select", {
1760
+ "aria-label": labels.sortBy,
1761
+ "data-adapttable-part": "sort-select",
1762
+ className: classNames.sortSelect,
1763
+ value: source.sortBy ?? "",
1764
+ onChange: (e) => source.setSort(e.currentTarget.value || void 0, source.sortDir ?? "asc"),
1765
+ children: [/* @__PURE__ */ jsx("option", {
1766
+ value: "",
1767
+ children: ""
1768
+ }), sortOptions.map((o) => /* @__PURE__ */ jsx("option", {
1769
+ value: o.value,
1770
+ children: o.label
1771
+ }, o.value))]
1772
+ })
1773
+ ] }),
1774
+ customToolbar,
1775
+ filters && (filtersMode === "popover" ? /* @__PURE__ */ jsx(FilterPopover, {
1776
+ open: filtersOpen,
1777
+ onClose: () => setFiltersOpen(false),
1778
+ filters,
1779
+ activeFilterCount: chrome.activeFilterCount,
1780
+ onClearFilters: chrome.clearFilters,
1781
+ labels,
1782
+ dir,
1783
+ classNames,
1784
+ children: filtersButton
1785
+ }) : filtersButton),
1786
+ props.enableColumnMenu && !chrome.isMobile && /* @__PURE__ */ jsx(ColumnMenu, {
1787
+ allColumns: chrome.allColumns,
1788
+ layout: chrome.columnLayout,
1789
+ labels,
1790
+ classNames,
1791
+ hasRowActions: (props.rowActions?.length ?? 0) > 0
1792
+ }),
1793
+ props.savedViews && /* @__PURE__ */ jsx(SavedViewsMenu, {
1794
+ options: {
1795
+ adapter: urlAdapter,
1796
+ urlKey,
1797
+ ...props.savedViews
1798
+ },
1799
+ labels,
1800
+ classNames
1801
+ }),
1802
+ canLoadMore && /* @__PURE__ */ jsx(RowsPerPageSelect, {
1803
+ source,
1804
+ labels,
1805
+ classNames
1806
+ })
1807
+ ]
1808
+ }),
1809
+ filters && filtersMode === "drawer" && /* @__PURE__ */ jsx(FilterPanel, {
1810
+ open: filtersOpen,
1811
+ onClose: () => setFiltersOpen(false),
1812
+ filters,
1813
+ activeFilterCount: chrome.activeFilterCount,
1814
+ onClearFilters: chrome.clearFilters,
1815
+ labels,
1816
+ dir,
1817
+ classNames
1818
+ }),
1819
+ /* @__PURE__ */ jsx(Chips, {
1820
+ chips: chrome.mergedChips,
1821
+ onClearAll: chrome.clearFilters,
1822
+ labels,
1823
+ classNames
1824
+ }),
1825
+ table.selection && bulkActions && /* @__PURE__ */ jsx(BulkBar, {
1826
+ selection: table.selection,
1827
+ total: source.total,
1828
+ bulkActions,
1829
+ confirm,
1830
+ labels,
1831
+ classNames
1832
+ }),
1833
+ chrome.isRefreshing && /* @__PURE__ */ jsx("progress", {
1834
+ "aria-label": labels.loading,
1835
+ "data-adapttable-part": "refresh-indicator",
1836
+ className: classNames.refreshIndicator
1837
+ }),
1838
+ source.error ? /* @__PURE__ */ jsx(ErrorState, {
1839
+ error: source.error,
1840
+ labels,
1841
+ onRetry: source.refetch ? () => void source.refetch?.() : void 0,
1842
+ classNames
1843
+ }) : /* @__PURE__ */ jsx(DataTableBody, {
1844
+ chrome,
1845
+ props: chromeProps,
1846
+ classNames,
1847
+ confirm,
1848
+ getRowId,
1849
+ virtualization,
1850
+ virtualScrollRef: bodyData.virtualScrollRef,
1851
+ labels
1852
+ }),
1853
+ canLoadMore && source.hasNextPage && /* @__PURE__ */ jsx("div", {
1854
+ ref: loadMoreRef,
1855
+ "data-adapttable-part": "load-more",
1856
+ className: classNames.loadMore,
1857
+ children: /* @__PURE__ */ jsx("button", {
1858
+ type: "button",
1859
+ disabled: source.isFetchingNextPage,
1860
+ "data-adapttable-part": "load-more-button",
1861
+ className: classNames.loadMoreButton,
1862
+ onClick: () => source.fetchNextPage(),
1863
+ children: labels.loadMore
1864
+ })
1865
+ }),
1866
+ chrome.showFooter && /* @__PURE__ */ jsx(Footer, {
1867
+ pagination: table.pagination,
1868
+ source,
1869
+ labels,
1870
+ classNames
1871
+ })
1872
+ ]
1873
+ });
2397
1874
  }
1875
+ //#endregion
1876
+ export { AutoFilterForm, DataTable, FILTER_TYPES, FilterPanel, FilterPopover, FiltersIcon, SavedViewsMenu, SearchIcon, createHistoryAdapter, createMemoryAdapter, cx, defaultConfirm, defaultLabels, deriveSortByOptions, filterLabel, filterStateKeys, getHistoryAdapter, useBackendData, useDataTable, useFrontendData, useSavedViews, useServerData, useTableData, useTableUrlState };
2398
1877
 
2399
- export { AutoFilterForm, DataTable, FilterPanel, FilterPopover, FiltersIcon, SavedViewsMenu, SearchIcon, cx };
2400
- //# sourceMappingURL=index.js.map
2401
1878
  //# sourceMappingURL=index.js.map