@adapttable/mantine 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2004 +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
- children: [
987
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Thead, { style: { background: "var(--mantine-color-body)" }, children: [
988
- groupCells && /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tr, { children: [
989
- expandable && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, {}),
990
- selection && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, {}),
991
- groupCells.map((cell) => /* @__PURE__ */ jsxRuntime.jsx(
992
- core$1.Table.Th,
993
- {
994
- colSpan: cell.span,
995
- ta: "center",
996
- fw: 600,
997
- style: {
998
- borderBottom: "1px solid var(--mantine-color-default-border)"
999
- },
1000
- children: cell.label
1001
- },
1002
- cell.key
1003
- )),
1004
- showActions && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, {})
1005
- ] }),
1006
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tr, { ...table.getHeaderRowProps(), children: [
1007
- expandable && /* @__PURE__ */ jsxRuntime.jsx(
1008
- core$1.Table.Th,
1009
- {
1010
- w: expansionWidth,
1011
- ta: "center",
1012
- style: expansionHeaderStyle,
1013
- children: /* @__PURE__ */ jsxRuntime.jsx(core$1.VisuallyHidden, { children: labels.expandRow })
1014
- }
1015
- ),
1016
- selection && /* @__PURE__ */ jsxRuntime.jsx(
1017
- core$1.Table.Th,
1018
- {
1019
- w: selectionWidth,
1020
- ta: "center",
1021
- style: selectionHeaderStyle,
1022
- children: /* @__PURE__ */ jsxRuntime.jsx(
1023
- core$1.Checkbox,
1024
- {
1025
- "aria-label": labels.selectAll,
1026
- checked: selection.headerState === "all",
1027
- indeterminate: selection.headerState === "some",
1028
- onChange: selection.toggleAll
1029
- }
1030
- )
1031
- }
1032
- ),
1033
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
1034
- HeaderCell,
1035
- {
1036
- table,
1037
- column,
1038
- stickyStyle: headerStyleFor(column),
1039
- resizeHandle: resizeHandleFor(column)
1040
- },
1041
- column.key
1042
- )),
1043
- showActions && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Th, { ta: "end", w: actionsWidth, style: actionsHeaderStyle, children: labels.actions })
1044
- ] })
1045
- ] }),
1046
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tbody, { ref: bodyRef, children: [
1047
- paddingTop > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tr, { "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
1048
- core$1.Table.Td,
1049
- {
1050
- colSpan: columnSpan,
1051
- style: { height: paddingTop, padding: 0 }
1052
- }
1053
- ) }),
1054
- entries.map(({ row, index, key }) => {
1055
- const id = getRowId(row);
1056
- return /* @__PURE__ */ jsxRuntime.jsx(
1057
- Row,
1058
- {
1059
- row,
1060
- index,
1061
- id,
1062
- columns,
1063
- getCellProps: table.getCellProps,
1064
- selected: selection?.isSelected(id),
1065
- selectLabel: labels.selectRow,
1066
- onToggleSelect: toggleSelect,
1067
- expanded: expansion?.isExpanded(id),
1068
- expandLabel: labels.expandRow,
1069
- collapseLabel: labels.collapseRow,
1070
- onToggleExpand: expansion?.toggle,
1071
- renderRowDetail,
1072
- columnSpan,
1073
- rowActions,
1074
- confirm,
1075
- cancelLabel: labels.cancel,
1076
- onRowClick,
1077
- prefetch,
1078
- className: rowClassName?.(row, index),
1079
- measureElement,
1080
- pinStyleFor: bodyPinStyle,
1081
- selectionCellStyle,
1082
- expansionCellStyle,
1083
- actionsCellStyle,
1084
- pinSignature
1085
- },
1086
- key
1087
- );
1088
- }),
1089
- paddingBottom > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tr, { "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
1090
- core$1.Table.Td,
1091
- {
1092
- colSpan: columnSpan,
1093
- style: { height: paddingBottom, padding: 0 }
1094
- }
1095
- ) })
1096
- ] }),
1097
- summaryCells && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Tfoot, { children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table.Tr, { children: [
1098
- expandable && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, {}),
1099
- selection && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, {}),
1100
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
1101
- core$1.Table.Td,
1102
- {
1103
- ...table.getCellProps(column),
1104
- fw: 600,
1105
- c: "dimmed",
1106
- children: summaryCells[column.key]
1107
- },
1108
- column.key
1109
- )),
1110
- showActions && /* @__PURE__ */ jsxRuntime.jsx(core$1.Table.Td, {})
1111
- ] }) })
1112
- ]
1113
- }
1114
- )
1115
- }
1116
- );
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
+ });
1117
1088
  }
1118
- function EmptyState({
1119
- title,
1120
- description,
1121
- icon,
1122
- action
1123
- }) {
1124
- return /* @__PURE__ */ jsxRuntime.jsxs(
1125
- core$1.Stack,
1126
- {
1127
- role: "status",
1128
- align: "center",
1129
- justify: "center",
1130
- gap: 6,
1131
- py: 48,
1132
- px: 16,
1133
- children: [
1134
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { c: "dimmed", "aria-hidden": true, children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(InboxIcon, { size: 40 }) }),
1135
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fw: 600, fz: "md", children: title }),
1136
- description && /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { c: "dimmed", fz: "sm", ta: "center", maw: 360, children: description }),
1137
- action
1138
- ]
1139
- }
1140
- );
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
+ });
1141
1121
  }
1142
- function ErrorState({
1143
- error,
1144
- title,
1145
- message,
1146
- retryLabel,
1147
- onRetry,
1148
- isRetrying
1149
- }) {
1150
- return /* @__PURE__ */ jsxRuntime.jsx(
1151
- core$1.Alert,
1152
- {
1153
- icon: /* @__PURE__ */ jsxRuntime.jsx(AlertIcon, { size: 16 }),
1154
- color: "red",
1155
- variant: "light",
1156
- title,
1157
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", align: "center", wrap: "nowrap", gap: "md", children: [
1158
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1159
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "sm", children: message }),
1160
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", mt: 2, children: error.message })
1161
- ] }),
1162
- onRetry && /* @__PURE__ */ jsxRuntime.jsx(
1163
- core$1.Button,
1164
- {
1165
- size: "xs",
1166
- variant: "light",
1167
- color: "red",
1168
- leftSection: /* @__PURE__ */ jsxRuntime.jsx(RefreshIcon, { size: 14 }),
1169
- onClick: onRetry,
1170
- loading: isRetrying,
1171
- children: retryLabel
1172
- }
1173
- )
1174
- ] })
1175
- }
1176
- );
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
+ });
1177
1155
  }
1178
- function FilterDrawer({
1179
- opened,
1180
- onClose,
1181
- filters,
1182
- activeFilterCount,
1183
- onClearFilters,
1184
- labels,
1185
- dir = "ltr"
1186
- }) {
1187
- return /* @__PURE__ */ jsxRuntime.jsx(
1188
- core$1.Drawer,
1189
- {
1190
- opened,
1191
- onClose,
1192
- position: dir === "rtl" ? "left" : "right",
1193
- size: 380,
1194
- title: labels.filters,
1195
- overlayProps: { opacity: 0.4, blur: 2 },
1196
- closeButtonProps: { "aria-label": labels.cancel },
1197
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: "md", mih: "60vh", justify: "space-between", children: [
1198
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Stack, { gap: "md", children: filters }),
1199
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", pt: "md", children: [
1200
- /* @__PURE__ */ jsxRuntime.jsx(
1201
- core$1.Button,
1202
- {
1203
- variant: "subtle",
1204
- onClick: onClearFilters,
1205
- disabled: activeFilterCount === 0,
1206
- children: labels.clearAll
1207
- }
1208
- ),
1209
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { onClick: onClose, children: labels.applyFilters })
1210
- ] })
1211
- ] })
1212
- }
1213
- );
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
+ });
1214
1193
  }
1194
+ //#endregion
1195
+ //#region src/components/MobileCards.tsx
1215
1196
  function mobileLabel(column) {
1216
- return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
1197
+ return column.mobileLabel ?? (typeof column.header === "string" ? column.header : column.key);
1217
1198
  }
1218
- function MobileCards({
1219
- table,
1220
- rows,
1221
- rowActions,
1222
- confirm,
1223
- getRowId,
1224
- bodyRef,
1225
- className,
1226
- rowEntries,
1227
- paddingTop = 0,
1228
- paddingBottom = 0,
1229
- measureElement,
1230
- density = "comfortable",
1231
- onRowClick,
1232
- rowClassName,
1233
- renderRowDetail,
1234
- summaryRow,
1235
- expansion
1236
- }) {
1237
- const { columns, selection, labels } = table;
1238
- const compact = density === "compact";
1239
- const cardPadding = compact ? "sm" : "md";
1240
- const cardGap = compact ? 4 : "xs";
1241
- const entries = rowEntries ?? rows.map((row, index) => ({
1242
- row,
1243
- index,
1244
- key: getRowId(row)
1245
- }));
1246
- const summaryCells = summaryRow?.(rows);
1247
- return /* @__PURE__ */ jsxRuntime.jsxs(
1248
- core$1.Stack,
1249
- {
1250
- gap: compact ? "xs" : "sm",
1251
- ref: bodyRef,
1252
- className,
1253
- ...table.getTableProps({ role: "list" }),
1254
- children: [
1255
- paddingTop > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, style: { height: paddingTop } }),
1256
- entries.map(({ row, index, key }) => {
1257
- const id = getRowId(row);
1258
- return /* @__PURE__ */ jsxRuntime.jsx(
1259
- core$1.Card,
1260
- {
1261
- ...core.rowClickProps(row, onRowClick),
1262
- className: rowClassName?.(row, index),
1263
- ref: measureElement,
1264
- "data-index": index,
1265
- withBorder: true,
1266
- radius: "md",
1267
- padding: cardPadding,
1268
- role: "listitem",
1269
- "data-stagger": "",
1270
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: cardGap, children: [
1271
- selection && /* @__PURE__ */ jsxRuntime.jsx(
1272
- core$1.Checkbox,
1273
- {
1274
- "aria-label": labels.selectRow,
1275
- checked: selection.isSelected(id),
1276
- onChange: () => selection.toggle(id)
1277
- }
1278
- ),
1279
- expansion && /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { justify: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(
1280
- ExpandToggle,
1281
- {
1282
- expanded: expansion.isExpanded(id),
1283
- expandLabel: labels.expandRow,
1284
- collapseLabel: labels.collapseRow,
1285
- onToggle: () => expansion.toggle(id)
1286
- }
1287
- ) }),
1288
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1289
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", tt: "uppercase", fw: 500, children: mobileLabel(column) }),
1290
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { component: "div", fz: "sm", children: column.Cell ? /* @__PURE__ */ jsxRuntime.jsx(column.Cell, { row, rowIndex: index }) : column.accessor?.(row) })
1291
- ] }, column.key)),
1292
- expansion?.isExpanded(id) === true && /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderRowDetail(row) }),
1293
- rowActions && rowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { gap: 4, justify: "flex-end", pt: 4, children: rowActions.map((action) => {
1294
- if (action.isHidden?.(row)) return null;
1295
- const reason = core.resolveDisabledReason(
1296
- action.disabledReason?.(row)
1297
- );
1298
- const disabled = reason !== void 0 || (action.isDisabled?.(row) ?? false);
1299
- const run = disabled ? void 0 : () => core.runRowAction(action, row, confirm, labels.cancel);
1300
- return action.icon ? /* @__PURE__ */ jsxRuntime.jsx(
1301
- core$1.Tooltip,
1302
- {
1303
- label: reason ?? action.label,
1304
- withArrow: true,
1305
- openDelay: 200,
1306
- children: /* @__PURE__ */ jsxRuntime.jsx(
1307
- core$1.ActionIcon,
1308
- {
1309
- variant: "subtle",
1310
- color: action.color,
1311
- size: "sm",
1312
- disabled,
1313
- "aria-label": action.label,
1314
- onClick: run,
1315
- children: action.icon
1316
- }
1317
- )
1318
- },
1319
- action.key
1320
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1321
- core$1.Button,
1322
- {
1323
- variant: "subtle",
1324
- color: action.color,
1325
- size: "compact-sm",
1326
- disabled,
1327
- onClick: run,
1328
- children: action.label
1329
- },
1330
- action.key
1331
- );
1332
- }) })
1333
- ] })
1334
- },
1335
- key
1336
- );
1337
- }),
1338
- paddingBottom > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, style: { height: paddingBottom } }),
1339
- 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: [
1340
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", tt: "uppercase", fw: 500, children: mobileLabel(column) }),
1341
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { component: "div", fz: "sm", fw: 600, children: summaryCells[column.key] })
1342
- ] }, column.key)) }) })
1343
- ]
1344
- }
1345
- );
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
+ });
1346
1328
  }
1347
- function PaginationFooter({
1348
- page,
1349
- totalPages,
1350
- limit,
1351
- total,
1352
- fromIndex,
1353
- toIndex,
1354
- onPageChange,
1355
- onLimitChange,
1356
- labels
1357
- }) {
1358
- const safeTotalPages = Math.max(totalPages, 1);
1359
- const safePage = Math.min(Math.max(page, 1), safeTotalPages);
1360
- const options = core.pageSizeOptions(limit).map((n) => ({
1361
- value: String(n),
1362
- label: String(n)
1363
- }));
1364
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", align: "center", wrap: "wrap", gap: "md", pt: "xs", children: [
1365
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", align: "center", wrap: "nowrap", children: [
1366
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.rowsPerPage }),
1367
- /* @__PURE__ */ jsxRuntime.jsx(
1368
- core$1.Select,
1369
- {
1370
- "aria-label": labels.rowsPerPage,
1371
- data: options,
1372
- value: String(limit),
1373
- onChange: (v) => onLimitChange(Number(v)),
1374
- size: "xs",
1375
- w: 76,
1376
- allowDeselect: false,
1377
- comboboxProps: { withinPortal: false }
1378
- }
1379
- ),
1380
- total > 0 && /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.showing({ from: fromIndex, to: toIndex, total }) })
1381
- ] }),
1382
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "sm", align: "center", wrap: "nowrap", children: [
1383
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.pageOf({ page: safePage, total: safeTotalPages }) }),
1384
- /* @__PURE__ */ jsxRuntime.jsx(
1385
- core$1.Pagination,
1386
- {
1387
- total: safeTotalPages,
1388
- value: safePage,
1389
- onChange: onPageChange,
1390
- size: "sm",
1391
- siblings: 1,
1392
- boundaries: 1,
1393
- getControlProps: (control) => ({
1394
- "aria-label": control === "previous" ? labels.previousPage : labels.nextPage
1395
- })
1396
- }
1397
- )
1398
- ] })
1399
- ] });
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
+ });
1400
1397
  }
1401
- function SavedViewsMenu({
1402
- views,
1403
- labels
1404
- }) {
1405
- const [name, setName] = react.useState("");
1406
- const trimmed = name.trim();
1407
- const handleSave = () => {
1408
- views.save(trimmed);
1409
- setName("");
1410
- };
1411
- return /* @__PURE__ */ jsxRuntime.jsxs(core$1.Menu, { closeOnItemClick: false, position: "bottom-end", withinPortal: true, children: [
1412
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Target, { children: /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { variant: "default", size: "sm", children: labels.savedViews }) }),
1413
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Dropdown, { children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Box, { p: 4, miw: 220, children: [
1414
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", px: 4, pb: 6, children: labels.savedViews }),
1415
- views.views.map((view) => /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: 6, px: 4, py: 2, wrap: "nowrap", children: [
1416
- /* @__PURE__ */ jsxRuntime.jsx(
1417
- core$1.Button,
1418
- {
1419
- variant: "subtle",
1420
- size: "compact-sm",
1421
- justify: "flex-start",
1422
- style: { flex: 1 },
1423
- onClick: () => views.apply(view.name),
1424
- children: view.name
1425
- }
1426
- ),
1427
- /* @__PURE__ */ jsxRuntime.jsx(
1428
- core$1.ActionIcon,
1429
- {
1430
- variant: "subtle",
1431
- color: "gray",
1432
- size: "sm",
1433
- "aria-label": `${labels.deleteView}: ${view.name}`,
1434
- onClick: () => views.remove(view.name),
1435
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { size: 12 })
1436
- }
1437
- )
1438
- ] }, view.name)),
1439
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Menu.Divider, {}),
1440
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: 6, p: 4, wrap: "nowrap", children: [
1441
- /* @__PURE__ */ jsxRuntime.jsx(
1442
- core$1.TextInput,
1443
- {
1444
- size: "xs",
1445
- style: { flex: 1 },
1446
- placeholder: labels.viewName,
1447
- value: name,
1448
- onChange: (e) => setName(e.currentTarget.value)
1449
- }
1450
- ),
1451
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { size: "xs", disabled: trimmed === "", onClick: handleSave, children: labels.saveView })
1452
- ] })
1453
- ] }) })
1454
- ] });
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
+ });
1455
1477
  }
1456
- function TableSkeleton({
1457
- columns,
1458
- rows = 5,
1459
- loadingLabel
1460
- }) {
1461
- const colKeys = Array.from({ length: Math.max(columns, 1) }, (_, i) => i);
1462
- const rowKeys = Array.from({ length: rows }, (_, i) => i);
1463
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "status", "aria-busy": "true", "aria-live": "polite", children: [
1464
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Table, { children: [
1465
- /* @__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(
1466
- core$1.Skeleton,
1467
- {
1468
- height: 12,
1469
- radius: "sm",
1470
- width: c === 0 ? "55%" : "40%"
1471
- }
1472
- ) }, c)) }) }),
1473
- /* @__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(
1474
- core$1.Skeleton,
1475
- {
1476
- height: 14,
1477
- radius: "sm",
1478
- width: c === 0 ? "70%" : "55%"
1479
- }
1480
- ) }, c)) }, r)) })
1481
- ] }),
1482
- loadingLabel ? /* @__PURE__ */ jsxRuntime.jsx(core$1.VisuallyHidden, { children: loadingLabel }) : null
1483
- ] });
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
+ });
1484
1498
  }
1485
- function FilterPopover({
1486
- open,
1487
- onClose,
1488
- filters,
1489
- activeFilterCount,
1490
- onClearFilters,
1491
- labels,
1492
- dir = "ltr",
1493
- children
1494
- }) {
1495
- return /* @__PURE__ */ jsxRuntime.jsxs(
1496
- core$1.Popover,
1497
- {
1498
- opened: open,
1499
- onDismiss: onClose,
1500
- position: dir === "rtl" ? "bottom-start" : "bottom-end",
1501
- withinPortal: true,
1502
- shadow: "md",
1503
- radius: "md",
1504
- width: 340,
1505
- children: [
1506
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Popover.Target, { children }),
1507
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Popover.Dropdown, { children: [
1508
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { justify: "space-between", align: "center", mb: "sm", children: [
1509
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fw: 600, fz: "sm", children: labels.filters }),
1510
- /* @__PURE__ */ jsxRuntime.jsx(
1511
- core$1.Button,
1512
- {
1513
- variant: "subtle",
1514
- size: "compact-xs",
1515
- onClick: onClearFilters,
1516
- disabled: activeFilterCount === 0,
1517
- children: labels.clearAll
1518
- }
1519
- )
1520
- ] }),
1521
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Stack, { gap: "md", children: filters })
1522
- ] })
1523
- ]
1524
- }
1525
- );
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
+ });
1526
1536
  }
1527
- function Toolbar({
1528
- table,
1529
- hideSearch,
1530
- searchPlaceholder,
1531
- sortByOptions,
1532
- customToolbar,
1533
- hasFilters,
1534
- activeFilterCount,
1535
- onToggleFilters,
1536
- onFiltersTriggerPointerDown,
1537
- onCloseFilters,
1538
- filtersOpen,
1539
- filtersMode,
1540
- filters,
1541
- onClearFilters,
1542
- dir,
1543
- columnMenu,
1544
- showRowsPerPage,
1545
- className
1546
- }) {
1547
- const { labels, source } = table;
1548
- const searchProps = table.getSearchInputProps(
1549
- searchPlaceholder ? { placeholder: searchPlaceholder } : void 0
1550
- );
1551
- const sortOptions = sortByOptions ?? (table.isMobile ? table.sortByOptions : void 0);
1552
- const filtersButton = /* @__PURE__ */ jsxRuntime.jsx(
1553
- core$1.Button,
1554
- {
1555
- variant: "default",
1556
- size: "sm",
1557
- "aria-expanded": filtersMode === "popover" ? filtersOpen : void 0,
1558
- "data-active": filtersOpen || void 0,
1559
- leftSection: /* @__PURE__ */ jsxRuntime.jsx(FiltersIcon, { size: 16 }),
1560
- rightSection: activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx(core$1.Badge, { size: "sm", circle: true, children: activeFilterCount }) : void 0,
1561
- onPointerDown: onFiltersTriggerPointerDown,
1562
- onClick: onToggleFilters,
1563
- children: labels.filters
1564
- }
1565
- );
1566
- return /* @__PURE__ */ jsxRuntime.jsxs(
1567
- core$1.Group,
1568
- {
1569
- gap: "sm",
1570
- justify: "space-between",
1571
- align: "center",
1572
- className,
1573
- children: [
1574
- !hideSearch && /* @__PURE__ */ jsxRuntime.jsx(
1575
- core$1.TextInput,
1576
- {
1577
- ...searchProps,
1578
- leftSection: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { size: 14 }),
1579
- size: "sm",
1580
- style: { flex: 1, minWidth: 160, maxWidth: 360 }
1581
- }
1582
- ),
1583
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", align: "center", children: [
1584
- sortOptions && sortOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1585
- core$1.Select,
1586
- {
1587
- "aria-label": labels.sortBy,
1588
- placeholder: labels.sortBy,
1589
- data: sortOptions,
1590
- value: source.sortBy ?? null,
1591
- onChange: (v) => source.setSort(v ?? void 0, source.sortDir ?? "asc"),
1592
- clearable: true,
1593
- size: "sm",
1594
- w: 160,
1595
- comboboxProps: { withinPortal: false }
1596
- }
1597
- ),
1598
- customToolbar,
1599
- hasFilters && (filtersMode === "popover" ? /* @__PURE__ */ jsxRuntime.jsx(
1600
- FilterPopover,
1601
- {
1602
- open: filtersOpen,
1603
- onClose: onCloseFilters,
1604
- filters,
1605
- activeFilterCount,
1606
- onClearFilters,
1607
- labels,
1608
- dir,
1609
- children: filtersButton
1610
- }
1611
- ) : filtersButton),
1612
- columnMenu,
1613
- showRowsPerPage && /* @__PURE__ */ jsxRuntime.jsxs(core$1.Group, { gap: "xs", align: "center", children: [
1614
- /* @__PURE__ */ jsxRuntime.jsx(core$1.Text, { fz: "xs", c: "dimmed", children: labels.rowsPerPage }),
1615
- /* @__PURE__ */ jsxRuntime.jsx(
1616
- core$1.Select,
1617
- {
1618
- "aria-label": labels.rowsPerPage,
1619
- data: core.pageSizeOptions(source.limit).map((n) => ({
1620
- value: String(n),
1621
- label: String(n)
1622
- })),
1623
- value: String(source.limit),
1624
- onChange: (v) => source.setLimit(Number(v)),
1625
- size: "sm",
1626
- w: 80,
1627
- allowDeselect: false,
1628
- comboboxProps: { withinPortal: false }
1629
- }
1630
- )
1631
- ] })
1632
- ] })
1633
- ]
1634
- }
1635
- );
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
+ });
1636
1624
  }
1637
- var stickyToolbarStyle = (top) => ({
1638
- position: "sticky",
1639
- top,
1640
- zIndex: 3,
1641
- background: "var(--mantine-color-body)",
1642
- 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)"
1643
1633
  });
1644
- function ColumnMenuSlot({
1645
- enabled,
1646
- ...props
1647
- }) {
1648
- if (!enabled) return null;
1649
- 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 });
1650
1638
  }
1651
- function SavedViewsSlot({
1652
- options,
1653
- labels
1654
- }) {
1655
- const views = core.useSavedViews(options);
1656
- 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
+ });
1657
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
+ */
1658
1656
  function useResolvedTableProps(props) {
1659
- const { source, runtime } = core.useTableData({
1660
- locale: props.locale,
1661
- source: props.source,
1662
- data: props.data,
1663
- total: props.total,
1664
- loading: props.loading,
1665
- onQueryChange: props.onQueryChange,
1666
- columns: props.columns,
1667
- filters: props.filters,
1668
- urlKey: props.urlKey,
1669
- adapter: props.urlSync === false ? void 0 : props.urlAdapter,
1670
- enabled: props.urlSync
1671
- });
1672
- const labels = react.useMemo(() => core.resolveLabels(props.labels), [props.labels]);
1673
- let filters;
1674
- if (core.isDeclarativeFilters(props.filters) || props.filters === void 0) {
1675
- filters = runtime.defs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AutoFilterForm, { defs: runtime.defs, source, labels }) : void 0;
1676
- } else {
1677
- filters = props.filters;
1678
- }
1679
- const filterLabels = react.useMemo(
1680
- () => ({ ...runtime.filterLabels, ...props.filterLabels }),
1681
- [runtime.filterLabels, props.filterLabels]
1682
- );
1683
- 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
+ };
1684
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
+ */
1685
1698
  function DataTable(props) {
1686
- const chromeProps = useResolvedTableProps(props);
1687
- const {
1688
- source,
1689
- rowActions,
1690
- searchPlaceholder,
1691
- sortByOptions,
1692
- dir,
1693
- prefetch,
1694
- hideSearch,
1695
- filters,
1696
- filtersMode = "popover",
1697
- bulkActions,
1698
- slots,
1699
- classNames,
1700
- toolbar: customToolbar,
1701
- skeletonRows,
1702
- stickyTop = 0,
1703
- animate = false,
1704
- stickyHeader = false,
1705
- enableColumnMenu = false,
1706
- savedViews
1707
- } = chromeProps;
1708
- const density = chromeProps.density ?? "comfortable";
1709
- const chrome = core.useTableChrome(chromeProps);
1710
- const { table, isMobile, confirm, getRowId } = chrome;
1711
- const hasRowActions = (rowActions?.length ?? 0) > 0;
1712
- const visibleRowActions = chrome.columnLayout.isHidden(core.ACTIONS_COLUMN_KEY) ? void 0 : rowActions;
1713
- const actionsPinned = chrome.columnLayout.state.pinned[core.ACTIONS_COLUMN_KEY] === "right";
1714
- const { virtualization, loadMoreRef, canLoadMore, virtualScrollRef } = core.useChromeBodyData(chrome, chromeProps);
1715
- const [drawerOpened, setDrawerOpened] = react.useState(false);
1716
- const filtersTrigger = core.useFilterTriggerToggle(drawerOpened, setDrawerOpened);
1717
- const rootRef = react.useRef(null);
1718
- const { ref: toolbarRef, height: toolbarHeight } = hooks.useElementSize();
1719
- const desktopBodyRef = react.useRef(null);
1720
- const mobileBodyRef = react.useRef(null);
1721
- core.useChromeScrollReset(rootRef, chrome, chromeProps);
1722
- useMountStagger(
1723
- isMobile ? mobileBodyRef : desktopBodyRef,
1724
- [virtualization.rows.length, isMobile],
1725
- { enabled: animate }
1726
- );
1727
- let body;
1728
- if (chrome.body === "skeleton") {
1729
- body = slots?.skeleton ?? /* @__PURE__ */ jsxRuntime.jsx(
1730
- TableSkeleton,
1731
- {
1732
- columns: table.columns.length || 1,
1733
- rows: skeletonRows ?? source.limit,
1734
- loadingLabel: table.labels.loading
1735
- }
1736
- );
1737
- } else if (chrome.body === "empty") {
1738
- body = slots?.empty ?? (chrome.emptyVariant === "noResults" ? /* @__PURE__ */ jsxRuntime.jsx(
1739
- EmptyState,
1740
- {
1741
- title: table.labels.noResults,
1742
- action: /* @__PURE__ */ jsxRuntime.jsx(core$1.Button, { variant: "light", size: "sm", onClick: chrome.clearFilters, children: table.labels.clearAll })
1743
- }
1744
- ) : /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: table.labels.noData }));
1745
- } else if (chrome.body === "mobile") {
1746
- body = /* @__PURE__ */ jsxRuntime.jsx(
1747
- MobileCards,
1748
- {
1749
- table,
1750
- rows: source.rows,
1751
- rowActions: visibleRowActions,
1752
- confirm,
1753
- getRowId,
1754
- onRowClick: props.onRowClick,
1755
- rowClassName: props.rowClassName,
1756
- renderRowDetail: props.renderRowDetail,
1757
- summaryRow: props.summaryRow,
1758
- expansion: chrome.detail?.expansion,
1759
- bodyRef: mobileBodyRef,
1760
- className: classNames?.card,
1761
- rowEntries: virtualization.enabled ? virtualization.rows : void 0,
1762
- paddingTop: virtualization.paddingTop,
1763
- paddingBottom: virtualization.paddingBottom,
1764
- measureElement: virtualization.measureElement,
1765
- density
1766
- }
1767
- );
1768
- } else {
1769
- body = /* @__PURE__ */ jsxRuntime.jsx(
1770
- DesktopTable,
1771
- {
1772
- table,
1773
- rows: source.rows,
1774
- rowActions: visibleRowActions,
1775
- confirm,
1776
- prefetch,
1777
- onRowClick: props.onRowClick,
1778
- rowClassName: props.rowClassName,
1779
- renderRowDetail: props.renderRowDetail,
1780
- summaryRow: props.summaryRow,
1781
- expansion: chrome.detail?.expansion,
1782
- getRowId,
1783
- bodyRef: desktopBodyRef,
1784
- className: classNames?.table,
1785
- rowEntries: virtualization.enabled ? virtualization.rows : void 0,
1786
- paddingTop: virtualization.paddingTop,
1787
- paddingBottom: virtualization.paddingBottom,
1788
- measureElement: virtualization.measureElement,
1789
- stickyHeaderOffset: stickyTop + toolbarHeight,
1790
- stickyHeader,
1791
- pinOffset: chrome.columnLayout.pinOffset,
1792
- actionsPinned,
1793
- maxHeight: props.maxHeight,
1794
- virtualScrollRef,
1795
- setWidth: props.resizableColumns ? chrome.columnLayout.setWidth : void 0,
1796
- columnWidths: chrome.columnLayout.state.widths,
1797
- resizeLabel: table.labels.resizeColumn,
1798
- density
1799
- }
1800
- );
1801
- }
1802
- return /* @__PURE__ */ jsxRuntime.jsxs(
1803
- core$1.Paper,
1804
- {
1805
- ref: rootRef,
1806
- p: "xs",
1807
- radius: "md",
1808
- withBorder: true,
1809
- dir,
1810
- "aria-busy": chrome.isRefreshing || void 0,
1811
- className: classNames?.root,
1812
- children: [
1813
- /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: "xs", children: [
1814
- /* @__PURE__ */ jsxRuntime.jsx(
1815
- core$1.Box,
1816
- {
1817
- ref: toolbarRef,
1818
- style: stickyToolbarStyle(stickyTop),
1819
- className: classNames?.toolbar,
1820
- children: /* @__PURE__ */ jsxRuntime.jsxs(core$1.Stack, { gap: "xs", children: [
1821
- /* @__PURE__ */ jsxRuntime.jsx(
1822
- Toolbar,
1823
- {
1824
- table,
1825
- hideSearch,
1826
- searchPlaceholder,
1827
- sortByOptions,
1828
- customToolbar,
1829
- hasFilters: Boolean(filters),
1830
- activeFilterCount: chrome.activeFilterCount,
1831
- filtersMode,
1832
- filters,
1833
- filtersOpen: drawerOpened,
1834
- onToggleFilters: filtersTrigger.onClick,
1835
- onFiltersTriggerPointerDown: filtersTrigger.onPointerDown,
1836
- onCloseFilters: () => setDrawerOpened(false),
1837
- onClearFilters: chrome.clearFilters,
1838
- dir,
1839
- columnMenu: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1840
- savedViews && /* @__PURE__ */ jsxRuntime.jsx(
1841
- SavedViewsSlot,
1842
- {
1843
- options: {
1844
- adapter: chromeProps.urlAdapter,
1845
- urlKey: chromeProps.urlKey,
1846
- ...savedViews
1847
- },
1848
- labels: table.labels
1849
- }
1850
- ),
1851
- /* @__PURE__ */ jsxRuntime.jsx(
1852
- ColumnMenuSlot,
1853
- {
1854
- enabled: enableColumnMenu && !isMobile,
1855
- allColumns: chrome.allColumns,
1856
- layout: chrome.columnLayout,
1857
- labels: table.labels,
1858
- hasRowActions
1859
- }
1860
- )
1861
- ] }),
1862
- showRowsPerPage: canLoadMore
1863
- }
1864
- ),
1865
- /* @__PURE__ */ jsxRuntime.jsx(
1866
- ActiveFilterChips,
1867
- {
1868
- chips: chrome.mergedChips,
1869
- onClearAll: chrome.clearFilters,
1870
- label: table.labels.filters,
1871
- clearAllLabel: table.labels.clearAll
1872
- }
1873
- ),
1874
- table.selection && bulkActions && /* @__PURE__ */ jsxRuntime.jsx(
1875
- BulkActionBar,
1876
- {
1877
- selection: table.selection,
1878
- total: source.total,
1879
- bulkActions,
1880
- confirm,
1881
- labels: table.labels
1882
- }
1883
- )
1884
- ] })
1885
- }
1886
- ),
1887
- chrome.isRefreshing && /* @__PURE__ */ jsxRuntime.jsx(
1888
- core$1.Progress,
1889
- {
1890
- size: "xs",
1891
- animated: true,
1892
- value: 100,
1893
- "aria-label": table.labels.loading
1894
- }
1895
- ),
1896
- source.error && /* @__PURE__ */ jsxRuntime.jsx(
1897
- ErrorState,
1898
- {
1899
- error: source.error,
1900
- title: table.labels.errorTitle,
1901
- message: table.labels.errorMessage,
1902
- retryLabel: table.labels.retry,
1903
- onRetry: source.refetch ? () => void source.refetch?.() : void 0,
1904
- isRetrying: source.isFetching
1905
- }
1906
- ),
1907
- !source.error && body,
1908
- canLoadMore && source.hasNextPage && /* @__PURE__ */ jsxRuntime.jsx(core$1.Group, { ref: loadMoreRef, justify: "center", py: "xs", children: /* @__PURE__ */ jsxRuntime.jsx(
1909
- core$1.Button,
1910
- {
1911
- variant: "default",
1912
- size: "sm",
1913
- loading: source.isFetchingNextPage,
1914
- onClick: () => source.fetchNextPage(),
1915
- children: table.labels.loadMore
1916
- }
1917
- ) }),
1918
- chrome.showFooter && /* @__PURE__ */ jsxRuntime.jsx(core$1.Box, { className: classNames?.footer, children: /* @__PURE__ */ jsxRuntime.jsx(
1919
- PaginationFooter,
1920
- {
1921
- page: table.pagination.safePage,
1922
- totalPages: table.pagination.totalPages,
1923
- limit: source.limit,
1924
- total: source.total,
1925
- fromIndex: table.pagination.fromIndex,
1926
- toIndex: table.pagination.toIndex,
1927
- onPageChange: source.setPage,
1928
- onLimitChange: source.setLimit,
1929
- labels: table.labels
1930
- }
1931
- ) })
1932
- ] }),
1933
- filters && filtersMode === "drawer" && /* @__PURE__ */ jsxRuntime.jsx(
1934
- FilterDrawer,
1935
- {
1936
- opened: drawerOpened,
1937
- onClose: () => setDrawerOpened(false),
1938
- filters,
1939
- activeFilterCount: chrome.activeFilterCount,
1940
- onClearFilters: chrome.clearFilters,
1941
- labels: table.labels,
1942
- dir
1943
- }
1944
- )
1945
- ]
1946
- }
1947
- );
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
+ });
1948
1897
  }
1949
-
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;
1950
1907
  Object.defineProperty(exports, "createHistoryAdapter", {
1951
- enumerable: true,
1952
- get: function () { return core.createHistoryAdapter; }
1908
+ enumerable: true,
1909
+ get: function() {
1910
+ return _adapttable_core.createHistoryAdapter;
1911
+ }
1953
1912
  });
1954
1913
  Object.defineProperty(exports, "createMemoryAdapter", {
1955
- enumerable: true,
1956
- get: function () { return core.createMemoryAdapter; }
1914
+ enumerable: true,
1915
+ get: function() {
1916
+ return _adapttable_core.createMemoryAdapter;
1917
+ }
1957
1918
  });
1958
1919
  Object.defineProperty(exports, "defaultConfirm", {
1959
- enumerable: true,
1960
- get: function () { return core.defaultConfirm; }
1920
+ enumerable: true,
1921
+ get: function() {
1922
+ return _adapttable_core.defaultConfirm;
1923
+ }
1961
1924
  });
1962
1925
  Object.defineProperty(exports, "defaultLabels", {
1963
- enumerable: true,
1964
- get: function () { return core.defaultLabels; }
1926
+ enumerable: true,
1927
+ get: function() {
1928
+ return _adapttable_core.defaultLabels;
1929
+ }
1965
1930
  });
1966
1931
  Object.defineProperty(exports, "deriveSortByOptions", {
1967
- enumerable: true,
1968
- get: function () { return core.deriveSortByOptions; }
1932
+ enumerable: true,
1933
+ get: function() {
1934
+ return _adapttable_core.deriveSortByOptions;
1935
+ }
1969
1936
  });
1970
1937
  Object.defineProperty(exports, "getHistoryAdapter", {
1971
- enumerable: true,
1972
- get: function () { return core.getHistoryAdapter; }
1938
+ enumerable: true,
1939
+ get: function() {
1940
+ return _adapttable_core.getHistoryAdapter;
1941
+ }
1973
1942
  });
1974
1943
  Object.defineProperty(exports, "useBackendData", {
1975
- enumerable: true,
1976
- get: function () { return core.useBackendData; }
1944
+ enumerable: true,
1945
+ get: function() {
1946
+ return _adapttable_core.useBackendData;
1947
+ }
1977
1948
  });
1978
1949
  Object.defineProperty(exports, "useDataTable", {
1979
- enumerable: true,
1980
- get: function () { return core.useDataTable; }
1950
+ enumerable: true,
1951
+ get: function() {
1952
+ return _adapttable_core.useDataTable;
1953
+ }
1981
1954
  });
1982
1955
  Object.defineProperty(exports, "useFrontendData", {
1983
- enumerable: true,
1984
- get: function () { return core.useFrontendData; }
1956
+ enumerable: true,
1957
+ get: function() {
1958
+ return _adapttable_core.useFrontendData;
1959
+ }
1985
1960
  });
1961
+ exports.useMountStagger = useMountStagger;
1986
1962
  Object.defineProperty(exports, "useSavedViews", {
1987
- enumerable: true,
1988
- get: function () { return core.useSavedViews; }
1963
+ enumerable: true,
1964
+ get: function() {
1965
+ return _adapttable_core.useSavedViews;
1966
+ }
1989
1967
  });
1990
1968
  Object.defineProperty(exports, "useTableUrlState", {
1991
- enumerable: true,
1992
- get: function () { return core.useTableUrlState; }
1969
+ enumerable: true,
1970
+ get: function() {
1971
+ return _adapttable_core.useTableUrlState;
1972
+ }
1993
1973
  });
1994
- exports.ActiveFilterChips = ActiveFilterChips;
1995
- exports.AutoFilterForm = AutoFilterForm;
1996
- exports.DataTable = DataTable;
1997
- exports.EmptyState = EmptyState;
1998
- exports.ErrorState = ErrorState;
1999
- exports.PaginationFooter = PaginationFooter;
2000
- exports.SavedViewsMenu = SavedViewsMenu;
2001
- exports.TableSkeleton = TableSkeleton;
2002
- exports.useMountStagger = useMountStagger;
2003
- //# sourceMappingURL=index.cjs.map
1974
+
2004
1975
  //# sourceMappingURL=index.cjs.map