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