@adapttable/mantine 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.cjs CHANGED
@@ -1,2005 +1,1975 @@
1
- 'use strict';
2
-
3
- var core = require('@adapttable/core');
4
- var core$1 = require('@mantine/core');
5
- var hooks = require('@mantine/hooks');
6
- var react = require('react');
7
- var jsxRuntime = require('react/jsx-runtime');
8
-
9
- // src/DataTable.tsx
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _adapttable_core = require("@adapttable/core");
3
+ let _mantine_core = require("@mantine/core");
4
+ let _mantine_hooks = require("@mantine/hooks");
5
+ let react = require("react");
6
+ let react_jsx_runtime = require("react/jsx-runtime");
7
+ //#region src/animation/useMountStagger.ts
8
+ /**
9
+ * Dependency-free entrance stagger using the Web Animations API. Animates
10
+ * descendants marked with `data-stagger` once on mount (and whenever
11
+ * `deps` change), honoring `prefers-reduced-motion`. Works without GSAP;
12
+ * GSAP fans can swap in their own hook of the same shape.
13
+ *
14
+ * @param ref - Ref to the container whose `[data-stagger]` items animate.
15
+ * @param deps - Re-run the stagger when these change (e.g. the row set).
16
+ * @param options - See {@link MountStaggerOptions}.
17
+ */
10
18
  function useMountStagger(ref, deps, options) {
11
- const reduced = core.usePrefersReducedMotion();
12
- const { enabled, step = 40, duration = 320 } = options;
13
- const depsKey = deps.map(String).join("|");
14
- react.useEffect(() => {
15
- if (!enabled || reduced) return;
16
- const root = ref.current;
17
- if (!root) return;
18
- const items = root.querySelectorAll("[data-stagger]");
19
- items.forEach((el, index) => {
20
- if (typeof el.animate !== "function") return;
21
- el.animate(
22
- [
23
- { opacity: 0, transform: "translateY(8px)" },
24
- { opacity: 1, transform: "translateY(0)" }
25
- ],
26
- {
27
- duration,
28
- delay: index * step,
29
- easing: "cubic-bezier(0.16, 1, 0.3, 1)",
30
- fill: "both"
31
- }
32
- );
33
- });
34
- }, [enabled, reduced, step, duration, ref, depsKey]);
19
+ const reduced = (0, _adapttable_core.usePrefersReducedMotion)();
20
+ const { enabled, step = 40, duration = 320 } = options;
21
+ (0, react.useEffect)(() => {
22
+ if (!enabled || reduced) return;
23
+ const root = ref.current;
24
+ if (!root) return;
25
+ root.querySelectorAll("[data-stagger]").forEach((el, index) => {
26
+ if (typeof el.animate !== "function") return;
27
+ el.animate([{
28
+ opacity: 0,
29
+ transform: "translateY(8px)"
30
+ }, {
31
+ opacity: 1,
32
+ transform: "translateY(0)"
33
+ }], {
34
+ duration,
35
+ delay: index * step,
36
+ easing: "cubic-bezier(0.16, 1, 0.3, 1)",
37
+ fill: "both"
38
+ });
39
+ });
40
+ }, [
41
+ enabled,
42
+ reduced,
43
+ step,
44
+ duration,
45
+ ref,
46
+ deps.map(String).join("|")
47
+ ]);
35
48
  }
36
- function ActiveFilterChips({
37
- chips,
38
- onClearAll,
39
- label,
40
- clearAllLabel
41
- }) {
42
- if (chips.length === 0) return null;
43
- return /* @__PURE__ */ jsxRuntime.jsxs(
44
- core$1.Group,
45
- {
46
- gap: 6,
47
- "aria-label": label,
48
- component: "ul",
49
- style: { listStyle: "none", padding: 0, margin: 0 },
50
- children: [
51
- chips.map((chip) => /* @__PURE__ */ jsxRuntime.jsx(
52
- core$1.Pill,
53
- {
54
- component: "li",
55
- withRemoveButton: true,
56
- onRemove: chip.onRemove,
57
- removeButtonProps: {
58
- "aria-label": `${clearAllLabel}: ${chip.label}`
59
- },
60
- children: chip.label
61
- },
62
- chip.key
63
- )),
64
- onClearAll && /* @__PURE__ */ jsxRuntime.jsx(
65
- core$1.Anchor,
66
- {
67
- component: "button",
68
- type: "button",
69
- fz: "xs",
70
- fw: 600,
71
- onClick: onClearAll,
72
- children: clearAllLabel
73
- }
74
- )
75
- ]
76
- }
77
- );
49
+ //#endregion
50
+ //#region src/components/ActiveFilterChips.tsx
51
+ /** A wrapping strip of removable filter chips. Renders nothing when empty. */
52
+ function ActiveFilterChips({ chips, onClearAll, label, clearAllLabel }) {
53
+ if (chips.length === 0) return null;
54
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
55
+ gap: 6,
56
+ "aria-label": label,
57
+ component: "ul",
58
+ style: {
59
+ listStyle: "none",
60
+ padding: 0,
61
+ margin: 0
62
+ },
63
+ children: [chips.map((chip) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Pill, {
64
+ component: "li",
65
+ withRemoveButton: true,
66
+ onRemove: chip.onRemove,
67
+ removeButtonProps: { "aria-label": `${clearAllLabel}: ${chip.label}` },
68
+ children: chip.label
69
+ }, chip.key)), onClearAll && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Anchor, {
70
+ component: "button",
71
+ type: "button",
72
+ fz: "xs",
73
+ fw: 600,
74
+ onClick: onClearAll,
75
+ children: clearAllLabel
76
+ })]
77
+ });
78
78
  }
79
- var asText = (value) => value == null ? "" : String(value);
80
- var asList = (value) => {
81
- if (value == null || value === "") return [];
82
- return Array.isArray(value) ? value : [String(value)];
79
+ //#endregion
80
+ //#region src/components/AutoFilterForm.tsx
81
+ /** A scalar filter value as input text (`""` when unset). */
82
+ const asText = (value) => value == null ? "" : String(value);
83
+ /** A multi-select value as an array, tolerating a scalar from the URL. */
84
+ const asList = (value) => {
85
+ if (value == null || value === "") return [];
86
+ return Array.isArray(value) ? value : [String(value)];
87
+ };
88
+ /** The select's raw option value parsed back to a known operator. */
89
+ const asOp = (value) => _adapttable_core.RANGE_OPS.find((op) => op === value);
90
+ /** Which operator label set each range type reads. */
91
+ const RANGE_FLAVOUR = {
92
+ numberRange: "number",
93
+ dateRange: "date"
83
94
  };
84
- var asOp = (value) => core.RANGE_OPS.find((op) => op === value);
85
- var RANGE_FLAVOUR = { numberRange: "number", dateRange: "date" };
86
- function RangeField({
87
- def,
88
- source,
89
- kind,
90
- labels
91
- }) {
92
- const label = core.filterLabel(def);
93
- const lowKey = def.key + core.RANGE_SUFFIXES[kind].start;
94
- const highKey = def.key + core.RANGE_SUFFIXES[kind].end;
95
- const derived = core.readRangeWidget(source.extra, lowKey, highKey);
96
- const [chosen, setChosen] = react.useState(null);
97
- const op = chosen ?? derived.op ?? null;
98
- const low = asText(source.extra[lowKey]);
99
- const high = asText(source.extra[highKey]);
100
- const single = op === "lte" ? high : low;
101
- const write = (nextOp, a, b) => source.setExtras(core.writeRangeWidget(nextOp, a, b, lowKey, highKey));
102
- const handleOp = (value) => {
103
- const next = asOp(value);
104
- setChosen(next ?? null);
105
- write(next, single, "");
106
- };
107
- const flavour = RANGE_FLAVOUR[kind];
108
- const opLabelKeys = core.RANGE_OP_LABEL_KEYS[flavour];
109
- const data = core.RANGE_OPS.map((value) => ({
110
- value,
111
- label: labels[opLabelKeys[value]]
112
- }));
113
- const valueInput = (text, value, commit) => flavour === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
114
- core$1.NumberInput,
115
- {
116
- size: "sm",
117
- hideControls: true,
118
- style: { flex: "1 1 6rem", minWidth: "6rem" },
119
- "aria-label": `${label} ${text}`,
120
- placeholder: text,
121
- value,
122
- onChange: (next) => commit(String(next))
123
- }
124
- ) : /* @__PURE__ */ jsxRuntime.jsx(
125
- core$1.TextInput,
126
- {
127
- type: "date",
128
- size: "sm",
129
- style: { flex: "1 1 8.5rem", minWidth: "8.5rem" },
130
- "aria-label": `${label} ${text}`,
131
- placeholder: text,
132
- value,
133
- onChange: (e) => commit(e.currentTarget.value)
134
- }
135
- );
136
- let values = null;
137
- if (op === "between") {
138
- values = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
139
- valueInput(labels.from, low, (next) => write("between", next, high)),
140
- valueInput(labels.to, high, (next) => write("between", low, next))
141
- ] });
142
- } else if (op) {
143
- values = valueInput(labels.value, single, (next) => write(op, next, ""));
144
- }
145
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: 4, children: [
146
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Input.Label, { size: "sm", children: label }),
147
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", align: "flex-start", children: [
148
- /* @__PURE__ */ jsxRuntime.jsx(
149
- core$1.Select,
150
- {
151
- size: "sm",
152
- clearable: true,
153
- style: { flex: "0 0 8.5rem", width: "8.5rem" },
154
- "aria-label": `${label} ${labels.operator}`,
155
- placeholder: labels.operator,
156
- data,
157
- value: op,
158
- onChange: handleOp,
159
- comboboxProps: { withinPortal: false }
160
- }
161
- ),
162
- values
163
- ] })
164
- ] });
95
+ /**
96
+ * The operator-first control shared by the `numberRange` / `dateRange`
97
+ * types: pick a comparison (Equal / At least / …), then fill ONE value —
98
+ * or From/To when "Between". The persisted state stays the inclusive
99
+ * `Min`/`Max` (`From`/`To`) pair via {@link readRangeWidget} /
100
+ * {@link writeRangeWidget}, so URLs, chips and predicates are unchanged.
101
+ */
102
+ function RangeField({ def, source, kind, labels }) {
103
+ const label = (0, _adapttable_core.filterLabel)(def);
104
+ const lowKey = def.key + _adapttable_core.RANGE_SUFFIXES[kind].start;
105
+ const highKey = def.key + _adapttable_core.RANGE_SUFFIXES[kind].end;
106
+ const derived = (0, _adapttable_core.readRangeWidget)(source.extra, lowKey, highKey);
107
+ const [chosen, setChosen] = (0, react.useState)(null);
108
+ const op = chosen ?? derived.op ?? null;
109
+ const low = asText(source.extra[lowKey]);
110
+ const high = asText(source.extra[highKey]);
111
+ /** The one visible value outside "Between" (`lte` stores the upper bound). */
112
+ const single = op === "lte" ? high : low;
113
+ const write = (nextOp, a, b) => source.setExtras((0, _adapttable_core.writeRangeWidget)(nextOp, a, b, lowKey, highKey));
114
+ const handleOp = (value) => {
115
+ const next = asOp(value);
116
+ setChosen(next ?? null);
117
+ write(next, single, "");
118
+ };
119
+ const flavour = RANGE_FLAVOUR[kind];
120
+ const opLabelKeys = _adapttable_core.RANGE_OP_LABEL_KEYS[flavour];
121
+ const data = _adapttable_core.RANGE_OPS.map((value) => ({
122
+ value,
123
+ label: labels[opLabelKeys[value]]
124
+ }));
125
+ const valueInput = (text, value, commit) => flavour === "number" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.NumberInput, {
126
+ size: "sm",
127
+ hideControls: true,
128
+ style: {
129
+ flex: "1 1 6rem",
130
+ minWidth: "6rem"
131
+ },
132
+ "aria-label": `${label} ${text}`,
133
+ placeholder: text,
134
+ value,
135
+ onChange: (next) => commit(String(next))
136
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.TextInput, {
137
+ type: "date",
138
+ size: "sm",
139
+ style: {
140
+ flex: "1 1 8.5rem",
141
+ minWidth: "8.5rem"
142
+ },
143
+ "aria-label": `${label} ${text}`,
144
+ placeholder: text,
145
+ value,
146
+ onChange: (e) => commit(e.currentTarget.value)
147
+ });
148
+ let values = null;
149
+ if (op === "between") values = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [valueInput(labels.from, low, (next) => write("between", next, high)), valueInput(labels.to, high, (next) => write("between", low, next))] });
150
+ else if (op) values = valueInput(labels.value, single, (next) => write(op, next, ""));
151
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
152
+ gap: 4,
153
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Input.Label, {
154
+ size: "sm",
155
+ children: label
156
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
157
+ gap: "xs",
158
+ align: "flex-start",
159
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Select, {
160
+ size: "sm",
161
+ clearable: true,
162
+ style: {
163
+ flex: "0 0 8.5rem",
164
+ width: "8.5rem"
165
+ },
166
+ "aria-label": `${label} ${labels.operator}`,
167
+ placeholder: labels.operator,
168
+ data,
169
+ value: op,
170
+ onChange: handleOp,
171
+ comboboxProps: { withinPortal: false }
172
+ }), values]
173
+ })]
174
+ });
165
175
  }
166
- function SelectControl({
167
- def,
168
- source
169
- }) {
170
- const label = core.filterLabel(def);
171
- const { options, loading } = core.useFilterOptions(def);
172
- const data = loading ? [{ value: "", label: "\u2026", disabled: true }] : [{ value: "", label: "All" }, ...options];
173
- return /* @__PURE__ */ jsxRuntime.jsx(
174
- core$1.NativeSelect,
175
- {
176
- size: "sm",
177
- label,
178
- data,
179
- value: asText(source.extra[def.key]),
180
- onChange: (e) => source.setExtra(def.key, e.currentTarget.value)
181
- }
182
- );
176
+ /**
177
+ * Single-choice control. Options resolve through {@link useFilterOptions}
178
+ * (static array, async loader, or none); while a loader is in flight the
179
+ * select shows one disabled placeholder option.
180
+ */
181
+ function SelectControl({ def, source }) {
182
+ const label = (0, _adapttable_core.filterLabel)(def);
183
+ const { options, loading } = (0, _adapttable_core.useFilterOptions)(def);
184
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.NativeSelect, {
185
+ size: "sm",
186
+ label,
187
+ data: loading ? [{
188
+ value: "",
189
+ label: "…",
190
+ disabled: true
191
+ }] : [{
192
+ value: "",
193
+ label: "All"
194
+ }, ...options],
195
+ value: asText(source.extra[def.key]),
196
+ onChange: (e) => source.setExtra(def.key, e.currentTarget.value)
197
+ });
183
198
  }
184
- function MultiSelectControl({
185
- def,
186
- source
187
- }) {
188
- const label = core.filterLabel(def);
189
- const { options, loading } = core.useFilterOptions(def);
190
- return /* @__PURE__ */ jsxRuntime.jsx(
191
- core$1.Checkbox.Group,
192
- {
193
- label,
194
- value: asList(source.extra[def.key]),
195
- onChange: (values) => source.setExtra(def.key, values),
196
- children: /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { gap: "sm", mt: 4, children: loading ? /* @__PURE__ */ jsxRuntime.jsx(core$1.Loader, { size: "xs" }) : options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
197
- core$1.Checkbox,
198
- {
199
- size: "sm",
200
- value: option.value,
201
- label: option.label
202
- },
203
- option.value
204
- )) })
205
- }
206
- );
199
+ /**
200
+ * Multi-choice control. Options resolve through {@link useFilterOptions};
201
+ * while a loader is in flight the group shows a small spinner instead of
202
+ * checkboxes.
203
+ */
204
+ function MultiSelectControl({ def, source }) {
205
+ const label = (0, _adapttable_core.filterLabel)(def);
206
+ const { options, loading } = (0, _adapttable_core.useFilterOptions)(def);
207
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Checkbox.Group, {
208
+ label,
209
+ value: asList(source.extra[def.key]),
210
+ onChange: (values) => source.setExtra(def.key, values),
211
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Group, {
212
+ gap: "sm",
213
+ mt: 4,
214
+ children: loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Loader, { size: "xs" }) : options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Checkbox, {
215
+ size: "sm",
216
+ value: option.value,
217
+ label: option.label
218
+ }, option.value))
219
+ })
220
+ });
207
221
  }
208
- function FilterControl({
209
- def,
210
- source,
211
- labels
212
- }) {
213
- switch (def.type) {
214
- case "text":
215
- return /* @__PURE__ */ jsxRuntime.jsx(
216
- core$1.TextInput,
217
- {
218
- size: "sm",
219
- label: core.filterLabel(def),
220
- placeholder: def.placeholder,
221
- value: asText(source.extra[def.key]),
222
- onChange: (e) => source.setExtra(def.key, e.currentTarget.value)
223
- }
224
- );
225
- case "select":
226
- return /* @__PURE__ */ jsxRuntime.jsx(SelectControl, { def, source });
227
- case "multiSelect":
228
- return /* @__PURE__ */ jsxRuntime.jsx(MultiSelectControl, { def, source });
229
- case "dateRange":
230
- case "numberRange":
231
- return /* @__PURE__ */ jsxRuntime.jsx(RangeField, { def, source, kind: def.type, labels });
232
- }
222
+ /** One labeled, kit-native control for a single filter definition. */
223
+ function FilterControl({ def, source, labels }) {
224
+ switch (def.type) {
225
+ case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.TextInput, {
226
+ size: "sm",
227
+ label: (0, _adapttable_core.filterLabel)(def),
228
+ placeholder: def.placeholder,
229
+ value: asText(source.extra[def.key]),
230
+ onChange: (e) => source.setExtra(def.key, e.currentTarget.value)
231
+ });
232
+ case "select": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectControl, {
233
+ def,
234
+ source
235
+ });
236
+ case "multiSelect": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MultiSelectControl, {
237
+ def,
238
+ source
239
+ });
240
+ case "dateRange":
241
+ case "numberRange": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RangeField, {
242
+ def,
243
+ source,
244
+ kind: def.type,
245
+ labels
246
+ });
247
+ }
233
248
  }
234
- function AutoFilterForm({
235
- defs,
236
- source,
237
- labels
238
- }) {
239
- return /* @__PURE__ */ jsxRuntime.jsx(core$1.Stack, { gap: "sm", children: defs.map((def) => /* @__PURE__ */ jsxRuntime.jsx(
240
- FilterControl,
241
- {
242
- def,
243
- source,
244
- labels
245
- },
246
- def.key
247
- )) });
249
+ /**
250
+ * The auto-built filter form: one labeled, Mantine-native control per
251
+ * declarative {@link FilterDef}. Values live in the source's `extra` bag
252
+ * (so the URL, chips and — on frontend data — the predicate all follow);
253
+ * clearing a control writes the empty value, which drops the URL param.
254
+ * Range types render operator-first: an operator select plus one value
255
+ * input (two for "Between"), persisted as the inclusive pair.
256
+ *
257
+ * @typeParam TRow - The row type.
258
+ */
259
+ function AutoFilterForm({ defs, source, labels }) {
260
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Stack, {
261
+ gap: "sm",
262
+ children: defs.map((def) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterControl, {
263
+ def,
264
+ source,
265
+ labels
266
+ }, def.key))
267
+ });
248
268
  }
249
- function BulkActionBar({
250
- selection,
251
- total,
252
- bulkActions,
253
- confirm,
254
- labels
255
- }) {
256
- const { selectedIds, selectedCount, clear, allMatching } = selection;
257
- const { pending, run } = core.useBulkActionRunner({
258
- confirm,
259
- cancelLabel: labels.cancel,
260
- onComplete: clear
261
- });
262
- if (selectedCount === 0) return null;
263
- const ids = [...selectedIds];
264
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: "xs", children: [
265
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", wrap: "wrap", gap: "sm", children: [
266
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "sm", children: labels.selectedCount(selectedCount) }),
267
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", wrap: "wrap", children: [
268
- /* @__PURE__ */ jsxRuntime.jsx(
269
- core$1.Button,
270
- {
271
- size: "xs",
272
- variant: "subtle",
273
- onClick: clear,
274
- disabled: pending !== null,
275
- children: labels.clearAll
276
- }
277
- ),
278
- bulkActions.map((action) => /* @__PURE__ */ jsxRuntime.jsx(
279
- BulkButton,
280
- {
281
- action,
282
- ids,
283
- pending,
284
- onRun: (a) => {
285
- if (allMatching) run(a, ids, { allMatching: true, total });
286
- else run(a, ids);
287
- }
288
- },
289
- action.key
290
- ))
291
- ] })
292
- ] }),
293
- /* @__PURE__ */ jsxRuntime.jsx(ScopeBanner, { selection, total, labels })
294
- ] });
269
+ //#endregion
270
+ //#region src/components/BulkActionBar.tsx
271
+ /** Selection toolbar: count, clear, and the configured bulk-action buttons. */
272
+ function BulkActionBar({ selection, total, bulkActions, confirm, labels }) {
273
+ const { selectedIds, selectedCount, clear, allMatching } = selection;
274
+ const { pending, run } = (0, _adapttable_core.useBulkActionRunner)({
275
+ confirm,
276
+ cancelLabel: labels.cancel,
277
+ onComplete: clear
278
+ });
279
+ if (selectedCount === 0) return null;
280
+ const ids = [...selectedIds];
281
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
282
+ gap: "xs",
283
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
284
+ justify: "space-between",
285
+ wrap: "wrap",
286
+ gap: "sm",
287
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
288
+ fz: "sm",
289
+ children: labels.selectedCount(selectedCount)
290
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
291
+ gap: "xs",
292
+ wrap: "wrap",
293
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
294
+ size: "xs",
295
+ variant: "subtle",
296
+ onClick: clear,
297
+ disabled: pending !== null,
298
+ children: labels.clearAll
299
+ }), bulkActions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BulkButton, {
300
+ action,
301
+ ids,
302
+ pending,
303
+ onRun: (a) => {
304
+ if (allMatching) run(a, ids, {
305
+ allMatching: true,
306
+ total
307
+ });
308
+ else run(a, ids);
309
+ }
310
+ }, action.key))]
311
+ })]
312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScopeBanner, {
313
+ selection,
314
+ total,
315
+ labels
316
+ })]
317
+ });
295
318
  }
296
- function ScopeBanner({
297
- selection,
298
- total,
299
- labels
300
- }) {
301
- if (selection.headerState !== "all" || total <= selection.visibleIds.length) {
302
- return null;
303
- }
304
- return /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { role: "status", gap: "xs", wrap: "wrap", children: selection.allMatching ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
305
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "sm", children: labels.allMatchingSelected(total) }),
306
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { size: "xs", variant: "subtle", onClick: selection.clear, children: labels.clearAll })
307
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
308
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "sm", children: labels.pageSelected(selection.selectedCount) }),
309
- /* @__PURE__ */ jsxRuntime.jsx(
310
- core$1.Button,
311
- {
312
- size: "xs",
313
- variant: "light",
314
- onClick: selection.selectAllMatching,
315
- children: labels.selectAllMatching(total)
316
- }
317
- )
318
- ] }) });
319
+ /**
320
+ * Gmail-style scope banner. When every row on the page is selected but more
321
+ * rows match elsewhere, offer to widen the selection to all matching rows;
322
+ * once widened, announce the scope and offer to clear it.
323
+ */
324
+ function ScopeBanner({ selection, total, labels }) {
325
+ if (selection.headerState !== "all" || total <= selection.visibleIds.length) return null;
326
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Group, {
327
+ role: "status",
328
+ gap: "xs",
329
+ wrap: "wrap",
330
+ children: selection.allMatching ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
331
+ fz: "sm",
332
+ children: labels.allMatchingSelected(total)
333
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
334
+ size: "xs",
335
+ variant: "subtle",
336
+ onClick: selection.clear,
337
+ children: labels.clearAll
338
+ })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
339
+ fz: "sm",
340
+ children: labels.pageSelected(selection.selectedCount)
341
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
342
+ size: "xs",
343
+ variant: "light",
344
+ onClick: selection.selectAllMatching,
345
+ children: labels.selectAllMatching(total)
346
+ })] })
347
+ });
319
348
  }
320
- function BulkButton({
321
- action,
322
- ids,
323
- pending,
324
- onRun
325
- }) {
326
- const reason = core.resolveDisabledReason(action.disabledReason?.(ids));
327
- const ineligible = reason !== void 0;
328
- const button = /* @__PURE__ */ jsxRuntime.jsx(
329
- core$1.Button,
330
- {
331
- size: "xs",
332
- color: action.color,
333
- leftSection: action.icon,
334
- onClick: () => onRun(action),
335
- loading: pending === action.key,
336
- disabled: ineligible || pending !== null && pending !== action.key,
337
- children: action.label
338
- }
339
- );
340
- if (reason !== void 0) {
341
- return /* @__PURE__ */ jsxRuntime.jsx(core$1.Tooltip, { label: reason, withArrow: true, openDelay: 150, children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: button }) });
342
- }
343
- return button;
349
+ function BulkButton({ action, ids, pending, onRun }) {
350
+ const reason = (0, _adapttable_core.resolveDisabledReason)(action.disabledReason?.(ids));
351
+ const ineligible = reason !== void 0;
352
+ const button = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
353
+ size: "xs",
354
+ color: action.color,
355
+ leftSection: action.icon,
356
+ onClick: () => onRun(action),
357
+ loading: pending === action.key,
358
+ disabled: ineligible || pending !== null && pending !== action.key,
359
+ children: action.label
360
+ });
361
+ if (reason !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Tooltip, {
362
+ label: reason,
363
+ withArrow: true,
364
+ openDelay: 150,
365
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: button })
366
+ });
367
+ return button;
344
368
  }
345
- function RowVisibility({
346
- hidden,
347
- name,
348
- labels,
349
- onToggle
350
- }) {
351
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
352
- /* @__PURE__ */ jsxRuntime.jsx(
353
- core$1.ActionIcon,
354
- {
355
- variant: hidden ? "subtle" : "light",
356
- color: hidden ? "gray" : "blue",
357
- size: "sm",
358
- "aria-label": `${hidden ? labels.showColumn : labels.hideColumn}: ${name}`,
359
- "aria-pressed": !hidden,
360
- onClick: onToggle,
361
- children: /* @__PURE__ */ jsxRuntime.jsx(core.EyeIcon, { off: hidden })
362
- }
363
- ),
364
- /* @__PURE__ */ jsxRuntime.jsx(
365
- core$1.Text,
366
- {
367
- size: "sm",
368
- style: { flex: 1 },
369
- c: hidden ? "dimmed" : void 0,
370
- td: hidden ? "line-through" : void 0,
371
- children: name
372
- }
373
- )
374
- ] });
369
+ //#endregion
370
+ //#region src/components/ColumnMenu.tsx
371
+ /** The eye toggle + struck-through name shared by data and actions rows. */
372
+ function RowVisibility({ hidden, name, labels, onToggle }) {
373
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
374
+ variant: hidden ? "subtle" : "light",
375
+ color: hidden ? "gray" : "blue",
376
+ size: "sm",
377
+ "aria-label": `${hidden ? labels.showColumn : labels.hideColumn}: ${name}`,
378
+ "aria-pressed": !hidden,
379
+ onClick: onToggle,
380
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_adapttable_core.EyeIcon, { off: hidden })
381
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
382
+ size: "sm",
383
+ style: { flex: 1 },
384
+ c: hidden ? "dimmed" : void 0,
385
+ td: hidden ? "line-through" : void 0,
386
+ children: name
387
+ })] });
375
388
  }
376
- function PinToggle({
377
- pinned,
378
- label,
379
- onClick
380
- }) {
381
- return /* @__PURE__ */ jsxRuntime.jsx(
382
- core$1.ActionIcon,
383
- {
384
- variant: pinned ? "filled" : "subtle",
385
- color: pinned ? "blue" : "gray",
386
- size: "sm",
387
- "aria-label": label,
388
- onClick,
389
- children: /* @__PURE__ */ jsxRuntime.jsx(core.PinIcon, {})
390
- }
391
- );
389
+ /** The pin control shared by data and actions rows. */
390
+ function PinToggle({ pinned, label, onClick }) {
391
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
392
+ variant: pinned ? "filled" : "subtle",
393
+ color: pinned ? "blue" : "gray",
394
+ size: "sm",
395
+ "aria-label": label,
396
+ onClick,
397
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_adapttable_core.PinIcon, {})
398
+ });
392
399
  }
393
- function ActionsRow({
394
- layout,
395
- labels
396
- }) {
397
- const hidden = layout.isHidden(core.ACTIONS_COLUMN_KEY);
398
- const pinned = layout.state.pinned[core.ACTIONS_COLUMN_KEY] === "right";
399
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "flex-start", wrap: "nowrap", gap: 6, px: 4, py: 2, children: [
400
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Box, { w: 22 }),
401
- /* @__PURE__ */ jsxRuntime.jsx(
402
- RowVisibility,
403
- {
404
- hidden,
405
- name: labels.actions,
406
- labels,
407
- onToggle: () => layout.toggleVisible(core.ACTIONS_COLUMN_KEY)
408
- }
409
- ),
410
- /* @__PURE__ */ jsxRuntime.jsx(
411
- PinToggle,
412
- {
413
- pinned,
414
- label: `${pinned ? labels.unpin : labels.pinRight}: ${labels.actions}`,
415
- onClick: () => layout.setPinned(core.ACTIONS_COLUMN_KEY, pinned ? void 0 : "right")
416
- }
417
- )
418
- ] });
400
+ /**
401
+ * The injected actions column's menu row: the same eye toggle as data
402
+ * columns plus a pin toggle that flips right ↔ unpinned in one click. No
403
+ * drag grip (the column always trails) and no left pin.
404
+ */
405
+ function ActionsRow({ layout, labels }) {
406
+ const hidden = layout.isHidden(_adapttable_core.ACTIONS_COLUMN_KEY);
407
+ const pinned = layout.state.pinned[_adapttable_core.ACTIONS_COLUMN_KEY] === "right";
408
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
409
+ justify: "flex-start",
410
+ wrap: "nowrap",
411
+ gap: 6,
412
+ px: 4,
413
+ py: 2,
414
+ children: [
415
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, { w: 22 }),
416
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowVisibility, {
417
+ hidden,
418
+ name: labels.actions,
419
+ labels,
420
+ onToggle: () => layout.toggleVisible(_adapttable_core.ACTIONS_COLUMN_KEY)
421
+ }),
422
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PinToggle, {
423
+ pinned,
424
+ label: `${pinned ? labels.unpin : labels.pinRight}: ${labels.actions}`,
425
+ onClick: () => layout.setPinned(_adapttable_core.ACTIONS_COLUMN_KEY, pinned ? void 0 : "right")
426
+ })
427
+ ]
428
+ });
419
429
  }
420
- function ColumnMenu({
421
- allColumns,
422
- layout,
423
- labels,
424
- hasRowActions = false
425
- }) {
426
- const drag = core.useColumnDragState();
427
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Menu, { closeOnItemClick: false, position: "bottom-end", withinPortal: true, children: [
428
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Target, { children: /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { variant: "default", size: "sm", children: labels.columns }) }),
429
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Dropdown, { children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Box, { p: 4, miw: 250, children: [
430
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", px: 4, pb: 6, children: labels.columns }),
431
- core.columnMenuRows(allColumns, layout).map((r) => {
432
- const indicator = drag.rowAttrs(r.key, r.index);
433
- const edge = indicator["data-drop"];
434
- const edgeOffset = edge === "before" ? "2px" : "-2px";
435
- return /* @__PURE__ */ jsxRuntime.jsxs(
436
- core$1.Group,
437
- {
438
- justify: "flex-start",
439
- wrap: "nowrap",
440
- gap: 6,
441
- px: 4,
442
- py: 2,
443
- style: {
444
- cursor: "grab",
445
- opacity: "data-dragging" in indicator ? 0.4 : void 0,
446
- boxShadow: edge ? `inset 0 ${edgeOffset} 0 0 var(--mantine-primary-color-filled)` : void 0
447
- },
448
- ...drag.rowDragProps(r.key, r.index),
449
- ...drag.dropProps(r.index, layout.move),
450
- ...indicator,
451
- children: [
452
- /* @__PURE__ */ jsxRuntime.jsx(
453
- core$1.ActionIcon,
454
- {
455
- variant: "subtle",
456
- color: "gray",
457
- size: "sm",
458
- style: { cursor: "grab" },
459
- ...core.columnReorderKeyProps(
460
- r.key,
461
- r.index,
462
- layout.move,
463
- `${labels.moveLeft} / ${labels.moveRight}: ${r.name}`
464
- ),
465
- children: /* @__PURE__ */ jsxRuntime.jsx(core.GripIcon, {})
466
- }
467
- ),
468
- /* @__PURE__ */ jsxRuntime.jsx(
469
- RowVisibility,
470
- {
471
- hidden: r.hidden,
472
- name: r.name,
473
- labels,
474
- onToggle: () => layout.toggleVisible(r.key)
475
- }
476
- ),
477
- /* @__PURE__ */ jsxRuntime.jsx(
478
- PinToggle,
479
- {
480
- pinned: r.pinned !== void 0,
481
- label: `${core.pinActionLabel(r.pinned, labels)}: ${r.name}`,
482
- onClick: () => layout.setPinned(r.key, core.nextPinSide(r.pinned))
483
- }
484
- )
485
- ]
486
- },
487
- r.key
488
- );
489
- }),
490
- hasRowActions && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
491
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Divider, {}),
492
- /* @__PURE__ */ jsxRuntime.jsx(ActionsRow, { layout, labels })
493
- ] }),
494
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Divider, {}),
495
- /* @__PURE__ */ jsxRuntime.jsx(
496
- core$1.Button,
497
- {
498
- variant: "subtle",
499
- size: "xs",
500
- fullWidth: true,
501
- justify: "flex-start",
502
- onClick: () => layout.reset(),
503
- children: labels.resetColumns
504
- }
505
- )
506
- ] }) })
507
- ] });
430
+ /**
431
+ * Column-management popover: per-column drag grip (reorder), eye (show/hide),
432
+ * and pin toggle. Keyboard users focus a grip and use arrow keys.
433
+ */
434
+ function ColumnMenu({ allColumns, layout, labels, hasRowActions = false }) {
435
+ const drag = (0, _adapttable_core.useColumnDragState)();
436
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Menu, {
437
+ closeOnItemClick: false,
438
+ position: "bottom-end",
439
+ withinPortal: true,
440
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Menu.Target, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
441
+ variant: "default",
442
+ size: "sm",
443
+ children: labels.columns
444
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Menu.Dropdown, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Box, {
445
+ p: 4,
446
+ miw: 250,
447
+ children: [
448
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
449
+ size: "xs",
450
+ c: "dimmed",
451
+ fw: 600,
452
+ tt: "uppercase",
453
+ px: 4,
454
+ pb: 6,
455
+ children: labels.columns
456
+ }),
457
+ (0, _adapttable_core.columnMenuRows)(allColumns, layout).map((r) => {
458
+ const indicator = drag.rowAttrs(r.key, r.index);
459
+ const edge = indicator["data-drop"];
460
+ const edgeOffset = edge === "before" ? "2px" : "-2px";
461
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
462
+ justify: "flex-start",
463
+ wrap: "nowrap",
464
+ gap: 6,
465
+ px: 4,
466
+ py: 2,
467
+ style: {
468
+ cursor: "grab",
469
+ opacity: "data-dragging" in indicator ? .4 : void 0,
470
+ boxShadow: edge ? `inset 0 ${edgeOffset} 0 0 var(--mantine-primary-color-filled)` : void 0
471
+ },
472
+ ...drag.rowDragProps(r.key, r.index),
473
+ ...drag.dropProps(r.index, layout.move),
474
+ ...indicator,
475
+ children: [
476
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
477
+ variant: "subtle",
478
+ color: "gray",
479
+ size: "sm",
480
+ style: { cursor: "grab" },
481
+ ...(0, _adapttable_core.columnReorderKeyProps)(r.key, r.index, layout.move, `${labels.moveLeft} / ${labels.moveRight}: ${r.name}`),
482
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_adapttable_core.GripIcon, {})
483
+ }),
484
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowVisibility, {
485
+ hidden: r.hidden,
486
+ name: r.name,
487
+ labels,
488
+ onToggle: () => layout.toggleVisible(r.key)
489
+ }),
490
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PinToggle, {
491
+ pinned: r.pinned !== void 0,
492
+ label: `${(0, _adapttable_core.pinActionLabel)(r.pinned, labels)}: ${r.name}`,
493
+ onClick: () => layout.setPinned(r.key, (0, _adapttable_core.nextPinSide)(r.pinned))
494
+ })
495
+ ]
496
+ }, r.key);
497
+ }),
498
+ hasRowActions && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Menu.Divider, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionsRow, {
499
+ layout,
500
+ labels
501
+ })] }),
502
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Menu.Divider, {}),
503
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
504
+ variant: "subtle",
505
+ size: "xs",
506
+ fullWidth: true,
507
+ justify: "flex-start",
508
+ onClick: () => layout.reset(),
509
+ children: labels.resetColumns
510
+ })
511
+ ]
512
+ }) })]
513
+ });
508
514
  }
509
-
510
- // src/density.ts
511
- var DENSITY_SPACING = {
512
- comfortable: { verticalSpacing: "sm", horizontalSpacing: "md" },
513
- compact: { verticalSpacing: 4, horizontalSpacing: "sm" }
515
+ //#endregion
516
+ //#region src/density.ts
517
+ /**
518
+ * Maps each {@link Density} to the Mantine `<Table>` spacing props.
519
+ * `comfortable` keeps the original `sm`/`md` rhythm; `compact` tightens
520
+ * rows with a 4px vertical gap and `sm` horizontal padding.
521
+ */
522
+ const DENSITY_SPACING = {
523
+ comfortable: {
524
+ verticalSpacing: "sm",
525
+ horizontalSpacing: "md"
526
+ },
527
+ compact: {
528
+ verticalSpacing: 4,
529
+ horizontalSpacing: "sm"
530
+ }
514
531
  };
515
- function Svg({
516
- size = 16,
517
- className,
518
- style,
519
- children
520
- }) {
521
- return /* @__PURE__ */ jsxRuntime.jsx(
522
- "svg",
523
- {
524
- width: size,
525
- height: size,
526
- viewBox: "0 0 24 24",
527
- fill: "none",
528
- stroke: "currentColor",
529
- strokeWidth: 2,
530
- strokeLinecap: "round",
531
- strokeLinejoin: "round",
532
- className,
533
- style,
534
- "aria-hidden": "true",
535
- focusable: "false",
536
- children
537
- }
538
- );
532
+ //#endregion
533
+ //#region src/icons.tsx
534
+ function Svg({ size = 16, className, style, children }) {
535
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
536
+ width: size,
537
+ height: size,
538
+ viewBox: "0 0 24 24",
539
+ fill: "none",
540
+ stroke: "currentColor",
541
+ strokeWidth: 2,
542
+ strokeLinecap: "round",
543
+ strokeLinejoin: "round",
544
+ className,
545
+ style,
546
+ "aria-hidden": "true",
547
+ focusable: "false",
548
+ children
549
+ });
539
550
  }
540
- var SearchIcon = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { ...p, children: [
541
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
542
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m21 21-4.3-4.3" })
543
- ] });
544
- var ChevronUpIcon = (p) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 15 6-6 6 6" }) });
545
- var ChevronDownIcon = (p) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) });
546
- var ChevronRightIcon = (p) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 6 6 6-6 6" }) });
547
- var SelectorIcon = (p) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m8 9 4-4 4 4M8 15l4 4 4-4" }) });
548
- var CloseIcon = (p) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) });
549
- var FiltersIcon = (p) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6h16M7 12h10M10 18h4" }) });
550
- var AlertIcon = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { ...p, children: [
551
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" }),
552
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 9v4M12 17h.01" })
553
- ] });
554
- var RefreshIcon = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { ...p, children: [
555
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-3-6.7L21 8" }),
556
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 3v5h-5" })
557
- ] });
558
- var InboxIcon = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { ...p, children: [
559
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22 12h-6l-2 3h-4l-2-3H2" }),
560
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5.5 5.1 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.5-6.9A2 2 0 0 0 16.8 4H7.2a2 2 0 0 0-1.7 1.1Z" })
561
- ] });
562
- function ExpandToggle({
563
- expanded,
564
- expandLabel,
565
- collapseLabel,
566
- onToggle
567
- }) {
568
- return /* @__PURE__ */ jsxRuntime.jsx(
569
- core$1.ActionIcon,
570
- {
571
- variant: "subtle",
572
- color: "gray",
573
- size: "sm",
574
- "aria-expanded": expanded,
575
- "aria-label": expanded ? collapseLabel : expandLabel,
576
- onClick: onToggle,
577
- children: /* @__PURE__ */ jsxRuntime.jsx(
578
- ChevronRightIcon,
579
- {
580
- size: 14,
581
- style: {
582
- transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
583
- transition: "transform 150ms ease"
584
- }
585
- }
586
- )
587
- }
588
- );
551
+ /** Magnifying-glass search icon. */
552
+ const SearchIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
553
+ ...p,
554
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
555
+ cx: "11",
556
+ cy: "11",
557
+ r: "7"
558
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m21 21-4.3-4.3" })]
559
+ });
560
+ /** Up chevron (active ascending sort). */
561
+ const ChevronUpIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
562
+ ...p,
563
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m6 15 6-6 6 6" })
564
+ });
565
+ /** Down chevron (active descending sort). */
566
+ const ChevronDownIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
567
+ ...p,
568
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m6 9 6 6 6-6" })
569
+ });
570
+ /** Right chevron (collapsed row-detail toggle; rotates 90° when expanded). */
571
+ const ChevronRightIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
572
+ ...p,
573
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m9 6 6 6-6 6" })
574
+ });
575
+ /** Up/down selector (inactive sortable column). */
576
+ const SelectorIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
577
+ ...p,
578
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m8 9 4-4 4 4M8 15l4 4 4-4" })
579
+ });
580
+ /** Small ✕ used on chips. */
581
+ const CloseIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
582
+ ...p,
583
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M18 6 6 18M6 6l12 12" })
584
+ });
585
+ /** Sliders icon for the Filters button. */
586
+ const FiltersIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
587
+ ...p,
588
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4 6h16M7 12h10M10 18h4" })
589
+ });
590
+ /** Triangle alert icon for the error state. */
591
+ const AlertIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
592
+ ...p,
593
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 9v4M12 17h.01" })]
594
+ });
595
+ /** Refresh icon for retry. */
596
+ const RefreshIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
597
+ ...p,
598
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 1 1-3-6.7L21 8" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 3v5h-5" })]
599
+ });
600
+ /** Inbox icon for the empty state. */
601
+ const InboxIcon = (p) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
602
+ ...p,
603
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M22 12h-6l-2 3h-4l-2-3H2" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5.5 5.1 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.5-6.9A2 2 0 0 0 16.8 4H7.2a2 2 0 0 0-1.7 1.1Z" })]
604
+ });
605
+ //#endregion
606
+ //#region src/components/ExpandToggle.tsx
607
+ /**
608
+ * The chevron that toggles a row's detail panel — shared by the desktop
609
+ * table's leading cell and the mobile card. It is a real button, so the
610
+ * row-click interactive-child guard already keeps it from activating
611
+ * `onRowClick`.
612
+ */
613
+ function ExpandToggle({ expanded, expandLabel, collapseLabel, onToggle }) {
614
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
615
+ variant: "subtle",
616
+ color: "gray",
617
+ size: "sm",
618
+ "aria-expanded": expanded,
619
+ "aria-label": expanded ? collapseLabel : expandLabel,
620
+ onClick: onToggle,
621
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRightIcon, {
622
+ size: 14,
623
+ style: {
624
+ transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
625
+ transition: "transform 150ms ease"
626
+ }
627
+ })
628
+ });
589
629
  }
590
- var RESIZE_HANDLE_STYLE = {
591
- position: "absolute",
592
- insetInlineEnd: 0,
593
- top: 0,
594
- height: "100%",
595
- width: 8,
596
- cursor: "col-resize",
597
- touchAction: "none",
598
- userSelect: "none"
630
+ //#endregion
631
+ //#region src/components/DesktopTable.tsx
632
+ /** Inline style for an absolutely-positioned column-resize handle. */
633
+ const RESIZE_HANDLE_STYLE = {
634
+ position: "absolute",
635
+ insetInlineEnd: 0,
636
+ top: 0,
637
+ height: "100%",
638
+ width: 8,
639
+ cursor: "col-resize",
640
+ touchAction: "none",
641
+ userSelect: "none"
599
642
  };
600
- function SortIcon({
601
- active,
602
- dir
603
- }) {
604
- if (!active) return /* @__PURE__ */ jsxRuntime.jsx(SelectorIcon, { size: 12 });
605
- return dir === "asc" ? /* @__PURE__ */ jsxRuntime.jsx(ChevronUpIcon, { size: 12 }) : /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, { size: 12 });
643
+ function SortIcon({ active, dir }) {
644
+ if (!active) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectorIcon, { size: 12 });
645
+ return dir === "asc" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronUpIcon, { size: 12 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { size: 12 });
606
646
  }
607
- function HeaderCell({
608
- table,
609
- column,
610
- stickyStyle,
611
- resizeHandle
612
- }) {
613
- const cellProps = table.getHeaderCellProps(column);
614
- const headerStyle = {
615
- ...cellProps.style,
616
- ...stickyStyle
617
- };
618
- if (!column.sortable) {
619
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Th, { ...cellProps, style: headerStyle, children: [
620
- column.header,
621
- resizeHandle
622
- ] });
623
- }
624
- const buttonProps = table.getSortButtonProps(column);
625
- const sortIndex = buttonProps["data-sort-index"];
626
- const level = table.source.sortLevels.find((l) => l.key === column.key);
627
- const active = level !== void 0 || table.sortBy === column.key;
628
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Th, { ...cellProps, style: headerStyle, children: [
629
- /* @__PURE__ */ jsxRuntime.jsxs(
630
- core$1.Group,
631
- {
632
- component: "button",
633
- gap: 6,
634
- wrap: "nowrap",
635
- display: "inline-flex",
636
- style: {
637
- background: "none",
638
- border: 0,
639
- cursor: "pointer",
640
- font: "inherit",
641
- padding: 0,
642
- color: active ? "var(--mantine-primary-color-filled)" : "inherit"
643
- },
644
- ...buttonProps,
645
- children: [
646
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: column.header }),
647
- /* @__PURE__ */ jsxRuntime.jsx(SortIcon, { active, dir: level?.dir ?? table.sortDir }),
648
- typeof sortIndex === "number" && /* @__PURE__ */ jsxRuntime.jsx(core$1.Badge, { component: "span", size: "xs", variant: "light", children: sortIndex })
649
- ]
650
- }
651
- ),
652
- resizeHandle
653
- ] });
647
+ function HeaderCell({ table, column, stickyStyle, resizeHandle }) {
648
+ const cellProps = table.getHeaderCellProps(column);
649
+ const headerStyle = {
650
+ ...cellProps.style,
651
+ ...stickyStyle
652
+ };
653
+ if (!column.sortable) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Th, {
654
+ ...cellProps,
655
+ style: headerStyle,
656
+ children: [column.header, resizeHandle]
657
+ });
658
+ const buttonProps = table.getSortButtonProps(column);
659
+ const sortIndex = buttonProps["data-sort-index"];
660
+ const level = table.source.sortLevels.find((l) => l.key === column.key);
661
+ const active = level !== void 0 || table.sortBy === column.key;
662
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Th, {
663
+ ...cellProps,
664
+ style: headerStyle,
665
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
666
+ component: "button",
667
+ gap: 6,
668
+ wrap: "nowrap",
669
+ display: "inline-flex",
670
+ style: {
671
+ background: "none",
672
+ border: 0,
673
+ cursor: "pointer",
674
+ font: "inherit",
675
+ padding: 0,
676
+ color: active ? "var(--mantine-primary-color-filled)" : "inherit"
677
+ },
678
+ ...buttonProps,
679
+ children: [
680
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: column.header }),
681
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SortIcon, {
682
+ active,
683
+ dir: level?.dir ?? table.sortDir
684
+ }),
685
+ typeof sortIndex === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Badge, {
686
+ component: "span",
687
+ size: "xs",
688
+ variant: "light",
689
+ children: sortIndex
690
+ })
691
+ ]
692
+ }), resizeHandle]
693
+ });
654
694
  }
655
- function RowActions({
656
- row,
657
- actions,
658
- confirm,
659
- cancelLabel
660
- }) {
661
- return /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { gap: 4, justify: "flex-end", wrap: "nowrap", children: actions.map((action) => {
662
- if (action.isHidden?.(row)) return null;
663
- const reason = core.resolveDisabledReason(action.disabledReason?.(row));
664
- const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
665
- const handleClick = disabled ? void 0 : (e) => {
666
- e.stopPropagation();
667
- core.runRowAction(action, row, confirm, cancelLabel);
668
- };
669
- return action.icon ? /* @__PURE__ */ jsxRuntime.jsx(
670
- core$1.Tooltip,
671
- {
672
- label: reason ?? action.label,
673
- withArrow: true,
674
- openDelay: 200,
675
- children: /* @__PURE__ */ jsxRuntime.jsx(
676
- core$1.ActionIcon,
677
- {
678
- variant: "subtle",
679
- color: action.color,
680
- size: "sm",
681
- disabled,
682
- "aria-label": action.label,
683
- onClick: handleClick,
684
- children: action.icon
685
- }
686
- )
687
- },
688
- action.key
689
- ) : /* @__PURE__ */ jsxRuntime.jsx(
690
- core$1.Button,
691
- {
692
- variant: "subtle",
693
- color: action.color,
694
- size: "compact-sm",
695
- disabled,
696
- onClick: handleClick,
697
- children: action.label
698
- },
699
- action.key
700
- );
701
- }) });
695
+ function RowActions({ row, actions, confirm, cancelLabel }) {
696
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Group, {
697
+ gap: 4,
698
+ justify: "flex-end",
699
+ wrap: "nowrap",
700
+ children: actions.map((action) => {
701
+ if (action.isHidden?.(row)) return null;
702
+ const reason = (0, _adapttable_core.resolveDisabledReason)(action.disabledReason?.(row));
703
+ const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
704
+ const handleClick = disabled ? void 0 : (e) => {
705
+ e.stopPropagation();
706
+ (0, _adapttable_core.runRowAction)(action, row, confirm, cancelLabel);
707
+ };
708
+ return action.icon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Tooltip, {
709
+ label: reason ?? action.label,
710
+ withArrow: true,
711
+ openDelay: 200,
712
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
713
+ variant: "subtle",
714
+ color: action.color,
715
+ size: "sm",
716
+ disabled,
717
+ "aria-label": action.label,
718
+ onClick: handleClick,
719
+ children: action.icon
720
+ })
721
+ }, action.key) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
722
+ variant: "subtle",
723
+ color: action.color,
724
+ size: "compact-sm",
725
+ disabled,
726
+ onClick: handleClick,
727
+ children: action.label
728
+ }, action.key);
729
+ })
730
+ });
702
731
  }
703
- var COMPARED_ROW_PROPS = [
704
- "row",
705
- "index",
706
- "id",
707
- "columns",
708
- "getCellProps",
709
- "selected",
710
- "selectLabel",
711
- "onToggleSelect",
712
- "expanded",
713
- "expandLabel",
714
- "collapseLabel",
715
- "onToggleExpand",
716
- "renderRowDetail",
717
- "columnSpan",
718
- "rowActions",
719
- "confirm",
720
- "cancelLabel",
721
- "onRowClick",
722
- "prefetch",
723
- "className",
724
- "measureElement",
725
- "pinSignature"
732
+ /** Every row prop the memo comparator checks with `Object.is`. */
733
+ const COMPARED_ROW_PROPS = [
734
+ "row",
735
+ "index",
736
+ "id",
737
+ "columns",
738
+ "getCellProps",
739
+ "selected",
740
+ "selectLabel",
741
+ "onToggleSelect",
742
+ "expanded",
743
+ "expandLabel",
744
+ "collapseLabel",
745
+ "onToggleExpand",
746
+ "renderRowDetail",
747
+ "columnSpan",
748
+ "rowActions",
749
+ "confirm",
750
+ "cancelLabel",
751
+ "onRowClick",
752
+ "prefetch",
753
+ "className",
754
+ "measureElement",
755
+ "pinSignature"
726
756
  ];
757
+ /**
758
+ * Row memo comparator: `Object.is` over every prop except the per-render
759
+ * style derivations excluded above. All event handlers passed to the row
760
+ * are identity-stable (or compared here, so a changed handler re-renders
761
+ * the row and is captured fresh) — a held row can never fire a stale
762
+ * closure.
763
+ */
727
764
  function desktopRowPropsEqual(prev, next) {
728
- return COMPARED_ROW_PROPS.every((key) => Object.is(prev[key], next[key]));
765
+ return COMPARED_ROW_PROPS.every((key) => Object.is(prev[key], next[key]));
729
766
  }
767
+ /**
768
+ * Sticky style for a leading chrome cell (chevron / checkbox) pinned
769
+ * `inset` px past the inline-start edge, active only while a data column is
770
+ * pinned on that side. Body cells pass a `background` so scrolled data
771
+ * never shows through.
772
+ */
730
773
  function leadingPinStyle(active, inset, zIndex, background) {
731
- if (!active) return void 0;
732
- const style = core.pinnedCellStyle({ side: "left", inset }, zIndex);
733
- return background ? { ...style, background } : style;
774
+ if (!active) return void 0;
775
+ const style = (0, _adapttable_core.pinnedCellStyle)({
776
+ side: "left",
777
+ inset
778
+ }, zIndex);
779
+ return background ? {
780
+ ...style,
781
+ background
782
+ } : style;
734
783
  }
784
+ /**
785
+ * Visual fingerprint of the pin layout (sides, insets, edge-pinned chrome
786
+ * columns). Memoized rows compare this one string instead of the per-render
787
+ * style objects derived from it.
788
+ */
735
789
  function pinLayoutSignature(columns, pinOffset, hasLeftPin, actionsEdgePinned) {
736
- const perColumn = columns.map((column) => {
737
- const pin = pinOffset?.(column.key);
738
- return pin ? `${column.key}:${pin.side}${pin.inset}` : column.key;
739
- });
740
- return `${perColumn.join("|")}|${String(hasLeftPin)}|${String(actionsEdgePinned)}`;
790
+ return `${columns.map((column) => {
791
+ const pin = pinOffset?.(column.key);
792
+ return pin ? `${column.key}:${pin.side}${pin.inset}` : column.key;
793
+ }).join("|")}|${String(hasLeftPin)}|${String(actionsEdgePinned)}`;
741
794
  }
742
- function DesktopRowBase({
743
- row,
744
- index,
745
- id,
746
- columns,
747
- getCellProps,
748
- selected,
749
- selectLabel,
750
- onToggleSelect,
751
- expanded,
752
- expandLabel,
753
- collapseLabel,
754
- onToggleExpand,
755
- renderRowDetail,
756
- columnSpan,
757
- rowActions,
758
- confirm,
759
- cancelLabel,
760
- onRowClick,
761
- prefetch,
762
- className,
763
- measureElement,
764
- pinStyleFor,
765
- selectionCellStyle,
766
- expansionCellStyle,
767
- actionsCellStyle
768
- }) {
769
- const showActions = (rowActions?.length ?? 0) > 0;
770
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
771
- /* @__PURE__ */ jsxRuntime.jsxs(
772
- core$1.Table.Tr,
773
- {
774
- role: "row",
775
- "data-index": index,
776
- "aria-selected": selected,
777
- ...core.rowClickProps(row, onRowClick),
778
- className,
779
- ref: measureElement,
780
- "data-stagger": "",
781
- onMouseEnter: prefetch ? () => prefetch(row) : void 0,
782
- children: [
783
- expanded !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, { ta: "center", style: expansionCellStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
784
- ExpandToggle,
785
- {
786
- expanded,
787
- expandLabel,
788
- collapseLabel,
789
- onToggle: () => onToggleExpand(id)
790
- }
791
- ) }),
792
- selected !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, { ta: "center", style: selectionCellStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
793
- core$1.Checkbox,
794
- {
795
- "aria-label": selectLabel,
796
- checked: selected,
797
- onChange: () => onToggleSelect(id)
798
- }
799
- ) }),
800
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
801
- core$1.Table.Td,
802
- {
803
- ...getCellProps(column),
804
- style: pinStyleFor(column.key),
805
- children: column.Cell ? /* @__PURE__ */ jsxRuntime.jsx(column.Cell, { row, rowIndex: index }) : column.accessor?.(row)
806
- },
807
- column.key
808
- )),
809
- showActions && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, { ta: "end", style: actionsCellStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
810
- RowActions,
811
- {
812
- row,
813
- actions: rowActions,
814
- confirm,
815
- cancelLabel
816
- }
817
- ) })
818
- ]
819
- }
820
- ),
821
- expanded === true && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, { colSpan: columnSpan, children: renderRowDetail(row) }) })
822
- ] });
795
+ /**
796
+ * One desktop row (plus its detail row when expanded), extracted so it can
797
+ * be memoized: typing in the search box or toggling another row's checkbox
798
+ * re-renders the table chrome but leaves untouched rows alone.
799
+ */
800
+ function DesktopRowBase({ row, index, id, columns, getCellProps, selected, selectLabel, onToggleSelect, expanded, expandLabel, collapseLabel, onToggleExpand, renderRowDetail, columnSpan, rowActions, confirm, cancelLabel, onRowClick, prefetch, className, measureElement, pinStyleFor, selectionCellStyle, expansionCellStyle, actionsCellStyle }) {
801
+ const showActions = (rowActions?.length ?? 0) > 0;
802
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Tr, {
803
+ role: "row",
804
+ "data-index": index,
805
+ "aria-selected": selected,
806
+ ...(0, _adapttable_core.rowClickProps)(row, onRowClick),
807
+ className,
808
+ ref: measureElement,
809
+ "data-stagger": "",
810
+ onMouseEnter: prefetch ? () => prefetch(row) : void 0,
811
+ children: [
812
+ expanded !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
813
+ ta: "center",
814
+ style: expansionCellStyle,
815
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExpandToggle, {
816
+ expanded,
817
+ expandLabel,
818
+ collapseLabel,
819
+ onToggle: () => onToggleExpand(id)
820
+ })
821
+ }),
822
+ selected !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
823
+ ta: "center",
824
+ style: selectionCellStyle,
825
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Checkbox, {
826
+ "aria-label": selectLabel,
827
+ checked: selected,
828
+ onChange: () => onToggleSelect(id)
829
+ })
830
+ }),
831
+ columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
832
+ ...getCellProps(column),
833
+ style: pinStyleFor(column.key),
834
+ children: column.Cell ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(column.Cell, {
835
+ row,
836
+ rowIndex: index
837
+ }) : column.accessor?.(row)
838
+ }, column.key)),
839
+ showActions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
840
+ ta: "end",
841
+ style: actionsCellStyle,
842
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowActions, {
843
+ row,
844
+ actions: rowActions,
845
+ confirm,
846
+ cancelLabel
847
+ })
848
+ })
849
+ ]
850
+ }), expanded === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Tr, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
851
+ colSpan: columnSpan,
852
+ children: renderRowDetail(row)
853
+ }) })] });
823
854
  }
824
- function DesktopTable({
825
- table,
826
- rows,
827
- rowActions,
828
- confirm,
829
- prefetch,
830
- onRowClick,
831
- rowClassName,
832
- renderRowDetail,
833
- summaryRow,
834
- expansion,
835
- getRowId,
836
- bodyRef,
837
- className,
838
- rowEntries,
839
- paddingTop = 0,
840
- paddingBottom = 0,
841
- measureElement,
842
- stickyHeaderOffset = 0,
843
- stickyHeader = false,
844
- pinOffset,
845
- maxHeight,
846
- virtualScrollRef,
847
- setWidth,
848
- columnWidths,
849
- resizeLabel = "Resize column",
850
- actionsPinned = false,
851
- density = "comfortable"
852
- }) {
853
- const { columns, selection, labels, showActions, entries, columnSpan } = core.tableRenderModel({
854
- table,
855
- rows,
856
- rowActions,
857
- getRowId,
858
- rowEntries,
859
- renderRowDetail,
860
- expansion
861
- });
862
- const expandable = expansion !== void 0;
863
- const groupCells = core.headerGroupRow(columns);
864
- const summaryCells = summaryRow?.(rows);
865
- const hasRightPin = table.columns.some(
866
- (c) => pinOffset?.(c.key)?.side === "right"
867
- );
868
- const actionsEdgePinned = showActions && (hasRightPin || actionsPinned);
869
- const hasPinned = table.columns.some((c) => pinOffset?.(c.key) != null) || actionsEdgePinned;
870
- const { ref: wrapperRef, overflowing } = core.useHorizontalOverflow();
871
- const inScrollBox = maxHeight != null || hasPinned || overflowing;
872
- const headerCellStyle = stickyHeader ? {
873
- position: "sticky",
874
- top: inScrollBox ? 0 : stickyHeaderOffset,
875
- zIndex: core.PIN_Z.header,
876
- background: "var(--mantine-color-body)",
877
- boxShadow: "0 1px 0 var(--mantine-color-default-border)"
878
- } : { background: "var(--mantine-color-body)" };
879
- const expansionWidth = 36;
880
- const selectionWidth = 40;
881
- const actionsWidth = 120;
882
- const expansionLead = expandable ? expansionWidth : 0;
883
- const leads = {
884
- left: expansionLead + (selection ? selectionWidth : 0),
885
- right: showActions ? actionsWidth : 0
886
- };
887
- const hasLeftPin = table.columns.some(
888
- (c) => pinOffset?.(c.key)?.side === "left"
889
- );
890
- const pinBg = "var(--mantine-color-body)";
891
- const headerStyleFor = (column) => {
892
- const key = column.key;
893
- const pin = core.pinnedCellStyle(pinOffset?.(key), core.PIN_Z.headerPinned, leads);
894
- const merged = {
895
- ...headerCellStyle,
896
- ...pin,
897
- // A pinned column renders at the same width its sticky inset assumed,
898
- // so stacked pins stay flush even with no declared width.
899
- width: pin ? core.pinnedColumnWidth(column, columnWidths) : columnWidths?.[key]
900
- };
901
- if (setWidth && !merged.position) merged.position = "relative";
902
- return merged;
903
- };
904
- const expansionHeaderStyle = {
905
- ...headerCellStyle,
906
- ...leadingPinStyle(hasLeftPin, 0, core.PIN_Z.headerPinned)
907
- };
908
- const selectionHeaderStyle = {
909
- ...headerCellStyle,
910
- ...leadingPinStyle(hasLeftPin, expansionLead, core.PIN_Z.headerPinned)
911
- };
912
- const actionsHeaderStyle = {
913
- ...headerCellStyle,
914
- ...core.edgePinStyle("right", actionsEdgePinned, core.PIN_Z.headerPinned)
915
- };
916
- const edgeBodyStyle = (side, active) => {
917
- const pin = core.edgePinStyle(side, active, core.PIN_Z.body);
918
- return pin ? { ...pin, background: pinBg } : void 0;
919
- };
920
- const expansionCellStyle = leadingPinStyle(hasLeftPin, 0, core.PIN_Z.body, pinBg);
921
- const selectionCellStyle = leadingPinStyle(
922
- hasLeftPin,
923
- expansionLead,
924
- core.PIN_Z.body,
925
- pinBg
926
- );
927
- const actionsCellStyle = edgeBodyStyle("right", actionsEdgePinned);
928
- const columnName = (column) => typeof column.header === "string" ? column.header : column.key;
929
- const resizeHandleFor = (column) => setWidth ? /* @__PURE__ */ jsxRuntime.jsx(
930
- "span",
931
- {
932
- ...core.columnResizeHandleProps(
933
- column.key,
934
- setWidth,
935
- `${resizeLabel}: ${columnName(column)}`
936
- ),
937
- style: RESIZE_HANDLE_STYLE
938
- }
939
- ) : void 0;
940
- const bodyPinStyle = (key) => {
941
- const pin = core.pinnedCellStyle(pinOffset?.(key), core.PIN_Z.body, leads);
942
- return pin ? { ...pin, background: pinBg } : void 0;
943
- };
944
- const { verticalSpacing, horizontalSpacing } = DENSITY_SPACING[density];
945
- const minWidth = core.tableMinWidth(columns, {
946
- widths: columnWidths,
947
- extra: expansionLead + (selection ? 40 : 0) + (showActions ? 120 : 0)
948
- });
949
- const selectionRef = react.useRef(selection);
950
- selectionRef.current = selection;
951
- const toggleSelect = react.useCallback(
952
- (id) => selectionRef.current.toggle(id),
953
- []
954
- );
955
- const Row = react.useMemo(
956
- () => react.memo(DesktopRowBase, desktopRowPropsEqual),
957
- []
958
- );
959
- const pinSignature = pinLayoutSignature(
960
- columns,
961
- pinOffset,
962
- hasLeftPin,
963
- actionsEdgePinned
964
- );
965
- const wrapperStyle = maxHeight == null ? {
966
- width: "100%",
967
- ...hasPinned || overflowing ? { overflowX: "auto" } : {}
968
- } : { width: "100%", maxHeight, overflow: "auto" };
969
- return /* @__PURE__ */ jsxRuntime.jsx(
970
- "div",
971
- {
972
- ref: (node) => {
973
- wrapperRef(node);
974
- virtualScrollRef?.(node);
975
- },
976
- style: wrapperStyle,
977
- children: /* @__PURE__ */ jsxRuntime.jsxs(
978
- core$1.Table,
979
- {
980
- ...table.getTableProps(),
981
- className,
982
- highlightOnHover: true,
983
- verticalSpacing,
984
- horizontalSpacing,
985
- miw: Math.max(480, minWidth),
986
- style: stickyHeader ? { borderCollapse: "separate", borderSpacing: 0 } : void 0,
987
- children: [
988
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Thead, { style: { background: "var(--mantine-color-body)" }, children: [
989
- groupCells && /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tr, { children: [
990
- expandable && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, {}),
991
- selection && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, {}),
992
- groupCells.map((cell) => /* @__PURE__ */ jsxRuntime.jsx(
993
- core$1.Table.Th,
994
- {
995
- colSpan: cell.span,
996
- ta: "center",
997
- fw: 600,
998
- style: {
999
- borderBottom: "1px solid var(--mantine-color-default-border)"
1000
- },
1001
- children: cell.label
1002
- },
1003
- cell.key
1004
- )),
1005
- showActions && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, {})
1006
- ] }),
1007
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tr, { ...table.getHeaderRowProps(), children: [
1008
- expandable && /* @__PURE__ */ jsxRuntime.jsx(
1009
- core$1.Table.Th,
1010
- {
1011
- w: expansionWidth,
1012
- ta: "center",
1013
- style: expansionHeaderStyle,
1014
- children: /* @__PURE__ */ jsxRuntime.jsx(core$1.VisuallyHidden, { children: labels.expandRow })
1015
- }
1016
- ),
1017
- selection && /* @__PURE__ */ jsxRuntime.jsx(
1018
- core$1.Table.Th,
1019
- {
1020
- w: selectionWidth,
1021
- ta: "center",
1022
- style: selectionHeaderStyle,
1023
- children: /* @__PURE__ */ jsxRuntime.jsx(
1024
- core$1.Checkbox,
1025
- {
1026
- "aria-label": labels.selectAll,
1027
- checked: selection.headerState === "all",
1028
- indeterminate: selection.headerState === "some",
1029
- onChange: selection.toggleAll
1030
- }
1031
- )
1032
- }
1033
- ),
1034
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
1035
- HeaderCell,
1036
- {
1037
- table,
1038
- column,
1039
- stickyStyle: headerStyleFor(column),
1040
- resizeHandle: resizeHandleFor(column)
1041
- },
1042
- column.key
1043
- )),
1044
- showActions && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, { ta: "end", w: actionsWidth, style: actionsHeaderStyle, children: labels.actions })
1045
- ] })
1046
- ] }),
1047
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tbody, { ref: bodyRef, children: [
1048
- paddingTop > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tr, { "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
1049
- core$1.Table.Td,
1050
- {
1051
- colSpan: columnSpan,
1052
- style: { height: paddingTop, padding: 0 }
1053
- }
1054
- ) }),
1055
- entries.map(({ row, index, key }) => {
1056
- const id = getRowId(row);
1057
- return /* @__PURE__ */ jsxRuntime.jsx(
1058
- Row,
1059
- {
1060
- row,
1061
- index,
1062
- id,
1063
- columns,
1064
- getCellProps: table.getCellProps,
1065
- selected: selection?.isSelected(id),
1066
- selectLabel: labels.selectRow,
1067
- onToggleSelect: toggleSelect,
1068
- expanded: expansion?.isExpanded(id),
1069
- expandLabel: labels.expandRow,
1070
- collapseLabel: labels.collapseRow,
1071
- onToggleExpand: expansion?.toggle,
1072
- renderRowDetail,
1073
- columnSpan,
1074
- rowActions,
1075
- confirm,
1076
- cancelLabel: labels.cancel,
1077
- onRowClick,
1078
- prefetch,
1079
- className: rowClassName?.(row, index),
1080
- measureElement,
1081
- pinStyleFor: bodyPinStyle,
1082
- selectionCellStyle,
1083
- expansionCellStyle,
1084
- actionsCellStyle,
1085
- pinSignature
1086
- },
1087
- key
1088
- );
1089
- }),
1090
- paddingBottom > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tr, { "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
1091
- core$1.Table.Td,
1092
- {
1093
- colSpan: columnSpan,
1094
- style: { height: paddingBottom, padding: 0 }
1095
- }
1096
- ) })
1097
- ] }),
1098
- summaryCells && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tfoot, { children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tr, { children: [
1099
- expandable && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, {}),
1100
- selection && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, {}),
1101
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
1102
- core$1.Table.Td,
1103
- {
1104
- ...table.getCellProps(column),
1105
- fw: 600,
1106
- c: "dimmed",
1107
- children: summaryCells[column.key]
1108
- },
1109
- column.key
1110
- )),
1111
- showActions && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, {})
1112
- ] }) })
1113
- ]
1114
- }
1115
- )
1116
- }
1117
- );
855
+ /** Desktop table rendering driven by core prop-getters. */
856
+ function DesktopTable({ table, rows, rowActions, confirm, prefetch, onRowClick, rowClassName, renderRowDetail, summaryRow, expansion, getRowId, bodyRef, className, rowEntries, paddingTop = 0, paddingBottom = 0, measureElement, stickyHeaderOffset = 0, stickyHeader = false, pinOffset, maxHeight, virtualScrollRef, setWidth, columnWidths, resizeLabel = "Resize column", actionsPinned = false, density = "comfortable" }) {
857
+ const { columns, selection, labels, showActions, entries, columnSpan } = (0, _adapttable_core.tableRenderModel)({
858
+ table,
859
+ rows,
860
+ rowActions,
861
+ getRowId,
862
+ rowEntries,
863
+ renderRowDetail,
864
+ expansion
865
+ });
866
+ const expandable = expansion !== void 0;
867
+ const groupCells = (0, _adapttable_core.headerGroupRow)(columns);
868
+ const summaryCells = summaryRow?.(rows);
869
+ const hasRightPin = table.columns.some((c) => pinOffset?.(c.key)?.side === "right");
870
+ const actionsEdgePinned = showActions && (hasRightPin || actionsPinned);
871
+ const hasPinned = table.columns.some((c) => pinOffset?.(c.key) != null) || actionsEdgePinned;
872
+ const { ref: wrapperRef, overflowing } = (0, _adapttable_core.useHorizontalOverflow)();
873
+ const headerCellStyle = stickyHeader ? {
874
+ position: "sticky",
875
+ top: maxHeight != null || hasPinned || overflowing ? 0 : stickyHeaderOffset,
876
+ zIndex: _adapttable_core.PIN_Z.header,
877
+ background: "var(--mantine-color-body)",
878
+ boxShadow: "0 1px 0 var(--mantine-color-default-border)"
879
+ } : { background: "var(--mantine-color-body)" };
880
+ const expansionWidth = 36;
881
+ const selectionWidth = 40;
882
+ const actionsWidth = 120;
883
+ const expansionLead = expandable ? expansionWidth : 0;
884
+ const leads = {
885
+ left: expansionLead + (selection ? selectionWidth : 0),
886
+ right: showActions ? actionsWidth : 0
887
+ };
888
+ const hasLeftPin = table.columns.some((c) => pinOffset?.(c.key)?.side === "left");
889
+ const pinBg = "var(--mantine-color-body)";
890
+ const headerStyleFor = (column) => {
891
+ const key = column.key;
892
+ const pin = (0, _adapttable_core.pinnedCellStyle)(pinOffset?.(key), _adapttable_core.PIN_Z.headerPinned, leads);
893
+ const merged = {
894
+ ...headerCellStyle,
895
+ ...pin,
896
+ width: pin ? (0, _adapttable_core.pinnedColumnWidth)(column, columnWidths) : columnWidths?.[key]
897
+ };
898
+ if (setWidth && !merged.position) merged.position = "relative";
899
+ return merged;
900
+ };
901
+ const expansionHeaderStyle = {
902
+ ...headerCellStyle,
903
+ ...leadingPinStyle(hasLeftPin, 0, _adapttable_core.PIN_Z.headerPinned)
904
+ };
905
+ const selectionHeaderStyle = {
906
+ ...headerCellStyle,
907
+ ...leadingPinStyle(hasLeftPin, expansionLead, _adapttable_core.PIN_Z.headerPinned)
908
+ };
909
+ const actionsHeaderStyle = {
910
+ ...headerCellStyle,
911
+ ...(0, _adapttable_core.edgePinStyle)("right", actionsEdgePinned, _adapttable_core.PIN_Z.headerPinned)
912
+ };
913
+ const edgeBodyStyle = (side, active) => {
914
+ const pin = (0, _adapttable_core.edgePinStyle)(side, active, _adapttable_core.PIN_Z.body);
915
+ return pin ? {
916
+ ...pin,
917
+ background: pinBg
918
+ } : void 0;
919
+ };
920
+ const expansionCellStyle = leadingPinStyle(hasLeftPin, 0, _adapttable_core.PIN_Z.body, pinBg);
921
+ const selectionCellStyle = leadingPinStyle(hasLeftPin, expansionLead, _adapttable_core.PIN_Z.body, pinBg);
922
+ const actionsCellStyle = edgeBodyStyle("right", actionsEdgePinned);
923
+ const columnName = (column) => typeof column.header === "string" ? column.header : column.key;
924
+ const resizeHandleFor = (column) => setWidth ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
925
+ ...(0, _adapttable_core.columnResizeHandleProps)(column.key, setWidth, `${resizeLabel}: ${columnName(column)}`),
926
+ style: RESIZE_HANDLE_STYLE
927
+ }) : void 0;
928
+ const bodyPinStyle = (key) => {
929
+ const pin = (0, _adapttable_core.pinnedCellStyle)(pinOffset?.(key), _adapttable_core.PIN_Z.body, leads);
930
+ return pin ? {
931
+ ...pin,
932
+ background: pinBg
933
+ } : void 0;
934
+ };
935
+ const { verticalSpacing, horizontalSpacing } = DENSITY_SPACING[density];
936
+ const minWidth = (0, _adapttable_core.tableMinWidth)(columns, {
937
+ widths: columnWidths,
938
+ extra: expansionLead + (selection ? 40 : 0) + (showActions ? 120 : 0)
939
+ });
940
+ const selectionRef = (0, react.useRef)(selection);
941
+ selectionRef.current = selection;
942
+ const toggleSelect = (0, react.useCallback)((id) => selectionRef.current.toggle(id), []);
943
+ const Row = (0, react.useMemo)(() => (0, react.memo)(DesktopRowBase, desktopRowPropsEqual), []);
944
+ const pinSignature = pinLayoutSignature(columns, pinOffset, hasLeftPin, actionsEdgePinned);
945
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
946
+ ref: (node) => {
947
+ wrapperRef(node);
948
+ virtualScrollRef?.(node);
949
+ },
950
+ style: maxHeight == null ? {
951
+ width: "100%",
952
+ ...hasPinned || overflowing ? { overflowX: "auto" } : {}
953
+ } : {
954
+ width: "100%",
955
+ maxHeight,
956
+ overflow: "auto"
957
+ },
958
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table, {
959
+ ...table.getTableProps(),
960
+ className,
961
+ highlightOnHover: true,
962
+ verticalSpacing,
963
+ horizontalSpacing,
964
+ miw: Math.max(480, minWidth),
965
+ style: stickyHeader ? {
966
+ borderCollapse: "separate",
967
+ borderSpacing: 0
968
+ } : void 0,
969
+ children: [
970
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Thead, {
971
+ style: { background: "var(--mantine-color-body)" },
972
+ children: [groupCells && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Tr, { children: [
973
+ expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, {}),
974
+ selection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, {}),
975
+ groupCells.map((cell) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, {
976
+ colSpan: cell.span,
977
+ ta: "center",
978
+ fw: 600,
979
+ style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
980
+ children: cell.label
981
+ }, cell.key)),
982
+ showActions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, {})
983
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Tr, {
984
+ ...table.getHeaderRowProps(),
985
+ children: [
986
+ expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, {
987
+ w: expansionWidth,
988
+ ta: "center",
989
+ style: expansionHeaderStyle,
990
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.VisuallyHidden, { children: labels.expandRow })
991
+ }),
992
+ selection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, {
993
+ w: selectionWidth,
994
+ ta: "center",
995
+ style: selectionHeaderStyle,
996
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Checkbox, {
997
+ "aria-label": labels.selectAll,
998
+ checked: selection.headerState === "all",
999
+ indeterminate: selection.headerState === "some",
1000
+ onChange: selection.toggleAll
1001
+ })
1002
+ }),
1003
+ columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HeaderCell, {
1004
+ table,
1005
+ column,
1006
+ stickyStyle: headerStyleFor(column),
1007
+ resizeHandle: resizeHandleFor(column)
1008
+ }, column.key)),
1009
+ showActions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, {
1010
+ ta: "end",
1011
+ w: actionsWidth,
1012
+ style: actionsHeaderStyle,
1013
+ children: labels.actions
1014
+ })
1015
+ ]
1016
+ })]
1017
+ }),
1018
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Tbody, {
1019
+ ref: bodyRef,
1020
+ children: [
1021
+ paddingTop > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Tr, {
1022
+ "aria-hidden": true,
1023
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
1024
+ colSpan: columnSpan,
1025
+ style: {
1026
+ height: paddingTop,
1027
+ padding: 0
1028
+ }
1029
+ })
1030
+ }),
1031
+ entries.map(({ row, index, key }) => {
1032
+ const id = getRowId(row);
1033
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
1034
+ row,
1035
+ index,
1036
+ id,
1037
+ columns,
1038
+ getCellProps: table.getCellProps,
1039
+ selected: selection?.isSelected(id),
1040
+ selectLabel: labels.selectRow,
1041
+ onToggleSelect: toggleSelect,
1042
+ expanded: expansion?.isExpanded(id),
1043
+ expandLabel: labels.expandRow,
1044
+ collapseLabel: labels.collapseRow,
1045
+ onToggleExpand: expansion?.toggle,
1046
+ renderRowDetail,
1047
+ columnSpan,
1048
+ rowActions,
1049
+ confirm,
1050
+ cancelLabel: labels.cancel,
1051
+ onRowClick,
1052
+ prefetch,
1053
+ className: rowClassName?.(row, index),
1054
+ measureElement,
1055
+ pinStyleFor: bodyPinStyle,
1056
+ selectionCellStyle,
1057
+ expansionCellStyle,
1058
+ actionsCellStyle,
1059
+ pinSignature
1060
+ }, key);
1061
+ }),
1062
+ paddingBottom > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Tr, {
1063
+ "aria-hidden": true,
1064
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
1065
+ colSpan: columnSpan,
1066
+ style: {
1067
+ height: paddingBottom,
1068
+ padding: 0
1069
+ }
1070
+ })
1071
+ })
1072
+ ]
1073
+ }),
1074
+ summaryCells && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Tfoot, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table.Tr, { children: [
1075
+ expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {}),
1076
+ selection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {}),
1077
+ columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {
1078
+ ...table.getCellProps(column),
1079
+ fw: 600,
1080
+ c: "dimmed",
1081
+ children: summaryCells[column.key]
1082
+ }, column.key)),
1083
+ showActions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, {})
1084
+ ] }) })
1085
+ ]
1086
+ })
1087
+ });
1118
1088
  }
1119
- function EmptyState({
1120
- title,
1121
- description,
1122
- icon,
1123
- action
1124
- }) {
1125
- return /* @__PURE__ */ jsxRuntime.jsxs(
1126
- core$1.Stack,
1127
- {
1128
- role: "status",
1129
- align: "center",
1130
- justify: "center",
1131
- gap: 6,
1132
- py: 48,
1133
- px: 16,
1134
- children: [
1135
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { c: "dimmed", "aria-hidden": true, children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(InboxIcon, { size: 40 }) }),
1136
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fw: 600, fz: "md", children: title }),
1137
- description && /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { c: "dimmed", fz: "sm", ta: "center", maw: 360, children: description }),
1138
- action
1139
- ]
1140
- }
1141
- );
1089
+ //#endregion
1090
+ //#region src/components/EmptyState.tsx
1091
+ /** Centred "nothing to show" placeholder. */
1092
+ function EmptyState({ title, description, icon, action }) {
1093
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
1094
+ role: "status",
1095
+ align: "center",
1096
+ justify: "center",
1097
+ gap: 6,
1098
+ py: 48,
1099
+ px: 16,
1100
+ children: [
1101
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1102
+ c: "dimmed",
1103
+ "aria-hidden": true,
1104
+ children: icon ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InboxIcon, { size: 40 })
1105
+ }),
1106
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1107
+ fw: 600,
1108
+ fz: "md",
1109
+ children: title
1110
+ }),
1111
+ description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1112
+ c: "dimmed",
1113
+ fz: "sm",
1114
+ ta: "center",
1115
+ maw: 360,
1116
+ children: description
1117
+ }),
1118
+ action
1119
+ ]
1120
+ });
1142
1121
  }
1143
- function ErrorState({
1144
- error,
1145
- title,
1146
- message,
1147
- retryLabel,
1148
- onRetry,
1149
- isRetrying
1150
- }) {
1151
- return /* @__PURE__ */ jsxRuntime.jsx(
1152
- core$1.Alert,
1153
- {
1154
- icon: /* @__PURE__ */ jsxRuntime.jsx(AlertIcon, { size: 16 }),
1155
- color: "red",
1156
- variant: "light",
1157
- title,
1158
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", align: "center", wrap: "nowrap", gap: "md", children: [
1159
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1160
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "sm", children: message }),
1161
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", mt: 2, children: error.message })
1162
- ] }),
1163
- onRetry && /* @__PURE__ */ jsxRuntime.jsx(
1164
- core$1.Button,
1165
- {
1166
- size: "xs",
1167
- variant: "light",
1168
- color: "red",
1169
- leftSection: /* @__PURE__ */ jsxRuntime.jsx(RefreshIcon, { size: 14 }),
1170
- onClick: onRetry,
1171
- loading: isRetrying,
1172
- children: retryLabel
1173
- }
1174
- )
1175
- ] })
1176
- }
1177
- );
1122
+ //#endregion
1123
+ //#region src/components/ErrorState.tsx
1124
+ /** Inline error alert with an optional retry button. */
1125
+ function ErrorState({ error, title, message, retryLabel, onRetry, isRetrying }) {
1126
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Alert, {
1127
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AlertIcon, { size: 16 }),
1128
+ color: "red",
1129
+ variant: "light",
1130
+ title,
1131
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1132
+ justify: "space-between",
1133
+ align: "center",
1134
+ wrap: "nowrap",
1135
+ gap: "md",
1136
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1137
+ fz: "sm",
1138
+ children: message
1139
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1140
+ fz: "xs",
1141
+ c: "dimmed",
1142
+ mt: 2,
1143
+ children: error.message
1144
+ })] }), onRetry && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1145
+ size: "xs",
1146
+ variant: "light",
1147
+ color: "red",
1148
+ leftSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RefreshIcon, { size: 14 }),
1149
+ onClick: onRetry,
1150
+ loading: isRetrying,
1151
+ children: retryLabel
1152
+ })]
1153
+ })
1154
+ });
1178
1155
  }
1179
- function FilterDrawer({
1180
- opened,
1181
- onClose,
1182
- filters,
1183
- activeFilterCount,
1184
- onClearFilters,
1185
- labels,
1186
- dir = "ltr"
1187
- }) {
1188
- return /* @__PURE__ */ jsxRuntime.jsx(
1189
- core$1.Drawer,
1190
- {
1191
- opened,
1192
- onClose,
1193
- position: dir === "rtl" ? "left" : "right",
1194
- size: 380,
1195
- title: labels.filters,
1196
- overlayProps: { opacity: 0.4, blur: 2 },
1197
- closeButtonProps: { "aria-label": labels.cancel },
1198
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: "md", mih: "60vh", justify: "space-between", children: [
1199
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Stack, { gap: "md", children: filters }),
1200
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", pt: "md", children: [
1201
- /* @__PURE__ */ jsxRuntime.jsx(
1202
- core$1.Button,
1203
- {
1204
- variant: "subtle",
1205
- onClick: onClearFilters,
1206
- disabled: activeFilterCount === 0,
1207
- children: labels.clearAll
1208
- }
1209
- ),
1210
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { onClick: onClose, children: labels.applyFilters })
1211
- ] })
1212
- ] })
1213
- }
1214
- );
1156
+ //#endregion
1157
+ //#region src/components/FilterDrawer.tsx
1158
+ /** Right-side drawer holding the caller's filter widgets + apply/clear. */
1159
+ function FilterDrawer({ opened, onClose, filters, activeFilterCount, onClearFilters, labels, dir = "ltr" }) {
1160
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Drawer, {
1161
+ opened,
1162
+ onClose,
1163
+ position: dir === "rtl" ? "left" : "right",
1164
+ size: 380,
1165
+ title: labels.filters,
1166
+ overlayProps: {
1167
+ opacity: .4,
1168
+ blur: 2
1169
+ },
1170
+ closeButtonProps: { "aria-label": labels.cancel },
1171
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
1172
+ gap: "md",
1173
+ mih: "60vh",
1174
+ justify: "space-between",
1175
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Stack, {
1176
+ gap: "md",
1177
+ children: filters
1178
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1179
+ justify: "space-between",
1180
+ pt: "md",
1181
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1182
+ variant: "subtle",
1183
+ onClick: onClearFilters,
1184
+ disabled: activeFilterCount === 0,
1185
+ children: labels.clearAll
1186
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1187
+ onClick: onClose,
1188
+ children: labels.applyFilters
1189
+ })]
1190
+ })]
1191
+ })
1192
+ });
1215
1193
  }
1194
+ //#endregion
1195
+ //#region src/components/MobileCards.tsx
1216
1196
  function mobileLabel(column) {
1217
- return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
1197
+ return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
1218
1198
  }
1219
- function MobileCards({
1220
- table,
1221
- rows,
1222
- rowActions,
1223
- confirm,
1224
- getRowId,
1225
- bodyRef,
1226
- className,
1227
- rowEntries,
1228
- paddingTop = 0,
1229
- paddingBottom = 0,
1230
- measureElement,
1231
- density = "comfortable",
1232
- onRowClick,
1233
- rowClassName,
1234
- renderRowDetail,
1235
- summaryRow,
1236
- expansion
1237
- }) {
1238
- const { columns, selection, labels } = table;
1239
- const compact = density === "compact";
1240
- const cardPadding = compact ? "sm" : "md";
1241
- const cardGap = compact ? 4 : "xs";
1242
- const entries = rowEntries ?? rows.map((row, index) => ({
1243
- row,
1244
- index,
1245
- key: getRowId(row)
1246
- }));
1247
- const summaryCells = summaryRow?.(rows);
1248
- return /* @__PURE__ */ jsxRuntime.jsxs(
1249
- core$1.Stack,
1250
- {
1251
- gap: compact ? "xs" : "sm",
1252
- ref: bodyRef,
1253
- className,
1254
- ...table.getTableProps({ role: "list" }),
1255
- children: [
1256
- paddingTop > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, style: { height: paddingTop } }),
1257
- entries.map(({ row, index, key }) => {
1258
- const id = getRowId(row);
1259
- return /* @__PURE__ */ jsxRuntime.jsx(
1260
- core$1.Card,
1261
- {
1262
- ...core.rowClickProps(row, onRowClick),
1263
- className: rowClassName?.(row, index),
1264
- ref: measureElement,
1265
- "data-index": index,
1266
- withBorder: true,
1267
- radius: "md",
1268
- padding: cardPadding,
1269
- role: "listitem",
1270
- "data-stagger": "",
1271
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: cardGap, children: [
1272
- selection && /* @__PURE__ */ jsxRuntime.jsx(
1273
- core$1.Checkbox,
1274
- {
1275
- "aria-label": labels.selectRow,
1276
- checked: selection.isSelected(id),
1277
- onChange: () => selection.toggle(id)
1278
- }
1279
- ),
1280
- expansion && /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { justify: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(
1281
- ExpandToggle,
1282
- {
1283
- expanded: expansion.isExpanded(id),
1284
- expandLabel: labels.expandRow,
1285
- collapseLabel: labels.collapseRow,
1286
- onToggle: () => expansion.toggle(id)
1287
- }
1288
- ) }),
1289
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1290
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", tt: "uppercase", fw: 500, children: mobileLabel(column) }),
1291
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { component: "div", fz: "sm", children: column.Cell ? /* @__PURE__ */ jsxRuntime.jsx(column.Cell, { row, rowIndex: index }) : column.accessor?.(row) })
1292
- ] }, column.key)),
1293
- expansion?.isExpanded(id) === true && /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderRowDetail(row) }),
1294
- rowActions && rowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { gap: 4, justify: "flex-end", pt: 4, children: rowActions.map((action) => {
1295
- if (action.isHidden?.(row)) return null;
1296
- const reason = core.resolveDisabledReason(
1297
- action.disabledReason?.(row)
1298
- );
1299
- const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
1300
- const run = disabled ? void 0 : () => core.runRowAction(action, row, confirm, labels.cancel);
1301
- return action.icon ? /* @__PURE__ */ jsxRuntime.jsx(
1302
- core$1.Tooltip,
1303
- {
1304
- label: reason ?? action.label,
1305
- withArrow: true,
1306
- openDelay: 200,
1307
- children: /* @__PURE__ */ jsxRuntime.jsx(
1308
- core$1.ActionIcon,
1309
- {
1310
- variant: "subtle",
1311
- color: action.color,
1312
- size: "sm",
1313
- disabled,
1314
- "aria-label": action.label,
1315
- onClick: run,
1316
- children: action.icon
1317
- }
1318
- )
1319
- },
1320
- action.key
1321
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1322
- core$1.Button,
1323
- {
1324
- variant: "subtle",
1325
- color: action.color,
1326
- size: "compact-sm",
1327
- disabled,
1328
- onClick: run,
1329
- children: action.label
1330
- },
1331
- action.key
1332
- );
1333
- }) })
1334
- ] })
1335
- },
1336
- key
1337
- );
1338
- }),
1339
- paddingBottom > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, style: { height: paddingBottom } }),
1340
- summaryCells && /* @__PURE__ */ jsxRuntime.jsx(core$1.Card, { withBorder: true, radius: "md", padding: cardPadding, role: "listitem", children: /* @__PURE__ */ jsxRuntime.jsx(core$1.Stack, { gap: cardGap, children: columns.filter((column) => summaryCells[column.key] !== void 0).map((column) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1341
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", tt: "uppercase", fw: 500, children: mobileLabel(column) }),
1342
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { component: "div", fz: "sm", fw: 600, children: summaryCells[column.key] })
1343
- ] }, column.key)) }) })
1344
- ]
1345
- }
1346
- );
1199
+ /** Mobile rendering: one Mantine Card per row with labelled key/value rows. */
1200
+ function MobileCards({ table, rows, rowActions, confirm, getRowId, bodyRef, className, rowEntries, paddingTop = 0, paddingBottom = 0, measureElement, density = "comfortable", onRowClick, rowClassName, renderRowDetail, summaryRow, expansion }) {
1201
+ const { columns, selection, labels } = table;
1202
+ const compact = density === "compact";
1203
+ const cardPadding = compact ? "sm" : "md";
1204
+ const cardGap = compact ? 4 : "xs";
1205
+ const entries = rowEntries ?? rows.map((row, index) => ({
1206
+ row,
1207
+ index,
1208
+ key: getRowId(row)
1209
+ }));
1210
+ const summaryCells = summaryRow?.(rows);
1211
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
1212
+ gap: compact ? "xs" : "sm",
1213
+ ref: bodyRef,
1214
+ className,
1215
+ ...table.getTableProps({ role: "list" }),
1216
+ children: [
1217
+ paddingTop > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1218
+ "aria-hidden": true,
1219
+ style: { height: paddingTop }
1220
+ }),
1221
+ entries.map(({ row, index, key }) => {
1222
+ const id = getRowId(row);
1223
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Card, {
1224
+ ...(0, _adapttable_core.rowClickProps)(row, onRowClick),
1225
+ className: rowClassName?.(row, index),
1226
+ ref: measureElement,
1227
+ "data-index": index,
1228
+ withBorder: true,
1229
+ radius: "md",
1230
+ padding: cardPadding,
1231
+ role: "listitem",
1232
+ "data-stagger": "",
1233
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
1234
+ gap: cardGap,
1235
+ children: [
1236
+ selection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Checkbox, {
1237
+ "aria-label": labels.selectRow,
1238
+ checked: selection.isSelected(id),
1239
+ onChange: () => selection.toggle(id)
1240
+ }),
1241
+ expansion && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Group, {
1242
+ justify: "flex-end",
1243
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExpandToggle, {
1244
+ expanded: expansion.isExpanded(id),
1245
+ expandLabel: labels.expandRow,
1246
+ collapseLabel: labels.collapseRow,
1247
+ onToggle: () => expansion.toggle(id)
1248
+ })
1249
+ }),
1250
+ columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1251
+ fz: "xs",
1252
+ c: "dimmed",
1253
+ tt: "uppercase",
1254
+ fw: 500,
1255
+ children: mobileLabel(column)
1256
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1257
+ component: "div",
1258
+ fz: "sm",
1259
+ children: column.Cell ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(column.Cell, {
1260
+ row,
1261
+ rowIndex: index
1262
+ }) : column.accessor?.(row)
1263
+ })] }, column.key)),
1264
+ expansion?.isExpanded(id) === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: renderRowDetail(row) }),
1265
+ rowActions && rowActions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Group, {
1266
+ gap: 4,
1267
+ justify: "flex-end",
1268
+ pt: 4,
1269
+ children: rowActions.map((action) => {
1270
+ if (action.isHidden?.(row)) return null;
1271
+ const reason = (0, _adapttable_core.resolveDisabledReason)(action.disabledReason?.(row));
1272
+ const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
1273
+ const run = disabled ? void 0 : () => (0, _adapttable_core.runRowAction)(action, row, confirm, labels.cancel);
1274
+ return action.icon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Tooltip, {
1275
+ label: reason ?? action.label,
1276
+ withArrow: true,
1277
+ openDelay: 200,
1278
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
1279
+ variant: "subtle",
1280
+ color: action.color,
1281
+ size: "sm",
1282
+ disabled,
1283
+ "aria-label": action.label,
1284
+ onClick: run,
1285
+ children: action.icon
1286
+ })
1287
+ }, action.key) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1288
+ variant: "subtle",
1289
+ color: action.color,
1290
+ size: "compact-sm",
1291
+ disabled,
1292
+ onClick: run,
1293
+ children: action.label
1294
+ }, action.key);
1295
+ })
1296
+ })
1297
+ ]
1298
+ })
1299
+ }, key);
1300
+ }),
1301
+ paddingBottom > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1302
+ "aria-hidden": true,
1303
+ style: { height: paddingBottom }
1304
+ }),
1305
+ summaryCells && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Card, {
1306
+ withBorder: true,
1307
+ radius: "md",
1308
+ padding: cardPadding,
1309
+ role: "listitem",
1310
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Stack, {
1311
+ gap: cardGap,
1312
+ children: columns.filter((column) => summaryCells[column.key] !== void 0).map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1313
+ fz: "xs",
1314
+ c: "dimmed",
1315
+ tt: "uppercase",
1316
+ fw: 500,
1317
+ children: mobileLabel(column)
1318
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1319
+ component: "div",
1320
+ fz: "sm",
1321
+ fw: 600,
1322
+ children: summaryCells[column.key]
1323
+ })] }, column.key))
1324
+ })
1325
+ })
1326
+ ]
1327
+ });
1347
1328
  }
1348
- function PaginationFooter({
1349
- page,
1350
- totalPages,
1351
- limit,
1352
- total,
1353
- fromIndex,
1354
- toIndex,
1355
- onPageChange,
1356
- onLimitChange,
1357
- labels
1358
- }) {
1359
- const safeTotalPages = Math.max(totalPages, 1);
1360
- const safePage = Math.min(Math.max(page, 1), safeTotalPages);
1361
- const options = core.pageSizeOptions(limit).map((n) => ({
1362
- value: String(n),
1363
- label: String(n)
1364
- }));
1365
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", align: "center", wrap: "wrap", gap: "md", pt: "xs", children: [
1366
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", align: "center", wrap: "nowrap", children: [
1367
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.rowsPerPage }),
1368
- /* @__PURE__ */ jsxRuntime.jsx(
1369
- core$1.Select,
1370
- {
1371
- "aria-label": labels.rowsPerPage,
1372
- data: options,
1373
- value: String(limit),
1374
- onChange: (v) => onLimitChange(Number(v)),
1375
- size: "xs",
1376
- w: 76,
1377
- allowDeselect: false,
1378
- comboboxProps: { withinPortal: false }
1379
- }
1380
- ),
1381
- total > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.showing({ from: fromIndex, to: toIndex, total }) })
1382
- ] }),
1383
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "sm", align: "center", wrap: "nowrap", children: [
1384
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.pageOf({ page: safePage, total: safeTotalPages }) }),
1385
- /* @__PURE__ */ jsxRuntime.jsx(
1386
- core$1.Pagination,
1387
- {
1388
- total: safeTotalPages,
1389
- value: safePage,
1390
- onChange: onPageChange,
1391
- size: "sm",
1392
- siblings: 1,
1393
- boundaries: 1,
1394
- getControlProps: (control) => ({
1395
- "aria-label": control === "previous" ? labels.previousPage : labels.nextPage
1396
- })
1397
- }
1398
- )
1399
- ] })
1400
- ] });
1329
+ //#endregion
1330
+ //#region src/components/PaginationFooter.tsx
1331
+ /** Desktop pagination bar: page-size + range on the left, pager on the right. */
1332
+ function PaginationFooter({ page, totalPages, limit, total, fromIndex, toIndex, onPageChange, onLimitChange, labels }) {
1333
+ const safeTotalPages = Math.max(totalPages, 1);
1334
+ const safePage = Math.min(Math.max(page, 1), safeTotalPages);
1335
+ const options = (0, _adapttable_core.pageSizeOptions)(limit).map((n) => ({
1336
+ value: String(n),
1337
+ label: String(n)
1338
+ }));
1339
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1340
+ justify: "space-between",
1341
+ align: "center",
1342
+ wrap: "wrap",
1343
+ gap: "md",
1344
+ pt: "xs",
1345
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1346
+ gap: "xs",
1347
+ align: "center",
1348
+ wrap: "nowrap",
1349
+ children: [
1350
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1351
+ fz: "xs",
1352
+ c: "dimmed",
1353
+ children: labels.rowsPerPage
1354
+ }),
1355
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Select, {
1356
+ "aria-label": labels.rowsPerPage,
1357
+ data: options,
1358
+ value: String(limit),
1359
+ onChange: (v) => onLimitChange(Number(v)),
1360
+ size: "xs",
1361
+ w: 76,
1362
+ allowDeselect: false,
1363
+ comboboxProps: { withinPortal: false }
1364
+ }),
1365
+ total > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1366
+ fz: "xs",
1367
+ c: "dimmed",
1368
+ children: labels.showing({
1369
+ from: fromIndex,
1370
+ to: toIndex,
1371
+ total
1372
+ })
1373
+ })
1374
+ ]
1375
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1376
+ gap: "sm",
1377
+ align: "center",
1378
+ wrap: "nowrap",
1379
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1380
+ fz: "xs",
1381
+ c: "dimmed",
1382
+ children: labels.pageOf({
1383
+ page: safePage,
1384
+ total: safeTotalPages
1385
+ })
1386
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Pagination, {
1387
+ total: safeTotalPages,
1388
+ value: safePage,
1389
+ onChange: onPageChange,
1390
+ size: "sm",
1391
+ siblings: 1,
1392
+ boundaries: 1,
1393
+ getControlProps: (control) => ({ "aria-label": control === "previous" ? labels.previousPage : labels.nextPage })
1394
+ })]
1395
+ })]
1396
+ });
1401
1397
  }
1402
- function SavedViewsMenu({
1403
- views,
1404
- labels
1405
- }) {
1406
- const [name, setName] = react.useState("");
1407
- const trimmed = name.trim();
1408
- const handleSave = () => {
1409
- views.save(trimmed);
1410
- setName("");
1411
- };
1412
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Menu, { closeOnItemClick: false, position: "bottom-end", withinPortal: true, children: [
1413
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Target, { children: /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { variant: "default", size: "sm", children: labels.savedViews }) }),
1414
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Dropdown, { children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Box, { p: 4, miw: 220, children: [
1415
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", px: 4, pb: 6, children: labels.savedViews }),
1416
- views.views.map((view) => /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: 6, px: 4, py: 2, wrap: "nowrap", children: [
1417
- /* @__PURE__ */ jsxRuntime.jsx(
1418
- core$1.Button,
1419
- {
1420
- variant: "subtle",
1421
- size: "compact-sm",
1422
- justify: "flex-start",
1423
- style: { flex: 1 },
1424
- onClick: () => views.apply(view.name),
1425
- children: view.name
1426
- }
1427
- ),
1428
- /* @__PURE__ */ jsxRuntime.jsx(
1429
- core$1.ActionIcon,
1430
- {
1431
- variant: "subtle",
1432
- color: "gray",
1433
- size: "sm",
1434
- "aria-label": `${labels.deleteView}: ${view.name}`,
1435
- onClick: () => views.remove(view.name),
1436
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { size: 12 })
1437
- }
1438
- )
1439
- ] }, view.name)),
1440
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Divider, {}),
1441
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: 6, p: 4, wrap: "nowrap", children: [
1442
- /* @__PURE__ */ jsxRuntime.jsx(
1443
- core$1.TextInput,
1444
- {
1445
- size: "xs",
1446
- style: { flex: 1 },
1447
- placeholder: labels.viewName,
1448
- value: name,
1449
- onChange: (e) => setName(e.currentTarget.value)
1450
- }
1451
- ),
1452
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { size: "xs", disabled: trimmed === "", onClick: handleSave, children: labels.saveView })
1453
- ] })
1454
- ] }) })
1455
- ] });
1398
+ //#endregion
1399
+ //#region src/components/SavedViewsMenu.tsx
1400
+ /**
1401
+ * Saved-views menu: lists every captured view (click a name to apply it, the
1402
+ * trailing to delete it) above a save row that captures the table's
1403
+ * CURRENT URL state under the typed name. Pairs with core's `useSavedViews`
1404
+ * and composes into the `toolbar` slot — or let `<DataTable savedViews>`
1405
+ * mount it for you next to the Columns menu.
1406
+ */
1407
+ function SavedViewsMenu({ views, labels }) {
1408
+ const [name, setName] = (0, react.useState)("");
1409
+ const trimmed = name.trim();
1410
+ const handleSave = () => {
1411
+ views.save(trimmed);
1412
+ setName("");
1413
+ };
1414
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Menu, {
1415
+ closeOnItemClick: false,
1416
+ position: "bottom-end",
1417
+ withinPortal: true,
1418
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Menu.Target, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1419
+ variant: "default",
1420
+ size: "sm",
1421
+ children: labels.savedViews
1422
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Menu.Dropdown, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Box, {
1423
+ p: 4,
1424
+ miw: 220,
1425
+ children: [
1426
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1427
+ size: "xs",
1428
+ c: "dimmed",
1429
+ fw: 600,
1430
+ tt: "uppercase",
1431
+ px: 4,
1432
+ pb: 6,
1433
+ children: labels.savedViews
1434
+ }),
1435
+ views.views.map((view) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1436
+ gap: 6,
1437
+ px: 4,
1438
+ py: 2,
1439
+ wrap: "nowrap",
1440
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1441
+ variant: "subtle",
1442
+ size: "compact-sm",
1443
+ justify: "flex-start",
1444
+ style: { flex: 1 },
1445
+ onClick: () => views.apply(view.name),
1446
+ children: view.name
1447
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
1448
+ variant: "subtle",
1449
+ color: "gray",
1450
+ size: "sm",
1451
+ "aria-label": `${labels.deleteView}: ${view.name}`,
1452
+ onClick: () => views.remove(view.name),
1453
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseIcon, { size: 12 })
1454
+ })]
1455
+ }, view.name)),
1456
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Menu.Divider, {}),
1457
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1458
+ gap: 6,
1459
+ p: 4,
1460
+ wrap: "nowrap",
1461
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.TextInput, {
1462
+ size: "xs",
1463
+ style: { flex: 1 },
1464
+ placeholder: labels.viewName,
1465
+ value: name,
1466
+ onChange: (e) => setName(e.currentTarget.value)
1467
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1468
+ size: "xs",
1469
+ disabled: trimmed === "",
1470
+ onClick: handleSave,
1471
+ children: labels.saveView
1472
+ })]
1473
+ })
1474
+ ]
1475
+ }) })]
1476
+ });
1456
1477
  }
1457
- function TableSkeleton({
1458
- columns,
1459
- rows = 5,
1460
- loadingLabel
1461
- }) {
1462
- const colKeys = Array.from({ length: Math.max(columns, 1) }, (_, i) => i);
1463
- const rowKeys = Array.from({ length: rows }, (_, i) => i);
1464
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "status", "aria-busy": "true", "aria-live": "polite", children: [
1465
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table, { children: [
1466
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Thead, { children: /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tr, { children: colKeys.map((c) => /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(
1467
- core$1.Skeleton,
1468
- {
1469
- height: 12,
1470
- radius: "sm",
1471
- width: c === 0 ? "55%" : "40%"
1472
- }
1473
- ) }, c)) }) }),
1474
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tbody, { children: rowKeys.map((r) => /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tr, { children: colKeys.map((c) => /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
1475
- core$1.Skeleton,
1476
- {
1477
- height: 14,
1478
- radius: "sm",
1479
- width: c === 0 ? "70%" : "55%"
1480
- }
1481
- ) }, c)) }, r)) })
1482
- ] }),
1483
- loadingLabel ? /* @__PURE__ */ jsxRuntime.jsx(core$1.VisuallyHidden, { children: loadingLabel }) : null
1484
- ] });
1478
+ //#endregion
1479
+ //#region src/components/TableSkeleton.tsx
1480
+ /** Loading placeholder that mirrors the table shape to avoid layout shift. */
1481
+ function TableSkeleton({ columns, rows = 5, loadingLabel }) {
1482
+ const colKeys = Array.from({ length: Math.max(columns, 1) }, (_, i) => i);
1483
+ const rowKeys = Array.from({ length: rows }, (_, i) => i);
1484
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1485
+ role: "status",
1486
+ "aria-busy": "true",
1487
+ "aria-live": "polite",
1488
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Table, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Thead, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Tr, { children: colKeys.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Th, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Skeleton, {
1489
+ height: 12,
1490
+ radius: "sm",
1491
+ width: c === 0 ? "55%" : "40%"
1492
+ }) }, c)) }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Tbody, { children: rowKeys.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Tr, { children: colKeys.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Table.Td, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Skeleton, {
1493
+ height: 14,
1494
+ radius: "sm",
1495
+ width: c === 0 ? "70%" : "55%"
1496
+ }) }, c)) }, r)) })] }), loadingLabel ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.VisuallyHidden, { children: loadingLabel }) : null]
1497
+ });
1485
1498
  }
1486
- function FilterPopover({
1487
- open,
1488
- onClose,
1489
- filters,
1490
- activeFilterCount,
1491
- onClearFilters,
1492
- labels,
1493
- dir = "ltr",
1494
- children
1495
- }) {
1496
- return /* @__PURE__ */ jsxRuntime.jsxs(
1497
- core$1.Popover,
1498
- {
1499
- opened: open,
1500
- onDismiss: onClose,
1501
- position: dir === "rtl" ? "bottom-start" : "bottom-end",
1502
- withinPortal: true,
1503
- shadow: "md",
1504
- radius: "md",
1505
- width: 340,
1506
- children: [
1507
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Popover.Target, { children }),
1508
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Popover.Dropdown, { children: [
1509
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", align: "center", mb: "sm", children: [
1510
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fw: 600, fz: "sm", children: labels.filters }),
1511
- /* @__PURE__ */ jsxRuntime.jsx(
1512
- core$1.Button,
1513
- {
1514
- variant: "subtle",
1515
- size: "compact-xs",
1516
- onClick: onClearFilters,
1517
- disabled: activeFilterCount === 0,
1518
- children: labels.clearAll
1519
- }
1520
- )
1521
- ] }),
1522
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Stack, { gap: "md", children: filters })
1523
- ] })
1524
- ]
1525
- }
1526
- );
1499
+ //#endregion
1500
+ //#region src/components/FilterPopover.tsx
1501
+ /**
1502
+ * Anchored filter card (the default filter container). Opens under the Filters
1503
+ * button and tracks it on scroll. No backdrop — the background stays visible
1504
+ * and interactive; clicking outside or pressing Escape closes it. Pair with
1505
+ * `filtersMode="drawer"` for the slide-in panel instead.
1506
+ */
1507
+ function FilterPopover({ open, onClose, filters, activeFilterCount, onClearFilters, labels, dir = "ltr", children }) {
1508
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Popover, {
1509
+ opened: open,
1510
+ onDismiss: onClose,
1511
+ position: dir === "rtl" ? "bottom-start" : "bottom-end",
1512
+ withinPortal: true,
1513
+ shadow: "md",
1514
+ radius: "md",
1515
+ width: 340,
1516
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Popover.Target, { children }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Popover.Dropdown, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1517
+ justify: "space-between",
1518
+ align: "center",
1519
+ mb: "sm",
1520
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1521
+ fw: 600,
1522
+ fz: "sm",
1523
+ children: labels.filters
1524
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1525
+ variant: "subtle",
1526
+ size: "compact-xs",
1527
+ onClick: onClearFilters,
1528
+ disabled: activeFilterCount === 0,
1529
+ children: labels.clearAll
1530
+ })]
1531
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Stack, {
1532
+ gap: "md",
1533
+ children: filters
1534
+ })] })]
1535
+ });
1527
1536
  }
1528
- function Toolbar({
1529
- table,
1530
- hideSearch,
1531
- searchPlaceholder,
1532
- sortByOptions,
1533
- customToolbar,
1534
- hasFilters,
1535
- activeFilterCount,
1536
- onToggleFilters,
1537
- onFiltersTriggerPointerDown,
1538
- onCloseFilters,
1539
- filtersOpen,
1540
- filtersMode,
1541
- filters,
1542
- onClearFilters,
1543
- dir,
1544
- columnMenu,
1545
- showRowsPerPage,
1546
- className
1547
- }) {
1548
- const { labels, source } = table;
1549
- const searchProps = table.getSearchInputProps(
1550
- searchPlaceholder ? { placeholder: searchPlaceholder } : void 0
1551
- );
1552
- const sortOptions = sortByOptions ?? (table.isMobile ? table.sortByOptions : void 0);
1553
- const filtersButton = /* @__PURE__ */ jsxRuntime.jsx(
1554
- core$1.Button,
1555
- {
1556
- variant: "default",
1557
- size: "sm",
1558
- "aria-expanded": filtersMode === "popover" ? filtersOpen : void 0,
1559
- "data-active": filtersOpen || void 0,
1560
- leftSection: /* @__PURE__ */ jsxRuntime.jsx(FiltersIcon, { size: 16 }),
1561
- rightSection: activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx(core$1.Badge, { size: "sm", circle: true, children: activeFilterCount }) : void 0,
1562
- onPointerDown: onFiltersTriggerPointerDown,
1563
- onClick: onToggleFilters,
1564
- children: labels.filters
1565
- }
1566
- );
1567
- return /* @__PURE__ */ jsxRuntime.jsxs(
1568
- core$1.Group,
1569
- {
1570
- gap: "sm",
1571
- justify: "space-between",
1572
- align: "center",
1573
- className,
1574
- children: [
1575
- !hideSearch && /* @__PURE__ */ jsxRuntime.jsx(
1576
- core$1.TextInput,
1577
- {
1578
- ...searchProps,
1579
- leftSection: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { size: 14 }),
1580
- size: "sm",
1581
- style: { flex: 1, minWidth: 160, maxWidth: 360 }
1582
- }
1583
- ),
1584
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", align: "center", children: [
1585
- sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1586
- core$1.Select,
1587
- {
1588
- "aria-label": labels.sortBy,
1589
- placeholder: labels.sortBy,
1590
- data: sortOptions,
1591
- value: source.sortBy ?? null,
1592
- onChange: (v) => source.setSort(v ?? void 0, source.sortDir ?? "asc"),
1593
- clearable: true,
1594
- size: "sm",
1595
- w: 160,
1596
- comboboxProps: { withinPortal: false }
1597
- }
1598
- ),
1599
- customToolbar,
1600
- hasFilters && (filtersMode === "popover" ? /* @__PURE__ */ jsxRuntime.jsx(
1601
- FilterPopover,
1602
- {
1603
- open: filtersOpen,
1604
- onClose: onCloseFilters,
1605
- filters,
1606
- activeFilterCount,
1607
- onClearFilters,
1608
- labels,
1609
- dir,
1610
- children: filtersButton
1611
- }
1612
- ) : filtersButton),
1613
- columnMenu,
1614
- showRowsPerPage && /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", align: "center", children: [
1615
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.rowsPerPage }),
1616
- /* @__PURE__ */ jsxRuntime.jsx(
1617
- core$1.Select,
1618
- {
1619
- "aria-label": labels.rowsPerPage,
1620
- data: core.pageSizeOptions(source.limit).map((n) => ({
1621
- value: String(n),
1622
- label: String(n)
1623
- })),
1624
- value: String(source.limit),
1625
- onChange: (v) => source.setLimit(Number(v)),
1626
- size: "sm",
1627
- w: 80,
1628
- allowDeselect: false,
1629
- comboboxProps: { withinPortal: false }
1630
- }
1631
- )
1632
- ] })
1633
- ] })
1634
- ]
1635
- }
1636
- );
1537
+ //#endregion
1538
+ //#region src/components/Toolbar.tsx
1539
+ /** Sticky toolbar: search, optional sort select, custom slot, filters, size. */
1540
+ function Toolbar({ table, hideSearch, searchPlaceholder, sortByOptions, customToolbar, hasFilters, activeFilterCount, onToggleFilters, onFiltersTriggerPointerDown, onCloseFilters, filtersOpen, filtersMode, filters, onClearFilters, dir, columnMenu, showRowsPerPage, className }) {
1541
+ const { labels, source } = table;
1542
+ const searchProps = table.getSearchInputProps(searchPlaceholder ? { placeholder: searchPlaceholder } : void 0);
1543
+ const sortOptions = sortByOptions ?? (table.isMobile ? table.sortByOptions : void 0);
1544
+ const filtersButton = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1545
+ variant: "default",
1546
+ size: "sm",
1547
+ "aria-expanded": filtersMode === "popover" ? filtersOpen : void 0,
1548
+ "data-active": filtersOpen || void 0,
1549
+ leftSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FiltersIcon, { size: 16 }),
1550
+ rightSection: activeFilterCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Badge, {
1551
+ size: "sm",
1552
+ circle: true,
1553
+ children: activeFilterCount
1554
+ }) : void 0,
1555
+ onPointerDown: onFiltersTriggerPointerDown,
1556
+ onClick: onToggleFilters,
1557
+ children: labels.filters
1558
+ });
1559
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1560
+ gap: "sm",
1561
+ justify: "space-between",
1562
+ align: "center",
1563
+ className,
1564
+ children: [!hideSearch && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.TextInput, {
1565
+ ...searchProps,
1566
+ leftSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchIcon, { size: 14 }),
1567
+ size: "sm",
1568
+ style: {
1569
+ flex: 1,
1570
+ minWidth: 160,
1571
+ maxWidth: 360
1572
+ }
1573
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1574
+ gap: "xs",
1575
+ align: "center",
1576
+ children: [
1577
+ sortOptions && sortOptions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Select, {
1578
+ "aria-label": labels.sortBy,
1579
+ placeholder: labels.sortBy,
1580
+ data: sortOptions,
1581
+ value: source.sortBy ?? null,
1582
+ onChange: (v) => source.setSort(v ?? void 0, source.sortDir ?? "asc"),
1583
+ clearable: true,
1584
+ size: "sm",
1585
+ w: 160,
1586
+ comboboxProps: { withinPortal: false }
1587
+ }),
1588
+ customToolbar,
1589
+ hasFilters && (filtersMode === "popover" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterPopover, {
1590
+ open: filtersOpen,
1591
+ onClose: onCloseFilters,
1592
+ filters,
1593
+ activeFilterCount,
1594
+ onClearFilters,
1595
+ labels,
1596
+ dir,
1597
+ children: filtersButton
1598
+ }) : filtersButton),
1599
+ columnMenu,
1600
+ showRowsPerPage && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
1601
+ gap: "xs",
1602
+ align: "center",
1603
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1604
+ fz: "xs",
1605
+ c: "dimmed",
1606
+ children: labels.rowsPerPage
1607
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Select, {
1608
+ "aria-label": labels.rowsPerPage,
1609
+ data: (0, _adapttable_core.pageSizeOptions)(source.limit).map((n) => ({
1610
+ value: String(n),
1611
+ label: String(n)
1612
+ })),
1613
+ value: String(source.limit),
1614
+ onChange: (v) => source.setLimit(Number(v)),
1615
+ size: "sm",
1616
+ w: 80,
1617
+ allowDeselect: false,
1618
+ comboboxProps: { withinPortal: false }
1619
+ })]
1620
+ })
1621
+ ]
1622
+ })]
1623
+ });
1637
1624
  }
1638
- var stickyToolbarStyle = (top) => ({
1639
- position: "sticky",
1640
- top,
1641
- zIndex: 3,
1642
- background: "var(--mantine-color-body)",
1643
- paddingBottom: "var(--mantine-spacing-xs)"
1625
+ //#endregion
1626
+ //#region src/DataTable.tsx
1627
+ const stickyToolbarStyle = (top) => ({
1628
+ position: "sticky",
1629
+ top,
1630
+ zIndex: 3,
1631
+ background: "var(--mantine-color-body)",
1632
+ paddingBottom: "var(--mantine-spacing-xs)"
1644
1633
  });
1645
- function ColumnMenuSlot({
1646
- enabled,
1647
- ...props
1648
- }) {
1649
- if (!enabled) return null;
1650
- return /* @__PURE__ */ jsxRuntime.jsx(ColumnMenu, { ...props });
1634
+ /** The Columns menu, rendered inline in the toolbar — or nothing when off. */
1635
+ function ColumnMenuSlot({ enabled, ...props }) {
1636
+ if (!enabled) return null;
1637
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ColumnMenu, { ...props });
1651
1638
  }
1652
- function SavedViewsSlot({
1653
- options,
1654
- labels
1655
- }) {
1656
- const views = core.useSavedViews(options);
1657
- return /* @__PURE__ */ jsxRuntime.jsx(SavedViewsMenu, { views, labels });
1639
+ /**
1640
+ * The Saved-views menu in the toolbar. A component (not inline JSX) so
1641
+ * `useSavedViews` only runs when the `savedViews` prop is set.
1642
+ */
1643
+ function SavedViewsSlot({ options, labels }) {
1644
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SavedViewsMenu, {
1645
+ views: (0, _adapttable_core.useSavedViews)(options),
1646
+ labels
1647
+ });
1658
1648
  }
1649
+ /**
1650
+ * Resolve the data tier (source ▸ server ▸ frontend) and the declarative
1651
+ * filter runtime into the full chrome prop set: the RESOLVED source, the
1652
+ * filters node (auto-built form for the declarative array, JSX as-is) and
1653
+ * the chip-label resolvers (derived under the caller's — the user wins
1654
+ * per key). Everything downstream consumes these.
1655
+ */
1659
1656
  function useResolvedTableProps(props) {
1660
- const { source, runtime } = core.useTableData({
1661
- locale: props.locale,
1662
- source: props.source,
1663
- data: props.data,
1664
- total: props.total,
1665
- loading: props.loading,
1666
- onQueryChange: props.onQueryChange,
1667
- columns: props.columns,
1668
- filters: props.filters,
1669
- urlKey: props.urlKey,
1670
- adapter: props.urlSync === false ? void 0 : props.urlAdapter,
1671
- enabled: props.urlSync
1672
- });
1673
- const labels = react.useMemo(() => core.resolveLabels(props.labels), [props.labels]);
1674
- let filters;
1675
- if (core.isDeclarativeFilters(props.filters) || props.filters === void 0) {
1676
- filters = runtime.defs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AutoFilterForm, { defs: runtime.defs, source, labels }) : void 0;
1677
- } else {
1678
- filters = props.filters;
1679
- }
1680
- const filterLabels = react.useMemo(
1681
- () => ({ ...runtime.filterLabels, ...props.filterLabels }),
1682
- [runtime.filterLabels, props.filterLabels]
1683
- );
1684
- return { ...props, source, filters, filterLabels };
1657
+ const { source, runtime } = (0, _adapttable_core.useTableData)({
1658
+ locale: props.locale,
1659
+ source: props.source,
1660
+ data: props.data,
1661
+ total: props.total,
1662
+ loading: props.loading,
1663
+ onQueryChange: props.onQueryChange,
1664
+ columns: props.columns,
1665
+ filters: props.filters,
1666
+ urlKey: props.urlKey,
1667
+ adapter: props.urlSync === false ? void 0 : props.urlAdapter,
1668
+ enabled: props.urlSync
1669
+ });
1670
+ const labels = (0, react.useMemo)(() => (0, _adapttable_core.resolveLabels)(props.labels), [props.labels]);
1671
+ let filters;
1672
+ if ((0, _adapttable_core.isDeclarativeFilters)(props.filters) || props.filters === void 0) filters = runtime.defs.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoFilterForm, {
1673
+ defs: runtime.defs,
1674
+ source,
1675
+ labels
1676
+ }) : void 0;
1677
+ else filters = props.filters;
1678
+ const filterLabels = (0, react.useMemo)(() => ({
1679
+ ...runtime.filterLabels,
1680
+ ...props.filterLabels
1681
+ }), [runtime.filterLabels, props.filterLabels]);
1682
+ return {
1683
+ ...props,
1684
+ source,
1685
+ filters,
1686
+ filterLabels
1687
+ };
1685
1688
  }
1689
+ /**
1690
+ * Batteries-included Mantine data table. Drop in `columns`, a `rowKey`,
1691
+ * and a data tier — raw `data` (frontend), `data` + `onQueryChange`
1692
+ * (server), or a prebuilt `source` — to get a fully styled, sortable,
1693
+ * filterable, paginated table with selection, bulk actions, RTL, dark
1694
+ * mode, and optional entrance animation.
1695
+ *
1696
+ * @typeParam TRow - The row type.
1697
+ */
1686
1698
  function DataTable(props) {
1687
- const chromeProps = useResolvedTableProps(props);
1688
- const {
1689
- source,
1690
- rowActions,
1691
- searchPlaceholder,
1692
- sortByOptions,
1693
- dir,
1694
- prefetch,
1695
- hideSearch,
1696
- filters,
1697
- filtersMode = "popover",
1698
- bulkActions,
1699
- slots,
1700
- classNames,
1701
- toolbar: customToolbar,
1702
- skeletonRows,
1703
- stickyTop = 0,
1704
- animate = false,
1705
- stickyHeader = false,
1706
- enableColumnMenu = false,
1707
- savedViews
1708
- } = chromeProps;
1709
- const density = chromeProps.density ?? "comfortable";
1710
- const chrome = core.useTableChrome(chromeProps);
1711
- const { table, isMobile, confirm, getRowId } = chrome;
1712
- const hasRowActions = (rowActions?.length ?? 0) > 0;
1713
- const visibleRowActions = chrome.columnLayout.isHidden(core.ACTIONS_COLUMN_KEY) ? void 0 : rowActions;
1714
- const actionsPinned = chrome.columnLayout.state.pinned[core.ACTIONS_COLUMN_KEY] === "right";
1715
- const { virtualization, loadMoreRef, canLoadMore, virtualScrollRef } = core.useChromeBodyData(chrome, chromeProps);
1716
- const [drawerOpened, setDrawerOpened] = react.useState(false);
1717
- const filtersTrigger = core.useFilterTriggerToggle(drawerOpened, setDrawerOpened);
1718
- const rootRef = react.useRef(null);
1719
- const { ref: toolbarRef, height: toolbarHeight } = hooks.useElementSize();
1720
- const desktopBodyRef = react.useRef(null);
1721
- const mobileBodyRef = react.useRef(null);
1722
- core.useChromeScrollReset(rootRef, chrome, chromeProps);
1723
- useMountStagger(
1724
- isMobile ? mobileBodyRef : desktopBodyRef,
1725
- [virtualization.rows.length, isMobile],
1726
- { enabled: animate }
1727
- );
1728
- let body;
1729
- if (chrome.body === "skeleton") {
1730
- body = slots?.skeleton ?? /* @__PURE__ */ jsxRuntime.jsx(
1731
- TableSkeleton,
1732
- {
1733
- columns: table.columns.length || 1,
1734
- rows: skeletonRows ?? source.limit,
1735
- loadingLabel: table.labels.loading
1736
- }
1737
- );
1738
- } else if (chrome.body === "empty") {
1739
- body = slots?.empty ?? (chrome.emptyVariant === "noResults" ? /* @__PURE__ */ jsxRuntime.jsx(
1740
- EmptyState,
1741
- {
1742
- title: table.labels.noResults,
1743
- action: /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { variant: "light", size: "sm", onClick: chrome.clearFilters, children: table.labels.clearAll })
1744
- }
1745
- ) : /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: table.labels.noData }));
1746
- } else if (chrome.body === "mobile") {
1747
- body = /* @__PURE__ */ jsxRuntime.jsx(
1748
- MobileCards,
1749
- {
1750
- table,
1751
- rows: source.rows,
1752
- rowActions: visibleRowActions,
1753
- confirm,
1754
- getRowId,
1755
- onRowClick: props.onRowClick,
1756
- rowClassName: props.rowClassName,
1757
- renderRowDetail: props.renderRowDetail,
1758
- summaryRow: props.summaryRow,
1759
- expansion: chrome.detail?.expansion,
1760
- bodyRef: mobileBodyRef,
1761
- className: classNames?.card,
1762
- rowEntries: virtualization.enabled ? virtualization.rows : void 0,
1763
- paddingTop: virtualization.paddingTop,
1764
- paddingBottom: virtualization.paddingBottom,
1765
- measureElement: virtualization.measureElement,
1766
- density
1767
- }
1768
- );
1769
- } else {
1770
- body = /* @__PURE__ */ jsxRuntime.jsx(
1771
- DesktopTable,
1772
- {
1773
- table,
1774
- rows: source.rows,
1775
- rowActions: visibleRowActions,
1776
- confirm,
1777
- prefetch,
1778
- onRowClick: props.onRowClick,
1779
- rowClassName: props.rowClassName,
1780
- renderRowDetail: props.renderRowDetail,
1781
- summaryRow: props.summaryRow,
1782
- expansion: chrome.detail?.expansion,
1783
- getRowId,
1784
- bodyRef: desktopBodyRef,
1785
- className: classNames?.table,
1786
- rowEntries: virtualization.enabled ? virtualization.rows : void 0,
1787
- paddingTop: virtualization.paddingTop,
1788
- paddingBottom: virtualization.paddingBottom,
1789
- measureElement: virtualization.measureElement,
1790
- stickyHeaderOffset: stickyTop + toolbarHeight,
1791
- stickyHeader,
1792
- pinOffset: chrome.columnLayout.pinOffset,
1793
- actionsPinned,
1794
- maxHeight: props.maxHeight,
1795
- virtualScrollRef,
1796
- setWidth: props.resizableColumns ? chrome.columnLayout.setWidth : void 0,
1797
- columnWidths: chrome.columnLayout.state.widths,
1798
- resizeLabel: table.labels.resizeColumn,
1799
- density
1800
- }
1801
- );
1802
- }
1803
- return /* @__PURE__ */ jsxRuntime.jsxs(
1804
- core$1.Paper,
1805
- {
1806
- ref: rootRef,
1807
- p: "xs",
1808
- radius: "md",
1809
- withBorder: true,
1810
- dir,
1811
- "aria-busy": chrome.isRefreshing || void 0,
1812
- className: classNames?.root,
1813
- children: [
1814
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: "xs", children: [
1815
- /* @__PURE__ */ jsxRuntime.jsx(
1816
- core$1.Box,
1817
- {
1818
- ref: toolbarRef,
1819
- style: stickyToolbarStyle(stickyTop),
1820
- className: classNames?.toolbar,
1821
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: "xs", children: [
1822
- /* @__PURE__ */ jsxRuntime.jsx(
1823
- Toolbar,
1824
- {
1825
- table,
1826
- hideSearch,
1827
- searchPlaceholder,
1828
- sortByOptions,
1829
- customToolbar,
1830
- hasFilters: Boolean(filters),
1831
- activeFilterCount: chrome.activeFilterCount,
1832
- filtersMode,
1833
- filters,
1834
- filtersOpen: drawerOpened,
1835
- onToggleFilters: filtersTrigger.onClick,
1836
- onFiltersTriggerPointerDown: filtersTrigger.onPointerDown,
1837
- onCloseFilters: () => setDrawerOpened(false),
1838
- onClearFilters: chrome.clearFilters,
1839
- dir,
1840
- columnMenu: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1841
- savedViews && /* @__PURE__ */ jsxRuntime.jsx(
1842
- SavedViewsSlot,
1843
- {
1844
- options: {
1845
- adapter: chromeProps.urlAdapter,
1846
- urlKey: chromeProps.urlKey,
1847
- ...savedViews
1848
- },
1849
- labels: table.labels
1850
- }
1851
- ),
1852
- /* @__PURE__ */ jsxRuntime.jsx(
1853
- ColumnMenuSlot,
1854
- {
1855
- enabled: enableColumnMenu && !isMobile,
1856
- allColumns: chrome.allColumns,
1857
- layout: chrome.columnLayout,
1858
- labels: table.labels,
1859
- hasRowActions
1860
- }
1861
- )
1862
- ] }),
1863
- showRowsPerPage: canLoadMore
1864
- }
1865
- ),
1866
- /* @__PURE__ */ jsxRuntime.jsx(
1867
- ActiveFilterChips,
1868
- {
1869
- chips: chrome.mergedChips,
1870
- onClearAll: chrome.clearFilters,
1871
- label: table.labels.filters,
1872
- clearAllLabel: table.labels.clearAll
1873
- }
1874
- ),
1875
- table.selection && bulkActions && /* @__PURE__ */ jsxRuntime.jsx(
1876
- BulkActionBar,
1877
- {
1878
- selection: table.selection,
1879
- total: source.total,
1880
- bulkActions,
1881
- confirm,
1882
- labels: table.labels
1883
- }
1884
- )
1885
- ] })
1886
- }
1887
- ),
1888
- chrome.isRefreshing && /* @__PURE__ */ jsxRuntime.jsx(
1889
- core$1.Progress,
1890
- {
1891
- size: "xs",
1892
- animated: true,
1893
- value: 100,
1894
- "aria-label": table.labels.loading
1895
- }
1896
- ),
1897
- source.error && /* @__PURE__ */ jsxRuntime.jsx(
1898
- ErrorState,
1899
- {
1900
- error: source.error,
1901
- title: table.labels.errorTitle,
1902
- message: table.labels.errorMessage,
1903
- retryLabel: table.labels.retry,
1904
- onRetry: source.refetch ? () => void source.refetch?.() : void 0,
1905
- isRetrying: source.isFetching
1906
- }
1907
- ),
1908
- !source.error && body,
1909
- canLoadMore && source.hasNextPage && /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { ref: loadMoreRef, justify: "center", py: "xs", children: /* @__PURE__ */ jsxRuntime.jsx(
1910
- core$1.Button,
1911
- {
1912
- variant: "default",
1913
- size: "sm",
1914
- loading: source.isFetchingNextPage,
1915
- onClick: () => source.fetchNextPage(),
1916
- children: table.labels.loadMore
1917
- }
1918
- ) }),
1919
- chrome.showFooter && /* @__PURE__ */ jsxRuntime.jsx(core$1.Box, { className: classNames?.footer, children: /* @__PURE__ */ jsxRuntime.jsx(
1920
- PaginationFooter,
1921
- {
1922
- page: table.pagination.safePage,
1923
- totalPages: table.pagination.totalPages,
1924
- limit: source.limit,
1925
- total: source.total,
1926
- fromIndex: table.pagination.fromIndex,
1927
- toIndex: table.pagination.toIndex,
1928
- onPageChange: source.setPage,
1929
- onLimitChange: source.setLimit,
1930
- labels: table.labels
1931
- }
1932
- ) })
1933
- ] }),
1934
- filters && filtersMode === "drawer" && /* @__PURE__ */ jsxRuntime.jsx(
1935
- FilterDrawer,
1936
- {
1937
- opened: drawerOpened,
1938
- onClose: () => setDrawerOpened(false),
1939
- filters,
1940
- activeFilterCount: chrome.activeFilterCount,
1941
- onClearFilters: chrome.clearFilters,
1942
- labels: table.labels,
1943
- dir
1944
- }
1945
- )
1946
- ]
1947
- }
1948
- );
1699
+ const chromeProps = useResolvedTableProps(props);
1700
+ const { source, rowActions, searchPlaceholder, sortByOptions, dir, prefetch, hideSearch, filters, filtersMode = "popover", bulkActions, slots, classNames, toolbar: customToolbar, skeletonRows, stickyTop = 0, animate = false, stickyHeader = false, enableColumnMenu = false, savedViews } = chromeProps;
1701
+ const density = chromeProps.density ?? "comfortable";
1702
+ const chrome = (0, _adapttable_core.useTableChrome)(chromeProps);
1703
+ const { table, isMobile, confirm, getRowId } = chrome;
1704
+ const hasRowActions = (rowActions?.length ?? 0) > 0;
1705
+ const visibleRowActions = chrome.columnLayout.isHidden(_adapttable_core.ACTIONS_COLUMN_KEY) ? void 0 : rowActions;
1706
+ const actionsPinned = chrome.columnLayout.state.pinned[_adapttable_core.ACTIONS_COLUMN_KEY] === "right";
1707
+ const { virtualization, loadMoreRef, canLoadMore, virtualScrollRef } = (0, _adapttable_core.useChromeBodyData)(chrome, chromeProps);
1708
+ const [drawerOpened, setDrawerOpened] = (0, react.useState)(false);
1709
+ const filtersTrigger = (0, _adapttable_core.useFilterTriggerToggle)(drawerOpened, setDrawerOpened);
1710
+ const rootRef = (0, react.useRef)(null);
1711
+ const { ref: toolbarRef, height: toolbarHeight } = (0, _mantine_hooks.useElementSize)();
1712
+ const desktopBodyRef = (0, react.useRef)(null);
1713
+ const mobileBodyRef = (0, react.useRef)(null);
1714
+ (0, _adapttable_core.useChromeScrollReset)(rootRef, chrome, chromeProps);
1715
+ useMountStagger(isMobile ? mobileBodyRef : desktopBodyRef, [virtualization.rows.length, isMobile], { enabled: animate });
1716
+ let body;
1717
+ if (chrome.body === "skeleton") body = slots?.skeleton ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TableSkeleton, {
1718
+ columns: table.columns.length || 1,
1719
+ rows: skeletonRows ?? source.limit,
1720
+ loadingLabel: table.labels.loading
1721
+ });
1722
+ else if (chrome.body === "empty") body = slots?.empty ?? (chrome.emptyVariant === "noResults" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
1723
+ title: table.labels.noResults,
1724
+ action: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1725
+ variant: "light",
1726
+ size: "sm",
1727
+ onClick: chrome.clearFilters,
1728
+ children: table.labels.clearAll
1729
+ })
1730
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, { title: table.labels.noData }));
1731
+ else if (chrome.body === "mobile") body = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobileCards, {
1732
+ table,
1733
+ rows: source.rows,
1734
+ rowActions: visibleRowActions,
1735
+ confirm,
1736
+ getRowId,
1737
+ onRowClick: props.onRowClick,
1738
+ rowClassName: props.rowClassName,
1739
+ renderRowDetail: props.renderRowDetail,
1740
+ summaryRow: props.summaryRow,
1741
+ expansion: chrome.detail?.expansion,
1742
+ bodyRef: mobileBodyRef,
1743
+ className: classNames?.card,
1744
+ rowEntries: virtualization.enabled ? virtualization.rows : void 0,
1745
+ paddingTop: virtualization.paddingTop,
1746
+ paddingBottom: virtualization.paddingBottom,
1747
+ measureElement: virtualization.measureElement,
1748
+ density
1749
+ });
1750
+ else body = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DesktopTable, {
1751
+ table,
1752
+ rows: source.rows,
1753
+ rowActions: visibleRowActions,
1754
+ confirm,
1755
+ prefetch,
1756
+ onRowClick: props.onRowClick,
1757
+ rowClassName: props.rowClassName,
1758
+ renderRowDetail: props.renderRowDetail,
1759
+ summaryRow: props.summaryRow,
1760
+ expansion: chrome.detail?.expansion,
1761
+ getRowId,
1762
+ bodyRef: desktopBodyRef,
1763
+ className: classNames?.table,
1764
+ rowEntries: virtualization.enabled ? virtualization.rows : void 0,
1765
+ paddingTop: virtualization.paddingTop,
1766
+ paddingBottom: virtualization.paddingBottom,
1767
+ measureElement: virtualization.measureElement,
1768
+ stickyHeaderOffset: stickyTop + toolbarHeight,
1769
+ stickyHeader,
1770
+ pinOffset: chrome.columnLayout.pinOffset,
1771
+ actionsPinned,
1772
+ maxHeight: props.maxHeight,
1773
+ virtualScrollRef,
1774
+ setWidth: props.resizableColumns ? chrome.columnLayout.setWidth : void 0,
1775
+ columnWidths: chrome.columnLayout.state.widths,
1776
+ resizeLabel: table.labels.resizeColumn,
1777
+ density
1778
+ });
1779
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Paper, {
1780
+ ref: rootRef,
1781
+ p: "xs",
1782
+ radius: "md",
1783
+ withBorder: true,
1784
+ dir,
1785
+ "aria-busy": chrome.isRefreshing || void 0,
1786
+ className: classNames?.root,
1787
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
1788
+ gap: "xs",
1789
+ children: [
1790
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
1791
+ ref: toolbarRef,
1792
+ style: stickyToolbarStyle(stickyTop),
1793
+ className: classNames?.toolbar,
1794
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Stack, {
1795
+ gap: "xs",
1796
+ children: [
1797
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toolbar, {
1798
+ table,
1799
+ hideSearch,
1800
+ searchPlaceholder,
1801
+ sortByOptions,
1802
+ customToolbar,
1803
+ hasFilters: Boolean(filters),
1804
+ activeFilterCount: chrome.activeFilterCount,
1805
+ filtersMode,
1806
+ filters,
1807
+ filtersOpen: drawerOpened,
1808
+ onToggleFilters: filtersTrigger.onClick,
1809
+ onFiltersTriggerPointerDown: filtersTrigger.onPointerDown,
1810
+ onCloseFilters: () => setDrawerOpened(false),
1811
+ onClearFilters: chrome.clearFilters,
1812
+ dir,
1813
+ columnMenu: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [savedViews && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SavedViewsSlot, {
1814
+ options: {
1815
+ adapter: chromeProps.urlAdapter,
1816
+ urlKey: chromeProps.urlKey,
1817
+ ...savedViews
1818
+ },
1819
+ labels: table.labels
1820
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ColumnMenuSlot, {
1821
+ enabled: enableColumnMenu && !isMobile,
1822
+ allColumns: chrome.allColumns,
1823
+ layout: chrome.columnLayout,
1824
+ labels: table.labels,
1825
+ hasRowActions
1826
+ })] }),
1827
+ showRowsPerPage: canLoadMore
1828
+ }),
1829
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActiveFilterChips, {
1830
+ chips: chrome.mergedChips,
1831
+ onClearAll: chrome.clearFilters,
1832
+ label: table.labels.filters,
1833
+ clearAllLabel: table.labels.clearAll
1834
+ }),
1835
+ table.selection && bulkActions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BulkActionBar, {
1836
+ selection: table.selection,
1837
+ total: source.total,
1838
+ bulkActions,
1839
+ confirm,
1840
+ labels: table.labels
1841
+ })
1842
+ ]
1843
+ })
1844
+ }),
1845
+ chrome.isRefreshing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Progress, {
1846
+ size: "xs",
1847
+ animated: true,
1848
+ value: 100,
1849
+ "aria-label": table.labels.loading
1850
+ }),
1851
+ source.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorState, {
1852
+ error: source.error,
1853
+ title: table.labels.errorTitle,
1854
+ message: table.labels.errorMessage,
1855
+ retryLabel: table.labels.retry,
1856
+ onRetry: source.refetch ? () => void source.refetch?.() : void 0,
1857
+ isRetrying: source.isFetching
1858
+ }),
1859
+ !source.error && body,
1860
+ canLoadMore && source.hasNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Group, {
1861
+ ref: loadMoreRef,
1862
+ justify: "center",
1863
+ py: "xs",
1864
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
1865
+ variant: "default",
1866
+ size: "sm",
1867
+ loading: source.isFetchingNextPage,
1868
+ onClick: () => source.fetchNextPage(),
1869
+ children: table.labels.loadMore
1870
+ })
1871
+ }),
1872
+ chrome.showFooter && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
1873
+ className: classNames?.footer,
1874
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PaginationFooter, {
1875
+ page: table.pagination.safePage,
1876
+ totalPages: table.pagination.totalPages,
1877
+ limit: source.limit,
1878
+ total: source.total,
1879
+ fromIndex: table.pagination.fromIndex,
1880
+ toIndex: table.pagination.toIndex,
1881
+ onPageChange: source.setPage,
1882
+ onLimitChange: source.setLimit,
1883
+ labels: table.labels
1884
+ })
1885
+ })
1886
+ ]
1887
+ }), filters && filtersMode === "drawer" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterDrawer, {
1888
+ opened: drawerOpened,
1889
+ onClose: () => setDrawerOpened(false),
1890
+ filters,
1891
+ activeFilterCount: chrome.activeFilterCount,
1892
+ onClearFilters: chrome.clearFilters,
1893
+ labels: table.labels,
1894
+ dir
1895
+ })]
1896
+ });
1949
1897
  }
1950
-
1898
+ //#endregion
1899
+ exports.ActiveFilterChips = ActiveFilterChips;
1900
+ exports.AutoFilterForm = AutoFilterForm;
1901
+ exports.DataTable = DataTable;
1902
+ exports.EmptyState = EmptyState;
1903
+ exports.ErrorState = ErrorState;
1904
+ exports.PaginationFooter = PaginationFooter;
1905
+ exports.SavedViewsMenu = SavedViewsMenu;
1906
+ exports.TableSkeleton = TableSkeleton;
1951
1907
  Object.defineProperty(exports, "createHistoryAdapter", {
1952
- enumerable: true,
1953
- get: function () { return core.createHistoryAdapter; }
1908
+ enumerable: true,
1909
+ get: function() {
1910
+ return _adapttable_core.createHistoryAdapter;
1911
+ }
1954
1912
  });
1955
1913
  Object.defineProperty(exports, "createMemoryAdapter", {
1956
- enumerable: true,
1957
- get: function () { return core.createMemoryAdapter; }
1914
+ enumerable: true,
1915
+ get: function() {
1916
+ return _adapttable_core.createMemoryAdapter;
1917
+ }
1958
1918
  });
1959
1919
  Object.defineProperty(exports, "defaultConfirm", {
1960
- enumerable: true,
1961
- get: function () { return core.defaultConfirm; }
1920
+ enumerable: true,
1921
+ get: function() {
1922
+ return _adapttable_core.defaultConfirm;
1923
+ }
1962
1924
  });
1963
1925
  Object.defineProperty(exports, "defaultLabels", {
1964
- enumerable: true,
1965
- get: function () { return core.defaultLabels; }
1926
+ enumerable: true,
1927
+ get: function() {
1928
+ return _adapttable_core.defaultLabels;
1929
+ }
1966
1930
  });
1967
1931
  Object.defineProperty(exports, "deriveSortByOptions", {
1968
- enumerable: true,
1969
- get: function () { return core.deriveSortByOptions; }
1932
+ enumerable: true,
1933
+ get: function() {
1934
+ return _adapttable_core.deriveSortByOptions;
1935
+ }
1970
1936
  });
1971
1937
  Object.defineProperty(exports, "getHistoryAdapter", {
1972
- enumerable: true,
1973
- get: function () { return core.getHistoryAdapter; }
1938
+ enumerable: true,
1939
+ get: function() {
1940
+ return _adapttable_core.getHistoryAdapter;
1941
+ }
1974
1942
  });
1975
1943
  Object.defineProperty(exports, "useBackendData", {
1976
- enumerable: true,
1977
- get: function () { return core.useBackendData; }
1944
+ enumerable: true,
1945
+ get: function() {
1946
+ return _adapttable_core.useBackendData;
1947
+ }
1978
1948
  });
1979
1949
  Object.defineProperty(exports, "useDataTable", {
1980
- enumerable: true,
1981
- get: function () { return core.useDataTable; }
1950
+ enumerable: true,
1951
+ get: function() {
1952
+ return _adapttable_core.useDataTable;
1953
+ }
1982
1954
  });
1983
1955
  Object.defineProperty(exports, "useFrontendData", {
1984
- enumerable: true,
1985
- get: function () { return core.useFrontendData; }
1956
+ enumerable: true,
1957
+ get: function() {
1958
+ return _adapttable_core.useFrontendData;
1959
+ }
1986
1960
  });
1961
+ exports.useMountStagger = useMountStagger;
1987
1962
  Object.defineProperty(exports, "useSavedViews", {
1988
- enumerable: true,
1989
- get: function () { return core.useSavedViews; }
1963
+ enumerable: true,
1964
+ get: function() {
1965
+ return _adapttable_core.useSavedViews;
1966
+ }
1990
1967
  });
1991
1968
  Object.defineProperty(exports, "useTableUrlState", {
1992
- enumerable: true,
1993
- get: function () { return core.useTableUrlState; }
1969
+ enumerable: true,
1970
+ get: function() {
1971
+ return _adapttable_core.useTableUrlState;
1972
+ }
1994
1973
  });
1995
- exports.ActiveFilterChips = ActiveFilterChips;
1996
- exports.AutoFilterForm = AutoFilterForm;
1997
- exports.DataTable = DataTable;
1998
- exports.EmptyState = EmptyState;
1999
- exports.ErrorState = ErrorState;
2000
- exports.PaginationFooter = PaginationFooter;
2001
- exports.SavedViewsMenu = SavedViewsMenu;
2002
- exports.TableSkeleton = TableSkeleton;
2003
- exports.useMountStagger = useMountStagger;
2004
- //# sourceMappingURL=index.cjs.map
1974
+
2005
1975
  //# sourceMappingURL=index.cjs.map