@adapttable/unstyled 0.1.1 → 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,2402 +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", { "data-adapttable-part": "chip", className: classNames.chip, children: /* @__PURE__ */ jsx(
767
- "button",
768
- {
769
- type: "button",
770
- "data-adapttable-part": "chip-remove",
771
- className: classNames.chipRemove,
772
- onClick: onClearAll,
773
- children: labels.clearAll
774
- }
775
- ) })
776
- ]
777
- }
778
- );
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
+ });
779
653
  }
780
- function BulkBar({
781
- selection,
782
- total,
783
- bulkActions,
784
- confirm,
785
- labels,
786
- classNames
787
- }) {
788
- const {
789
- selectedIds,
790
- selectedCount,
791
- clear,
792
- headerState,
793
- visibleIds,
794
- allMatching,
795
- selectAllMatching
796
- } = selection;
797
- const { pending, run } = useBulkActionRunner({
798
- confirm,
799
- cancelLabel: labels.cancel,
800
- onComplete: clear
801
- });
802
- if (selectedCount === 0) return null;
803
- const ids = [...selectedIds];
804
- const showBanner = headerState === "all" && total > visibleIds.length;
805
- const scope = allMatching ? { allMatching: true, total } : void 0;
806
- return /* @__PURE__ */ jsxs("div", { "data-adapttable-part": "bulk-bar", className: classNames.bulkBar, children: [
807
- /* @__PURE__ */ jsx("span", { children: labels.selectedCount(selectedCount) }),
808
- showBanner && /* @__PURE__ */ jsxs(
809
- "div",
810
- {
811
- "data-adapttable-part": "select-all-banner",
812
- className: classNames.selectAllBanner,
813
- children: [
814
- /* @__PURE__ */ jsx(
815
- "span",
816
- {
817
- "data-adapttable-part": "select-all-text",
818
- className: classNames.selectAllText,
819
- children: allMatching ? labels.allMatchingSelected(total) : labels.pageSelected(visibleIds.length)
820
- }
821
- ),
822
- /* @__PURE__ */ jsx(
823
- "button",
824
- {
825
- type: "button",
826
- "data-adapttable-part": "select-all-button",
827
- className: classNames.selectAllButton,
828
- onClick: allMatching ? clear : selectAllMatching,
829
- children: allMatching ? labels.clearAll : labels.selectAllMatching(total)
830
- }
831
- )
832
- ]
833
- }
834
- ),
835
- /* @__PURE__ */ jsx("button", { type: "button", onClick: clear, disabled: pending !== null, children: labels.clearAll }),
836
- bulkActions.map((action) => {
837
- const reason = resolveDisabledReason(action.disabledReason?.(ids));
838
- return /* @__PURE__ */ jsxs(
839
- "button",
840
- {
841
- type: "button",
842
- title: reason,
843
- disabled: reason !== void 0 || pending !== null,
844
- "data-adapttable-part": "bulk-button",
845
- "data-color": action.color,
846
- className: classNames.bulkButton,
847
- onClick: () => run(action, ids, scope),
848
- children: [
849
- action.icon,
850
- action.label
851
- ]
852
- },
853
- action.key
854
- );
855
- })
856
- ] });
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
+ });
857
710
  }
858
- function RowsPerPageSelect({
859
- source,
860
- labels,
861
- classNames
862
- }) {
863
- return /* @__PURE__ */ jsxs("label", { children: [
864
- labels.rowsPerPage,
865
- " ",
866
- /* @__PURE__ */ jsx(
867
- "select",
868
- {
869
- "aria-label": labels.rowsPerPage,
870
- "data-adapttable-part": "rows-per-page",
871
- className: classNames.rowsPerPageSelect,
872
- value: source.limit,
873
- onChange: (e) => source.setLimit(Number(e.currentTarget.value)),
874
- children: pageSizeOptions(source.limit).map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n))
875
- }
876
- )
877
- ] });
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
+ ] });
878
728
  }
879
- function Footer({
880
- pagination,
881
- source,
882
- labels,
883
- classNames
884
- }) {
885
- const { safePage, totalPages, fromIndex, toIndex } = pagination;
886
- return /* @__PURE__ */ jsxs("div", { "data-adapttable-part": "footer", className: classNames.footer, children: [
887
- /* @__PURE__ */ jsx(
888
- RowsPerPageSelect,
889
- {
890
- source,
891
- labels,
892
- classNames
893
- }
894
- ),
895
- source.total > 0 && /* @__PURE__ */ jsx("span", { children: labels.showing({
896
- from: fromIndex,
897
- to: toIndex,
898
- total: source.total
899
- }) }),
900
- /* @__PURE__ */ jsx("span", { children: labels.pageOf({ page: safePage, total: totalPages }) }),
901
- /* @__PURE__ */ jsx(
902
- "button",
903
- {
904
- type: "button",
905
- "aria-label": labels.previousPage,
906
- "data-adapttable-part": "page-prev",
907
- className: classNames.pageButton,
908
- disabled: safePage <= 1,
909
- onClick: () => source.setPage(safePage - 1),
910
- children: "\u2039"
911
- }
912
- ),
913
- /* @__PURE__ */ jsx(
914
- "button",
915
- {
916
- type: "button",
917
- "aria-label": labels.nextPage,
918
- "data-adapttable-part": "page-next",
919
- className: classNames.pageButton,
920
- disabled: safePage >= totalPages,
921
- onClick: () => source.setPage(safePage + 1),
922
- children: "\u203A"
923
- }
924
- )
925
- ] });
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
+ });
926
770
  }
927
- function ErrorState({
928
- error,
929
- labels,
930
- onRetry,
931
- classNames
932
- }) {
933
- return /* @__PURE__ */ jsxs("div", { role: "alert", "data-adapttable-part": "error", className: classNames.error, children: [
934
- /* @__PURE__ */ jsx("strong", { children: labels.errorTitle }),
935
- /* @__PURE__ */ jsx("p", { children: labels.errorMessage }),
936
- /* @__PURE__ */ jsx("small", { children: error.message }),
937
- onRetry && /* @__PURE__ */ jsx(
938
- "button",
939
- {
940
- type: "button",
941
- onClick: onRetry,
942
- "data-adapttable-part": "retry",
943
- className: classNames.retryButton,
944
- children: labels.retry
945
- }
946
- )
947
- ] });
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
+ });
948
790
  }
949
791
  function loadingLineWidth(column, total) {
950
- if (column === 0) return "70%";
951
- if (column === total - 1) return "42%";
952
- return "55%";
792
+ if (column === 0) return "70%";
793
+ if (column === total - 1) return "42%";
794
+ return "55%";
953
795
  }
954
- function LoadingState({
955
- rows,
956
- columns,
957
- variant,
958
- labels,
959
- classNames,
960
- hasActions = false
961
- }) {
962
- const rowKeys = Array.from({ length: rows }, (_, i) => i);
963
- const dataColumns = Math.max(columns, 1);
964
- const columnCount = dataColumns + (hasActions ? 1 : 0);
965
- const columnKeys = Array.from({ length: columnCount }, (_, i) => i);
966
- return /* @__PURE__ */ jsxs(
967
- "div",
968
- {
969
- role: "status",
970
- "aria-busy": "true",
971
- "aria-live": "polite",
972
- "data-adapttable-part": "loading",
973
- className: cx(classNames.loading),
974
- children: [
975
- variant === "table" ? /* @__PURE__ */ jsxs("table", { "data-adapttable-part": "loading-table", children: [
976
- /* @__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(
977
- "span",
978
- {
979
- "data-adapttable-part": "loading-line",
980
- style: { width: loadingLineWidth(column, columnCount) }
981
- }
982
- ) }, column)) }) }),
983
- /* @__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(
984
- "span",
985
- {
986
- "data-adapttable-part": "loading-line",
987
- style: {
988
- width: loadingLineWidth(column, columnCount)
989
- }
990
- }
991
- ) }, column)) }, row)) })
992
- ] }) : /* @__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(
993
- "span",
994
- {
995
- "data-adapttable-part": "loading-line",
996
- style: {
997
- width: loadingLineWidth(column, columnKeys.length)
998
- }
999
- },
1000
- column
1001
- )) }, row)) }),
1002
- /* @__PURE__ */ jsx("span", { className: "adapttable-sr-only", children: labels.loading })
1003
- ]
1004
- }
1005
- );
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
+ });
1006
842
  }
1007
- function VisibilityToggle({
1008
- hidden,
1009
- name,
1010
- labels,
1011
- classNames,
1012
- onToggle
1013
- }) {
1014
- return /* @__PURE__ */ jsx(
1015
- "button",
1016
- {
1017
- type: "button",
1018
- "data-adapttable-part": "column-menu-visibility",
1019
- "data-active": !hidden || void 0,
1020
- "aria-pressed": !hidden,
1021
- "aria-label": `${hidden ? labels.showColumn : labels.hideColumn}: ${name}`,
1022
- className: classNames.columnMenuVisibility,
1023
- onClick: onToggle,
1024
- children: /* @__PURE__ */ jsx(EyeIcon, { off: hidden })
1025
- }
1026
- );
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
+ });
1027
857
  }
1028
- function RowName({
1029
- hidden,
1030
- name,
1031
- classNames
1032
- }) {
1033
- return /* @__PURE__ */ jsx(
1034
- "span",
1035
- {
1036
- "data-adapttable-part": "column-menu-label",
1037
- "data-hidden": hidden || void 0,
1038
- className: classNames.columnMenuLabel,
1039
- children: name
1040
- }
1041
- );
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
+ });
1042
866
  }
1043
- function PinToggle({
1044
- active,
1045
- actionLabel,
1046
- classNames,
1047
- onClick
1048
- }) {
1049
- return /* @__PURE__ */ jsx(
1050
- "button",
1051
- {
1052
- type: "button",
1053
- "data-adapttable-part": "column-menu-pin",
1054
- "data-active": active || void 0,
1055
- "aria-pressed": active,
1056
- "aria-label": actionLabel,
1057
- className: classNames.columnMenuPin,
1058
- onClick,
1059
- children: /* @__PURE__ */ jsx(PinIcon, {})
1060
- }
1061
- );
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
+ });
1062
879
  }
1063
- function ColumnMenuRowItem({
1064
- row,
1065
- layout,
1066
- labels,
1067
- classNames,
1068
- drag
1069
- }) {
1070
- const { key, name, hidden, pinned, index } = row;
1071
- return /* @__PURE__ */ jsxs(
1072
- "div",
1073
- {
1074
- "data-adapttable-part": "column-menu-item",
1075
- "data-hidden": hidden || void 0,
1076
- "data-pinned": pinned,
1077
- className: classNames.columnMenuItem,
1078
- style: { cursor: "grab" },
1079
- ...drag.rowDragProps(key, index),
1080
- ...drag.dropProps(index, layout.move),
1081
- ...drag.rowAttrs(key, index),
1082
- children: [
1083
- /* @__PURE__ */ jsx(
1084
- "span",
1085
- {
1086
- "data-adapttable-part": "column-menu-grip",
1087
- className: classNames.columnMenuGrip,
1088
- ...columnReorderKeyProps(
1089
- key,
1090
- index,
1091
- layout.move,
1092
- `${labels.moveLeft} / ${labels.moveRight}: ${name}`
1093
- ),
1094
- children: /* @__PURE__ */ jsx(GripIcon, {})
1095
- }
1096
- ),
1097
- /* @__PURE__ */ jsx(
1098
- VisibilityToggle,
1099
- {
1100
- hidden,
1101
- name,
1102
- labels,
1103
- classNames,
1104
- onToggle: () => layout.toggleVisible(key)
1105
- }
1106
- ),
1107
- /* @__PURE__ */ jsx(RowName, { hidden, name, classNames }),
1108
- /* @__PURE__ */ jsx(
1109
- PinToggle,
1110
- {
1111
- active: pinned !== void 0,
1112
- actionLabel: `${pinActionLabel(pinned, labels)}: ${name}`,
1113
- classNames,
1114
- onClick: () => layout.setPinned(key, nextPinSide(pinned))
1115
- }
1116
- )
1117
- ]
1118
- }
1119
- );
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
+ });
1120
918
  }
1121
- function ActionsMenuRowItem({
1122
- layout,
1123
- labels,
1124
- classNames
1125
- }) {
1126
- const hidden = layout.isHidden(ACTIONS_COLUMN_KEY);
1127
- const pinned = layout.state.pinned[ACTIONS_COLUMN_KEY] !== void 0;
1128
- const name = labels.actions;
1129
- return /* @__PURE__ */ jsxs(
1130
- "div",
1131
- {
1132
- "data-adapttable-part": "column-menu-item",
1133
- "data-actions": "",
1134
- "data-hidden": hidden || void 0,
1135
- "data-pinned": pinned ? "right" : void 0,
1136
- className: classNames.columnMenuItem,
1137
- children: [
1138
- /* @__PURE__ */ jsx(
1139
- VisibilityToggle,
1140
- {
1141
- hidden,
1142
- name,
1143
- labels,
1144
- classNames,
1145
- onToggle: () => layout.toggleVisible(ACTIONS_COLUMN_KEY)
1146
- }
1147
- ),
1148
- /* @__PURE__ */ jsx(RowName, { hidden, name, classNames }),
1149
- /* @__PURE__ */ jsx(
1150
- PinToggle,
1151
- {
1152
- active: pinned,
1153
- actionLabel: `${pinned ? labels.unpin : labels.pinRight}: ${name}`,
1154
- classNames,
1155
- onClick: () => layout.setPinned(ACTIONS_COLUMN_KEY, pinned ? void 0 : "right")
1156
- }
1157
- )
1158
- ]
1159
- }
1160
- );
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
+ });
1161
955
  }
1162
- function ColumnMenu({
1163
- allColumns,
1164
- layout,
1165
- labels,
1166
- classNames,
1167
- hasRowActions
1168
- }) {
1169
- const drag = useColumnDragState();
1170
- const { open, setOpen, rootRef, triggerRef } = useMenuPopover();
1171
- return /* @__PURE__ */ jsxs(
1172
- "div",
1173
- {
1174
- ref: rootRef,
1175
- "data-adapttable-part": "column-menu",
1176
- className: classNames.columnMenu,
1177
- style: { position: "relative" },
1178
- children: [
1179
- /* @__PURE__ */ jsx(
1180
- "button",
1181
- {
1182
- ref: triggerRef,
1183
- type: "button",
1184
- "aria-expanded": open,
1185
- "aria-haspopup": "true",
1186
- "data-adapttable-part": "column-menu-button",
1187
- "data-active": open || void 0,
1188
- className: classNames.columnMenuButton,
1189
- style: { flexShrink: 0, whiteSpace: "nowrap" },
1190
- onClick: () => setOpen((v) => !v),
1191
- children: labels.columns
1192
- }
1193
- ),
1194
- open && /* @__PURE__ */ jsxs(
1195
- "fieldset",
1196
- {
1197
- "aria-label": labels.columns,
1198
- "data-adapttable-part": "column-menu-panel",
1199
- className: classNames.columnMenuPanel,
1200
- style: MENU_PANEL_STYLE,
1201
- children: [
1202
- /* @__PURE__ */ jsx(
1203
- "div",
1204
- {
1205
- "data-adapttable-part": "column-menu-header",
1206
- className: classNames.columnMenuHeader,
1207
- children: /* @__PURE__ */ jsx(
1208
- "span",
1209
- {
1210
- "data-adapttable-part": "column-menu-title",
1211
- className: classNames.columnMenuTitle,
1212
- children: labels.columns
1213
- }
1214
- )
1215
- }
1216
- ),
1217
- columnMenuRows(allColumns, layout).map((row) => /* @__PURE__ */ jsx(
1218
- ColumnMenuRowItem,
1219
- {
1220
- row,
1221
- layout,
1222
- labels,
1223
- classNames,
1224
- drag
1225
- },
1226
- row.key
1227
- )),
1228
- hasRowActions && /* @__PURE__ */ jsxs(Fragment, { children: [
1229
- /* @__PURE__ */ jsx(
1230
- "hr",
1231
- {
1232
- "data-adapttable-part": "column-menu-separator",
1233
- className: classNames.columnMenuSeparator
1234
- }
1235
- ),
1236
- /* @__PURE__ */ jsx(
1237
- ActionsMenuRowItem,
1238
- {
1239
- layout,
1240
- labels,
1241
- classNames
1242
- }
1243
- )
1244
- ] }),
1245
- /* @__PURE__ */ jsx(
1246
- "button",
1247
- {
1248
- type: "button",
1249
- "data-adapttable-part": "column-menu-reset",
1250
- className: cx(classNames.columnMenuReset),
1251
- onClick: () => layout.reset(),
1252
- children: labels.resetColumns
1253
- }
1254
- )
1255
- ]
1256
- }
1257
- )
1258
- ]
1259
- }
1260
- );
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
+ });
1261
1024
  }
1262
- var RESIZE_HANDLE_STYLE = {
1263
- position: "absolute",
1264
- insetInlineEnd: 0,
1265
- top: 0,
1266
- height: "100%",
1267
- width: 8,
1268
- cursor: "col-resize",
1269
- touchAction: "none",
1270
- 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"
1271
1037
  };
1272
- var SELECTION_WIDTH = 44;
1273
- 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
+ */
1274
1047
  function scrollBoxStyle(maxHeight, scrollX) {
1275
- if (maxHeight != null) {
1276
- return { maxHeight, overflowX: "auto", overflowY: "auto" };
1277
- }
1278
- 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;
1279
1054
  }
1280
- function RowActionButtons({
1281
- row,
1282
- actions,
1283
- confirm,
1284
- cancelLabel,
1285
- classNames
1286
- }) {
1287
- return /* @__PURE__ */ jsx(Fragment, { children: actions.map((action) => {
1288
- if (action.isHidden?.(row)) return null;
1289
- const reason = resolveDisabledReason(action.disabledReason?.(row));
1290
- const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
1291
- const handleClick = disabled ? void 0 : (e) => {
1292
- e.stopPropagation();
1293
- runRowAction(action, row, confirm, cancelLabel);
1294
- };
1295
- return /* @__PURE__ */ jsx(
1296
- "button",
1297
- {
1298
- type: "button",
1299
- disabled,
1300
- title: reason,
1301
- "aria-label": action.label,
1302
- "data-adapttable-part": "action-button",
1303
- "data-color": action.color,
1304
- className: classNames.actionButton,
1305
- onClick: handleClick,
1306
- children: action.icon ?? action.label
1307
- },
1308
- action.key
1309
- );
1310
- }) });
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
+ }) });
1311
1076
  }
1312
- function ExpandButton({
1313
- expanded,
1314
- labels,
1315
- classNames,
1316
- onToggle
1317
- }) {
1318
- return /* @__PURE__ */ jsx(
1319
- "button",
1320
- {
1321
- type: "button",
1322
- "data-adapttable-part": "expand-button",
1323
- "data-expanded": expanded ? "" : void 0,
1324
- className: classNames.expandButton,
1325
- "aria-expanded": expanded,
1326
- "aria-label": expanded ? labels.collapseRow : labels.expandRow,
1327
- onClick: onToggle,
1328
- children: /* @__PURE__ */ jsx(ChevronIcon, { size: 14 })
1329
- }
1330
- );
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
+ });
1331
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
+ */
1332
1100
  function desktopRowPropsEqual(prev, next) {
1333
- 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;
1334
1102
  }
1335
1103
  function DesktopRowBase(props) {
1336
- const {
1337
- row,
1338
- index,
1339
- id,
1340
- table,
1341
- columns,
1342
- labels,
1343
- classNames,
1344
- selected,
1345
- expanded,
1346
- showActions,
1347
- rowActions,
1348
- confirm,
1349
- columnSpan,
1350
- pinOffset,
1351
- hasLeftPin,
1352
- hasRightPin,
1353
- actionsPinned,
1354
- rowClass,
1355
- clickable,
1356
- hasPrefetch,
1357
- onRowClick,
1358
- onPrefetch,
1359
- onToggleSelect,
1360
- onToggleExpand,
1361
- renderDetail,
1362
- measureElement
1363
- } = props;
1364
- const expandable = expanded !== void 0;
1365
- const leads = {
1366
- left: selected === void 0 ? 0 : SELECTION_WIDTH,
1367
- right: showActions ? ACTIONS_WIDTH : 0
1368
- };
1369
- const bodyPinStyle = (key) => pinnedCellStyle(pinOffset?.(key), PIN_Z.body, leads);
1370
- const rowProps = { ...table.getRowProps(row, index) };
1371
- delete rowProps.key;
1372
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1373
- /* @__PURE__ */ jsxs(
1374
- "tr",
1375
- {
1376
- ...rowProps,
1377
- ...rowClickProps(row, clickable ? onRowClick : void 0),
1378
- ref: measureElement,
1379
- "data-adapttable-part": "row",
1380
- "data-selected": selected ? "" : void 0,
1381
- "data-clickable": clickable ? "" : void 0,
1382
- className: cx(classNames.row, rowClass),
1383
- onMouseEnter: hasPrefetch ? () => onPrefetch(row) : void 0,
1384
- children: [
1385
- expandable && /* @__PURE__ */ jsx(
1386
- "td",
1387
- {
1388
- "data-adapttable-part": "expand-cell",
1389
- className: classNames.expandCell,
1390
- children: /* @__PURE__ */ jsx(
1391
- ExpandButton,
1392
- {
1393
- expanded,
1394
- labels,
1395
- classNames,
1396
- onToggle: () => onToggleExpand(id)
1397
- }
1398
- )
1399
- }
1400
- ),
1401
- selected !== void 0 && /* @__PURE__ */ jsx(
1402
- "td",
1403
- {
1404
- "data-adapttable-part": "selection-cell",
1405
- "data-pinned": hasLeftPin ? "left" : void 0,
1406
- style: edgePinStyle("left", hasLeftPin, PIN_Z.body),
1407
- className: cx(classNames.cell, classNames.selectionCell),
1408
- children: /* @__PURE__ */ jsx(
1409
- "input",
1410
- {
1411
- type: "checkbox",
1412
- "aria-label": labels.selectRow,
1413
- checked: selected,
1414
- onChange: () => onToggleSelect(id),
1415
- className: classNames.checkbox
1416
- }
1417
- )
1418
- }
1419
- ),
1420
- columns.map((column) => {
1421
- const pinStyle = bodyPinStyle(column.key);
1422
- return /* @__PURE__ */ jsx(
1423
- "td",
1424
- {
1425
- ...table.getCellProps(column, pinStyle && { style: pinStyle }),
1426
- "data-adapttable-part": "cell",
1427
- "data-pinned": pinOffset?.(column.key)?.side,
1428
- className: classNames.cell,
1429
- children: column.Cell ? /* @__PURE__ */ jsx(column.Cell, { row, rowIndex: index }) : column.accessor?.(row)
1430
- },
1431
- column.key
1432
- );
1433
- }),
1434
- showActions && /* @__PURE__ */ jsx(
1435
- "td",
1436
- {
1437
- "data-adapttable-part": "actions-cell",
1438
- "data-pinned": hasRightPin || actionsPinned ? "right" : void 0,
1439
- style: edgePinStyle(
1440
- "right",
1441
- hasRightPin || actionsPinned,
1442
- PIN_Z.body
1443
- ),
1444
- className: cx(classNames.cell, classNames.actionsCell),
1445
- children: /* @__PURE__ */ jsx(
1446
- RowActionButtons,
1447
- {
1448
- row,
1449
- actions: rowActions,
1450
- confirm,
1451
- cancelLabel: labels.cancel,
1452
- classNames
1453
- }
1454
- )
1455
- }
1456
- )
1457
- ]
1458
- }
1459
- ),
1460
- expandable && expanded && /* @__PURE__ */ jsx("tr", { "data-adapttable-part": "detail-row", className: classNames.detailRow, children: /* @__PURE__ */ jsx(
1461
- "td",
1462
- {
1463
- colSpan: columnSpan,
1464
- "data-adapttable-part": "detail-cell",
1465
- className: classNames.detailCell,
1466
- children: renderDetail(row)
1467
- }
1468
- ) })
1469
- ] });
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
+ })] });
1470
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
+ */
1471
1190
  function createDesktopRow() {
1472
- return memo(DesktopRowBase, desktopRowPropsEqual);
1191
+ return memo(DesktopRowBase, desktopRowPropsEqual);
1473
1192
  }
1474
- function DesktopTable({
1475
- table,
1476
- rows,
1477
- rowActions,
1478
- confirm,
1479
- getRowId,
1480
- classNames,
1481
- prefetch,
1482
- onRowClick,
1483
- rowClassName,
1484
- renderRowDetail,
1485
- summaryRow,
1486
- expansion,
1487
- rowEntries,
1488
- paddingTop = 0,
1489
- paddingBottom = 0,
1490
- measureElement,
1491
- stickyHeader = false,
1492
- stickyTop = 0,
1493
- pinOffset,
1494
- maxHeight,
1495
- virtualScrollRef,
1496
- setWidth,
1497
- columnWidths,
1498
- resizeLabel = "Resize column",
1499
- actionsPinned = false
1500
- }) {
1501
- const { columns, selection, labels, showActions, entries, columnSpan } = tableRenderModel({
1502
- table,
1503
- rows,
1504
- rowActions,
1505
- getRowId,
1506
- rowEntries,
1507
- renderRowDetail,
1508
- expansion
1509
- });
1510
- const stickActions = showActions && actionsPinned;
1511
- const expansionState = renderRowDetail ? expansion : void 0;
1512
- const expandable = expansionState !== void 0;
1513
- const live = useRef({
1514
- selection,
1515
- expansion: expansionState,
1516
- onRowClick,
1517
- prefetch,
1518
- renderRowDetail
1519
- });
1520
- live.current = {
1521
- selection,
1522
- expansion: expansionState,
1523
- onRowClick,
1524
- prefetch,
1525
- renderRowDetail
1526
- };
1527
- const onToggleSelect = useCallback(
1528
- (id) => live.current.selection?.toggle(id),
1529
- []
1530
- );
1531
- const onToggleExpand = useCallback(
1532
- (id) => live.current.expansion?.toggle(id),
1533
- []
1534
- );
1535
- const handleRowClick = useCallback(
1536
- (row) => live.current.onRowClick?.(row),
1537
- []
1538
- );
1539
- const handlePrefetch = useCallback(
1540
- (row) => live.current.prefetch?.(row),
1541
- []
1542
- );
1543
- const renderDetail = useCallback(
1544
- (row) => live.current.renderRowDetail?.(row),
1545
- []
1546
- );
1547
- const Row = useMemo(() => createDesktopRow(), []);
1548
- const { ref: overflowRef, overflowing } = useHorizontalOverflow();
1549
- const hasPinned = columns.some((c) => pinOffset?.(c.key) != null) || stickActions;
1550
- const inScrollBox = maxHeight != null || hasPinned || overflowing;
1551
- const stickyStyle = stickyHeader ? {
1552
- position: "sticky",
1553
- top: inScrollBox ? 0 : stickyTop,
1554
- zIndex: PIN_Z.header
1555
- } : void 0;
1556
- const stickyAttr = stickyHeader || void 0;
1557
- const leads = {
1558
- left: selection ? SELECTION_WIDTH : 0,
1559
- right: showActions ? ACTIONS_WIDTH : 0
1560
- };
1561
- const hasLeftPin = columns.some((c) => pinOffset?.(c.key)?.side === "left");
1562
- const hasRightPin = columns.some((c) => pinOffset?.(c.key)?.side === "right");
1563
- const pinSignature = columns.map((c) => {
1564
- const pin = pinOffset?.(c.key);
1565
- return pin ? `${c.key}:${pin.side}:${pin.inset}` : "";
1566
- }).join("|");
1567
- const headPinStyle = (key) => pinnedCellStyle(pinOffset?.(key), PIN_Z.headerPinned, leads);
1568
- const headStyle = (column) => {
1569
- const key = column.key;
1570
- const pin = headPinStyle(key);
1571
- const width = pin ? pinnedColumnWidth(column, columnWidths) : columnWidths?.[key];
1572
- if (!stickyStyle && !pin && width == null && !setWidth) return void 0;
1573
- const merged = {
1574
- ...stickyStyle,
1575
- ...pin,
1576
- ...width != null && { width }
1577
- };
1578
- if (setWidth && !merged.position) merged.position = "relative";
1579
- return merged;
1580
- };
1581
- const edgeHeadStyle = (side, active) => {
1582
- const edge = edgePinStyle(side, active, PIN_Z.headerPinned);
1583
- if (!stickyStyle && !edge) return void 0;
1584
- return { ...stickyStyle, ...edge };
1585
- };
1586
- const columnName = (column) => typeof column.header === "string" ? column.header : column.key;
1587
- const minWidth = tableMinWidth(columns, {
1588
- widths: columnWidths,
1589
- extra: (selection ? SELECTION_WIDTH : 0) + (showActions ? ACTIONS_WIDTH : 0)
1590
- });
1591
- const groups = headerGroupRow(columns);
1592
- const summary = summaryRow?.(rows);
1593
- const groupPad = /* @__PURE__ */ jsx("th", { "data-adapttable-part": "group-cell", className: classNames.groupCell });
1594
- const summaryPad = /* @__PURE__ */ jsx(
1595
- "td",
1596
- {
1597
- "data-adapttable-part": "summary-cell",
1598
- className: classNames.summaryCell
1599
- }
1600
- );
1601
- const tableEl = /* @__PURE__ */ jsxs(
1602
- "table",
1603
- {
1604
- ...table.getTableProps(),
1605
- "data-adapttable-part": "table",
1606
- className: classNames.table,
1607
- style: minWidth > 0 ? { minWidth } : void 0,
1608
- children: [
1609
- /* @__PURE__ */ jsxs("thead", { "data-adapttable-part": "thead", className: classNames.thead, children: [
1610
- groups && /* @__PURE__ */ jsxs("tr", { "data-adapttable-part": "group-row", className: classNames.groupRow, children: [
1611
- expandable && groupPad,
1612
- selection && groupPad,
1613
- groups.map((group) => /* @__PURE__ */ jsx(
1614
- "th",
1615
- {
1616
- colSpan: group.span,
1617
- "data-adapttable-part": "group-cell",
1618
- className: classNames.groupCell,
1619
- children: group.label
1620
- },
1621
- group.key
1622
- )),
1623
- showActions && groupPad
1624
- ] }),
1625
- /* @__PURE__ */ jsxs(
1626
- "tr",
1627
- {
1628
- ...table.getHeaderRowProps(),
1629
- "data-adapttable-part": "header-row",
1630
- className: classNames.headerRow,
1631
- children: [
1632
- expandable && /* @__PURE__ */ jsx(
1633
- "th",
1634
- {
1635
- "aria-label": labels.expandRow,
1636
- "data-adapttable-part": "expand-header",
1637
- "data-sticky": stickyAttr,
1638
- style: stickyStyle,
1639
- className: cx(classNames.headerCell, classNames.expandHeader)
1640
- }
1641
- ),
1642
- selection && /* @__PURE__ */ jsx(
1643
- "th",
1644
- {
1645
- "data-adapttable-part": "selection-header",
1646
- "data-sticky": stickyAttr,
1647
- "data-pinned": hasLeftPin ? "left" : void 0,
1648
- style: edgeHeadStyle("left", hasLeftPin),
1649
- className: cx(classNames.headerCell, classNames.selectionCell),
1650
- children: /* @__PURE__ */ jsx(
1651
- "input",
1652
- {
1653
- type: "checkbox",
1654
- "aria-label": labels.selectAll,
1655
- checked: selection.headerState === "all",
1656
- ref: (el) => {
1657
- if (el) el.indeterminate = selection.headerState === "some";
1658
- },
1659
- onChange: selection.toggleAll,
1660
- className: classNames.checkbox
1661
- }
1662
- )
1663
- }
1664
- ),
1665
- columns.map((column) => {
1666
- const localStyle = headStyle(column);
1667
- const headerProps = table.getHeaderCellProps(
1668
- column,
1669
- localStyle && { style: localStyle }
1670
- );
1671
- const active = table.sortBy === column.key;
1672
- const sortButtonProps = table.getSortButtonProps(column);
1673
- const sortIndex = sortButtonProps["data-sort-index"];
1674
- return /* @__PURE__ */ jsxs(
1675
- "th",
1676
- {
1677
- ...headerProps,
1678
- "data-adapttable-part": "header-cell",
1679
- "data-sorted": active ? table.sortDir : void 0,
1680
- "data-sticky": stickyAttr,
1681
- "data-pinned": pinOffset?.(column.key)?.side,
1682
- className: classNames.headerCell,
1683
- children: [
1684
- column.sortable ? /* @__PURE__ */ jsxs(
1685
- "button",
1686
- {
1687
- ...sortButtonProps,
1688
- "data-adapttable-part": "sort-button",
1689
- className: classNames.sortButton,
1690
- children: [
1691
- column.header,
1692
- typeof sortIndex === "number" && /* @__PURE__ */ jsx(
1693
- "span",
1694
- {
1695
- "data-adapttable-part": "sort-index",
1696
- className: classNames.sortIndex,
1697
- children: sortIndex
1698
- }
1699
- ),
1700
- /* @__PURE__ */ jsxs("span", { "aria-hidden": true, children: [
1701
- " ",
1702
- sortGlyph(active, table.sortDir)
1703
- ] })
1704
- ]
1705
- }
1706
- ) : column.header,
1707
- setWidth && /* @__PURE__ */ jsx(
1708
- "span",
1709
- {
1710
- ...columnResizeHandleProps(
1711
- column.key,
1712
- setWidth,
1713
- `${resizeLabel}: ${columnName(column)}`
1714
- ),
1715
- "data-adapttable-part": "resize-handle",
1716
- className: classNames.resizeHandle,
1717
- style: RESIZE_HANDLE_STYLE
1718
- }
1719
- )
1720
- ]
1721
- },
1722
- column.key
1723
- );
1724
- }),
1725
- showActions && /* @__PURE__ */ jsx(
1726
- "th",
1727
- {
1728
- "data-adapttable-part": "actions-header",
1729
- "data-sticky": stickyAttr,
1730
- "data-pinned": hasRightPin || stickActions ? "right" : void 0,
1731
- style: edgeHeadStyle("right", hasRightPin || stickActions),
1732
- className: cx(classNames.headerCell, classNames.actionsCell),
1733
- children: labels.actions
1734
- }
1735
- )
1736
- ]
1737
- }
1738
- )
1739
- ] }),
1740
- /* @__PURE__ */ jsxs("tbody", { "data-adapttable-part": "tbody", className: classNames.tbody, children: [
1741
- paddingTop > 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
1742
- "td",
1743
- {
1744
- colSpan: columnSpan,
1745
- style: { height: paddingTop, padding: 0 }
1746
- }
1747
- ) }),
1748
- entries.map(({ row, index, key }) => {
1749
- const id = getRowId(row);
1750
- return /* @__PURE__ */ jsx(
1751
- Row,
1752
- {
1753
- row,
1754
- index,
1755
- id,
1756
- table,
1757
- columns,
1758
- labels,
1759
- classNames,
1760
- selected: selection ? selection.isSelected(id) : void 0,
1761
- expanded: expansionState ? expansionState.isExpanded(id) : void 0,
1762
- showActions,
1763
- rowActions,
1764
- confirm,
1765
- columnSpan,
1766
- columnWidths,
1767
- pinOffset,
1768
- pinSignature,
1769
- hasLeftPin,
1770
- hasRightPin,
1771
- actionsPinned: stickActions,
1772
- rowClass: rowClassName?.(row, index),
1773
- clickable: Boolean(onRowClick),
1774
- hasPrefetch: Boolean(prefetch),
1775
- onRowClick: handleRowClick,
1776
- onPrefetch: handlePrefetch,
1777
- onToggleSelect,
1778
- onToggleExpand,
1779
- renderDetail,
1780
- measureElement
1781
- },
1782
- key
1783
- );
1784
- }),
1785
- paddingBottom > 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
1786
- "td",
1787
- {
1788
- colSpan: columnSpan,
1789
- style: { height: paddingBottom, padding: 0 }
1790
- }
1791
- ) })
1792
- ] }),
1793
- summary && /* @__PURE__ */ jsx("tfoot", { "data-adapttable-part": "summary", className: classNames.summary, children: /* @__PURE__ */ jsxs(
1794
- "tr",
1795
- {
1796
- "data-adapttable-part": "summary-row",
1797
- className: classNames.summaryRow,
1798
- children: [
1799
- expandable && summaryPad,
1800
- selection && summaryPad,
1801
- columns.map((column) => /* @__PURE__ */ jsx(
1802
- "td",
1803
- {
1804
- "data-adapttable-part": "summary-cell",
1805
- className: classNames.summaryCell,
1806
- children: summary[column.key]
1807
- },
1808
- column.key
1809
- )),
1810
- showActions && summaryPad
1811
- ]
1812
- }
1813
- ) })
1814
- ]
1815
- }
1816
- );
1817
- return /* @__PURE__ */ jsx(
1818
- "div",
1819
- {
1820
- ref: (node) => {
1821
- overflowRef(node);
1822
- virtualScrollRef?.(node);
1823
- },
1824
- "data-adapttable-part": "scroll-box",
1825
- style: scrollBoxStyle(maxHeight, hasPinned || overflowing),
1826
- children: tableEl
1827
- }
1828
- );
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
+ });
1829
1464
  }
1830
- function MobileCards({
1831
- table,
1832
- rows,
1833
- rowActions,
1834
- confirm,
1835
- getRowId,
1836
- classNames,
1837
- onRowClick,
1838
- rowClassName,
1839
- renderRowDetail,
1840
- summaryRow,
1841
- expansion,
1842
- rowEntries,
1843
- paddingTop = 0,
1844
- paddingBottom = 0,
1845
- measureElement
1846
- }) {
1847
- const { columns, selection, labels } = table;
1848
- const entries = resolveVirtualRows(rows, getRowId, rowEntries);
1849
- const expansionState = renderRowDetail ? expansion : void 0;
1850
- const summary = summaryRow?.(rows);
1851
- return /* @__PURE__ */ jsxs(
1852
- "ul",
1853
- {
1854
- ...table.getTableProps({ role: void 0 }),
1855
- "data-adapttable-part": "cards",
1856
- className: classNames.cards,
1857
- style: { listStyle: "none", margin: 0, padding: 0 },
1858
- children: [
1859
- paddingTop > 0 && /* @__PURE__ */ jsx(
1860
- "li",
1861
- {
1862
- "aria-hidden": true,
1863
- "data-adapttable-part": "virtual-spacer",
1864
- style: { height: paddingTop }
1865
- }
1866
- ),
1867
- entries.map(({ row, index, key }) => {
1868
- const id = getRowId(row);
1869
- const expanded = expansionState?.isExpanded(id) ?? false;
1870
- return /* @__PURE__ */ jsxs(
1871
- "li",
1872
- {
1873
- ...rowClickProps(row, onRowClick),
1874
- ref: measureElement,
1875
- "data-index": index,
1876
- "data-adapttable-part": "card",
1877
- "data-selected": selection?.isSelected(id) ? "" : void 0,
1878
- "data-clickable": onRowClick ? "" : void 0,
1879
- className: cx(classNames.card, rowClassName?.(row, index)),
1880
- children: [
1881
- selection && /* @__PURE__ */ jsx(
1882
- "input",
1883
- {
1884
- type: "checkbox",
1885
- "aria-label": labels.selectRow,
1886
- checked: selection.isSelected(id),
1887
- onChange: () => selection.toggle(id),
1888
- className: classNames.checkbox
1889
- }
1890
- ),
1891
- expansionState && /* @__PURE__ */ jsx(
1892
- ExpandButton,
1893
- {
1894
- expanded,
1895
- labels,
1896
- classNames,
1897
- onToggle: () => expansionState.toggle(id)
1898
- }
1899
- ),
1900
- columns.map((column) => /* @__PURE__ */ jsxs(
1901
- "div",
1902
- {
1903
- "data-adapttable-part": "card-row",
1904
- className: classNames.cardRow,
1905
- children: [
1906
- /* @__PURE__ */ jsx(
1907
- "span",
1908
- {
1909
- "data-adapttable-part": "card-label",
1910
- className: classNames.cardLabel,
1911
- children: cardLabel(column)
1912
- }
1913
- ),
1914
- /* @__PURE__ */ jsx(
1915
- "span",
1916
- {
1917
- "data-adapttable-part": "card-value",
1918
- className: classNames.cardValue,
1919
- children: column.Cell ? /* @__PURE__ */ jsx(column.Cell, { row, rowIndex: index }) : column.accessor?.(row)
1920
- }
1921
- )
1922
- ]
1923
- },
1924
- column.key
1925
- )),
1926
- rowActions && rowActions.length > 0 && /* @__PURE__ */ jsx(
1927
- "div",
1928
- {
1929
- "data-adapttable-part": "card-actions",
1930
- className: classNames.actionsCell,
1931
- children: /* @__PURE__ */ jsx(
1932
- RowActionButtons,
1933
- {
1934
- row,
1935
- actions: rowActions,
1936
- confirm,
1937
- cancelLabel: labels.cancel,
1938
- classNames
1939
- }
1940
- )
1941
- }
1942
- ),
1943
- expanded && // Inside the measured card `<li>`, so the virtualizer's size
1944
- // measurement tracks the open detail panel.
1945
- /* @__PURE__ */ jsx(
1946
- "div",
1947
- {
1948
- "data-adapttable-part": "card-detail",
1949
- className: classNames.cardDetail,
1950
- children: renderRowDetail(row)
1951
- }
1952
- )
1953
- ]
1954
- },
1955
- key
1956
- );
1957
- }),
1958
- paddingBottom > 0 && /* @__PURE__ */ jsx(
1959
- "li",
1960
- {
1961
- "aria-hidden": true,
1962
- "data-adapttable-part": "virtual-spacer",
1963
- style: { height: paddingBottom }
1964
- }
1965
- ),
1966
- summary && /* @__PURE__ */ jsx(
1967
- "li",
1968
- {
1969
- "data-adapttable-part": "summary-card",
1970
- className: classNames.summaryCard,
1971
- children: columns.filter((column) => summary[column.key] !== void 0).map((column) => /* @__PURE__ */ jsxs(
1972
- "div",
1973
- {
1974
- "data-adapttable-part": "card-row",
1975
- className: classNames.cardRow,
1976
- children: [
1977
- /* @__PURE__ */ jsx(
1978
- "span",
1979
- {
1980
- "data-adapttable-part": "card-label",
1981
- className: classNames.cardLabel,
1982
- children: cardLabel(column)
1983
- }
1984
- ),
1985
- /* @__PURE__ */ jsx(
1986
- "span",
1987
- {
1988
- "data-adapttable-part": "card-value",
1989
- className: classNames.cardValue,
1990
- children: summary[column.key]
1991
- }
1992
- )
1993
- ]
1994
- },
1995
- column.key
1996
- ))
1997
- }
1998
- )
1999
- ]
2000
- }
2001
- );
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
+ });
2002
1570
  }
2003
1571
  function sortGlyph(active, dir) {
2004
- if (!active) return "\u2195";
2005
- return dir === "asc" ? "\u2191" : "\u2193";
1572
+ if (!active) return "";
1573
+ return dir === "asc" ? "" : "";
2006
1574
  }
2007
1575
  function cardLabel(column) {
2008
- return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
1576
+ return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
2009
1577
  }
2010
- var NO_CLASSNAMES = {};
2011
- function DataTableBody({
2012
- chrome,
2013
- props,
2014
- classNames,
2015
- confirm,
2016
- getRowId,
2017
- virtualization,
2018
- virtualScrollRef,
2019
- labels
2020
- }) {
2021
- const rowActions = chrome.columnLayout.isHidden(ACTIONS_COLUMN_KEY) ? void 0 : props.rowActions;
2022
- const actionsPinned = (rowActions?.length ?? 0) > 0 && chrome.columnLayout.state.pinned[ACTIONS_COLUMN_KEY] !== void 0;
2023
- if (chrome.body === "skeleton") {
2024
- return /* @__PURE__ */ jsx(Fragment, { children: props.slots?.skeleton ?? props.loadingState ?? /* @__PURE__ */ jsx(
2025
- LoadingState,
2026
- {
2027
- rows: props.skeletonRows ?? props.source.limit,
2028
- columns: chrome.table.columns.length,
2029
- variant: chrome.isMobile ? "cards" : "table",
2030
- labels,
2031
- classNames,
2032
- hasActions: (rowActions?.length ?? 0) > 0
2033
- }
2034
- ) });
2035
- }
2036
- if (chrome.body === "empty") {
2037
- const noResults = chrome.emptyVariant === "noResults";
2038
- return /* @__PURE__ */ jsx(Fragment, { children: props.slots?.empty ?? props.emptyState ?? /* @__PURE__ */ jsxs("output", { "data-adapttable-part": "empty", className: classNames.empty, children: [
2039
- noResults ? labels.noResults : labels.noData,
2040
- noResults && /* @__PURE__ */ jsx(
2041
- "button",
2042
- {
2043
- type: "button",
2044
- "data-adapttable-part": "empty-clear",
2045
- className: classNames.emptyClear,
2046
- onClick: chrome.clearFilters,
2047
- children: labels.clearAll
2048
- }
2049
- )
2050
- ] }) });
2051
- }
2052
- const Renderer = chrome.isMobile ? MobileCards : DesktopTable;
2053
- return /* @__PURE__ */ jsx(
2054
- Renderer,
2055
- {
2056
- table: chrome.table,
2057
- rows: props.source.rows,
2058
- rowActions,
2059
- actionsPinned,
2060
- confirm,
2061
- getRowId,
2062
- classNames,
2063
- prefetch: props.prefetch,
2064
- onRowClick: props.onRowClick,
2065
- rowClassName: props.rowClassName,
2066
- renderRowDetail: props.renderRowDetail,
2067
- summaryRow: props.summaryRow,
2068
- expansion: chrome.detail?.expansion,
2069
- rowEntries: virtualization.enabled ? virtualization.rows : void 0,
2070
- paddingTop: virtualization.paddingTop,
2071
- paddingBottom: virtualization.paddingBottom,
2072
- measureElement: virtualization.measureElement,
2073
- stickyHeader: props.stickyHeader,
2074
- stickyTop: props.stickyTop,
2075
- pinOffset: chrome.columnLayout.pinOffset,
2076
- maxHeight: props.maxHeight,
2077
- virtualScrollRef,
2078
- setWidth: props.resizableColumns ? chrome.columnLayout.setWidth : void 0,
2079
- columnWidths: chrome.columnLayout.state.widths,
2080
- resizeLabel: labels.resizeColumn
2081
- }
2082
- );
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
+ });
2083
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
+ */
2084
1641
  function DataTable(props) {
2085
- const {
2086
- data,
2087
- total,
2088
- loading,
2089
- onQueryChange,
2090
- urlAdapter,
2091
- urlKey,
2092
- searchPlaceholder,
2093
- sortByOptions,
2094
- dir,
2095
- hideSearch,
2096
- filtersMode = "popover",
2097
- bulkActions,
2098
- classNames = NO_CLASSNAMES,
2099
- toolbar: customToolbar
2100
- } = props;
2101
- const density = props.density ?? "comfortable";
2102
- const { source, runtime } = useTableData({
2103
- locale: props.locale,
2104
- source: props.source,
2105
- data,
2106
- total,
2107
- loading,
2108
- onQueryChange,
2109
- adapter: props.urlSync === false ? void 0 : urlAdapter,
2110
- enabled: props.urlSync,
2111
- urlKey,
2112
- columns: props.columns,
2113
- filters: props.filters
2114
- });
2115
- const autoForm = runtime.defs.length > 0 ? /* @__PURE__ */ jsx(
2116
- AutoFilterForm,
2117
- {
2118
- defs: runtime.defs,
2119
- source,
2120
- classNames,
2121
- labels: props.labels
2122
- }
2123
- ) : void 0;
2124
- const filters = isDeclarativeFilters(props.filters) || props.filters === void 0 ? autoForm : props.filters;
2125
- const chromeProps = {
2126
- ...props,
2127
- source,
2128
- filters,
2129
- filterLabels: { ...runtime.filterLabels, ...props.filterLabels }
2130
- };
2131
- const chrome = useTableChrome(chromeProps);
2132
- const { table, confirm, getRowId } = chrome;
2133
- const { labels } = table;
2134
- const [filtersOpen, setFiltersOpen] = useState(false);
2135
- const filtersTrigger = useFilterTriggerToggle(filtersOpen, setFiltersOpen);
2136
- const rootRef = useRef(null);
2137
- useChromeScrollReset(rootRef, chrome, chromeProps);
2138
- const bodyData = useChromeBodyData(chrome, chromeProps);
2139
- const { virtualization, canLoadMore } = bodyData;
2140
- const loadMoreRef = bodyData.loadMoreRef;
2141
- const searchProps = table.getSearchInputProps(
2142
- searchPlaceholder ? { placeholder: searchPlaceholder } : void 0
2143
- );
2144
- const sortOptions = sortByOptions ?? (chrome.isMobile ? table.sortByOptions : void 0);
2145
- const filtersButton = /* @__PURE__ */ jsxs(
2146
- "button",
2147
- {
2148
- type: "button",
2149
- "aria-expanded": filtersMode === "popover" ? filtersOpen : void 0,
2150
- "data-active": filtersOpen || void 0,
2151
- "data-adapttable-part": "filters-button",
2152
- className: classNames.filtersButton,
2153
- style: { flexShrink: 0, whiteSpace: "nowrap" },
2154
- onPointerDown: filtersTrigger.onPointerDown,
2155
- onClick: filtersTrigger.onClick,
2156
- children: [
2157
- /* @__PURE__ */ jsx(
2158
- "span",
2159
- {
2160
- "data-adapttable-part": "filters-icon",
2161
- className: classNames.filtersIcon,
2162
- style: { display: "inline-flex" },
2163
- children: /* @__PURE__ */ jsx(FiltersIcon, {})
2164
- }
2165
- ),
2166
- labels.filters,
2167
- chrome.activeFilterCount > 0 && /* @__PURE__ */ jsx(
2168
- "span",
2169
- {
2170
- "data-adapttable-part": "filters-count",
2171
- className: classNames.filtersCount,
2172
- children: chrome.activeFilterCount
2173
- }
2174
- )
2175
- ]
2176
- }
2177
- );
2178
- return /* @__PURE__ */ jsxs(
2179
- "div",
2180
- {
2181
- ref: rootRef,
2182
- dir,
2183
- "data-adapttable-part": "root",
2184
- "data-mobile": chrome.isMobile || void 0,
2185
- "data-density": density,
2186
- "data-refreshing": chrome.isRefreshing || void 0,
2187
- "aria-busy": chrome.isRefreshing || void 0,
2188
- className: cx("adapttable", classNames.root),
2189
- children: [
2190
- /* @__PURE__ */ jsxs(
2191
- "div",
2192
- {
2193
- "data-adapttable-part": "toolbar",
2194
- className: classNames.toolbar,
2195
- style: {
2196
- display: "flex",
2197
- flexWrap: "wrap",
2198
- alignItems: "center",
2199
- rowGap: 8
2200
- },
2201
- children: [
2202
- !hideSearch && /* @__PURE__ */ jsxs(
2203
- "span",
2204
- {
2205
- "data-adapttable-part": "search-field",
2206
- className: classNames.searchField,
2207
- style: {
2208
- flex: 1,
2209
- minWidth: 0,
2210
- display: "inline-flex",
2211
- alignItems: "center"
2212
- },
2213
- children: [
2214
- /* @__PURE__ */ jsx(
2215
- "span",
2216
- {
2217
- "data-adapttable-part": "search-icon",
2218
- className: classNames.searchIcon,
2219
- style: { display: "inline-flex" },
2220
- children: /* @__PURE__ */ jsx(SearchIcon, { size: 14 })
2221
- }
2222
- ),
2223
- /* @__PURE__ */ jsx(
2224
- "input",
2225
- {
2226
- ...searchProps,
2227
- "data-adapttable-part": "search",
2228
- className: classNames.search,
2229
- style: { flex: 1, minWidth: 0 }
2230
- }
2231
- )
2232
- ]
2233
- }
2234
- ),
2235
- sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxs("label", { children: [
2236
- labels.sortBy,
2237
- " ",
2238
- /* @__PURE__ */ jsxs(
2239
- "select",
2240
- {
2241
- "aria-label": labels.sortBy,
2242
- "data-adapttable-part": "sort-select",
2243
- className: classNames.sortSelect,
2244
- value: source.sortBy ?? "",
2245
- onChange: (e) => source.setSort(
2246
- e.currentTarget.value || void 0,
2247
- source.sortDir ?? "asc"
2248
- ),
2249
- children: [
2250
- /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
2251
- sortOptions.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
2252
- ]
2253
- }
2254
- )
2255
- ] }),
2256
- customToolbar,
2257
- filters && (filtersMode === "popover" ? /* @__PURE__ */ jsx(
2258
- FilterPopover,
2259
- {
2260
- open: filtersOpen,
2261
- onClose: () => setFiltersOpen(false),
2262
- filters,
2263
- activeFilterCount: chrome.activeFilterCount,
2264
- onClearFilters: chrome.clearFilters,
2265
- labels,
2266
- dir,
2267
- classNames,
2268
- children: filtersButton
2269
- }
2270
- ) : filtersButton),
2271
- props.enableColumnMenu && !chrome.isMobile && /* @__PURE__ */ jsx(
2272
- ColumnMenu,
2273
- {
2274
- allColumns: chrome.allColumns,
2275
- layout: chrome.columnLayout,
2276
- labels,
2277
- classNames,
2278
- hasRowActions: (props.rowActions?.length ?? 0) > 0
2279
- }
2280
- ),
2281
- props.savedViews && // The menu must capture/apply through the SAME URL backend and
2282
- // namespace the table reads, so those default from the table's
2283
- // own props (explicit option values still win).
2284
- /* @__PURE__ */ jsx(
2285
- SavedViewsMenu,
2286
- {
2287
- options: { adapter: urlAdapter, urlKey, ...props.savedViews },
2288
- labels,
2289
- classNames
2290
- }
2291
- ),
2292
- canLoadMore && /* @__PURE__ */ jsx(
2293
- RowsPerPageSelect,
2294
- {
2295
- source,
2296
- labels,
2297
- classNames
2298
- }
2299
- )
2300
- ]
2301
- }
2302
- ),
2303
- filters && filtersMode === "drawer" && /* @__PURE__ */ jsx(
2304
- FilterPanel,
2305
- {
2306
- open: filtersOpen,
2307
- onClose: () => setFiltersOpen(false),
2308
- filters,
2309
- activeFilterCount: chrome.activeFilterCount,
2310
- onClearFilters: chrome.clearFilters,
2311
- labels,
2312
- dir,
2313
- classNames
2314
- }
2315
- ),
2316
- /* @__PURE__ */ jsx(
2317
- Chips,
2318
- {
2319
- chips: chrome.mergedChips,
2320
- onClearAll: chrome.clearFilters,
2321
- labels,
2322
- classNames
2323
- }
2324
- ),
2325
- table.selection && bulkActions && /* @__PURE__ */ jsx(
2326
- BulkBar,
2327
- {
2328
- selection: table.selection,
2329
- total: source.total,
2330
- bulkActions,
2331
- confirm,
2332
- labels,
2333
- classNames
2334
- }
2335
- ),
2336
- chrome.isRefreshing && // Native indeterminate progress (no `value`) — implicit progressbar
2337
- // role with correct semantics on every device.
2338
- /* @__PURE__ */ jsx(
2339
- "progress",
2340
- {
2341
- "aria-label": labels.loading,
2342
- "data-adapttable-part": "refresh-indicator",
2343
- className: classNames.refreshIndicator
2344
- }
2345
- ),
2346
- source.error ? /* @__PURE__ */ jsx(
2347
- ErrorState,
2348
- {
2349
- error: source.error,
2350
- labels,
2351
- onRetry: source.refetch ? () => void source.refetch?.() : void 0,
2352
- classNames
2353
- }
2354
- ) : /* @__PURE__ */ jsx(
2355
- DataTableBody,
2356
- {
2357
- chrome,
2358
- props: chromeProps,
2359
- classNames,
2360
- confirm,
2361
- getRowId,
2362
- virtualization,
2363
- virtualScrollRef: bodyData.virtualScrollRef,
2364
- labels
2365
- }
2366
- ),
2367
- canLoadMore && source.hasNextPage && /* @__PURE__ */ jsx(
2368
- "div",
2369
- {
2370
- ref: loadMoreRef,
2371
- "data-adapttable-part": "load-more",
2372
- className: classNames.loadMore,
2373
- children: /* @__PURE__ */ jsx(
2374
- "button",
2375
- {
2376
- type: "button",
2377
- disabled: source.isFetchingNextPage,
2378
- "data-adapttable-part": "load-more-button",
2379
- className: classNames.loadMoreButton,
2380
- onClick: () => source.fetchNextPage(),
2381
- children: labels.loadMore
2382
- }
2383
- )
2384
- }
2385
- ),
2386
- chrome.showFooter && /* @__PURE__ */ jsx(
2387
- Footer,
2388
- {
2389
- pagination: table.pagination,
2390
- source,
2391
- labels,
2392
- classNames
2393
- }
2394
- )
2395
- ]
2396
- }
2397
- );
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
+ });
2398
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 };
2399
1877
 
2400
- export { AutoFilterForm, DataTable, FilterPanel, FilterPopover, FiltersIcon, SavedViewsMenu, SearchIcon, cx };
2401
- //# sourceMappingURL=index.js.map
2402
1878
  //# sourceMappingURL=index.js.map