@squirkle-ui/datagrid 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2690 @@
1
+ import { defineComponent, ref, computed, resolveComponent, openBlock, createElementBlock, withModifiers, Fragment, createVNode, createElementVNode, withCtx, createBlock, createCommentVNode, createTextVNode, toDisplayString, watch, toRaw, onMounted, onBeforeUnmount, nextTick, normalizeStyle, normalizeClass, renderSlot, renderList, mergeProps } from "vue";
2
+ import { toDate, compareValues, getByPath, clamp, toUnit, formatDate, downloadText } from "@squirkle-ui/core";
3
+ import { SqVirtualScroll, SqTextField, SqSelect, SqCheckbox, SqBtn, config, SqProgressCircular, SqPagination, SqMenu, SqListItem, SqIcon, SqEmptyState, SqDivider, SqChip, SqShape, useProxiedModel } from "@squirkle-ui/ui";
4
+ const TEXT_OPS = [
5
+ { title: "Contains", value: "contains" },
6
+ { title: "Does not contain", value: "notContains" },
7
+ { title: "Equals", value: "equals" },
8
+ { title: "Not equal", value: "notEqual" },
9
+ { title: "Starts with", value: "startsWith" },
10
+ { title: "Ends with", value: "endsWith" },
11
+ { title: "Blank", value: "blank" },
12
+ { title: "Not blank", value: "notBlank" }
13
+ ];
14
+ const NUM_OPS = [
15
+ { title: "Equals", value: "equals" },
16
+ { title: "Not equal", value: "notEqual" },
17
+ { title: "Greater than", value: "gt" },
18
+ { title: "≥", value: "gte" },
19
+ { title: "Less than", value: "lt" },
20
+ { title: "≤", value: "lte" },
21
+ { title: "Between", value: "between" },
22
+ { title: "Blank", value: "blank" },
23
+ { title: "Not blank", value: "notBlank" }
24
+ ];
25
+ const _sfc_main$1 = defineComponent({
26
+ name: "SqGridFilter",
27
+ components: { SqBtn, SqCheckbox, SqSelect, SqTextField, SqVirtualScroll },
28
+ props: {
29
+ kind: { type: String, required: true },
30
+ modelValue: { type: Object, default: void 0 },
31
+ /** Distinct values for the set filter. */
32
+ values: { type: Array, default: () => [] },
33
+ formatter: { type: Function, default: void 0 }
34
+ },
35
+ emits: ["update:modelValue"],
36
+ setup(props, { emit }) {
37
+ const search = ref("");
38
+ const ops = computed(() => props.kind === "text" ? TEXT_OPS : NUM_OPS);
39
+ const draft = computed(() => props.modelValue ?? { kind: props.kind, op: props.kind === "text" ? "contains" : "equals" });
40
+ const draftValue = computed(() => draft.value.value);
41
+ const draftValueTo = computed(() => draft.value.valueTo);
42
+ const needsValue = computed(() => draft.value.op !== "blank" && draft.value.op !== "notBlank");
43
+ const set = (key, v) => emit("update:modelValue", { ...draft.value, kind: props.kind, [key]: v });
44
+ const label = (v) => v == null || v === "" ? "(Blanks)" : props.formatter ? props.formatter(v) : String(v);
45
+ const shownValues = computed(() => {
46
+ const q = search.value.trim().toLowerCase();
47
+ return q ? props.values.filter((v) => label(v).toLowerCase().includes(q)) : props.values;
48
+ });
49
+ const checkedSet = computed(() => new Set((props.modelValue?.values ?? props.values).map(String)));
50
+ const isChecked = (v) => checkedSet.value.has(String(v));
51
+ const allChecked = computed(() => !props.modelValue?.values || props.modelValue.values.length === props.values.length);
52
+ const someChecked = computed(() => !!props.modelValue?.values && props.modelValue.values.length > 0 && !allChecked.value);
53
+ const toggleValue = (v) => {
54
+ const cur = props.modelValue?.values ?? props.values;
55
+ const next = isChecked(v) ? cur.filter((x) => String(x) !== String(v)) : [...cur, v];
56
+ emit("update:modelValue", next.length === props.values.length ? void 0 : { kind: "set", values: next });
57
+ };
58
+ const toggleAll = () => emit("update:modelValue", allChecked.value ? { kind: "set", values: [] } : void 0);
59
+ return { search, ops, draft, draftValue, draftValueTo, needsValue, set, label, shownValues, isChecked, allChecked, someChecked, toggleValue, toggleAll, messages: computed(() => config.locale.messages) };
60
+ }
61
+ });
62
+ const _export_sfc = (sfc, props) => {
63
+ const target = sfc.__vccOpts || sfc;
64
+ for (const [key, val] of props) {
65
+ target[key] = val;
66
+ }
67
+ return target;
68
+ };
69
+ const _hoisted_1$1 = { class: "sq-grid-filter__all" };
70
+ const _hoisted_2$1 = { class: "sq-grid-filter__actions" };
71
+ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
72
+ const _component_SqTextField = resolveComponent("SqTextField");
73
+ const _component_SqCheckbox = resolveComponent("SqCheckbox");
74
+ const _component_SqVirtualScroll = resolveComponent("SqVirtualScroll");
75
+ const _component_SqSelect = resolveComponent("SqSelect");
76
+ const _component_SqBtn = resolveComponent("SqBtn");
77
+ return openBlock(), createElementBlock("div", {
78
+ class: "sq-grid-filter",
79
+ onClick: _cache[5] || (_cache[5] = withModifiers(() => {
80
+ }, ["stop"]))
81
+ }, [
82
+ _ctx.kind === "set" ? (openBlock(), createElementBlock(
83
+ Fragment,
84
+ { key: 0 },
85
+ [
86
+ createVNode(_component_SqTextField, {
87
+ modelValue: _ctx.search,
88
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.search = $event),
89
+ placeholder: _ctx.messages.search,
90
+ density: "compact",
91
+ "prepend-inner-icon": "search",
92
+ "hide-details": "",
93
+ clearable: ""
94
+ }, null, 8, ["modelValue", "placeholder"]),
95
+ createElementVNode("label", _hoisted_1$1, [
96
+ createVNode(_component_SqCheckbox, {
97
+ "model-value": _ctx.allChecked,
98
+ indeterminate: _ctx.someChecked,
99
+ label: _ctx.messages.selectAll,
100
+ "onUpdate:modelValue": _ctx.toggleAll
101
+ }, null, 8, ["model-value", "indeterminate", "label", "onUpdate:modelValue"])
102
+ ]),
103
+ createVNode(_component_SqVirtualScroll, {
104
+ items: _ctx.shownValues,
105
+ "item-height": 32,
106
+ height: Math.min(_ctx.shownValues.length * 32, 224) || 32
107
+ }, {
108
+ default: withCtx(({ item }) => [
109
+ createVNode(_component_SqCheckbox, {
110
+ "model-value": _ctx.isChecked(item),
111
+ label: _ctx.label(item),
112
+ "onUpdate:modelValue": ($event) => _ctx.toggleValue(item)
113
+ }, null, 8, ["model-value", "label", "onUpdate:modelValue"])
114
+ ]),
115
+ _: 1
116
+ /* STABLE */
117
+ }, 8, ["items", "height"])
118
+ ],
119
+ 64
120
+ /* STABLE_FRAGMENT */
121
+ )) : (openBlock(), createElementBlock(
122
+ Fragment,
123
+ { key: 1 },
124
+ [
125
+ createVNode(_component_SqSelect, {
126
+ "model-value": _ctx.draft.op,
127
+ items: _ctx.ops,
128
+ density: "compact",
129
+ "hide-details": "",
130
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => _ctx.set("op", $event))
131
+ }, null, 8, ["model-value", "items"]),
132
+ _ctx.needsValue ? (openBlock(), createBlock(_component_SqTextField, {
133
+ key: 0,
134
+ "model-value": _ctx.draftValue,
135
+ type: _ctx.kind === "number" ? "number" : _ctx.kind === "date" ? "date" : "text",
136
+ placeholder: _ctx.kind === "text" ? _ctx.messages.search : "Value",
137
+ density: "compact",
138
+ "hide-details": "",
139
+ clearable: "",
140
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => _ctx.set("value", $event))
141
+ }, null, 8, ["model-value", "type", "placeholder"])) : createCommentVNode("v-if", true),
142
+ _ctx.draft.op === "between" ? (openBlock(), createBlock(_component_SqTextField, {
143
+ key: 1,
144
+ "model-value": _ctx.draftValueTo,
145
+ type: _ctx.kind === "number" ? "number" : "date",
146
+ placeholder: "To",
147
+ density: "compact",
148
+ "hide-details": "",
149
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => _ctx.set("valueTo", $event))
150
+ }, null, 8, ["model-value", "type"])) : createCommentVNode("v-if", true)
151
+ ],
152
+ 64
153
+ /* STABLE_FRAGMENT */
154
+ )),
155
+ createElementVNode("div", _hoisted_2$1, [
156
+ createVNode(_component_SqBtn, {
157
+ size: "small",
158
+ variant: "text",
159
+ color: "surface",
160
+ onClick: _cache[4] || (_cache[4] = ($event) => _ctx.$emit("update:modelValue", void 0))
161
+ }, {
162
+ default: withCtx(() => [
163
+ createTextVNode(
164
+ toDisplayString(_ctx.messages.clear),
165
+ 1
166
+ /* TEXT */
167
+ )
168
+ ]),
169
+ _: 1
170
+ /* STABLE */
171
+ })
172
+ ])
173
+ ]);
174
+ }
175
+ const SqGridFilter = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]);
176
+ const colIdOf = (c) => c.colId ?? c.field ?? c.headerName ?? "";
177
+ function makeGetter(col) {
178
+ if (col.valueGetter) return col.valueGetter;
179
+ const f = col.field;
180
+ if (!f) return () => void 0;
181
+ if (!f.includes(".")) return (row) => row[f];
182
+ return (row) => getByPath(row, f);
183
+ }
184
+ function filterKindOf(col) {
185
+ if (typeof col.filter === "string") return col.filter;
186
+ return col.type === "number" ? "number" : col.type === "date" ? "date" : col.type === "boolean" ? "set" : "text";
187
+ }
188
+ const isBlank = (v) => v == null || v === "";
189
+ function matchCondition(value, c) {
190
+ if (c.kind === "set") {
191
+ if (!c.values) return true;
192
+ return c.values.some((x) => x === value || isBlank(x) && isBlank(value) || String(x) === String(value));
193
+ }
194
+ const op = c.op ?? (c.kind === "text" ? "contains" : "equals");
195
+ if (op === "blank") return isBlank(value);
196
+ if (op === "notBlank") return !isBlank(value);
197
+ if (c.value == null || c.value === "") return true;
198
+ if (c.kind === "text") {
199
+ const v2 = String(value ?? "").toLowerCase();
200
+ const q = String(c.value).toLowerCase();
201
+ switch (op) {
202
+ case "contains":
203
+ return v2.includes(q);
204
+ case "notContains":
205
+ return !v2.includes(q);
206
+ case "equals":
207
+ return v2 === q;
208
+ case "notEqual":
209
+ return v2 !== q;
210
+ case "startsWith":
211
+ return v2.startsWith(q);
212
+ case "endsWith":
213
+ return v2.endsWith(q);
214
+ default:
215
+ return true;
216
+ }
217
+ }
218
+ const toNum = (x) => c.kind === "date" ? toDate(x)?.getTime() ?? NaN : Number(x);
219
+ const v = toNum(value);
220
+ const a = toNum(c.value);
221
+ if (isNaN(v)) return false;
222
+ switch (op) {
223
+ case "equals":
224
+ return c.kind === "date" ? Math.floor(v / 864e5) === Math.floor(a / 864e5) : v === a;
225
+ case "notEqual":
226
+ return v !== a;
227
+ case "gt":
228
+ return v > a;
229
+ case "gte":
230
+ return v >= a;
231
+ case "lt":
232
+ return v < a;
233
+ case "lte":
234
+ return v <= a;
235
+ case "between":
236
+ return v >= a && v <= toNum(c.valueTo);
237
+ default:
238
+ return true;
239
+ }
240
+ }
241
+ function filterRows(rows, columns, model, quick) {
242
+ const active = Object.entries(model).filter(([, c]) => c && (c.kind === "set" ? !!c.values : c.op === "blank" || c.op === "notBlank" || c.value != null && c.value !== ""));
243
+ const byId = new Map(columns.map((c) => [colIdOf(c), c]));
244
+ const checks = active.map(([id, cond]) => ({ get: makeGetter(byId.get(id) ?? { field: id }), cond }));
245
+ const q = quick.trim().toLowerCase();
246
+ const quickGetters = q ? columns.filter((c) => !c.hide).map((c) => makeGetter(c)) : [];
247
+ const out = [];
248
+ for (let i = 0; i < rows.length; i++) {
249
+ const row = rows[i];
250
+ let ok = true;
251
+ for (const { get, cond } of checks) {
252
+ if (!matchCondition(get(row), cond)) {
253
+ ok = false;
254
+ break;
255
+ }
256
+ }
257
+ if (ok && q) {
258
+ ok = false;
259
+ for (const get of quickGetters) {
260
+ const v = get(row);
261
+ if (v == null || typeof v === "object") continue;
262
+ if (String(v).toLowerCase().includes(q)) {
263
+ ok = true;
264
+ break;
265
+ }
266
+ }
267
+ }
268
+ if (ok) out.push(i);
269
+ }
270
+ return out;
271
+ }
272
+ function sortIndices(rows, indices, columns, sort) {
273
+ if (!sort.length) return indices;
274
+ const byId = new Map(columns.map((c) => [colIdOf(c), c]));
275
+ const specs = sort.map((s) => {
276
+ const col = byId.get(s.colId) ?? { field: s.colId };
277
+ const get = makeGetter(col);
278
+ const keys = new Array(rows.length);
279
+ for (const i of indices) keys[i] = get(rows[i]);
280
+ return { keys, dir: s.sort === "desc" ? -1 : 1, cmp: col.comparator, date: col.type === "date" };
281
+ });
282
+ for (const s of specs) if (s.date) for (const i of indices) s.keys[i] = toDate(s.keys[i])?.getTime() ?? null;
283
+ return indices.slice().sort((a, b) => {
284
+ for (const s of specs) {
285
+ const ka = s.keys[a];
286
+ const kb = s.keys[b];
287
+ const blankA = ka == null || ka === "";
288
+ const blankB = kb == null || kb === "";
289
+ if (blankA !== blankB) return blankA ? 1 : -1;
290
+ const r = s.cmp ? s.cmp(ka, kb, rows[a], rows[b]) : compareValues(ka, kb);
291
+ if (r) return r * s.dir;
292
+ }
293
+ return a - b;
294
+ });
295
+ }
296
+ function aggregate(values, fn) {
297
+ if (typeof fn === "function") return fn(values);
298
+ const nums = values.filter((v) => v != null && v !== "").map(Number).filter((n) => !isNaN(n));
299
+ switch (fn) {
300
+ case "sum":
301
+ return nums.reduce((a, b) => a + b, 0);
302
+ case "avg":
303
+ return nums.length ? nums.reduce((a, b) => a + b, 0) / nums.length : null;
304
+ case "min":
305
+ return nums.length ? Math.min(...nums) : null;
306
+ case "max":
307
+ return nums.length ? Math.max(...nums) : null;
308
+ case "count":
309
+ return values.length;
310
+ case "first":
311
+ return values[0];
312
+ case "last":
313
+ return values[values.length - 1];
314
+ }
315
+ }
316
+ function computeAgg(rows, leaves, aggCols) {
317
+ const agg = {};
318
+ for (const a of aggCols) agg[a.id] = aggregate(leaves.map((i) => a.get(rows[i])), a.fn);
319
+ return agg;
320
+ }
321
+ function groupRows(rows, indices, columns, groupBy) {
322
+ const byId = new Map(columns.map((c) => [colIdOf(c), c]));
323
+ const aggCols = columns.filter((c) => c.aggFunc).map((c) => ({ id: colIdOf(c), get: makeGetter(c), fn: c.aggFunc }));
324
+ const build = (idx, level, parentId) => {
325
+ const colId = groupBy[level];
326
+ const get = makeGetter(byId.get(colId) ?? { field: colId });
327
+ const buckets = /* @__PURE__ */ new Map();
328
+ for (const i of idx) {
329
+ const key = get(rows[i]);
330
+ const k = String(key ?? "");
331
+ let b = buckets.get(k);
332
+ if (!b) buckets.set(k, b = { key, leaves: [] });
333
+ b.leaves.push(i);
334
+ }
335
+ return Array.from(buckets.values()).map((b) => {
336
+ const id = `${parentId}/${colId}:${String(b.key ?? "")}`;
337
+ return {
338
+ key: b.key,
339
+ colId,
340
+ id,
341
+ level,
342
+ leaves: b.leaves,
343
+ children: level + 1 < groupBy.length ? build(b.leaves, level + 1, id) : [],
344
+ agg: computeAgg(rows, b.leaves, aggCols)
345
+ };
346
+ });
347
+ };
348
+ return groupBy.length ? build(indices, 0, "g") : [];
349
+ }
350
+ function treeRows(rows, indices, columns, getDataPath) {
351
+ const aggCols = columns.filter((c) => c.aggFunc).map((c) => ({ id: colIdOf(c), get: makeGetter(c), fn: c.aggFunc }));
352
+ const root = { children: [] };
353
+ const nodes = /* @__PURE__ */ new Map();
354
+ for (const i of indices) {
355
+ const path = getDataPath(rows[i]);
356
+ let parent = root;
357
+ let id = "t";
358
+ path.forEach((part, depth) => {
359
+ id += `/${part}`;
360
+ let node = nodes.get(id);
361
+ if (!node) {
362
+ node = { key: part, colId: "__tree", id, level: depth, children: [], leaves: [], agg: {} };
363
+ nodes.set(id, node);
364
+ parent.children.push(node);
365
+ }
366
+ if (depth === path.length - 1) node.self = i;
367
+ node.leaves.push(i);
368
+ parent = node;
369
+ });
370
+ }
371
+ for (const n of nodes.values()) if (n.children.length) n.agg = computeAgg(rows, n.leaves, aggCols);
372
+ return root.children;
373
+ }
374
+ function flatten(rows, indices, groups, opts) {
375
+ const out = [];
376
+ const pushData = (i, level) => {
377
+ const id = opts.rowId(rows[i], i);
378
+ out.push({ kind: "data", id, data: rows[i], level, sourceIndex: i });
379
+ if (opts.detailOpen?.has(id)) out.push({ kind: "detail", id: `${id}__detail`, data: rows[i], level, sourceIndex: i });
380
+ };
381
+ if (!groups) {
382
+ for (const i of indices) pushData(i, 0);
383
+ return out;
384
+ }
385
+ const isOpen = (id) => opts.expandAll ? !opts.collapsed?.has(id) : opts.expanded.has(id);
386
+ const walk = (nodes) => {
387
+ for (const g of nodes) {
388
+ const self = g.self;
389
+ if (opts.tree && !g.children.length && self != null) {
390
+ pushData(self, g.level);
391
+ continue;
392
+ }
393
+ const expanded = isOpen(g.id);
394
+ const leafIds = g.leaves.map((i) => opts.rowId(rows[i], i));
395
+ out.push({
396
+ kind: "group",
397
+ id: g.id,
398
+ data: opts.tree && self != null ? rows[self] : null,
399
+ level: g.level,
400
+ sourceIndex: self,
401
+ group: { key: g.key, colId: g.colId, count: opts.tree ? g.leaves.length - (self != null ? 1 : 0) : g.leaves.length, expanded, agg: g.agg, leafIds }
402
+ });
403
+ if (!expanded) continue;
404
+ if (g.children.length) walk(g.children);
405
+ else for (const i of g.leaves) pushData(i, g.level + 1);
406
+ }
407
+ };
408
+ walk(groups);
409
+ return out;
410
+ }
411
+ function allGroupIds(groups) {
412
+ const ids = [];
413
+ const walk = (n) => n.forEach((g) => {
414
+ if (g.children.length || g.colId !== "__tree") ids.push(g.id);
415
+ walk(g.children);
416
+ });
417
+ walk(groups);
418
+ return ids;
419
+ }
420
+ function rowLayout(rows, rowHeight, detailHeight) {
421
+ const offsets = new Float64Array(rows.length + 1);
422
+ for (let i = 0; i < rows.length; i++) offsets[i + 1] = offsets[i] + (rows[i].kind === "detail" ? detailHeight : rowHeight);
423
+ const indexAt = (y) => {
424
+ let lo = 0;
425
+ let hi = rows.length - 1;
426
+ while (lo < hi) {
427
+ const mid = lo + hi + 1 >> 1;
428
+ if (offsets[mid] <= y) lo = mid;
429
+ else hi = mid - 1;
430
+ }
431
+ return Math.max(0, lo);
432
+ };
433
+ return { offsets, total: offsets[rows.length], indexAt };
434
+ }
435
+ function pivotRows(rows, indices, columns, groupBy, pivotCol) {
436
+ const byId = new Map(columns.map((c) => [colIdOf(c), c]));
437
+ const valueCols = columns.filter((c) => c.aggFunc);
438
+ const pGet = makeGetter(byId.get(pivotCol) ?? { field: pivotCol });
439
+ const gGets = groupBy.map((id) => makeGetter(byId.get(id) ?? { field: id }));
440
+ const pivotKeys = [];
441
+ const seen = /* @__PURE__ */ new Set();
442
+ const buckets = /* @__PURE__ */ new Map();
443
+ for (const i of indices) {
444
+ const pk = String(pGet(rows[i]) ?? "");
445
+ if (!seen.has(pk)) {
446
+ seen.add(pk);
447
+ pivotKeys.push(pk);
448
+ }
449
+ const keys = gGets.map((g) => g(rows[i]));
450
+ const k = keys.map(String).join("");
451
+ let b = buckets.get(k);
452
+ if (!b) buckets.set(k, b = { keys, cells: /* @__PURE__ */ new Map() });
453
+ let cell = b.cells.get(pk);
454
+ if (!cell) b.cells.set(pk, cell = []);
455
+ cell.push(i);
456
+ }
457
+ pivotKeys.sort((a, b) => compareValues(a, b));
458
+ const outRows = [];
459
+ for (const b of buckets.values()) {
460
+ const r = {};
461
+ groupBy.forEach((id, k) => r[id] = b.keys[k]);
462
+ for (const pk of pivotKeys)
463
+ for (const vc of valueCols) {
464
+ const leaves = b.cells.get(pk) ?? [];
465
+ const get = makeGetter(vc);
466
+ r[`${pk}__${colIdOf(vc)}`] = leaves.length ? aggregate(leaves.map((i) => get(rows[i])), vc.aggFunc) : null;
467
+ }
468
+ outRows.push(r);
469
+ }
470
+ const outCols = [
471
+ ...groupBy.map((id) => ({ ...byId.get(id), colId: id, field: id, pinned: "left", rowGroup: false, valueGetter: void 0 })),
472
+ ...pivotKeys.flatMap(
473
+ (pk) => valueCols.map((vc) => ({
474
+ colId: `${pk}__${colIdOf(vc)}`,
475
+ field: `${pk}__${colIdOf(vc)}`,
476
+ headerName: valueCols.length > 1 ? `${vc.headerName ?? colIdOf(vc)}` : pk,
477
+ group: valueCols.length > 1 ? pk : void 0,
478
+ type: "number",
479
+ align: "right",
480
+ aggFunc: vc.aggFunc,
481
+ valueFormatter: vc.valueFormatter,
482
+ width: 120
483
+ }))
484
+ )
485
+ ];
486
+ return { rows: outRows, columns: outCols };
487
+ }
488
+ function toCsv(header, body, sep = ",") {
489
+ const esc = (s) => /[",\n\r]/.test(s) || s.includes(sep) ? `"${s.replace(/"/g, '""')}"` : s;
490
+ return [header, ...body].map((r) => r.map(esc).join(sep)).join("\r\n");
491
+ }
492
+ const parseTsv = (text) => text.replace(/\r?\n$/, "").split(/\r?\n/).map((l) => l.split(" "));
493
+ const SELECT_COL = { colId: "__select", headerName: "", width: 48, resizable: false, sortable: false, filter: false, suppressMenu: true, lockPosition: true };
494
+ function setByPath(obj, path, value) {
495
+ var _a;
496
+ const keys = path.split(".");
497
+ let cur = obj;
498
+ for (let i = 0; i < keys.length - 1; i++) cur = cur[_a = keys[i]] ?? (cur[_a] = {});
499
+ cur[keys[keys.length - 1]] = value;
500
+ }
501
+ const _sfc_main = defineComponent({
502
+ name: "SqDataGrid",
503
+ components: { SqShape, SqBtn, SqCheckbox, SqChip, SqDivider, SqEmptyState, SqIcon, SqListItem, SqMenu, SqPagination, SqProgressCircular, SqTextField, SqGridFilter },
504
+ props: {
505
+ rows: { type: Array, default: () => [] },
506
+ columns: { type: Array, default: () => [] },
507
+ defaultColDef: { type: Object, default: () => ({}) },
508
+ /** Field name or function producing a stable row id. */
509
+ rowId: { type: [String, Function], default: "id" },
510
+ height: { type: [Number, String], default: 520 },
511
+ rowHeight: { type: Number, default: 40 },
512
+ headerHeight: { type: Number, default: 42 },
513
+ detailHeight: { type: Number, default: 220 },
514
+ rowSelection: { type: String, default: null },
515
+ /** Auto checkbox column when rowSelection = multiple. */
516
+ selectionColumn: { type: Boolean, default: true },
517
+ selected: { type: Array, default: void 0 },
518
+ sortModel: { type: Array, default: void 0 },
519
+ filterModel: { type: Object, default: void 0 },
520
+ quickFilter: { type: String, default: void 0 },
521
+ groupBy: { type: Array, default: void 0 },
522
+ /** Levels expanded by default; -1 = all. */
523
+ groupDefaultExpanded: { type: Number, default: 0 },
524
+ groupColumn: { type: Object, default: () => ({}) },
525
+ treeData: Boolean,
526
+ getDataPath: { type: Function, default: void 0 },
527
+ pivotMode: Boolean,
528
+ pivotColumn: { type: String, default: void 0 },
529
+ masterDetail: Boolean,
530
+ pinnedTopRows: { type: Array, default: () => [] },
531
+ pinnedBottomRows: { type: Array, default: () => [] },
532
+ /** Bottom row with column aggFunc totals over the filtered rows. */
533
+ totalsRow: Boolean,
534
+ pagination: Boolean,
535
+ pageSize: { type: Number, default: 50 },
536
+ pageSizes: { type: Array, default: () => [25, 50, 100, 500] },
537
+ /** Infinite / server-side row model. Sorting & filtering are delegated to getRows. */
538
+ datasource: { type: Object, default: void 0 },
539
+ blockSize: { type: Number, default: 100 },
540
+ loading: Boolean,
541
+ toolbar: Boolean,
542
+ groupPanel: Boolean,
543
+ floatingFilters: Boolean,
544
+ statusBar: { type: Boolean, default: true },
545
+ striped: Boolean,
546
+ columnLines: Boolean,
547
+ rowClassName: { type: Function, default: void 0 },
548
+ locale: { type: String, default: void 0 }
549
+ },
550
+ emits: ["update:selected", "update:sortModel", "update:filterModel", "update:quickFilter", "update:groupBy", "row-click", "row-dblclick", "cell-click", "cell-value-changed", "column-state-change", "selection-change"],
551
+ setup(props, { emit, slots }) {
552
+ const viewport = ref(null);
553
+ const ctxAnchor = ref(null);
554
+ const scrollTop = ref(0);
555
+ const scrollLeft = ref(0);
556
+ const vpWidth = ref(800);
557
+ const vpHeight = ref(400);
558
+ const dataVersion = ref(0);
559
+ const loc = computed(() => props.locale ?? config.locale.code);
560
+ const isServer = computed(() => !!props.datasource);
561
+ const sortModelRef = useProxiedModel(props, emit, "sortModel", () => []);
562
+ const filterModelRef = useProxiedModel(props, emit, "filterModel", () => ({}));
563
+ const quick = useProxiedModel(props, emit, "quickFilter", () => "");
564
+ const groupByRef = useProxiedModel(props, emit, "groupBy", () => props.columns.filter((c) => c.rowGroup).map(colIdOf));
565
+ const selectedRef = useProxiedModel(props, emit, "selected", () => []);
566
+ const sortModelList = computed(() => sortModelRef.value ?? []);
567
+ const filterModelObj = computed(() => filterModelRef.value ?? {});
568
+ const groupBy = computed(() => groupByRef.value ?? []);
569
+ const selectedIds = computed(() => selectedRef.value ?? []);
570
+ const selectedSet = computed(() => new Set(selectedIds.value));
571
+ const colOrder = ref([]);
572
+ const colWidth = ref({});
573
+ const colHidden = ref({});
574
+ const colPinned = ref({});
575
+ const baseCols = computed(() => props.columns.map((c) => ({ ...props.defaultColDef, ...c })));
576
+ watch(baseCols, (cols) => {
577
+ const ids = cols.map(colIdOf);
578
+ colOrder.value = [...colOrder.value.filter((id) => ids.includes(id)), ...ids.filter((id) => !colOrder.value.includes(id))];
579
+ }, { immediate: true });
580
+ const rowIdOf = (row, i) => String(typeof props.rowId === "function" ? props.rowId(row, i) : row?.[props.rowId] ?? i);
581
+ const raw = computed(() => {
582
+ void dataVersion.value;
583
+ return toRaw(props.rows);
584
+ });
585
+ const quickApplied = ref(quick.value ?? "");
586
+ let quickApplyTimer;
587
+ watch(quick, (q) => {
588
+ clearTimeout(quickApplyTimer);
589
+ quickApplyTimer = setTimeout(() => quickApplied.value = q ?? "", raw.value.length > 2e4 ? 160 : 0);
590
+ });
591
+ const filteredIdx = computed(() => isServer.value ? [] : filterRows(raw.value, baseCols.value, filterModelObj.value, quickApplied.value));
592
+ const sortedIdx = computed(() => sortIndices(raw.value, filteredIdx.value, baseCols.value, sortModelList.value));
593
+ const pivot = computed(() => props.pivotMode && props.pivotColumn && !isServer.value ? pivotRows(raw.value, sortedIdx.value, baseCols.value, groupBy.value, props.pivotColumn) : null);
594
+ const viewRows = computed(() => pivot.value ? pivot.value.rows : raw.value);
595
+ const viewIdx = computed(() => pivot.value ? pivot.value.rows.map((_, i) => i) : sortedIdx.value);
596
+ const viewCols = computed(() => pivot.value ? pivot.value.columns.map((c) => ({ ...props.defaultColDef, ...c })) : baseCols.value);
597
+ const groups = computed(() => {
598
+ if (isServer.value || pivot.value) return null;
599
+ if (props.treeData && props.getDataPath) return treeRows(viewRows.value, viewIdx.value, viewCols.value, props.getDataPath);
600
+ return groupBy.value.length ? groupRows(viewRows.value, viewIdx.value, viewCols.value, groupBy.value) : null;
601
+ });
602
+ const hasGroups = computed(() => !!groups.value);
603
+ const expanded = ref(/* @__PURE__ */ new Set());
604
+ const collapsed = ref(/* @__PURE__ */ new Set());
605
+ const expandAllFlag = ref(props.groupDefaultExpanded === -1);
606
+ const detailOpen = ref(/* @__PURE__ */ new Set());
607
+ watch(groups, (g) => {
608
+ if (!g || props.groupDefaultExpanded <= 0) return;
609
+ const ids = new Set(expanded.value);
610
+ const walk = (nodes, lvl) => nodes.forEach((n) => {
611
+ if (lvl < props.groupDefaultExpanded) {
612
+ ids.add(n.id);
613
+ walk(n.children, lvl + 1);
614
+ }
615
+ });
616
+ walk(g, 0);
617
+ expanded.value = ids;
618
+ }, { immediate: true });
619
+ const display = computed(
620
+ () => flatten(viewRows.value, viewIdx.value, groups.value, {
621
+ expanded: expanded.value,
622
+ expandAll: expandAllFlag.value,
623
+ collapsed: collapsed.value,
624
+ rowId: rowIdOf,
625
+ detailOpen: props.masterDetail ? detailOpen.value : void 0,
626
+ tree: props.treeData
627
+ })
628
+ );
629
+ const page = ref(1);
630
+ const pageSizeState = ref(props.pageSize);
631
+ const pageCount = computed(() => Math.max(1, Math.ceil(display.value.length / pageSizeState.value)));
632
+ watch([pageCount, filteredIdx], () => page.value = Math.min(page.value, pageCount.value));
633
+ const paged = computed(() => props.pagination ? display.value.slice((page.value - 1) * pageSizeState.value, page.value * pageSizeState.value) : display.value);
634
+ const onPageSize = (e) => {
635
+ pageSizeState.value = Number(e.target.value);
636
+ page.value = 1;
637
+ };
638
+ const pageRangeText = computed(() => {
639
+ const n = display.value.length;
640
+ const a = n ? (page.value - 1) * pageSizeState.value + 1 : 0;
641
+ return config.locale.messages.pageRange.replace("{0}", String(a)).replace("{1}", String(Math.min(n, page.value * pageSizeState.value))).replace("{2}", String(n));
642
+ });
643
+ const blocks = /* @__PURE__ */ new Map();
644
+ const blockVersion = ref(0);
645
+ const serverCount = ref(0);
646
+ const serverLoading = ref(false);
647
+ let epoch = 0;
648
+ const loadBlock = async (b) => {
649
+ if (!props.datasource || blocks.has(b)) return;
650
+ blocks.set(b, "loading");
651
+ const my = epoch;
652
+ serverLoading.value = true;
653
+ try {
654
+ const res = await props.datasource.getRows({ startRow: b * props.blockSize, endRow: (b + 1) * props.blockSize, sortModel: sortModelList.value, filterModel: filterModelObj.value, quickFilter: quick.value ?? "" });
655
+ if (my !== epoch) return;
656
+ blocks.set(b, res.rows);
657
+ if (res.lastRow != null) serverCount.value = res.lastRow;
658
+ else if (res.rows.length < props.blockSize) serverCount.value = b * props.blockSize + res.rows.length;
659
+ else serverCount.value = Math.max(serverCount.value, (b + 2) * props.blockSize);
660
+ } catch {
661
+ if (my === epoch) blocks.delete(b);
662
+ } finally {
663
+ if (my === epoch) {
664
+ serverLoading.value = [...blocks.values()].some((v) => v === "loading");
665
+ blockVersion.value++;
666
+ }
667
+ }
668
+ };
669
+ const purge = () => {
670
+ epoch++;
671
+ blocks.clear();
672
+ serverCount.value = 0;
673
+ blockVersion.value++;
674
+ if (viewport.value) viewport.value.scrollTop = 0;
675
+ loadBlock(0);
676
+ };
677
+ let quickTimer;
678
+ watch([sortModelList, filterModelObj], () => isServer.value && purge(), { deep: true });
679
+ watch(quick, () => {
680
+ if (!isServer.value) return;
681
+ clearTimeout(quickTimer);
682
+ quickTimer = setTimeout(purge, 250);
683
+ });
684
+ watch(() => props.datasource, (ds) => ds && purge());
685
+ onMounted(() => props.datasource && purge());
686
+ const rowCount = computed(() => isServer.value ? serverCount.value : paged.value.length);
687
+ const rowAt = (i) => {
688
+ if (!isServer.value) return paged.value[i];
689
+ void blockVersion.value;
690
+ const b = Math.floor(i / props.blockSize);
691
+ const data = blocks.get(b);
692
+ if (Array.isArray(data)) {
693
+ const row = data[i - b * props.blockSize];
694
+ if (row) return { kind: "data", id: rowIdOf(row, i), data: row, level: 0, sourceIndex: i };
695
+ }
696
+ return { kind: "loading", id: `__loading_${i}`, data: null, level: 0 };
697
+ };
698
+ const titleOf = (id) => {
699
+ const c = viewCols.value.find((x) => colIdOf(x) === id) ?? baseCols.value.find((x) => colIdOf(x) === id);
700
+ return c?.headerName ?? (c?.field ? c.field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (s) => s.toUpperCase()) : id);
701
+ };
702
+ const groupColDef = computed(() => ({ colId: "__group", headerName: props.treeData ? "Name" : "Group", width: 240, sortable: false, filter: false, suppressMenu: true, lockPosition: true, ...props.groupColumn }));
703
+ const orderedCols = computed(() => {
704
+ const cols = viewCols.value;
705
+ const byId = new Map(cols.map((c) => [colIdOf(c), c]));
706
+ const ordered = pivot.value ? cols : [...colOrder.value.map((id) => byId.get(id)).filter(Boolean), ...cols.filter((c) => !colOrder.value.includes(colIdOf(c)))];
707
+ const auto = [];
708
+ if (props.rowSelection === "multiple" && props.selectionColumn) auto.push(SELECT_COL);
709
+ if (groups.value || props.masterDetail && !props.treeData) auto.push(groupColDef.value);
710
+ return { auto, ordered };
711
+ });
712
+ const visibleCols = computed(() => {
713
+ const { auto, ordered } = orderedCols.value;
714
+ const list = [
715
+ ...auto.map((c) => ({ id: colIdOf(c), col: c, auto: true })),
716
+ ...ordered.filter((c) => !(colHidden.value[colIdOf(c)] ?? c.hide)).map((c) => ({ id: colIdOf(c), col: c, auto: false }))
717
+ ];
718
+ const resolved = list.map((x) => ({
719
+ ...x,
720
+ pinned: x.auto ? "left" : colPinned.value[x.id] !== void 0 ? colPinned.value[x.id] : x.col.pinned ?? null,
721
+ width: colWidth.value[x.id] ?? x.col.width ?? (x.col.flex ? 0 : 150),
722
+ title: x.id === "__group" ? x.col.headerName : titleOf(x.id)
723
+ }));
724
+ const anyLeft = resolved.some((r) => !r.auto && r.pinned === "left");
725
+ if (!anyLeft) resolved.forEach((r) => {
726
+ if (r.auto) r.pinned = null;
727
+ });
728
+ const fixed = resolved.reduce((s, r) => s + (r.col.flex && colWidth.value[r.id] == null ? 0 : r.width), 0);
729
+ const flexCols = resolved.filter((r) => r.col.flex && colWidth.value[r.id] == null);
730
+ const totalFlex = flexCols.reduce((s, r) => s + (r.col.flex ?? 0), 0);
731
+ const avail = Math.max(0, vpWidth.value - fixed - 2);
732
+ for (const r of flexCols) r.width = clamp(Math.floor(avail * (r.col.flex ?? 1) / totalFlex), r.col.minWidth ?? 80, r.col.maxWidth ?? 4e3);
733
+ const left = resolved.filter((r) => r.pinned === "left");
734
+ const right = resolved.filter((r) => r.pinned === "right");
735
+ const center = resolved.filter((r) => !r.pinned);
736
+ return { left, center, right };
737
+ });
738
+ const flatCols = computed(() => [...visibleCols.value.left, ...visibleCols.value.center, ...visibleCols.value.right]);
739
+ const flatIndex = computed(() => new Map(flatCols.value.map((c, i) => [c.id, i])));
740
+ const leftWidth = computed(() => visibleCols.value.left.reduce((s, c) => s + c.width, 0));
741
+ const rightWidth = computed(() => visibleCols.value.right.reduce((s, c) => s + c.width, 0));
742
+ const centerOffsets = computed(() => {
743
+ const o = [0];
744
+ for (const c of visibleCols.value.center) o.push(o[o.length - 1] + c.width);
745
+ return o;
746
+ });
747
+ const totalWidth = computed(() => leftWidth.value + rightWidth.value + centerOffsets.value[centerOffsets.value.length - 1]);
748
+ const renderCols = computed(() => {
749
+ const { left, center, right } = visibleCols.value;
750
+ const out = [];
751
+ let acc = 0;
752
+ left.forEach((c, i) => {
753
+ out.push({ key: c.id, id: c.id, col: c.col, title: c.title, width: c.width, pinned: "left", auto: c.auto, flatIndex: flatIndex.value.get(c.id), edgeLeft: i === left.length - 1, style: { width: `${c.width}px`, left: `${acc}px` } });
754
+ acc += c.width;
755
+ });
756
+ const offs = centerOffsets.value;
757
+ const viewW = Math.max(0, vpWidth.value - leftWidth.value - rightWidth.value);
758
+ let start = 0;
759
+ while (start < center.length && offs[start + 1] < scrollLeft.value) start++;
760
+ let end = start;
761
+ while (end < center.length && offs[end] < scrollLeft.value + viewW) end++;
762
+ start = Math.max(0, start - 2);
763
+ end = Math.min(center.length, end + 2);
764
+ if (offs[start] > 0) out.push({ key: "__padL", id: "__padL", col: null, title: "", width: offs[start], pinned: null, flatIndex: -1, style: { width: `${offs[start]}px` } });
765
+ for (let i = start; i < end; i++) {
766
+ const c = center[i];
767
+ out.push({ key: c.id, id: c.id, col: c.col, title: c.title, width: c.width, pinned: null, auto: c.auto, flatIndex: flatIndex.value.get(c.id), style: { width: `${c.width}px` } });
768
+ }
769
+ const padR = offs[center.length] - offs[end];
770
+ if (padR > 0) out.push({ key: "__padR", id: "__padR", col: null, title: "", width: padR, pinned: null, flatIndex: -1, style: { width: `${padR}px` } });
771
+ let racc = 0;
772
+ for (let i = right.length - 1; i >= 0; i--) {
773
+ const c = right[i];
774
+ out.push({ key: c.id, id: c.id, col: c.col, title: c.title, width: c.width, pinned: "right", auto: c.auto, flatIndex: flatIndex.value.get(c.id), edgeRight: i === 0, style: { width: `${c.width}px`, right: `${racc}px` } });
775
+ racc += c.width;
776
+ }
777
+ const rightPart = out.splice(out.length - right.length, right.length).reverse();
778
+ return [...out, ...rightPart];
779
+ });
780
+ const hasHeaderGroups = computed(() => flatCols.value.some((c) => c.col.group));
781
+ const headerGroups = computed(() => {
782
+ const out = [];
783
+ for (const rc of renderCols.value) {
784
+ const label = rc.col?.group ?? "";
785
+ const last = out[out.length - 1];
786
+ if (last && label && rc.col && last.label === label && last.pin === rc.pinned) {
787
+ last.width += rc.width;
788
+ last.style.width = `${last.width}px`;
789
+ continue;
790
+ }
791
+ const style = { width: `${rc.width}px` };
792
+ if (rc.pinned === "left") style.left = rc.style.left;
793
+ if (rc.pinned === "right") style.right = rc.style.right;
794
+ out.push({
795
+ key: `${rc.key}-g`,
796
+ label: rc.col ? label : "",
797
+ pin: rc.pinned,
798
+ width: rc.width,
799
+ style,
800
+ cls: { "sq-datagrid__hcell--pinned-left": rc.pinned === "left", "sq-datagrid__hcell--pinned-right": rc.pinned === "right", "sq-datagrid__header-group--empty": !label }
801
+ });
802
+ }
803
+ return out;
804
+ });
805
+ const filterRowHeight = 38;
806
+ const headBlock = computed(() => props.headerHeight * (hasHeaderGroups.value ? 2 : 1) + (props.floatingFilters ? filterRowHeight : 0) + props.pinnedTopRows.length * props.rowHeight);
807
+ const layout = computed(() => {
808
+ if (isServer.value) {
809
+ const n = serverCount.value;
810
+ return { offsets: null, total: n * props.rowHeight, indexAt: (y) => Math.floor(y / props.rowHeight) };
811
+ }
812
+ return rowLayout(paged.value, props.rowHeight, props.detailHeight);
813
+ });
814
+ const range = computed(() => {
815
+ const n = rowCount.value;
816
+ if (!n) return { start: 0, end: -1 };
817
+ const top = Math.max(0, scrollTop.value);
818
+ const start = Math.max(0, layout.value.indexAt(top) - 6);
819
+ const end = Math.min(n - 1, layout.value.indexAt(top + vpHeight.value) + 6);
820
+ return { start, end };
821
+ });
822
+ const visibleRows = computed(() => {
823
+ const out = [];
824
+ const { start, end } = range.value;
825
+ const offs = layout.value.offsets;
826
+ for (let i = start; i <= end; i++) {
827
+ const row = rowAt(i);
828
+ if (!row) continue;
829
+ const top = offs ? offs[i] : i * props.rowHeight;
830
+ const height = offs ? offs[i + 1] - offs[i] : props.rowHeight;
831
+ out.push({ index: i, top, height, row });
832
+ }
833
+ return out;
834
+ });
835
+ watch(range, (r) => {
836
+ if (!isServer.value || r.end < 0) return;
837
+ for (let b = Math.floor(r.start / props.blockSize); b <= Math.floor(r.end / props.blockSize); b++) loadBlock(b);
838
+ });
839
+ const onScroll = () => {
840
+ const el = viewport.value;
841
+ if (!el) return;
842
+ scrollTop.value = el.scrollTop;
843
+ scrollLeft.value = el.scrollLeft;
844
+ };
845
+ let ro;
846
+ onMounted(() => {
847
+ const el = viewport.value;
848
+ const measure = () => {
849
+ vpWidth.value = el.clientWidth;
850
+ vpHeight.value = el.clientHeight;
851
+ };
852
+ measure();
853
+ if (typeof ResizeObserver !== "undefined") {
854
+ ro = new ResizeObserver(measure);
855
+ ro.observe(el);
856
+ }
857
+ });
858
+ onBeforeUnmount(() => {
859
+ ro?.disconnect();
860
+ clearTimeout(quickTimer);
861
+ clearTimeout(quickApplyTimer);
862
+ window.removeEventListener("pointermove", onResizeMove);
863
+ window.removeEventListener("pointerup", onResizeEnd);
864
+ window.removeEventListener("mouseup", endSelect);
865
+ });
866
+ const getters = /* @__PURE__ */ new WeakMap();
867
+ const cellValue = (rc, row) => {
868
+ if (!rc.col || !row) return void 0;
869
+ let g = getters.get(rc.col);
870
+ if (!g) getters.set(rc.col, g = makeGetter(rc.col));
871
+ return g(row);
872
+ };
873
+ let numFmt = null;
874
+ let numFmtLocale = "";
875
+ const fmtNum = (v) => {
876
+ if (numFmtLocale !== loc.value) {
877
+ numFmt = new Intl.NumberFormat(loc.value, { maximumFractionDigits: 2 });
878
+ numFmtLocale = loc.value;
879
+ }
880
+ return numFmt.format(v);
881
+ };
882
+ const formatValue = (col, v, row) => {
883
+ if (col.valueFormatter) return col.valueFormatter(v, row);
884
+ if (v == null || v === "") return "";
885
+ if (col.type === "number" && typeof v === "number") return fmtNum(v);
886
+ if (col.type === "date") return formatDate(v, loc.value);
887
+ return String(v);
888
+ };
889
+ const formatCell = (rc, row) => rc.col ? formatValue(rc.col, cellValue(rc, row), row) : "";
890
+ const cellParams = (row, rc, rowIndex) => ({ value: cellValue(rc, row), formatted: formatCell(rc, row), row, column: rc.col, rowIndex });
891
+ const groupLabel = (row) => {
892
+ if (row.kind === "group") {
893
+ const g = row.group;
894
+ if (g.colId === "__tree") return String(g.key ?? "");
895
+ const col = viewCols.value.find((c) => colIdOf(c) === g.colId);
896
+ return col ? formatValue(col, g.key, null) || "(Blank)" : String(g.key ?? "");
897
+ }
898
+ if (props.treeData && props.getDataPath && row.data) {
899
+ const p = props.getDataPath(row.data);
900
+ return p[p.length - 1];
901
+ }
902
+ return "";
903
+ };
904
+ const groupAggText = (row, rc) => {
905
+ if (!rc.col) return "";
906
+ const v = row.group?.agg[rc.id];
907
+ if (v === void 0) return row.data && props.treeData ? formatCell(rc, row.data) : "";
908
+ return formatValue(rc.col, v, null);
909
+ };
910
+ const filterKind = (col) => filterKindOf(col);
911
+ const distinctValues = (id) => {
912
+ const col = baseCols.value.find((c) => colIdOf(c) === id);
913
+ if (!col) return [];
914
+ const get = makeGetter(col);
915
+ const set = /* @__PURE__ */ new Set();
916
+ for (const r of raw.value) {
917
+ set.add(get(r));
918
+ if (set.size > 5e3) break;
919
+ }
920
+ return Array.from(set).sort((a, b) => String(a ?? "").localeCompare(String(b ?? ""), void 0, { numeric: true }));
921
+ };
922
+ const sortIndex = (id) => sortModelList.value.findIndex((s) => s.colId === id);
923
+ const sortDir = (id) => sortModelList.value.find((s) => s.colId === id)?.sort;
924
+ const ariaSort = (id) => sortDir(id) === "asc" ? "ascending" : sortDir(id) === "desc" ? "descending" : "none";
925
+ const setSort = (id, dir, multi = false) => {
926
+ const rest = multi ? sortModelList.value.filter((s) => s.colId !== id) : [];
927
+ sortModelRef.value = dir ? [...rest, { colId: id, sort: dir }] : rest;
928
+ };
929
+ let resized = false;
930
+ const onHeaderClick = (e, rc) => {
931
+ if (resized) return void (resized = false);
932
+ if (!rc.col || rc.auto || rc.col.sortable === false) return;
933
+ const cur = sortDir(rc.id);
934
+ const next = cur === "asc" ? "desc" : cur === "desc" ? null : "asc";
935
+ if (e.shiftKey) {
936
+ const list = sortModelList.value.slice();
937
+ const i = list.findIndex((s) => s.colId === rc.id);
938
+ if (next && i >= 0) list[i] = { colId: rc.id, sort: next };
939
+ else if (next) list.push({ colId: rc.id, sort: next });
940
+ else list.splice(i, 1);
941
+ sortModelRef.value = list;
942
+ } else setSort(rc.id, next);
943
+ };
944
+ const setFilter = (id, cond) => {
945
+ const next = { ...filterModelObj.value };
946
+ if (cond) next[id] = cond;
947
+ else delete next[id];
948
+ filterModelRef.value = next;
949
+ };
950
+ const floatingValue = (id) => {
951
+ const f = filterModelObj.value[id];
952
+ return f && f.kind !== "set" ? f.value ?? "" : "";
953
+ };
954
+ let floatTimer;
955
+ const onFloatingInput = (e, rc) => {
956
+ const value = e.target.value;
957
+ const kind = filterKind(rc.col);
958
+ clearTimeout(floatTimer);
959
+ floatTimer = setTimeout(() => setFilter(rc.id, value === "" ? void 0 : { kind, op: kind === "text" ? "contains" : "equals", value: kind === "number" ? Number(value) : value }), 180);
960
+ };
961
+ const toggleGroupBy = (id) => groupByRef.value = groupBy.value.includes(id) ? groupBy.value.filter((x) => x !== id) : [...groupBy.value, id];
962
+ const removeGroup = (id) => groupByRef.value = groupBy.value.filter((x) => x !== id);
963
+ const toggleGroup = (row) => {
964
+ if (expandAllFlag.value) {
965
+ const s = new Set(collapsed.value);
966
+ s.has(row.id) ? s.delete(row.id) : s.add(row.id);
967
+ collapsed.value = s;
968
+ } else {
969
+ const s = new Set(expanded.value);
970
+ s.has(row.id) ? s.delete(row.id) : s.add(row.id);
971
+ expanded.value = s;
972
+ }
973
+ };
974
+ const expandAll = () => {
975
+ expandAllFlag.value = true;
976
+ collapsed.value = /* @__PURE__ */ new Set();
977
+ };
978
+ const collapseAll = () => {
979
+ expandAllFlag.value = false;
980
+ expanded.value = /* @__PURE__ */ new Set();
981
+ };
982
+ const toggleDetail = (id) => {
983
+ const s = new Set(detailOpen.value);
984
+ s.has(id) ? s.delete(id) : s.add(id);
985
+ detailOpen.value = s;
986
+ };
987
+ const emitColumnState = () => emit("column-state-change", flatCols.value.filter((c) => !c.auto).map((c) => ({ colId: c.id, width: c.width, hide: false, pinned: c.pinned })));
988
+ const setHidden = (id, hide) => {
989
+ colHidden.value = { ...colHidden.value, [id]: hide };
990
+ emitColumnState();
991
+ };
992
+ const setPinned = (id, pin) => {
993
+ colPinned.value = { ...colPinned.value, [id]: pin };
994
+ emitColumnState();
995
+ };
996
+ const chooserCols = computed(() => orderedCols.value.ordered.map((c) => ({ id: colIdOf(c), title: titleOf(colIdOf(c)), hidden: colHidden.value[colIdOf(c)] ?? !!c.hide })));
997
+ let resizeState = null;
998
+ const onResizeMove = (e) => {
999
+ if (!resizeState) return;
1000
+ const w = clamp(resizeState.startW + e.clientX - resizeState.startX, resizeState.min, resizeState.max);
1001
+ colWidth.value = { ...colWidth.value, [resizeState.id]: Math.round(w) };
1002
+ };
1003
+ const onResizeEnd = () => {
1004
+ if (resizeState) {
1005
+ resized = true;
1006
+ setTimeout(() => resized = false, 0);
1007
+ emitColumnState();
1008
+ }
1009
+ resizeState = null;
1010
+ window.removeEventListener("pointermove", onResizeMove);
1011
+ window.removeEventListener("pointerup", onResizeEnd);
1012
+ };
1013
+ const startResize = (e, rc) => {
1014
+ resizeState = { id: rc.id, startX: e.clientX, startW: rc.width, min: rc.col?.minWidth ?? 48, max: rc.col?.maxWidth ?? 2e3 };
1015
+ window.addEventListener("pointermove", onResizeMove);
1016
+ window.addEventListener("pointerup", onResizeEnd);
1017
+ };
1018
+ let canvas = null;
1019
+ const autoSize = (ids) => {
1020
+ canvas ?? (canvas = document.createElement("canvas"));
1021
+ const ctx = canvas.getContext("2d");
1022
+ if (!ctx || !viewport.value) return;
1023
+ const cs = getComputedStyle(viewport.value);
1024
+ ctx.font = `${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`;
1025
+ const sample = isServer.value ? [] : paged.value.filter((r) => r.kind === "data").slice(0, 300);
1026
+ const next = { ...colWidth.value };
1027
+ for (const c of flatCols.value) {
1028
+ if (c.auto || ids && !ids.includes(c.id)) continue;
1029
+ let w = ctx.measureText(c.title).width + 64;
1030
+ for (const r of sample) w = Math.max(w, ctx.measureText(formatValue(c.col, cellValue(c, r.data), r.data)).width + 32);
1031
+ next[c.id] = Math.ceil(clamp(w, c.col.minWidth ?? 48, c.col.maxWidth ?? 600));
1032
+ }
1033
+ colWidth.value = next;
1034
+ emitColumnState();
1035
+ };
1036
+ const dragColId = ref(null);
1037
+ const dropTarget = ref(null);
1038
+ const onDragStart = (e, rc) => {
1039
+ if (!rc.col || rc.auto || rc.col.lockPosition) return e.preventDefault();
1040
+ dragColId.value = rc.id;
1041
+ e.dataTransfer?.setData("text/plain", rc.id);
1042
+ if (e.dataTransfer) e.dataTransfer.effectAllowed = "move";
1043
+ };
1044
+ const onDragOver = (e, rc) => {
1045
+ if (!dragColId.value || !rc.col || rc.auto) return;
1046
+ dropTarget.value = { id: rc.id, before: e.offsetX < rc.width / 2 };
1047
+ };
1048
+ const onDrop = (rc) => {
1049
+ const from = dragColId.value;
1050
+ const target = dropTarget.value;
1051
+ dragColId.value = null;
1052
+ dropTarget.value = null;
1053
+ if (!from || !target || from === target.id || !rc.col || rc.auto) return;
1054
+ const order = colOrder.value.filter((id) => id !== from);
1055
+ const i = order.indexOf(target.id);
1056
+ order.splice(target.before ? i : i + 1, 0, from);
1057
+ colOrder.value = order;
1058
+ const pin = visibleCols.value.left.some((c) => c.id === target.id) ? "left" : visibleCols.value.right.some((c) => c.id === target.id) ? "right" : null;
1059
+ colPinned.value = { ...colPinned.value, [from]: pin };
1060
+ emitColumnState();
1061
+ };
1062
+ const onGroupDrop = () => {
1063
+ const id = dragColId.value;
1064
+ dragColId.value = null;
1065
+ if (id && !groupBy.value.includes(id)) groupByRef.value = [...groupBy.value, id];
1066
+ };
1067
+ const dataIdsInView = () => isServer.value ? [] : viewIdx.value.map((i) => rowIdOf(viewRows.value[i], i));
1068
+ const setSelected = (ids) => {
1069
+ selectedRef.value = ids;
1070
+ emit("selection-change", ids);
1071
+ };
1072
+ const allSelected = computed(() => {
1073
+ const ids = filteredIdx.value;
1074
+ return ids.length > 0 && selectedIds.value.length >= ids.length && ids.every((i) => selectedSet.value.has(rowIdOf(raw.value[i], i)));
1075
+ });
1076
+ const someSelected = computed(() => !allSelected.value && selectedIds.value.length > 0);
1077
+ const toggleAll = () => setSelected(allSelected.value ? [] : dataIdsInView());
1078
+ const isRowChecked = (row) => row.kind === "group" ? row.group.leafIds.every((id) => selectedSet.value.has(id)) : selectedSet.value.has(row.id);
1079
+ const isRowPartial = (row) => row.kind === "group" && !isRowChecked(row) && row.group.leafIds.some((id) => selectedSet.value.has(id));
1080
+ const toggleRowCheck = (row) => {
1081
+ const ids = row.kind === "group" ? row.group.leafIds : [row.id];
1082
+ const on = isRowChecked(row);
1083
+ const s = new Set(selectedIds.value);
1084
+ ids.forEach((id) => on ? s.delete(id) : s.add(id));
1085
+ setSelected(Array.from(s));
1086
+ };
1087
+ let lastClicked = -1;
1088
+ const onRowClick = (e, vr) => {
1089
+ if (vr.row.kind !== "data") return;
1090
+ emit("row-click", { row: vr.row.data, event: e });
1091
+ if (!props.rowSelection) return;
1092
+ if (props.rowSelection === "single") setSelected(selectedSet.value.has(vr.row.id) && (e.ctrlKey || e.metaKey) ? [] : [vr.row.id]);
1093
+ else if (e.shiftKey && lastClicked >= 0) {
1094
+ const [a, b] = [Math.min(lastClicked, vr.index), Math.max(lastClicked, vr.index)];
1095
+ const ids = new Set(selectedIds.value);
1096
+ for (let i = a; i <= b; i++) {
1097
+ const r = rowAt(i);
1098
+ if (r?.kind === "data") ids.add(r.id);
1099
+ }
1100
+ setSelected(Array.from(ids));
1101
+ } else if (e.ctrlKey || e.metaKey) toggleRowCheck(vr.row);
1102
+ else if (!props.selectionColumn) setSelected([vr.row.id]);
1103
+ lastClicked = vr.index;
1104
+ };
1105
+ const focus = ref(null);
1106
+ const cellRange = ref(null);
1107
+ let anchor = null;
1108
+ let selecting = false;
1109
+ const endSelect = () => {
1110
+ selecting = false;
1111
+ window.removeEventListener("mouseup", endSelect);
1112
+ };
1113
+ const setRange = (a, b) => cellRange.value = { startRow: Math.min(a.row, b.row), endRow: Math.max(a.row, b.row), startCol: Math.min(a.col, b.col), endCol: Math.max(a.col, b.col) };
1114
+ const inRange = (row, col) => {
1115
+ const r = cellRange.value;
1116
+ return !!r && (r.startRow !== r.endRow || r.startCol !== r.endCol) && row >= r.startRow && row <= r.endRow && col >= r.startCol && col <= r.endCol;
1117
+ };
1118
+ const onCellMousedown = (e, vr, rc) => {
1119
+ if (!rc.col || e.button !== 0) return;
1120
+ const pos = { row: vr.index, col: rc.flatIndex };
1121
+ if (editing.value && !isEditing(vr, rc)) commitEdit();
1122
+ if (e.shiftKey && focus.value) setRange(focus.value, pos);
1123
+ else {
1124
+ focus.value = pos;
1125
+ anchor = pos;
1126
+ setRange(pos, pos);
1127
+ }
1128
+ selecting = true;
1129
+ window.addEventListener("mouseup", endSelect);
1130
+ emit("cell-click", { row: vr.row.data, colId: rc.id, value: cellValue(rc, vr.row.data), event: e });
1131
+ };
1132
+ const onCellEnter = (vr, rc) => {
1133
+ if (selecting && anchor && rc.col) setRange(anchor, { row: vr.index, col: rc.flatIndex });
1134
+ };
1135
+ const editing = ref(null);
1136
+ const isEditable = (col, row) => !!row && (typeof col.editable === "function" ? col.editable(row) : !!col.editable);
1137
+ const isEditing = (vr, rc) => !!editing.value && editing.value.row === vr.index && editing.value.colId === rc.id;
1138
+ const editorKind = (rc) => rc.col?.cellEditor ?? (rc.col?.type === "number" ? "number" : rc.col?.type === "date" ? "date" : "text");
1139
+ const undoStack = [];
1140
+ const redoStack = [];
1141
+ const canUndo = ref(false);
1142
+ const applyChanges = (changes, dir) => {
1143
+ for (const c of changes) {
1144
+ const v = dir === "new" ? c.newValue : c.oldValue;
1145
+ if (c.col.valueSetter) c.col.valueSetter(c.row, v);
1146
+ else if (c.col.field) setByPath(c.row, c.col.field, v);
1147
+ emit("cell-value-changed", { row: c.row, colId: colIdOf(c.col), oldValue: dir === "new" ? c.oldValue : c.newValue, newValue: v });
1148
+ }
1149
+ dataVersion.value++;
1150
+ };
1151
+ const record = (changes) => {
1152
+ if (!changes.length) return;
1153
+ applyChanges(changes, "new");
1154
+ undoStack.push(changes);
1155
+ if (undoStack.length > 100) undoStack.shift();
1156
+ redoStack.length = 0;
1157
+ canUndo.value = true;
1158
+ };
1159
+ const undo = () => {
1160
+ const c = undoStack.pop();
1161
+ if (c) {
1162
+ applyChanges(c, "old");
1163
+ redoStack.push(c);
1164
+ }
1165
+ canUndo.value = undoStack.length > 0;
1166
+ };
1167
+ const redo = () => {
1168
+ const c = redoStack.pop();
1169
+ if (c) {
1170
+ applyChanges(c, "new");
1171
+ undoStack.push(c);
1172
+ }
1173
+ canUndo.value = undoStack.length > 0;
1174
+ };
1175
+ const parseFor = (col, text, row) => {
1176
+ if (col.valueParser) return col.valueParser(text, row);
1177
+ if (col.type === "number") return text === "" ? null : Number(text.replace(/[^\d.-]/g, ""));
1178
+ if (col.type === "boolean") return /^(true|1|yes|✓)$/i.test(text);
1179
+ return text;
1180
+ };
1181
+ const startEdit = (rowIndex, flatCol, initial) => {
1182
+ const c = flatCols.value[flatCol];
1183
+ const r = rowAt(rowIndex);
1184
+ if (!c || !r || r.kind !== "data" || !isEditable(c.col, r.data)) return;
1185
+ if (c.col.type === "boolean") return record([{ row: r.data, col: c.col, oldValue: cellValue(c, r.data), newValue: !cellValue(c, r.data) }]);
1186
+ editing.value = { row: rowIndex, colId: c.id, value: initial ?? cellValue(c, r.data) };
1187
+ nextTick(() => {
1188
+ const el = viewport.value?.querySelector(".sq-datagrid__editor");
1189
+ el?.focus();
1190
+ if (initial === void 0) el?.select?.();
1191
+ });
1192
+ };
1193
+ const onEditorInput = (e) => editing.value && (editing.value = { ...editing.value, value: e.target.value });
1194
+ const commitEdit = () => {
1195
+ const ed = editing.value;
1196
+ if (!ed) return;
1197
+ editing.value = null;
1198
+ const r = rowAt(ed.row);
1199
+ const c = flatCols.value.find((x) => x.id === ed.colId);
1200
+ if (!r?.data || !c) return;
1201
+ const newValue = parseFor(c.col, String(ed.value ?? ""), r.data);
1202
+ const oldValue = cellValue(c, r.data);
1203
+ if (newValue !== oldValue) record([{ row: r.data, col: c.col, oldValue, newValue }]);
1204
+ };
1205
+ const cancelEdit = () => {
1206
+ editing.value = null;
1207
+ rootEl()?.focus();
1208
+ };
1209
+ const onEditorKey = (e) => {
1210
+ if (e.key === "Enter" || e.key === "Tab") {
1211
+ e.preventDefault();
1212
+ commitEdit();
1213
+ rootEl()?.focus();
1214
+ moveFocus(e.key === "Enter" ? e.shiftKey ? -1 : 1 : 0, e.key === "Tab" ? e.shiftKey ? -1 : 1 : 0, false);
1215
+ } else if (e.key === "Escape") cancelEdit();
1216
+ };
1217
+ const onCellDblclick = (vr, rc) => rc.col && startEdit(vr.index, rc.flatIndex);
1218
+ const rootEl = () => viewport.value?.parentElement;
1219
+ const ensureVisible = (row, col) => {
1220
+ const el = viewport.value;
1221
+ if (!el) return;
1222
+ const offs = layout.value.offsets;
1223
+ const top = offs ? offs[row] : row * props.rowHeight;
1224
+ const h = offs ? offs[row + 1] - offs[row] : props.rowHeight;
1225
+ const bodyTop = el.scrollTop;
1226
+ const visibleH = el.clientHeight - headBlock.value;
1227
+ if (top < bodyTop) el.scrollTop = top;
1228
+ else if (top + h > bodyTop + visibleH) el.scrollTop = top + h - visibleH;
1229
+ const c = flatCols.value[col];
1230
+ if (c && !c.pinned) {
1231
+ const ci = visibleCols.value.center.indexOf(c);
1232
+ const x = centerOffsets.value[ci];
1233
+ const viewW = el.clientWidth - leftWidth.value - rightWidth.value;
1234
+ if (x < el.scrollLeft) el.scrollLeft = x;
1235
+ else if (x + c.width > el.scrollLeft + viewW) el.scrollLeft = x + c.width - viewW;
1236
+ }
1237
+ };
1238
+ const moveFocus = (dr, dc, extend) => {
1239
+ const f = focus.value ?? { row: 0, col: 0 };
1240
+ const next = { row: clamp(f.row + dr, 0, Math.max(0, rowCount.value - 1)), col: clamp(f.col + dc, 0, Math.max(0, flatCols.value.length - 1)) };
1241
+ focus.value = next;
1242
+ if (extend && anchor) setRange(anchor, next);
1243
+ else {
1244
+ anchor = next;
1245
+ setRange(next, next);
1246
+ }
1247
+ ensureVisible(next.row, next.col);
1248
+ };
1249
+ const rangeCells = () => {
1250
+ const r = cellRange.value ?? (focus.value ? { startRow: focus.value.row, endRow: focus.value.row, startCol: focus.value.col, endCol: focus.value.col } : null);
1251
+ return r;
1252
+ };
1253
+ const copy = async (withHeaders = false) => {
1254
+ const r = rangeCells();
1255
+ let lines = [];
1256
+ let header = [];
1257
+ if (props.rowSelection && selectedIds.value.length && (!r || r.startRow === r.endRow && r.startCol === r.endCol)) {
1258
+ const cols = flatCols.value.filter((c) => !c.auto);
1259
+ header = cols.map((c) => c.title);
1260
+ const sel = selectedSet.value;
1261
+ lines = viewIdx.value.filter((i) => sel.has(rowIdOf(viewRows.value[i], i))).map((i) => cols.map((c) => String(cellValue(c, viewRows.value[i]) ?? "")));
1262
+ } else if (r) {
1263
+ const cols = flatCols.value.slice(r.startCol, r.endCol + 1).filter((c) => !c.auto);
1264
+ header = cols.map((c) => c.title);
1265
+ for (let i = r.startRow; i <= r.endRow; i++) {
1266
+ const row = rowAt(i);
1267
+ if (row?.kind === "data") lines.push(cols.map((c) => String(cellValue(c, row.data) ?? "")));
1268
+ }
1269
+ }
1270
+ const text = [...withHeaders ? [header] : [], ...lines].map((l) => l.join(" ")).join("\n");
1271
+ try {
1272
+ await navigator.clipboard.writeText(text);
1273
+ } catch {
1274
+ }
1275
+ return text;
1276
+ };
1277
+ const onPaste = (e) => {
1278
+ if (editing.value || !focus.value) return;
1279
+ const text = e.clipboardData?.getData("text/plain");
1280
+ if (!text) return;
1281
+ e.preventDefault();
1282
+ const grid = parseTsv(text);
1283
+ const changes = [];
1284
+ grid.forEach((line, dr) => line.forEach((cellText, dc) => {
1285
+ const row = rowAt(focus.value.row + dr);
1286
+ const c = flatCols.value[focus.value.col + dc];
1287
+ if (row?.kind === "data" && c && !c.auto && isEditable(c.col, row.data)) changes.push({ row: row.data, col: c.col, oldValue: cellValue(c, row.data), newValue: parseFor(c.col, cellText, row.data) });
1288
+ }));
1289
+ record(changes);
1290
+ };
1291
+ const clearRange = () => {
1292
+ const r = rangeCells();
1293
+ if (!r) return;
1294
+ const changes = [];
1295
+ for (let i = r.startRow; i <= r.endRow; i++)
1296
+ for (let j = r.startCol; j <= r.endCol; j++) {
1297
+ const row = rowAt(i);
1298
+ const c = flatCols.value[j];
1299
+ if (row?.kind === "data" && c && !c.auto && isEditable(c.col, row.data)) changes.push({ row: row.data, col: c.col, oldValue: cellValue(c, row.data), newValue: c.col.type === "number" ? null : "" });
1300
+ }
1301
+ record(changes);
1302
+ };
1303
+ const onKeydown = (e) => {
1304
+ if (editing.value || e.target.closest("input, select, textarea, .sq-datagrid__toolbar")) return;
1305
+ const mod = e.ctrlKey || e.metaKey;
1306
+ const page2 = Math.max(1, Math.floor((vpHeight.value - headBlock.value) / props.rowHeight) - 1);
1307
+ const map = { ArrowUp: [-1, 0], ArrowDown: [1, 0], ArrowLeft: [0, -1], ArrowRight: [0, 1], PageUp: [-page2, 0], PageDown: [page2, 0] };
1308
+ if (map[e.key]) {
1309
+ e.preventDefault();
1310
+ moveFocus(map[e.key][0], map[e.key][1], e.shiftKey);
1311
+ } else if (e.key === "Home") {
1312
+ e.preventDefault();
1313
+ moveFocus(mod ? -rowCount.value : 0, -flatCols.value.length, e.shiftKey);
1314
+ } else if (e.key === "End") {
1315
+ e.preventDefault();
1316
+ moveFocus(mod ? rowCount.value : 0, flatCols.value.length, e.shiftKey);
1317
+ } else if (e.key === "Tab" && focus.value) {
1318
+ e.preventDefault();
1319
+ moveFocus(0, e.shiftKey ? -1 : 1, false);
1320
+ } else if ((e.key === "Enter" || e.key === "F2") && focus.value) {
1321
+ e.preventDefault();
1322
+ const r = rowAt(focus.value.row);
1323
+ r?.kind === "group" ? toggleGroup(r) : startEdit(focus.value.row, focus.value.col);
1324
+ } else if (e.key === " " && focus.value && props.rowSelection) {
1325
+ e.preventDefault();
1326
+ const r = rowAt(focus.value.row);
1327
+ if (r && r.kind !== "loading" && r.kind !== "detail") toggleRowCheck(r);
1328
+ } else if (mod && e.key.toLowerCase() === "c") {
1329
+ e.preventDefault();
1330
+ copy(e.shiftKey);
1331
+ } else if (mod && e.key.toLowerCase() === "a") {
1332
+ e.preventDefault();
1333
+ if (props.rowSelection === "multiple") setSelected(dataIdsInView());
1334
+ else cellRange.value = { startRow: 0, endRow: rowCount.value - 1, startCol: 0, endCol: flatCols.value.length - 1 };
1335
+ } else if (mod && e.key.toLowerCase() === "z") {
1336
+ e.preventDefault();
1337
+ e.shiftKey ? redo() : undo();
1338
+ } else if (mod && e.key.toLowerCase() === "y") {
1339
+ e.preventDefault();
1340
+ redo();
1341
+ } else if (e.key === "Delete" || e.key === "Backspace") {
1342
+ e.preventDefault();
1343
+ clearRange();
1344
+ } else if (e.key.length === 1 && !mod && focus.value) startEdit(focus.value.row, focus.value.col, e.key);
1345
+ };
1346
+ const menuOpen = ref(false);
1347
+ const menuAnchor = ref(null);
1348
+ const menuColId = ref(null);
1349
+ const menuMode = ref("column");
1350
+ const ctxPos = ref({ x: 0, y: 0 });
1351
+ const menuCol = computed(() => menuColId.value ? flatCols.value.find((c) => c.id === menuColId.value) ?? null : null);
1352
+ const menuFormatter = (v) => menuCol.value ? formatValue(menuCol.value.col, v, null) : String(v ?? "");
1353
+ const openMenu = (e, id) => {
1354
+ menuMode.value = "column";
1355
+ menuColId.value = id;
1356
+ menuAnchor.value = e.currentTarget;
1357
+ menuOpen.value = true;
1358
+ };
1359
+ const openContext = (e, vr, rc) => {
1360
+ if (!rc.col) return;
1361
+ if (!inRange(vr.index, rc.flatIndex)) {
1362
+ const p = { row: vr.index, col: rc.flatIndex };
1363
+ focus.value = p;
1364
+ anchor = p;
1365
+ setRange(p, p);
1366
+ }
1367
+ const rect = rootEl().getBoundingClientRect();
1368
+ ctxPos.value = { x: e.clientX - rect.left, y: e.clientY - rect.top };
1369
+ menuMode.value = "context";
1370
+ menuColId.value = rc.id;
1371
+ menuAnchor.value = ctxAnchor.value;
1372
+ menuOpen.value = true;
1373
+ };
1374
+ const exportCsv = (opts = {}) => {
1375
+ const cols = flatCols.value.filter((c) => !c.auto);
1376
+ const sel = selectedSet.value;
1377
+ const idx = isServer.value ? [] : viewIdx.value.filter((i) => !opts.onlySelected || sel.has(rowIdOf(viewRows.value[i], i)));
1378
+ const body = idx.map((i) => cols.map((c) => formatValue(c.col, cellValue(c, viewRows.value[i]), viewRows.value[i])));
1379
+ const csv = toCsv(cols.map((c) => c.title), body, opts.separator);
1380
+ downloadText(opts.fileName ?? "export.csv", "\uFEFF" + csv, "text/csv;charset=utf-8");
1381
+ return csv;
1382
+ };
1383
+ const bottomRows = computed(() => {
1384
+ const extra = [];
1385
+ if (props.totalsRow && !isServer.value) {
1386
+ const r = {};
1387
+ for (const c of viewCols.value) if (c.aggFunc) {
1388
+ const get = makeGetter(c);
1389
+ const v = aggregate(viewIdx.value.map((i) => get(viewRows.value[i])), c.aggFunc);
1390
+ if (c.field) setByPath(r, c.field, v);
1391
+ else r[colIdOf(c)] = v;
1392
+ }
1393
+ extra.push(r);
1394
+ }
1395
+ return [...props.pinnedBottomRows, ...extra];
1396
+ });
1397
+ const statusText = computed(() => {
1398
+ if (isServer.value) return `${serverCount.value.toLocaleString(loc.value)} rows`;
1399
+ const total = raw.value.length;
1400
+ const shown = filteredIdx.value.length;
1401
+ return shown === total ? `${total.toLocaleString(loc.value)} rows` : `${shown.toLocaleString(loc.value)} of ${total.toLocaleString(loc.value)} rows`;
1402
+ });
1403
+ const rangeStats = computed(() => {
1404
+ const r = cellRange.value;
1405
+ if (!r || r.startRow === r.endRow && r.startCol === r.endCol) return null;
1406
+ const nums = [];
1407
+ let count = 0;
1408
+ const maxCells = 2e5;
1409
+ for (let i = r.startRow; i <= r.endRow && count < maxCells; i++) {
1410
+ const row = rowAt(i);
1411
+ if (row?.kind !== "data") continue;
1412
+ for (let j = r.startCol; j <= r.endCol; j++) {
1413
+ const c = flatCols.value[j];
1414
+ if (!c || c.auto) continue;
1415
+ const v = cellValue(c, row.data);
1416
+ if (v != null && v !== "") count++;
1417
+ if (typeof v === "number") nums.push(v);
1418
+ }
1419
+ }
1420
+ if (!nums.length) return { count, sum: 0, avg: 0, min: 0, max: 0 };
1421
+ const sum = nums.reduce((a, b) => a + b, 0);
1422
+ return { count, sum, avg: sum / nums.length, min: Math.min(...nums), max: Math.max(...nums) };
1423
+ });
1424
+ const headerCellClass = (rc) => ({
1425
+ "sq-datagrid__hcell--pinned-left": rc.pinned === "left",
1426
+ "sq-datagrid__hcell--pinned-right": rc.pinned === "right",
1427
+ "sq-datagrid__hcell--edge-left": rc.edgeLeft,
1428
+ "sq-datagrid__hcell--edge-right": rc.edgeRight,
1429
+ "sq-datagrid__hcell--sortable": !!rc.col && !rc.auto && rc.col.sortable !== false,
1430
+ "sq-datagrid__hcell--spacer": !rc.col,
1431
+ "sq-datagrid__hcell--drop-before": dropTarget.value?.id === rc.id && dropTarget.value.before,
1432
+ "sq-datagrid__hcell--drop-after": dropTarget.value?.id === rc.id && !dropTarget.value.before,
1433
+ [`sq-datagrid__align-${rc.col?.align ?? (rc.col?.type === "number" ? "right" : "left")}`]: true,
1434
+ [rc.col?.headerClass ?? ""]: !!rc.col?.headerClass
1435
+ });
1436
+ const cellAlignClass = (rc) => ({
1437
+ "sq-datagrid__cell--pinned-left": rc.pinned === "left",
1438
+ "sq-datagrid__cell--pinned-right": rc.pinned === "right",
1439
+ "sq-datagrid__cell--edge-left": !!rc.edgeLeft,
1440
+ "sq-datagrid__cell--edge-right": !!rc.edgeRight,
1441
+ [`sq-datagrid__align-${rc.col?.align ?? (rc.col?.type === "number" ? "right" : rc.col?.type === "boolean" ? "center" : "left")}`]: !!rc.col
1442
+ });
1443
+ const cellClass = (vr, rc) => {
1444
+ const base = cellAlignClass(rc);
1445
+ if (!rc.col) return base;
1446
+ base["sq-datagrid__cell--focused"] = !!focus.value && focus.value.row === vr.index && focus.value.col === rc.flatIndex;
1447
+ base["sq-datagrid__cell--range"] = inRange(vr.index, rc.flatIndex);
1448
+ base["sq-datagrid__cell--editable"] = vr.row.kind === "data" && isEditable(rc.col, vr.row.data);
1449
+ if (rc.col.cellClass && vr.row.kind === "data") {
1450
+ const extra = typeof rc.col.cellClass === "function" ? rc.col.cellClass({ value: cellValue(rc, vr.row.data), row: vr.row.data, column: rc.col, rowIndex: vr.index }) : rc.col.cellClass;
1451
+ if (extra) base[extra] = true;
1452
+ }
1453
+ return base;
1454
+ };
1455
+ const cellStyle = (vr, rc) => {
1456
+ if (!rc.col?.cellStyle || vr.row.kind !== "data") return rc.style;
1457
+ const extra = typeof rc.col.cellStyle === "function" ? rc.col.cellStyle({ value: cellValue(rc, vr.row.data), row: vr.row.data, column: rc.col, rowIndex: vr.index }) : rc.col.cellStyle;
1458
+ return extra ? { ...rc.style, ...extra } : rc.style;
1459
+ };
1460
+ const rowClass = (vr) => {
1461
+ const c = {
1462
+ "sq-datagrid__row--group": vr.row.kind === "group",
1463
+ "sq-datagrid__row--detail": vr.row.kind === "detail",
1464
+ "sq-datagrid__row--selected": vr.row.kind === "data" && selectedSet.value.has(vr.row.id),
1465
+ "sq-datagrid__row--odd": vr.index % 2 === 1
1466
+ };
1467
+ if (props.rowClassName && vr.row.data && vr.row.kind === "data") {
1468
+ const x = props.rowClassName(vr.row.data);
1469
+ if (x) c[x] = true;
1470
+ }
1471
+ return c;
1472
+ };
1473
+ const showLoading = computed(() => props.loading || isServer.value && serverLoading.value && serverCount.value === 0);
1474
+ const rootStyle = { "--sq-r": "var(--sq-radius-xl)", "--sq-bg": "var(--sq-surface)", "--sq-bd": "var(--sq-border)", "--sq-bw": "1px", "--sq-grid-row-h": `${props.rowHeight}px` };
1475
+ const api = {
1476
+ getSelectedRows: () => isServer.value ? [] : viewIdx.value.map((i) => viewRows.value[i]).filter((r, k) => selectedSet.value.has(rowIdOf(r, viewIdx.value[k]))),
1477
+ getDisplayedRows: () => display.value,
1478
+ selectAll: () => setSelected(dataIdsInView()),
1479
+ deselectAll: () => setSelected([]),
1480
+ exportCsv,
1481
+ copy,
1482
+ undo,
1483
+ redo,
1484
+ expandAll,
1485
+ collapseAll,
1486
+ autoSize,
1487
+ refresh: () => isServer.value ? purge() : dataVersion.value++,
1488
+ ensureIndexVisible: (i) => ensureVisible(i, focus.value?.col ?? 0),
1489
+ getColumnState: () => flatCols.value.filter((c) => !c.auto).map((c) => ({ colId: c.id, width: c.width, hide: false, pinned: c.pinned })),
1490
+ setColumnState: (state) => {
1491
+ colOrder.value = [...state.map((s) => s.colId), ...colOrder.value.filter((id) => !state.some((s) => s.colId === id))];
1492
+ colWidth.value = { ...colWidth.value, ...Object.fromEntries(state.filter((s) => s.width).map((s) => [s.colId, s.width])) };
1493
+ colHidden.value = { ...colHidden.value, ...Object.fromEntries(state.filter((s) => s.hide !== void 0).map((s) => [s.colId, s.hide])) };
1494
+ colPinned.value = { ...colPinned.value, ...Object.fromEntries(state.filter((s) => s.pinned !== void 0).map((s) => [s.colId, s.pinned])) };
1495
+ }
1496
+ };
1497
+ return {
1498
+ ...api,
1499
+ api,
1500
+ viewport,
1501
+ ctxAnchor,
1502
+ scrollLeft,
1503
+ vpWidth,
1504
+ isServer,
1505
+ quick,
1506
+ groupBy,
1507
+ selectedIds,
1508
+ selectedSet,
1509
+ sortModelList,
1510
+ filterModelObj,
1511
+ renderCols,
1512
+ flatCols,
1513
+ totalWidth,
1514
+ hasHeaderGroups,
1515
+ headerGroups,
1516
+ layout,
1517
+ visibleRows,
1518
+ rowCount,
1519
+ filterRowHeight,
1520
+ page,
1521
+ pageSizeState,
1522
+ pageCount,
1523
+ onPageSize,
1524
+ pageRangeText,
1525
+ hasGroups,
1526
+ detailOpen,
1527
+ onScroll,
1528
+ cellValue,
1529
+ formatValue,
1530
+ formatCell,
1531
+ cellParams,
1532
+ groupLabel,
1533
+ groupAggText,
1534
+ filterKind,
1535
+ distinctValues,
1536
+ sortIndex,
1537
+ sortDir,
1538
+ ariaSort,
1539
+ setSort,
1540
+ onHeaderClick,
1541
+ setFilter,
1542
+ floatingValue,
1543
+ onFloatingInput,
1544
+ toggleGroupBy,
1545
+ removeGroup,
1546
+ toggleGroup,
1547
+ toggleDetail,
1548
+ setHidden,
1549
+ setPinned,
1550
+ chooserCols,
1551
+ startResize,
1552
+ dragColId,
1553
+ onDragStart,
1554
+ onDragOver,
1555
+ onDrop,
1556
+ onGroupDrop,
1557
+ allSelected,
1558
+ someSelected,
1559
+ toggleAll,
1560
+ isRowChecked,
1561
+ isRowPartial,
1562
+ toggleRowCheck,
1563
+ onRowClick,
1564
+ onCellMousedown,
1565
+ onCellEnter,
1566
+ editing,
1567
+ isEditing,
1568
+ editorKind,
1569
+ onEditorInput,
1570
+ commitEdit,
1571
+ onEditorKey,
1572
+ onCellDblclick,
1573
+ canUndo,
1574
+ onKeydown,
1575
+ onPaste,
1576
+ menuOpen,
1577
+ menuAnchor,
1578
+ menuMode,
1579
+ menuCol,
1580
+ menuFormatter,
1581
+ openMenu,
1582
+ openContext,
1583
+ ctxPos,
1584
+ bottomRows,
1585
+ statusText,
1586
+ rangeStats,
1587
+ fmtNum,
1588
+ headerCellClass,
1589
+ cellAlignClass,
1590
+ cellClass,
1591
+ cellStyle,
1592
+ rowClass,
1593
+ showLoading,
1594
+ rootStyle,
1595
+ titleOf,
1596
+ toUnit,
1597
+ getByPath,
1598
+ has: (n) => !!slots[n],
1599
+ messages: computed(() => config.locale.messages)
1600
+ };
1601
+ }
1602
+ });
1603
+ const _hoisted_1 = ["aria-rowcount", "aria-colcount"];
1604
+ const _hoisted_2 = {
1605
+ key: 0,
1606
+ class: "sq-datagrid__toolbar"
1607
+ };
1608
+ const _hoisted_3 = { class: "sq-datagrid__chooser" };
1609
+ const _hoisted_4 = {
1610
+ key: 0,
1611
+ class: "sq-datagrid__group-hint"
1612
+ };
1613
+ const _hoisted_5 = {
1614
+ class: "sq-datagrid__head",
1615
+ role: "rowgroup"
1616
+ };
1617
+ const _hoisted_6 = ["aria-sort", "draggable", "onClick", "onDragstart", "onDragover", "onDrop"];
1618
+ const _hoisted_7 = { class: "sq-datagrid__htitle" };
1619
+ const _hoisted_8 = {
1620
+ key: 0,
1621
+ class: "sq-datagrid__sort"
1622
+ };
1623
+ const _hoisted_9 = { key: 0 };
1624
+ const _hoisted_10 = ["onClick"];
1625
+ const _hoisted_11 = ["onPointerdown", "onDblclick"];
1626
+ const _hoisted_12 = ["type", "value", "placeholder", "aria-label", "onInput"];
1627
+ const _hoisted_13 = ["aria-rowindex", "aria-selected", "onClick", "onDblclick"];
1628
+ const _hoisted_14 = ["onMousedown", "onMouseenter", "onDblclick", "onContextmenu"];
1629
+ const _hoisted_15 = {
1630
+ key: 1,
1631
+ class: "sq-datagrid__skeleton sq-skeleton-shimmer"
1632
+ };
1633
+ const _hoisted_16 = ["onClick"];
1634
+ const _hoisted_17 = ["onClick"];
1635
+ const _hoisted_18 = {
1636
+ key: 2,
1637
+ class: "sq-datagrid__expander-spacer"
1638
+ };
1639
+ const _hoisted_19 = { class: "sq-datagrid__group-key" };
1640
+ const _hoisted_20 = {
1641
+ key: 3,
1642
+ class: "sq-datagrid__group-count"
1643
+ };
1644
+ const _hoisted_21 = {
1645
+ key: 4,
1646
+ class: "sq-datagrid__agg"
1647
+ };
1648
+ const _hoisted_22 = ["value"];
1649
+ const _hoisted_23 = ["value"];
1650
+ const _hoisted_24 = ["type", "value"];
1651
+ const _hoisted_25 = {
1652
+ key: 1,
1653
+ class: "sq-datagrid__text"
1654
+ };
1655
+ const _hoisted_26 = {
1656
+ key: 0,
1657
+ class: "sq-datagrid__foot"
1658
+ };
1659
+ const _hoisted_27 = { key: 0 };
1660
+ const _hoisted_28 = {
1661
+ key: 0,
1662
+ class: "sq-datagrid__overlay"
1663
+ };
1664
+ const _hoisted_29 = {
1665
+ key: 1,
1666
+ class: "sq-datagrid__overlay sq-datagrid__overlay--empty"
1667
+ };
1668
+ const _hoisted_30 = {
1669
+ key: 2,
1670
+ class: "sq-datagrid__footer"
1671
+ };
1672
+ const _hoisted_31 = {
1673
+ key: 0,
1674
+ class: "sq-datagrid__status"
1675
+ };
1676
+ const _hoisted_32 = { key: 0 };
1677
+ const _hoisted_33 = {
1678
+ key: 1,
1679
+ class: "sq-datagrid__range-stats"
1680
+ };
1681
+ const _hoisted_34 = { class: "sq-datagrid__page-size" };
1682
+ const _hoisted_35 = ["value"];
1683
+ const _hoisted_36 = ["value"];
1684
+ const _hoisted_37 = { class: "sq-datagrid__page-range" };
1685
+ const _hoisted_38 = {
1686
+ key: 0,
1687
+ class: "sq-datagrid__menu"
1688
+ };
1689
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
1690
+ const _component_SqShape = resolveComponent("SqShape");
1691
+ const _component_SqTextField = resolveComponent("SqTextField");
1692
+ const _component_SqBtn = resolveComponent("SqBtn");
1693
+ const _component_SqCheckbox = resolveComponent("SqCheckbox");
1694
+ const _component_SqMenu = resolveComponent("SqMenu");
1695
+ const _component_SqIcon = resolveComponent("SqIcon");
1696
+ const _component_SqChip = resolveComponent("SqChip");
1697
+ const _component_SqProgressCircular = resolveComponent("SqProgressCircular");
1698
+ const _component_SqEmptyState = resolveComponent("SqEmptyState");
1699
+ const _component_SqPagination = resolveComponent("SqPagination");
1700
+ const _component_SqListItem = resolveComponent("SqListItem");
1701
+ const _component_SqDivider = resolveComponent("SqDivider");
1702
+ const _component_SqGridFilter = resolveComponent("SqGridFilter");
1703
+ return openBlock(), createElementBlock("div", {
1704
+ class: normalizeClass(["sq-datagrid sq-surface", { "sq-datagrid--striped": _ctx.striped, "sq-datagrid--column-lines": _ctx.columnLines, "sq-datagrid--scrolled-x": _ctx.scrollLeft > 0 }]),
1705
+ style: normalizeStyle(_ctx.rootStyle),
1706
+ tabindex: "0",
1707
+ role: "grid",
1708
+ "aria-rowcount": _ctx.rowCount,
1709
+ "aria-colcount": _ctx.flatCols.length,
1710
+ onKeydown: _cache[37] || (_cache[37] = (...args) => _ctx.onKeydown && _ctx.onKeydown(...args)),
1711
+ onPaste: _cache[38] || (_cache[38] = (...args) => _ctx.onPaste && _ctx.onPaste(...args))
1712
+ }, [
1713
+ createVNode(_component_SqShape, { clip: "" }),
1714
+ _ctx.toolbar || _ctx.has("toolbar") ? (openBlock(), createElementBlock("div", _hoisted_2, [
1715
+ renderSlot(_ctx.$slots, "toolbar", { api: _ctx.api }),
1716
+ _ctx.toolbar ? (openBlock(), createBlock(_component_SqTextField, {
1717
+ key: 0,
1718
+ "model-value": _ctx.quick,
1719
+ class: "sq-datagrid__quick",
1720
+ placeholder: _ctx.messages.search,
1721
+ "prepend-inner-icon": "search",
1722
+ density: "compact",
1723
+ "hide-details": "",
1724
+ clearable: "",
1725
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.quick = $event || "")
1726
+ }, null, 8, ["model-value", "placeholder"])) : createCommentVNode("v-if", true),
1727
+ _cache[41] || (_cache[41] = createElementVNode(
1728
+ "span",
1729
+ { class: "sq-spacer" },
1730
+ null,
1731
+ -1
1732
+ /* CACHED */
1733
+ )),
1734
+ _ctx.toolbar ? (openBlock(), createBlock(_component_SqMenu, {
1735
+ key: 1,
1736
+ "close-on-content-click": false,
1737
+ location: "bottom end"
1738
+ }, {
1739
+ activator: withCtx(() => [
1740
+ createVNode(_component_SqBtn, {
1741
+ "prepend-icon": "columns",
1742
+ variant: "text",
1743
+ color: "surface",
1744
+ size: "small"
1745
+ }, {
1746
+ default: withCtx(() => [..._cache[39] || (_cache[39] = [
1747
+ createTextVNode(
1748
+ "Columns",
1749
+ -1
1750
+ /* CACHED */
1751
+ )
1752
+ ])]),
1753
+ _: 1
1754
+ /* STABLE */
1755
+ })
1756
+ ]),
1757
+ default: withCtx(() => [
1758
+ createElementVNode("div", _hoisted_3, [
1759
+ (openBlock(true), createElementBlock(
1760
+ Fragment,
1761
+ null,
1762
+ renderList(_ctx.chooserCols, (c) => {
1763
+ return openBlock(), createBlock(_component_SqCheckbox, {
1764
+ key: c.id,
1765
+ "model-value": !c.hidden,
1766
+ label: c.title,
1767
+ "onUpdate:modelValue": ($event) => _ctx.setHidden(c.id, !$event)
1768
+ }, null, 8, ["model-value", "label", "onUpdate:modelValue"]);
1769
+ }),
1770
+ 128
1771
+ /* KEYED_FRAGMENT */
1772
+ ))
1773
+ ])
1774
+ ]),
1775
+ _: 1
1776
+ /* STABLE */
1777
+ })) : createCommentVNode("v-if", true),
1778
+ _ctx.toolbar ? (openBlock(), createBlock(_component_SqBtn, {
1779
+ key: 2,
1780
+ "prepend-icon": "download",
1781
+ variant: "text",
1782
+ color: "surface",
1783
+ size: "small",
1784
+ onClick: _cache[1] || (_cache[1] = ($event) => _ctx.exportCsv())
1785
+ }, {
1786
+ default: withCtx(() => [..._cache[40] || (_cache[40] = [
1787
+ createTextVNode(
1788
+ "CSV",
1789
+ -1
1790
+ /* CACHED */
1791
+ )
1792
+ ])]),
1793
+ _: 1
1794
+ /* STABLE */
1795
+ })) : createCommentVNode("v-if", true)
1796
+ ])) : createCommentVNode("v-if", true),
1797
+ _ctx.groupPanel && !_ctx.treeData && !_ctx.isServer ? (openBlock(), createElementBlock(
1798
+ "div",
1799
+ {
1800
+ key: 1,
1801
+ class: "sq-datagrid__group-panel",
1802
+ onDragover: _cache[2] || (_cache[2] = withModifiers(() => {
1803
+ }, ["prevent"])),
1804
+ onDrop: _cache[3] || (_cache[3] = (...args) => _ctx.onGroupDrop && _ctx.onGroupDrop(...args))
1805
+ },
1806
+ [
1807
+ createVNode(_component_SqIcon, {
1808
+ icon: "menu",
1809
+ size: "16px"
1810
+ }),
1811
+ !_ctx.groupBy.length ? (openBlock(), createElementBlock("span", _hoisted_4, "Drag a column header here to group rows")) : createCommentVNode("v-if", true),
1812
+ (openBlock(true), createElementBlock(
1813
+ Fragment,
1814
+ null,
1815
+ renderList(_ctx.groupBy, (id) => {
1816
+ return openBlock(), createBlock(_component_SqChip, {
1817
+ key: id,
1818
+ size: "small",
1819
+ variant: "tonal",
1820
+ color: "primary",
1821
+ closable: "",
1822
+ "onClick:close": ($event) => _ctx.removeGroup(id)
1823
+ }, {
1824
+ default: withCtx(() => [
1825
+ createTextVNode(
1826
+ toDisplayString(_ctx.titleOf(id)),
1827
+ 1
1828
+ /* TEXT */
1829
+ )
1830
+ ]),
1831
+ _: 2
1832
+ /* DYNAMIC */
1833
+ }, 1032, ["onClick:close"]);
1834
+ }),
1835
+ 128
1836
+ /* KEYED_FRAGMENT */
1837
+ ))
1838
+ ],
1839
+ 32
1840
+ /* NEED_HYDRATION */
1841
+ )) : createCommentVNode("v-if", true),
1842
+ createElementVNode(
1843
+ "div",
1844
+ {
1845
+ ref: "viewport",
1846
+ class: "sq-datagrid__viewport",
1847
+ style: normalizeStyle({ height: _ctx.toUnit(_ctx.height) }),
1848
+ onScrollPassive: _cache[16] || (_cache[16] = (...args) => _ctx.onScroll && _ctx.onScroll(...args))
1849
+ },
1850
+ [
1851
+ createElementVNode(
1852
+ "div",
1853
+ {
1854
+ class: "sq-datagrid__canvas",
1855
+ style: normalizeStyle({ width: _ctx.totalWidth + "px" })
1856
+ },
1857
+ [
1858
+ createCommentVNode(" header (sticky) "),
1859
+ createElementVNode("div", _hoisted_5, [
1860
+ _ctx.hasHeaderGroups ? (openBlock(), createElementBlock(
1861
+ "div",
1862
+ {
1863
+ key: 0,
1864
+ class: "sq-datagrid__header-row sq-datagrid__header-row--groups",
1865
+ style: normalizeStyle({ height: _ctx.headerHeight + "px" })
1866
+ },
1867
+ [
1868
+ (openBlock(true), createElementBlock(
1869
+ Fragment,
1870
+ null,
1871
+ renderList(_ctx.headerGroups, (g) => {
1872
+ return openBlock(), createElementBlock(
1873
+ "div",
1874
+ {
1875
+ key: g.key,
1876
+ class: normalizeClass(["sq-datagrid__header-group", g.cls]),
1877
+ style: normalizeStyle(g.style)
1878
+ },
1879
+ toDisplayString(g.label),
1880
+ 7
1881
+ /* TEXT, CLASS, STYLE */
1882
+ );
1883
+ }),
1884
+ 128
1885
+ /* KEYED_FRAGMENT */
1886
+ ))
1887
+ ],
1888
+ 4
1889
+ /* STYLE */
1890
+ )) : createCommentVNode("v-if", true),
1891
+ createElementVNode(
1892
+ "div",
1893
+ {
1894
+ class: "sq-datagrid__header-row",
1895
+ role: "row",
1896
+ style: normalizeStyle({ height: _ctx.headerHeight + "px" })
1897
+ },
1898
+ [
1899
+ (openBlock(true), createElementBlock(
1900
+ Fragment,
1901
+ null,
1902
+ renderList(_ctx.renderCols, (rc) => {
1903
+ return openBlock(), createElementBlock("div", {
1904
+ key: rc.key,
1905
+ class: normalizeClass(["sq-datagrid__hcell", _ctx.headerCellClass(rc)]),
1906
+ style: normalizeStyle(rc.style),
1907
+ role: "columnheader",
1908
+ "aria-sort": rc.col ? _ctx.ariaSort(rc.id) : void 0,
1909
+ draggable: !!rc.col && !rc.auto && !rc.col.lockPosition,
1910
+ onClick: ($event) => rc.col && _ctx.onHeaderClick($event, rc),
1911
+ onDragstart: ($event) => _ctx.onDragStart($event, rc),
1912
+ onDragover: withModifiers(($event) => _ctx.onDragOver($event, rc), ["prevent"]),
1913
+ onDrop: withModifiers(($event) => _ctx.onDrop(rc), ["prevent"]),
1914
+ onDragend: _cache[6] || (_cache[6] = ($event) => _ctx.dragColId = null)
1915
+ }, [
1916
+ rc.col ? (openBlock(), createElementBlock(
1917
+ Fragment,
1918
+ { key: 0 },
1919
+ [
1920
+ rc.id === "__select" ? (openBlock(), createElementBlock("span", {
1921
+ key: 0,
1922
+ class: "sq-datagrid__check",
1923
+ onClick: _cache[4] || (_cache[4] = withModifiers(() => {
1924
+ }, ["stop"]))
1925
+ }, [
1926
+ createVNode(_component_SqCheckbox, {
1927
+ "model-value": _ctx.allSelected,
1928
+ indeterminate: _ctx.someSelected,
1929
+ "aria-label": "Select all rows",
1930
+ "onUpdate:modelValue": _ctx.toggleAll
1931
+ }, null, 8, ["model-value", "indeterminate", "onUpdate:modelValue"])
1932
+ ])) : (openBlock(), createElementBlock(
1933
+ Fragment,
1934
+ { key: 1 },
1935
+ [
1936
+ createElementVNode("span", _hoisted_7, [
1937
+ renderSlot(_ctx.$slots, `header-${rc.id}`, {
1938
+ column: rc.col
1939
+ }, () => [
1940
+ createTextVNode(
1941
+ toDisplayString(rc.title),
1942
+ 1
1943
+ /* TEXT */
1944
+ )
1945
+ ])
1946
+ ]),
1947
+ _ctx.sortIndex(rc.id) >= 0 ? (openBlock(), createElementBlock("span", _hoisted_8, [
1948
+ createVNode(_component_SqIcon, {
1949
+ icon: _ctx.sortDir(rc.id) === "asc" ? "arrowUp" : "arrowDown",
1950
+ size: "14px"
1951
+ }, null, 8, ["icon"]),
1952
+ _ctx.sortModelList.length > 1 ? (openBlock(), createElementBlock(
1953
+ "sup",
1954
+ _hoisted_9,
1955
+ toDisplayString(_ctx.sortIndex(rc.id) + 1),
1956
+ 1
1957
+ /* TEXT */
1958
+ )) : createCommentVNode("v-if", true)
1959
+ ])) : createCommentVNode("v-if", true),
1960
+ _ctx.filterModelObj[rc.id] ? (openBlock(), createBlock(_component_SqIcon, {
1961
+ key: 1,
1962
+ icon: "filter",
1963
+ size: "14px",
1964
+ class: "sq-datagrid__filtered"
1965
+ })) : createCommentVNode("v-if", true),
1966
+ !rc.col.suppressMenu && !rc.auto ? (openBlock(), createElementBlock("button", {
1967
+ key: 2,
1968
+ type: "button",
1969
+ class: "sq-datagrid__menu-btn",
1970
+ tabindex: "-1",
1971
+ "aria-label": "Column menu",
1972
+ onClick: withModifiers(($event) => _ctx.openMenu($event, rc.id), ["stop"])
1973
+ }, [
1974
+ createVNode(_component_SqIcon, {
1975
+ icon: "more",
1976
+ size: "16px"
1977
+ })
1978
+ ], 8, _hoisted_10)) : createCommentVNode("v-if", true)
1979
+ ],
1980
+ 64
1981
+ /* STABLE_FRAGMENT */
1982
+ )),
1983
+ rc.col.resizable !== false ? (openBlock(), createElementBlock("span", {
1984
+ key: 2,
1985
+ class: "sq-datagrid__resizer",
1986
+ onPointerdown: withModifiers(($event) => _ctx.startResize($event, rc), ["stop", "prevent"]),
1987
+ onDblclick: withModifiers(($event) => _ctx.autoSize([rc.id]), ["stop"]),
1988
+ onClick: _cache[5] || (_cache[5] = withModifiers(() => {
1989
+ }, ["stop"]))
1990
+ }, null, 40, _hoisted_11)) : createCommentVNode("v-if", true)
1991
+ ],
1992
+ 64
1993
+ /* STABLE_FRAGMENT */
1994
+ )) : createCommentVNode("v-if", true)
1995
+ ], 46, _hoisted_6);
1996
+ }),
1997
+ 128
1998
+ /* KEYED_FRAGMENT */
1999
+ ))
2000
+ ],
2001
+ 4
2002
+ /* STYLE */
2003
+ ),
2004
+ _ctx.floatingFilters ? (openBlock(), createElementBlock(
2005
+ "div",
2006
+ {
2007
+ key: 1,
2008
+ class: "sq-datagrid__header-row sq-datagrid__header-row--filters",
2009
+ style: normalizeStyle({ height: _ctx.filterRowHeight + "px" })
2010
+ },
2011
+ [
2012
+ (openBlock(true), createElementBlock(
2013
+ Fragment,
2014
+ null,
2015
+ renderList(_ctx.renderCols, (rc) => {
2016
+ return openBlock(), createElementBlock(
2017
+ "div",
2018
+ {
2019
+ key: rc.key,
2020
+ class: normalizeClass(["sq-datagrid__hcell sq-datagrid__fcell", _ctx.headerCellClass(rc)]),
2021
+ style: normalizeStyle(rc.style)
2022
+ },
2023
+ [
2024
+ rc.col && !rc.auto && rc.col.filter !== false && _ctx.filterKind(rc.col) !== "set" ? (openBlock(), createElementBlock("input", {
2025
+ key: 0,
2026
+ class: "sq-datagrid__ffilter sq-squircle",
2027
+ type: _ctx.filterKind(rc.col) === "number" ? "number" : _ctx.filterKind(rc.col) === "date" ? "date" : "text",
2028
+ value: _ctx.floatingValue(rc.id),
2029
+ placeholder: _ctx.filterKind(rc.col) === "text" ? "…" : "=",
2030
+ "aria-label": `Filter ${rc.title}`,
2031
+ onInput: ($event) => _ctx.onFloatingInput($event, rc)
2032
+ }, null, 40, _hoisted_12)) : createCommentVNode("v-if", true)
2033
+ ],
2034
+ 6
2035
+ /* CLASS, STYLE */
2036
+ );
2037
+ }),
2038
+ 128
2039
+ /* KEYED_FRAGMENT */
2040
+ ))
2041
+ ],
2042
+ 4
2043
+ /* STYLE */
2044
+ )) : createCommentVNode("v-if", true),
2045
+ (openBlock(true), createElementBlock(
2046
+ Fragment,
2047
+ null,
2048
+ renderList(_ctx.pinnedTopRows, (pr, pi) => {
2049
+ return openBlock(), createElementBlock(
2050
+ "div",
2051
+ {
2052
+ key: "pt" + pi,
2053
+ class: "sq-datagrid__row sq-datagrid__row--pinned",
2054
+ style: normalizeStyle({ height: _ctx.rowHeight + "px" })
2055
+ },
2056
+ [
2057
+ (openBlock(true), createElementBlock(
2058
+ Fragment,
2059
+ null,
2060
+ renderList(_ctx.renderCols, (rc) => {
2061
+ return openBlock(), createElementBlock(
2062
+ "div",
2063
+ {
2064
+ key: rc.key,
2065
+ class: normalizeClass(["sq-datagrid__cell", _ctx.cellAlignClass(rc)]),
2066
+ style: normalizeStyle(rc.style)
2067
+ },
2068
+ [
2069
+ rc.col && !rc.auto ? renderSlot(_ctx.$slots, `cell-${rc.id}`, mergeProps({ ref_for: true }, _ctx.cellParams(pr, rc, -1)), () => [
2070
+ createTextVNode(
2071
+ toDisplayString(_ctx.formatCell(rc, pr)),
2072
+ 1
2073
+ /* TEXT */
2074
+ )
2075
+ ], void 0, 0) : createCommentVNode("v-if", true)
2076
+ ],
2077
+ 6
2078
+ /* CLASS, STYLE */
2079
+ );
2080
+ }),
2081
+ 128
2082
+ /* KEYED_FRAGMENT */
2083
+ ))
2084
+ ],
2085
+ 4
2086
+ /* STYLE */
2087
+ );
2088
+ }),
2089
+ 128
2090
+ /* KEYED_FRAGMENT */
2091
+ ))
2092
+ ]),
2093
+ createCommentVNode(" body "),
2094
+ createElementVNode(
2095
+ "div",
2096
+ {
2097
+ class: "sq-datagrid__body",
2098
+ role: "rowgroup",
2099
+ style: normalizeStyle({ height: _ctx.layout.total + "px" })
2100
+ },
2101
+ [
2102
+ (openBlock(true), createElementBlock(
2103
+ Fragment,
2104
+ null,
2105
+ renderList(_ctx.visibleRows, (vr) => {
2106
+ return openBlock(), createElementBlock("div", {
2107
+ key: vr.row.id,
2108
+ class: normalizeClass(["sq-datagrid__row", _ctx.rowClass(vr)]),
2109
+ style: normalizeStyle({ transform: `translateY(${vr.top}px)`, height: vr.height + "px" }),
2110
+ role: "row",
2111
+ "aria-rowindex": vr.index + 1,
2112
+ "aria-selected": vr.row.kind === "data" && _ctx.rowSelection ? _ctx.selectedSet.has(vr.row.id) ? "true" : "false" : void 0,
2113
+ onClick: ($event) => _ctx.onRowClick($event, vr),
2114
+ onDblclick: ($event) => _ctx.$emit("row-dblclick", { row: vr.row.data, event: $event })
2115
+ }, [
2116
+ vr.row.kind === "detail" ? (openBlock(), createElementBlock(
2117
+ "div",
2118
+ {
2119
+ key: 0,
2120
+ class: "sq-datagrid__detail",
2121
+ style: normalizeStyle({ width: _ctx.vpWidth + "px" })
2122
+ },
2123
+ [
2124
+ renderSlot(_ctx.$slots, "detail", {
2125
+ row: vr.row.data
2126
+ })
2127
+ ],
2128
+ 4
2129
+ /* STYLE */
2130
+ )) : (openBlock(true), createElementBlock(
2131
+ Fragment,
2132
+ { key: 1 },
2133
+ renderList(_ctx.renderCols, (rc) => {
2134
+ return openBlock(), createElementBlock("div", {
2135
+ key: rc.key,
2136
+ class: normalizeClass(["sq-datagrid__cell", _ctx.cellClass(vr, rc)]),
2137
+ style: normalizeStyle(_ctx.cellStyle(vr, rc)),
2138
+ role: "gridcell",
2139
+ onMousedown: ($event) => _ctx.onCellMousedown($event, vr, rc),
2140
+ onMouseenter: ($event) => _ctx.onCellEnter(vr, rc),
2141
+ onDblclick: withModifiers(($event) => _ctx.onCellDblclick(vr, rc), ["stop"]),
2142
+ onContextmenu: withModifiers(($event) => _ctx.openContext($event, vr, rc), ["prevent"])
2143
+ }, [
2144
+ !rc.col ? (openBlock(), createElementBlock(
2145
+ Fragment,
2146
+ { key: 0 },
2147
+ [],
2148
+ 64
2149
+ /* STABLE_FRAGMENT */
2150
+ )) : vr.row.kind === "loading" ? (openBlock(), createElementBlock("span", _hoisted_15)) : rc.id === "__select" ? (openBlock(), createElementBlock(
2151
+ "span",
2152
+ {
2153
+ key: 2,
2154
+ class: "sq-datagrid__check",
2155
+ onClick: _cache[7] || (_cache[7] = withModifiers(() => {
2156
+ }, ["stop"])),
2157
+ onMousedown: _cache[8] || (_cache[8] = withModifiers(() => {
2158
+ }, ["stop"]))
2159
+ },
2160
+ [
2161
+ createVNode(_component_SqCheckbox, {
2162
+ "model-value": _ctx.isRowChecked(vr.row),
2163
+ indeterminate: _ctx.isRowPartial(vr.row),
2164
+ "aria-label": "Select row",
2165
+ "onUpdate:modelValue": ($event) => _ctx.toggleRowCheck(vr.row)
2166
+ }, null, 8, ["model-value", "indeterminate", "onUpdate:modelValue"])
2167
+ ],
2168
+ 32
2169
+ /* NEED_HYDRATION */
2170
+ )) : rc.id === "__group" ? (openBlock(), createElementBlock(
2171
+ "span",
2172
+ {
2173
+ key: 3,
2174
+ class: "sq-datagrid__group-cell",
2175
+ style: normalizeStyle({ paddingInlineStart: vr.row.level * 18 + "px" })
2176
+ },
2177
+ [
2178
+ vr.row.kind === "group" ? (openBlock(), createElementBlock("button", {
2179
+ key: 0,
2180
+ type: "button",
2181
+ class: normalizeClass(["sq-datagrid__expander", { "sq-datagrid__expander--open": vr.row.group?.expanded }]),
2182
+ tabindex: "-1",
2183
+ onClick: withModifiers(($event) => _ctx.toggleGroup(vr.row), ["stop"])
2184
+ }, [
2185
+ createVNode(_component_SqIcon, {
2186
+ icon: "chevronRight",
2187
+ size: "18px"
2188
+ })
2189
+ ], 10, _hoisted_16)) : _ctx.masterDetail && !_ctx.treeData ? (openBlock(), createElementBlock("button", {
2190
+ key: 1,
2191
+ type: "button",
2192
+ class: normalizeClass(["sq-datagrid__expander", { "sq-datagrid__expander--open": _ctx.detailOpen.has(vr.row.id) }]),
2193
+ tabindex: "-1",
2194
+ onClick: withModifiers(($event) => _ctx.toggleDetail(vr.row.id), ["stop"])
2195
+ }, [
2196
+ createVNode(_component_SqIcon, {
2197
+ icon: "chevronRight",
2198
+ size: "18px"
2199
+ })
2200
+ ], 10, _hoisted_17)) : (openBlock(), createElementBlock("span", _hoisted_18)),
2201
+ createElementVNode("span", _hoisted_19, [
2202
+ renderSlot(_ctx.$slots, "group", {
2203
+ row: vr.row
2204
+ }, () => [
2205
+ createTextVNode(
2206
+ toDisplayString(_ctx.groupLabel(vr.row)),
2207
+ 1
2208
+ /* TEXT */
2209
+ )
2210
+ ])
2211
+ ]),
2212
+ vr.row.kind === "group" && vr.row.group?.count ? (openBlock(), createElementBlock(
2213
+ "span",
2214
+ _hoisted_20,
2215
+ toDisplayString(vr.row.group?.count),
2216
+ 1
2217
+ /* TEXT */
2218
+ )) : createCommentVNode("v-if", true)
2219
+ ],
2220
+ 4
2221
+ /* STYLE */
2222
+ )) : vr.row.kind === "group" ? (openBlock(), createElementBlock(
2223
+ "span",
2224
+ _hoisted_21,
2225
+ toDisplayString(_ctx.groupAggText(vr.row, rc)),
2226
+ 1
2227
+ /* TEXT */
2228
+ )) : _ctx.isEditing(vr, rc) ? (openBlock(), createElementBlock(
2229
+ "span",
2230
+ {
2231
+ key: 5,
2232
+ class: "sq-datagrid__editor-wrap",
2233
+ onMousedown: _cache[15] || (_cache[15] = withModifiers(() => {
2234
+ }, ["stop"]))
2235
+ },
2236
+ [
2237
+ _ctx.editorKind(rc) === "select" ? (openBlock(), createElementBlock("select", {
2238
+ key: 0,
2239
+ class: "sq-datagrid__editor",
2240
+ value: String(_ctx.editing?.value ?? ""),
2241
+ onChange: _cache[9] || (_cache[9] = (...args) => _ctx.onEditorInput && _ctx.onEditorInput(...args)),
2242
+ onKeydown: _cache[10] || (_cache[10] = withModifiers((...args) => _ctx.onEditorKey && _ctx.onEditorKey(...args), ["stop"])),
2243
+ onBlur: _cache[11] || (_cache[11] = (...args) => _ctx.commitEdit && _ctx.commitEdit(...args))
2244
+ }, [
2245
+ (openBlock(true), createElementBlock(
2246
+ Fragment,
2247
+ null,
2248
+ renderList(rc.col.cellEditorParams?.values ?? [], (opt) => {
2249
+ return openBlock(), createElementBlock("option", {
2250
+ key: String(opt),
2251
+ value: String(opt)
2252
+ }, toDisplayString(opt), 9, _hoisted_23);
2253
+ }),
2254
+ 128
2255
+ /* KEYED_FRAGMENT */
2256
+ ))
2257
+ ], 40, _hoisted_22)) : (openBlock(), createElementBlock("input", {
2258
+ key: 1,
2259
+ class: "sq-datagrid__editor",
2260
+ type: _ctx.editorKind(rc),
2261
+ value: _ctx.editing?.value ?? "",
2262
+ onInput: _cache[12] || (_cache[12] = (...args) => _ctx.onEditorInput && _ctx.onEditorInput(...args)),
2263
+ onKeydown: _cache[13] || (_cache[13] = withModifiers((...args) => _ctx.onEditorKey && _ctx.onEditorKey(...args), ["stop"])),
2264
+ onBlur: _cache[14] || (_cache[14] = (...args) => _ctx.commitEdit && _ctx.commitEdit(...args))
2265
+ }, null, 40, _hoisted_24))
2266
+ ],
2267
+ 32
2268
+ /* NEED_HYDRATION */
2269
+ )) : renderSlot(_ctx.$slots, `cell-${rc.id}`, mergeProps({ ref_for: true }, _ctx.cellParams(vr.row.data, rc, vr.index)), () => [
2270
+ renderSlot(_ctx.$slots, "cell", mergeProps({ ref_for: true }, _ctx.cellParams(vr.row.data, rc, vr.index)), () => [
2271
+ rc.col.type === "boolean" ? (openBlock(), createElementBlock(
2272
+ "span",
2273
+ {
2274
+ key: 0,
2275
+ class: normalizeClass(["sq-datagrid__bool", { "sq-datagrid__bool--on": !!_ctx.cellValue(rc, vr.row.data) }])
2276
+ },
2277
+ [
2278
+ createVNode(_component_SqIcon, {
2279
+ icon: _ctx.cellValue(rc, vr.row.data) ? "check" : "minus",
2280
+ size: "16px"
2281
+ }, null, 8, ["icon"])
2282
+ ],
2283
+ 2
2284
+ /* CLASS */
2285
+ )) : (openBlock(), createElementBlock(
2286
+ "span",
2287
+ _hoisted_25,
2288
+ toDisplayString(_ctx.formatCell(rc, vr.row.data)),
2289
+ 1
2290
+ /* TEXT */
2291
+ ))
2292
+ ])
2293
+ ], void 0, 6)
2294
+ ], 46, _hoisted_14);
2295
+ }),
2296
+ 128
2297
+ /* KEYED_FRAGMENT */
2298
+ ))
2299
+ ], 46, _hoisted_13);
2300
+ }),
2301
+ 128
2302
+ /* KEYED_FRAGMENT */
2303
+ ))
2304
+ ],
2305
+ 4
2306
+ /* STYLE */
2307
+ ),
2308
+ createCommentVNode(" pinned bottom / totals (sticky) "),
2309
+ _ctx.bottomRows.length ? (openBlock(), createElementBlock("div", _hoisted_26, [
2310
+ (openBlock(true), createElementBlock(
2311
+ Fragment,
2312
+ null,
2313
+ renderList(_ctx.bottomRows, (pr, pi) => {
2314
+ return openBlock(), createElementBlock(
2315
+ "div",
2316
+ {
2317
+ key: "pb" + pi,
2318
+ class: "sq-datagrid__row sq-datagrid__row--pinned",
2319
+ style: normalizeStyle({ height: _ctx.rowHeight + "px" })
2320
+ },
2321
+ [
2322
+ (openBlock(true), createElementBlock(
2323
+ Fragment,
2324
+ null,
2325
+ renderList(_ctx.renderCols, (rc) => {
2326
+ return openBlock(), createElementBlock(
2327
+ "div",
2328
+ {
2329
+ key: rc.key,
2330
+ class: normalizeClass(["sq-datagrid__cell", _ctx.cellAlignClass(rc)]),
2331
+ style: normalizeStyle(rc.style)
2332
+ },
2333
+ [
2334
+ rc.id === "__group" ? (openBlock(), createElementBlock("strong", _hoisted_27, "Total")) : rc.col && !rc.auto ? renderSlot(_ctx.$slots, `cell-${rc.id}`, mergeProps({ ref_for: true }, _ctx.cellParams(pr, rc, -1)), () => [
2335
+ createTextVNode(
2336
+ toDisplayString(_ctx.formatCell(rc, pr)),
2337
+ 1
2338
+ /* TEXT */
2339
+ )
2340
+ ], void 0, 1) : createCommentVNode("v-if", true)
2341
+ ],
2342
+ 6
2343
+ /* CLASS, STYLE */
2344
+ );
2345
+ }),
2346
+ 128
2347
+ /* KEYED_FRAGMENT */
2348
+ ))
2349
+ ],
2350
+ 4
2351
+ /* STYLE */
2352
+ );
2353
+ }),
2354
+ 128
2355
+ /* KEYED_FRAGMENT */
2356
+ ))
2357
+ ])) : createCommentVNode("v-if", true)
2358
+ ],
2359
+ 4
2360
+ /* STYLE */
2361
+ ),
2362
+ _ctx.showLoading ? (openBlock(), createElementBlock("div", _hoisted_28, [
2363
+ renderSlot(_ctx.$slots, "loading", {}, () => [
2364
+ createVNode(_component_SqProgressCircular, {
2365
+ indeterminate: "",
2366
+ size: 28,
2367
+ width: 3
2368
+ })
2369
+ ])
2370
+ ])) : !_ctx.rowCount ? (openBlock(), createElementBlock("div", _hoisted_29, [
2371
+ renderSlot(_ctx.$slots, "no-rows", {}, () => [
2372
+ createVNode(_component_SqEmptyState, {
2373
+ title: _ctx.messages.noData,
2374
+ icon: "search"
2375
+ }, null, 8, ["title"])
2376
+ ])
2377
+ ])) : createCommentVNode("v-if", true)
2378
+ ],
2379
+ 36
2380
+ /* STYLE, NEED_HYDRATION */
2381
+ ),
2382
+ _ctx.statusBar || _ctx.pagination ? (openBlock(), createElementBlock("div", _hoisted_30, [
2383
+ _ctx.statusBar ? (openBlock(), createElementBlock("div", _hoisted_31, [
2384
+ createElementVNode(
2385
+ "span",
2386
+ null,
2387
+ toDisplayString(_ctx.statusText),
2388
+ 1
2389
+ /* TEXT */
2390
+ ),
2391
+ _ctx.selectedIds.length ? (openBlock(), createElementBlock(
2392
+ "span",
2393
+ _hoisted_32,
2394
+ "· " + toDisplayString(_ctx.selectedIds.length) + " selected",
2395
+ 1
2396
+ /* TEXT */
2397
+ )) : createCommentVNode("v-if", true),
2398
+ _ctx.rangeStats ? (openBlock(), createElementBlock(
2399
+ "span",
2400
+ _hoisted_33,
2401
+ "Count " + toDisplayString(_ctx.rangeStats.count) + " · Sum " + toDisplayString(_ctx.fmtNum(_ctx.rangeStats.sum)) + " · Avg " + toDisplayString(_ctx.fmtNum(_ctx.rangeStats.avg)) + " · Min " + toDisplayString(_ctx.fmtNum(_ctx.rangeStats.min)) + " · Max " + toDisplayString(_ctx.fmtNum(_ctx.rangeStats.max)),
2402
+ 1
2403
+ /* TEXT */
2404
+ )) : createCommentVNode("v-if", true)
2405
+ ])) : createCommentVNode("v-if", true),
2406
+ _cache[42] || (_cache[42] = createElementVNode(
2407
+ "span",
2408
+ { class: "sq-spacer" },
2409
+ null,
2410
+ -1
2411
+ /* CACHED */
2412
+ )),
2413
+ _ctx.pagination && !_ctx.isServer ? (openBlock(), createElementBlock(
2414
+ Fragment,
2415
+ { key: 1 },
2416
+ [
2417
+ createElementVNode("span", _hoisted_34, [
2418
+ createTextVNode(
2419
+ toDisplayString(_ctx.messages.rowsPerPage) + " ",
2420
+ 1
2421
+ /* TEXT */
2422
+ ),
2423
+ createElementVNode("select", {
2424
+ class: "sq-datagrid__page-select sq-squircle",
2425
+ value: _ctx.pageSizeState,
2426
+ onChange: _cache[17] || (_cache[17] = (...args) => _ctx.onPageSize && _ctx.onPageSize(...args))
2427
+ }, [
2428
+ (openBlock(true), createElementBlock(
2429
+ Fragment,
2430
+ null,
2431
+ renderList(_ctx.pageSizes, (s) => {
2432
+ return openBlock(), createElementBlock("option", {
2433
+ key: s,
2434
+ value: s
2435
+ }, toDisplayString(s), 9, _hoisted_36);
2436
+ }),
2437
+ 128
2438
+ /* KEYED_FRAGMENT */
2439
+ ))
2440
+ ], 40, _hoisted_35)
2441
+ ]),
2442
+ createElementVNode(
2443
+ "span",
2444
+ _hoisted_37,
2445
+ toDisplayString(_ctx.pageRangeText),
2446
+ 1
2447
+ /* TEXT */
2448
+ ),
2449
+ createVNode(_component_SqPagination, {
2450
+ modelValue: _ctx.page,
2451
+ "onUpdate:modelValue": _cache[18] || (_cache[18] = ($event) => _ctx.page = $event),
2452
+ length: _ctx.pageCount,
2453
+ "total-visible": 5,
2454
+ size: "x-small"
2455
+ }, null, 8, ["modelValue", "length"])
2456
+ ],
2457
+ 64
2458
+ /* STABLE_FRAGMENT */
2459
+ )) : createCommentVNode("v-if", true)
2460
+ ])) : createCommentVNode("v-if", true),
2461
+ createVNode(_component_SqMenu, {
2462
+ modelValue: _ctx.menuOpen,
2463
+ "onUpdate:modelValue": _cache[36] || (_cache[36] = ($event) => _ctx.menuOpen = $event),
2464
+ activator: _ctx.menuAnchor || void 0,
2465
+ "close-on-content-click": false,
2466
+ location: "bottom end",
2467
+ "max-height": 480
2468
+ }, {
2469
+ default: withCtx(() => [
2470
+ _ctx.menuCol ? (openBlock(), createElementBlock("div", _hoisted_38, [
2471
+ _ctx.menuMode === "column" ? (openBlock(), createElementBlock(
2472
+ Fragment,
2473
+ { key: 0 },
2474
+ [
2475
+ _ctx.menuCol.col.sortable !== false ? (openBlock(), createBlock(_component_SqListItem, {
2476
+ key: 0,
2477
+ title: "Sort ascending",
2478
+ "prepend-icon": "arrowUp",
2479
+ link: "",
2480
+ onClick: _cache[19] || (_cache[19] = ($event) => _ctx.setSort(_ctx.menuCol.id, "asc"))
2481
+ })) : createCommentVNode("v-if", true),
2482
+ _ctx.menuCol.col.sortable !== false ? (openBlock(), createBlock(_component_SqListItem, {
2483
+ key: 1,
2484
+ title: "Sort descending",
2485
+ "prepend-icon": "arrowDown",
2486
+ link: "",
2487
+ onClick: _cache[20] || (_cache[20] = ($event) => _ctx.setSort(_ctx.menuCol.id, "desc"))
2488
+ })) : createCommentVNode("v-if", true),
2489
+ _ctx.sortIndex(_ctx.menuCol.id) >= 0 ? (openBlock(), createBlock(_component_SqListItem, {
2490
+ key: 2,
2491
+ title: "Clear sort",
2492
+ "prepend-icon": "sort",
2493
+ link: "",
2494
+ onClick: _cache[21] || (_cache[21] = ($event) => _ctx.setSort(_ctx.menuCol.id, null))
2495
+ })) : createCommentVNode("v-if", true),
2496
+ createVNode(_component_SqDivider),
2497
+ createVNode(_component_SqListItem, {
2498
+ title: _ctx.menuCol.pinned === "left" ? "Unpin" : "Pin left",
2499
+ "prepend-icon": "pin",
2500
+ link: "",
2501
+ onClick: _cache[22] || (_cache[22] = ($event) => _ctx.setPinned(_ctx.menuCol.id, _ctx.menuCol.pinned === "left" ? null : "left"))
2502
+ }, null, 8, ["title"]),
2503
+ _ctx.menuCol.pinned !== "right" ? (openBlock(), createBlock(_component_SqListItem, {
2504
+ key: 3,
2505
+ title: "Pin right",
2506
+ "prepend-icon": "pin",
2507
+ link: "",
2508
+ onClick: _cache[23] || (_cache[23] = ($event) => _ctx.setPinned(_ctx.menuCol.id, "right"))
2509
+ })) : createCommentVNode("v-if", true),
2510
+ createVNode(_component_SqListItem, {
2511
+ title: "Autosize column",
2512
+ "prepend-icon": "columns",
2513
+ link: "",
2514
+ onClick: _cache[24] || (_cache[24] = ($event) => _ctx.autoSize([_ctx.menuCol.id]))
2515
+ }),
2516
+ createVNode(_component_SqListItem, {
2517
+ title: "Autosize all columns",
2518
+ "prepend-icon": "columns",
2519
+ link: "",
2520
+ onClick: _cache[25] || (_cache[25] = ($event) => _ctx.autoSize())
2521
+ }),
2522
+ !_ctx.treeData && !_ctx.isServer ? (openBlock(), createBlock(_component_SqListItem, {
2523
+ key: 4,
2524
+ title: _ctx.groupBy.includes(_ctx.menuCol.id) ? `Ungroup by ${_ctx.menuCol.title}` : `Group by ${_ctx.menuCol.title}`,
2525
+ "prepend-icon": "menu",
2526
+ link: "",
2527
+ onClick: _cache[26] || (_cache[26] = ($event) => _ctx.toggleGroupBy(_ctx.menuCol.id))
2528
+ }, null, 8, ["title"])) : createCommentVNode("v-if", true),
2529
+ createVNode(_component_SqListItem, {
2530
+ title: "Hide column",
2531
+ "prepend-icon": "eyeOff",
2532
+ link: "",
2533
+ onClick: _cache[27] || (_cache[27] = ($event) => {
2534
+ _ctx.setHidden(_ctx.menuCol.id, true);
2535
+ _ctx.menuOpen = false;
2536
+ })
2537
+ }),
2538
+ _ctx.menuCol.col.filter !== false ? (openBlock(), createElementBlock(
2539
+ Fragment,
2540
+ { key: 5 },
2541
+ [
2542
+ createVNode(_component_SqDivider, null, {
2543
+ default: withCtx(() => [..._cache[43] || (_cache[43] = [
2544
+ createTextVNode(
2545
+ "Filter",
2546
+ -1
2547
+ /* CACHED */
2548
+ )
2549
+ ])]),
2550
+ _: 1
2551
+ /* STABLE */
2552
+ }),
2553
+ createVNode(_component_SqGridFilter, {
2554
+ kind: _ctx.filterKind(_ctx.menuCol.col),
2555
+ "model-value": _ctx.filterModelObj[_ctx.menuCol.id],
2556
+ values: _ctx.distinctValues(_ctx.menuCol.id),
2557
+ formatter: _ctx.menuFormatter,
2558
+ "onUpdate:modelValue": _cache[28] || (_cache[28] = ($event) => _ctx.setFilter(_ctx.menuCol.id, $event))
2559
+ }, null, 8, ["kind", "model-value", "values", "formatter"])
2560
+ ],
2561
+ 64
2562
+ /* STABLE_FRAGMENT */
2563
+ )) : createCommentVNode("v-if", true)
2564
+ ],
2565
+ 64
2566
+ /* STABLE_FRAGMENT */
2567
+ )) : (openBlock(), createElementBlock(
2568
+ Fragment,
2569
+ { key: 1 },
2570
+ [
2571
+ createVNode(_component_SqListItem, {
2572
+ title: "Copy",
2573
+ "prepend-icon": "copy",
2574
+ link: "",
2575
+ onClick: _cache[29] || (_cache[29] = ($event) => {
2576
+ _ctx.copy(false);
2577
+ _ctx.menuOpen = false;
2578
+ })
2579
+ }),
2580
+ createVNode(_component_SqListItem, {
2581
+ title: "Copy with headers",
2582
+ "prepend-icon": "copy",
2583
+ link: "",
2584
+ onClick: _cache[30] || (_cache[30] = ($event) => {
2585
+ _ctx.copy(true);
2586
+ _ctx.menuOpen = false;
2587
+ })
2588
+ }),
2589
+ _ctx.canUndo ? (openBlock(), createBlock(_component_SqListItem, {
2590
+ key: 0,
2591
+ title: "Undo",
2592
+ "prepend-icon": "refresh",
2593
+ link: "",
2594
+ onClick: _cache[31] || (_cache[31] = ($event) => {
2595
+ _ctx.undo();
2596
+ _ctx.menuOpen = false;
2597
+ })
2598
+ })) : createCommentVNode("v-if", true),
2599
+ createVNode(_component_SqDivider),
2600
+ createVNode(_component_SqListItem, {
2601
+ title: "Export CSV",
2602
+ "prepend-icon": "download",
2603
+ link: "",
2604
+ onClick: _cache[32] || (_cache[32] = ($event) => {
2605
+ _ctx.exportCsv();
2606
+ _ctx.menuOpen = false;
2607
+ })
2608
+ }),
2609
+ _ctx.selectedIds.length ? (openBlock(), createBlock(_component_SqListItem, {
2610
+ key: 1,
2611
+ title: "Export selected rows",
2612
+ "prepend-icon": "download",
2613
+ link: "",
2614
+ onClick: _cache[33] || (_cache[33] = ($event) => {
2615
+ _ctx.exportCsv({ onlySelected: true });
2616
+ _ctx.menuOpen = false;
2617
+ })
2618
+ })) : createCommentVNode("v-if", true),
2619
+ _ctx.hasGroups ? (openBlock(), createElementBlock(
2620
+ Fragment,
2621
+ { key: 2 },
2622
+ [
2623
+ createVNode(_component_SqDivider),
2624
+ createVNode(_component_SqListItem, {
2625
+ title: "Expand all",
2626
+ "prepend-icon": "plus",
2627
+ link: "",
2628
+ onClick: _cache[34] || (_cache[34] = ($event) => {
2629
+ _ctx.expandAll();
2630
+ _ctx.menuOpen = false;
2631
+ })
2632
+ }),
2633
+ createVNode(_component_SqListItem, {
2634
+ title: "Collapse all",
2635
+ "prepend-icon": "minus",
2636
+ link: "",
2637
+ onClick: _cache[35] || (_cache[35] = ($event) => {
2638
+ _ctx.collapseAll();
2639
+ _ctx.menuOpen = false;
2640
+ })
2641
+ })
2642
+ ],
2643
+ 64
2644
+ /* STABLE_FRAGMENT */
2645
+ )) : createCommentVNode("v-if", true)
2646
+ ],
2647
+ 64
2648
+ /* STABLE_FRAGMENT */
2649
+ ))
2650
+ ])) : createCommentVNode("v-if", true)
2651
+ ]),
2652
+ _: 1
2653
+ /* STABLE */
2654
+ }, 8, ["modelValue", "activator"]),
2655
+ createElementVNode(
2656
+ "div",
2657
+ {
2658
+ ref: "ctxAnchor",
2659
+ class: "sq-datagrid__ctx-anchor",
2660
+ style: normalizeStyle({ left: _ctx.ctxPos.x + "px", top: _ctx.ctxPos.y + "px" })
2661
+ },
2662
+ null,
2663
+ 4
2664
+ /* STYLE */
2665
+ )
2666
+ ], 46, _hoisted_1);
2667
+ }
2668
+ const SqDataGrid = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
2669
+ const componentNames = ["SqDataGrid"];
2670
+ export {
2671
+ SqDataGrid,
2672
+ aggregate,
2673
+ allGroupIds,
2674
+ colIdOf,
2675
+ componentNames,
2676
+ SqDataGrid as default,
2677
+ filterKindOf,
2678
+ filterRows,
2679
+ flatten,
2680
+ groupRows,
2681
+ makeGetter,
2682
+ matchCondition,
2683
+ parseTsv,
2684
+ pivotRows,
2685
+ rowLayout,
2686
+ sortIndices,
2687
+ toCsv,
2688
+ treeRows
2689
+ };
2690
+ //# sourceMappingURL=index.mjs.map