velox-grid 0.11.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +483 -0
  2. package/README.md +755 -0
  3. package/dist/react/index.esm.js +3757 -0
  4. package/dist/react/index.esm.js.map +1 -0
  5. package/dist/react/index.js +7 -0
  6. package/dist/react/index.js.map +1 -0
  7. package/dist/react/react/VeloxGridReact.d.ts +33 -0
  8. package/dist/react/react/VeloxGridReact.d.ts.map +1 -0
  9. package/dist/react/react/index.d.ts +9 -0
  10. package/dist/react/react/index.d.ts.map +1 -0
  11. package/dist/react/react/types.d.ts +52 -0
  12. package/dist/react/react/types.d.ts.map +1 -0
  13. package/dist/react/react/useVeloxGrid.d.ts +23 -0
  14. package/dist/react/react/useVeloxGrid.d.ts.map +1 -0
  15. package/dist/react/types/index.d.ts +878 -0
  16. package/dist/react/types/index.d.ts.map +1 -0
  17. package/dist/types/core/GridColumnMenu.d.ts +35 -0
  18. package/dist/types/core/GridColumnMenu.d.ts.map +1 -0
  19. package/dist/types/core/GridDragManager.d.ts +83 -0
  20. package/dist/types/core/GridDragManager.d.ts.map +1 -0
  21. package/dist/types/core/GridEditorFactory.d.ts +33 -0
  22. package/dist/types/core/GridEditorFactory.d.ts.map +1 -0
  23. package/dist/types/core/GridFilterPopup.d.ts +43 -0
  24. package/dist/types/core/GridFilterPopup.d.ts.map +1 -0
  25. package/dist/types/core/GridHistory.d.ts +84 -0
  26. package/dist/types/core/GridHistory.d.ts.map +1 -0
  27. package/dist/types/core/GridRenderer.d.ts +73 -0
  28. package/dist/types/core/GridRenderer.d.ts.map +1 -0
  29. package/dist/types/core/GridSummary.d.ts +98 -0
  30. package/dist/types/core/GridSummary.d.ts.map +1 -0
  31. package/dist/types/core/GridTooltip.d.ts +43 -0
  32. package/dist/types/core/GridTooltip.d.ts.map +1 -0
  33. package/dist/types/core/GridValidator.d.ts +63 -0
  34. package/dist/types/core/GridValidator.d.ts.map +1 -0
  35. package/dist/types/core/VeloxGrid.d.ts +437 -0
  36. package/dist/types/core/VeloxGrid.d.ts.map +1 -0
  37. package/dist/types/core/index.d.ts +15 -0
  38. package/dist/types/core/index.d.ts.map +1 -0
  39. package/dist/types/index.d.ts +16 -0
  40. package/dist/types/index.d.ts.map +1 -0
  41. package/dist/types/react/VeloxGridReact.d.ts +40 -0
  42. package/dist/types/react/VeloxGridReact.d.ts.map +1 -0
  43. package/dist/types/react/index.d.ts +9 -0
  44. package/dist/types/react/index.d.ts.map +1 -0
  45. package/dist/types/react/types.d.ts +55 -0
  46. package/dist/types/react/types.d.ts.map +1 -0
  47. package/dist/types/react/useVeloxGrid.d.ts +54 -0
  48. package/dist/types/react/useVeloxGrid.d.ts.map +1 -0
  49. package/dist/types/types/index.d.ts +878 -0
  50. package/dist/types/types/index.d.ts.map +1 -0
  51. package/dist/types/utils/data.d.ts +41 -0
  52. package/dist/types/utils/data.d.ts.map +1 -0
  53. package/dist/types/utils/dom.d.ts +13 -0
  54. package/dist/types/utils/dom.d.ts.map +1 -0
  55. package/dist/types/utils/export.d.ts +60 -0
  56. package/dist/types/utils/export.d.ts.map +1 -0
  57. package/dist/types/utils/index.d.ts +4 -0
  58. package/dist/types/utils/index.d.ts.map +1 -0
  59. package/dist/types/vue/index.d.ts +9 -0
  60. package/dist/types/vue/index.d.ts.map +1 -0
  61. package/dist/types/vue/types.d.ts +68 -0
  62. package/dist/types/vue/types.d.ts.map +1 -0
  63. package/dist/types/vue/useVeloxGrid.d.ts +49 -0
  64. package/dist/types/vue/useVeloxGrid.d.ts.map +1 -0
  65. package/dist/velox-grid.css +1 -0
  66. package/dist/velox-grid.esm.js +3387 -0
  67. package/dist/velox-grid.esm.js.map +1 -0
  68. package/dist/velox-grid.iife.js +14 -0
  69. package/dist/velox-grid.iife.js.map +1 -0
  70. package/dist/velox-grid.js +14 -0
  71. package/dist/velox-grid.js.map +1 -0
  72. package/dist/vue/index.esm.js +3754 -0
  73. package/dist/vue/index.esm.js.map +1 -0
  74. package/dist/vue/index.js +7 -0
  75. package/dist/vue/index.js.map +1 -0
  76. package/dist/vue/types/index.d.ts +878 -0
  77. package/dist/vue/types/index.d.ts.map +1 -0
  78. package/dist/vue/vue/index.d.ts +9 -0
  79. package/dist/vue/vue/index.d.ts.map +1 -0
  80. package/dist/vue/vue/types.d.ts +65 -0
  81. package/dist/vue/vue/types.d.ts.map +1 -0
  82. package/dist/vue/vue/useVeloxGrid.d.ts +21 -0
  83. package/dist/vue/vue/useVeloxGrid.d.ts.map +1 -0
  84. package/package.json +120 -0
@@ -0,0 +1,3754 @@
1
+ import { defineComponent as mt, ref as P, onMounted as _, onUnmounted as W, watch as O, openBlock as gt, createElementBlock as Ct, normalizeClass as xt } from "vue";
2
+ function p(c, e, i) {
3
+ const s = document.createElement(c);
4
+ return e && (s.className = e), s;
5
+ }
6
+ function w(c, ...e) {
7
+ c.classList.add(...e);
8
+ }
9
+ function k(c, ...e) {
10
+ c.classList.remove(...e);
11
+ }
12
+ function yt(c, e) {
13
+ let i = !1;
14
+ return function(...s) {
15
+ i || (c.apply(this, s), i = !0, setTimeout(() => i = !1, e));
16
+ };
17
+ }
18
+ function vt(c = "velox") {
19
+ return `${c}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
20
+ }
21
+ function H(c, e = "text") {
22
+ if (c == null)
23
+ return "";
24
+ switch (e) {
25
+ case "number":
26
+ return typeof c == "number" ? c.toLocaleString() : String(c);
27
+ case "boolean":
28
+ return c ? "Yes" : "No";
29
+ case "date":
30
+ return c instanceof Date ? c.toLocaleDateString() : String(c);
31
+ case "datetime":
32
+ return c instanceof Date ? c.toLocaleString() : String(c);
33
+ case "text":
34
+ default:
35
+ return String(c);
36
+ }
37
+ }
38
+ function wt(c, e, i = "text") {
39
+ if (c == null) return e == null ? 0 : -1;
40
+ if (e == null) return 1;
41
+ switch (i) {
42
+ case "number":
43
+ return c - e;
44
+ case "boolean":
45
+ return c === e ? 0 : c ? 1 : -1;
46
+ case "date":
47
+ case "datetime":
48
+ const s = c instanceof Date ? c : new Date(c), o = e instanceof Date ? e : new Date(e);
49
+ return s.getTime() - o.getTime();
50
+ case "text":
51
+ default:
52
+ return String(c).localeCompare(String(e));
53
+ }
54
+ }
55
+ function V(c, e, i) {
56
+ return e.length ? [...c].sort((s, o) => {
57
+ for (const { field: n, direction: t } of e) {
58
+ if (!t) continue;
59
+ const l = i[n] || "text", a = wt(s[n], o[n], l);
60
+ if (a !== 0)
61
+ return t === "asc" ? a : -a;
62
+ }
63
+ return 0;
64
+ }) : c;
65
+ }
66
+ function bt(c, e) {
67
+ const { operator: i, value: s, value2: o } = e;
68
+ if (i === "isEmpty")
69
+ return c == null || c === "";
70
+ if (i === "isNotEmpty")
71
+ return c != null && c !== "";
72
+ const n = String(c ?? "").toLowerCase(), t = String(s ?? "").toLowerCase();
73
+ switch (i) {
74
+ case "equals":
75
+ return n === t;
76
+ case "notEquals":
77
+ return n !== t;
78
+ case "contains":
79
+ return n.includes(t);
80
+ case "notContains":
81
+ return !n.includes(t);
82
+ case "startsWith":
83
+ return n.startsWith(t);
84
+ case "endsWith":
85
+ return n.endsWith(t);
86
+ case "greaterThan":
87
+ return Number(c) > Number(s);
88
+ case "lessThan":
89
+ return Number(c) < Number(s);
90
+ case "greaterThanOrEqual":
91
+ return Number(c) >= Number(s);
92
+ case "lessThanOrEqual":
93
+ return Number(c) <= Number(s);
94
+ case "between":
95
+ const l = Number(c);
96
+ return l >= Number(s) && l <= Number(o);
97
+ default:
98
+ return !0;
99
+ }
100
+ }
101
+ function A(c, e) {
102
+ if (!e || !e.conditions.length)
103
+ return c;
104
+ const { conditions: i, logic: s } = e;
105
+ return c.filter((o) => {
106
+ const n = i.map(
107
+ (t) => bt(o[t.field], t)
108
+ );
109
+ return s === "and" ? n.every(Boolean) : n.some(Boolean);
110
+ });
111
+ }
112
+ function K(c) {
113
+ const { data: e, displayData: i, columns: s, selectedRows: o, options: n } = c, t = n.columns ? s.filter((r) => n.columns.includes(r.field) && r.visible !== !1) : s.filter((r) => r.visible !== !1);
114
+ let l;
115
+ if (n.selectedOnly && o.length > 0) {
116
+ const r = n.filteredOnly ? i : e;
117
+ l = o.map((h) => r[h]).filter(Boolean);
118
+ } else n.filteredOnly ? l = i : l = e;
119
+ const a = [];
120
+ if (n.includeHeader !== !1) {
121
+ const r = t.map((h) => z(h.header));
122
+ a.push(r.join(","));
123
+ }
124
+ return l.forEach((r) => {
125
+ const h = t.map((g) => {
126
+ const d = r[g.field];
127
+ return z(kt(d, g.type));
128
+ });
129
+ a.push(h.join(","));
130
+ }), a.join(`\r
131
+ `);
132
+ }
133
+ function z(c) {
134
+ if (c == null) return "";
135
+ const e = String(c);
136
+ return e.includes(",") || e.includes('"') || e.includes(`
137
+ `) || e.includes("\r") ? `"${e.replace(/"/g, '""')}"` : e;
138
+ }
139
+ function q(c) {
140
+ const { data: e, displayData: i, columns: s, selectedRows: o, options: n } = c, t = n.columns ? s.filter((r) => n.columns.includes(r.field) && r.visible !== !1) : s.filter((r) => r.visible !== !1);
141
+ let l;
142
+ if (n.selectedOnly && o.length > 0) {
143
+ const r = n.filteredOnly ? i : e;
144
+ l = o.map((h) => r[h]).filter(Boolean);
145
+ } else n.filteredOnly ? l = i : l = e;
146
+ const a = l.map((r) => {
147
+ const h = {};
148
+ return t.forEach((g) => {
149
+ h[g.field] = r[g.field];
150
+ }), h;
151
+ });
152
+ return JSON.stringify(a, null, 2);
153
+ }
154
+ function U() {
155
+ return typeof window.XLSX < "u";
156
+ }
157
+ function j() {
158
+ const c = window.XLSX;
159
+ if (!c)
160
+ throw new Error(
161
+ 'SheetJS (xlsx) library is not loaded. Please include it via CDN: <script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"><\/script>'
162
+ );
163
+ return c;
164
+ }
165
+ function St(c) {
166
+ const e = j(), { data: i, displayData: s, columns: o, selectedRows: n, options: t } = c, l = t.columns ? o.filter((x) => t.columns.includes(x.field) && x.visible !== !1) : o.filter((x) => x.visible !== !1);
167
+ let a;
168
+ if (t.selectedOnly && n.length > 0) {
169
+ const x = t.filteredOnly ? s : i;
170
+ a = n.map((b) => x[b]).filter(Boolean);
171
+ } else t.filteredOnly ? a = s : a = i;
172
+ const r = [];
173
+ t.includeHeader !== !1 && r.push(l.map((x) => x.header)), a.forEach((x) => {
174
+ const b = l.map((y) => {
175
+ const S = x[y.field];
176
+ return Et(S, y.type);
177
+ });
178
+ r.push(b);
179
+ });
180
+ const h = e.utils.aoa_to_sheet(r), g = l.map((x) => ({
181
+ wch: Math.max(
182
+ x.header.length,
183
+ ...a.slice(0, 100).map((b) => {
184
+ const y = b[x.field];
185
+ return String(y ?? "").length;
186
+ })
187
+ ) + 2
188
+ }));
189
+ h["!cols"] = g;
190
+ const d = e.utils.book_new(), f = t.sheetName || "Sheet1";
191
+ e.utils.book_append_sheet(d, h, f);
192
+ const C = (t.filename || "export") + ".xlsx";
193
+ e.writeFile(d, C);
194
+ }
195
+ function Et(c, e) {
196
+ if (c == null) return "";
197
+ switch (e) {
198
+ case "number":
199
+ return typeof c == "number" ? c : parseFloat(String(c)) || 0;
200
+ case "boolean":
201
+ return !!c;
202
+ case "date":
203
+ case "datetime":
204
+ if (c instanceof Date) return c;
205
+ if (typeof c == "string" || typeof c == "number") {
206
+ const i = new Date(c);
207
+ return isNaN(i.getTime()) ? String(c) : i;
208
+ }
209
+ return String(c);
210
+ default:
211
+ return String(c);
212
+ }
213
+ }
214
+ function kt(c, e) {
215
+ if (c == null) return "";
216
+ switch (e) {
217
+ case "date":
218
+ return c instanceof Date ? c.toISOString().split("T")[0] : String(c);
219
+ case "datetime":
220
+ return c instanceof Date ? c.toISOString() : String(c);
221
+ default:
222
+ return String(c);
223
+ }
224
+ }
225
+ function Rt(c, e = !0) {
226
+ var s;
227
+ const i = {
228
+ data: [],
229
+ headers: [],
230
+ errors: []
231
+ };
232
+ try {
233
+ const o = Dt(c);
234
+ if (o.length === 0)
235
+ return i.errors.push("CSV file is empty"), i;
236
+ let n = 0;
237
+ if (e)
238
+ i.headers = o[0], n = 1;
239
+ else {
240
+ const t = ((s = o[0]) == null ? void 0 : s.length) || 0;
241
+ i.headers = Array.from({ length: t }, (l, a) => `Column${a + 1}`);
242
+ }
243
+ for (let t = n; t < o.length; t++) {
244
+ const l = o[t], a = {};
245
+ i.headers.forEach((r, h) => {
246
+ a[r] = l[h] ?? "";
247
+ }), i.data.push(a);
248
+ }
249
+ } catch (o) {
250
+ i.errors.push(`CSV parsing error: ${o instanceof Error ? o.message : "Unknown error"}`);
251
+ }
252
+ return i;
253
+ }
254
+ function Dt(c) {
255
+ const e = [];
256
+ let i = [], s = "", o = !1;
257
+ for (let n = 0; n < c.length; n++) {
258
+ const t = c[n], l = c[n + 1];
259
+ if (o)
260
+ t === '"' ? l === '"' ? (s += '"', n++) : o = !1 : s += t;
261
+ else if (t === '"')
262
+ o = !0;
263
+ else if (t === ",")
264
+ i.push(s), s = "";
265
+ else {
266
+ if (t === "\r")
267
+ continue;
268
+ t === `
269
+ ` ? (i.push(s), i.some((a) => a.trim() !== "") && e.push(i), i = [], s = "") : s += t;
270
+ }
271
+ }
272
+ return (s !== "" || i.length > 0) && (i.push(s), i.some((n) => n.trim() !== "") && e.push(i)), e;
273
+ }
274
+ function Lt(c, e = 0) {
275
+ return new Promise((i) => {
276
+ const s = {
277
+ data: [],
278
+ headers: [],
279
+ errors: []
280
+ };
281
+ if (!U()) {
282
+ s.errors.push(
283
+ 'SheetJS (xlsx) library is not loaded. Please include it via CDN: <script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"><\/script>'
284
+ ), i(s);
285
+ return;
286
+ }
287
+ const o = j(), n = new FileReader();
288
+ n.onload = (t) => {
289
+ var l;
290
+ try {
291
+ const a = (l = t.target) == null ? void 0 : l.result, r = o.read(a, { type: "array" }), h = r.SheetNames;
292
+ if (e >= h.length) {
293
+ s.errors.push(`Sheet index ${e} not found. Available sheets: ${h.join(", ")}`), i(s);
294
+ return;
295
+ }
296
+ const g = h[e], d = r.Sheets[g], f = o.utils.sheet_to_json(d, { header: 1 });
297
+ if (f.length === 0) {
298
+ s.errors.push("Excel sheet is empty"), i(s);
299
+ return;
300
+ }
301
+ s.headers = f[0].map((C) => String(C ?? ""));
302
+ for (let C = 1; C < f.length; C++) {
303
+ const x = {}, b = f[C];
304
+ s.headers.forEach((y, S) => {
305
+ const E = b[S];
306
+ x[y] = E ?? "";
307
+ }), Object.values(x).some((y) => y !== "") && s.data.push(x);
308
+ }
309
+ i(s);
310
+ } catch (a) {
311
+ s.errors.push(`Excel parsing error: ${a instanceof Error ? a.message : "Unknown error"}`), i(s);
312
+ }
313
+ }, n.onerror = () => {
314
+ s.errors.push("Failed to read file"), i(s);
315
+ }, n.readAsArrayBuffer(c);
316
+ });
317
+ }
318
+ function X(c, e, i = "text/plain") {
319
+ const s = c instanceof Blob ? c : new Blob([c], { type: i }), o = URL.createObjectURL(s), n = document.createElement("a");
320
+ n.href = o, n.download = e, n.style.display = "none", document.body.appendChild(n), n.click(), document.body.removeChild(n), URL.revokeObjectURL(o);
321
+ }
322
+ function Tt(c) {
323
+ const e = K(c), i = (c.options.filename || "export") + ".csv";
324
+ X(e, i, "text/csv;charset=utf-8");
325
+ }
326
+ function Bt(c) {
327
+ const e = q(c), i = (c.options.filename || "export") + ".json";
328
+ X(e, i, "application/json");
329
+ }
330
+ const Mt = {
331
+ enabled: !0,
332
+ maxSize: 50
333
+ };
334
+ class Pt {
335
+ constructor(e = {}) {
336
+ this.undoStack = [], this.redoStack = [], this.options = { ...Mt, ...e };
337
+ }
338
+ /**
339
+ * Check if history tracking is enabled
340
+ */
341
+ isEnabled() {
342
+ return this.options.enabled;
343
+ }
344
+ /**
345
+ * Set enabled state
346
+ */
347
+ setEnabled(e) {
348
+ this.options.enabled = e;
349
+ }
350
+ /**
351
+ * Set maximum stack size
352
+ */
353
+ setMaxSize(e) {
354
+ this.options.maxSize = e, this.trimStack();
355
+ }
356
+ /**
357
+ * Push an action to the undo stack
358
+ */
359
+ push(e) {
360
+ this.options.enabled && (this.undoStack.push(e), this.trimStack(), this.redoStack = []);
361
+ }
362
+ /**
363
+ * Create and push a cell edit action
364
+ */
365
+ pushCellEdit(e, i, s, o) {
366
+ this.push({
367
+ type: "cell_edit",
368
+ timestamp: Date.now(),
369
+ data: { rowIndex: e, field: i, oldValue: s, newValue: o }
370
+ });
371
+ }
372
+ /**
373
+ * Create and push a bulk edit action (paste, cut, delete)
374
+ */
375
+ pushBulkEdit(e, i) {
376
+ i.length !== 0 && this.push({
377
+ type: e,
378
+ timestamp: Date.now(),
379
+ data: { changes: i }
380
+ });
381
+ }
382
+ /**
383
+ * Create and push a row add action
384
+ */
385
+ pushRowAdd(e, i) {
386
+ this.push({
387
+ type: "row_add",
388
+ timestamp: Date.now(),
389
+ data: { row: { ...e }, index: i }
390
+ });
391
+ }
392
+ /**
393
+ * Create and push a row remove action
394
+ */
395
+ pushRowRemove(e, i) {
396
+ this.push({
397
+ type: "row_remove",
398
+ timestamp: Date.now(),
399
+ data: { row: { ...e }, index: i }
400
+ });
401
+ }
402
+ /**
403
+ * Pop from undo stack and push to redo stack
404
+ * Returns the action to be undone
405
+ */
406
+ popUndo() {
407
+ if (!this.options.enabled || this.undoStack.length === 0)
408
+ return null;
409
+ const e = this.undoStack.pop();
410
+ return this.redoStack.push(e), e;
411
+ }
412
+ /**
413
+ * Pop from redo stack and push to undo stack
414
+ * Returns the action to be redone
415
+ */
416
+ popRedo() {
417
+ if (!this.options.enabled || this.redoStack.length === 0)
418
+ return null;
419
+ const e = this.redoStack.pop();
420
+ return this.undoStack.push(e), e;
421
+ }
422
+ /**
423
+ * Check if undo is available
424
+ */
425
+ canUndo() {
426
+ return this.options.enabled && this.undoStack.length > 0;
427
+ }
428
+ /**
429
+ * Check if redo is available
430
+ */
431
+ canRedo() {
432
+ return this.options.enabled && this.redoStack.length > 0;
433
+ }
434
+ /**
435
+ * Get undo stack size
436
+ */
437
+ getUndoCount() {
438
+ return this.undoStack.length;
439
+ }
440
+ /**
441
+ * Get redo stack size
442
+ */
443
+ getRedoCount() {
444
+ return this.redoStack.length;
445
+ }
446
+ /**
447
+ * Clear all history
448
+ */
449
+ clear() {
450
+ this.undoStack = [], this.redoStack = [];
451
+ }
452
+ /**
453
+ * Trim undo stack to max size
454
+ */
455
+ trimStack() {
456
+ for (; this.undoStack.length > this.options.maxSize; )
457
+ this.undoStack.shift();
458
+ }
459
+ }
460
+ class Ht {
461
+ /**
462
+ * 단일 값에 대한 유효성 검사
463
+ * @param value - 검사할 값
464
+ * @param rules - 유효성 규칙 배열
465
+ * @param row - 전체 행 데이터 (custom validator용)
466
+ * @returns 검사 결과
467
+ */
468
+ static validate(e, i, s) {
469
+ const o = [];
470
+ for (const n of i) {
471
+ const t = this.validateRule(e, n, s);
472
+ t && o.push({ field: "", message: t });
473
+ }
474
+ return {
475
+ valid: o.length === 0,
476
+ errors: o
477
+ };
478
+ }
479
+ /**
480
+ * 단일 규칙 검사
481
+ * @param value - 검사할 값
482
+ * @param rule - 유효성 규칙
483
+ * @param row - 전체 행 데이터
484
+ * @returns 에러 메시지 또는 null
485
+ */
486
+ static validateRule(e, i, s) {
487
+ switch (i.type) {
488
+ case "required":
489
+ return this.validateRequired(e) ? null : i.message;
490
+ case "min":
491
+ return this.validateMin(e, i.value) ? null : i.message;
492
+ case "max":
493
+ return this.validateMax(e, i.value) ? null : i.message;
494
+ case "minLength":
495
+ return this.validateMinLength(e, i.value) ? null : i.message;
496
+ case "maxLength":
497
+ return this.validateMaxLength(e, i.value) ? null : i.message;
498
+ case "pattern":
499
+ return this.validatePattern(e, i.value) ? null : i.message;
500
+ case "custom":
501
+ if (i.validator) {
502
+ const o = i.validator(e, s || {});
503
+ return typeof o == "boolean" ? o ? null : i.message : o || null;
504
+ }
505
+ return null;
506
+ default:
507
+ return null;
508
+ }
509
+ }
510
+ /**
511
+ * Required 검사 - null, undefined, 빈 문자열 체크
512
+ */
513
+ static validateRequired(e) {
514
+ return !(e == null || typeof e == "string" && e.trim() === "");
515
+ }
516
+ /**
517
+ * Min 검사 - 숫자 최소값
518
+ */
519
+ static validateMin(e, i) {
520
+ if (e == null)
521
+ return !0;
522
+ const s = typeof e == "number" ? e : parseFloat(String(e));
523
+ return !isNaN(s) && s >= i;
524
+ }
525
+ /**
526
+ * Max 검사 - 숫자 최대값
527
+ */
528
+ static validateMax(e, i) {
529
+ if (e == null)
530
+ return !0;
531
+ const s = typeof e == "number" ? e : parseFloat(String(e));
532
+ return !isNaN(s) && s <= i;
533
+ }
534
+ /**
535
+ * MinLength 검사 - 문자열 최소 길이
536
+ */
537
+ static validateMinLength(e, i) {
538
+ return e == null ? !0 : String(e).length >= i;
539
+ }
540
+ /**
541
+ * MaxLength 검사 - 문자열 최대 길이
542
+ */
543
+ static validateMaxLength(e, i) {
544
+ return e == null ? !0 : String(e).length <= i;
545
+ }
546
+ /**
547
+ * Pattern 검사 - 정규식 매칭
548
+ */
549
+ static validatePattern(e, i) {
550
+ return e == null ? !0 : (typeof i == "string" ? new RegExp(i) : i).test(String(e));
551
+ }
552
+ /**
553
+ * 전체 행 유효성 검사
554
+ * @param row - 검사할 행 데이터
555
+ * @param columns - 컬럼 정의 (validation 규칙 포함)
556
+ * @returns 검사 결과
557
+ */
558
+ static validateRow(e, i) {
559
+ const s = [];
560
+ for (const o of i)
561
+ if (o.validation && o.validation.length > 0) {
562
+ const n = e[o.field], t = this.validate(n, o.validation, e);
563
+ if (!t.valid)
564
+ for (const l of t.errors)
565
+ s.push({
566
+ field: o.field,
567
+ message: l.message
568
+ });
569
+ }
570
+ return {
571
+ valid: s.length === 0,
572
+ errors: s
573
+ };
574
+ }
575
+ /**
576
+ * 전체 데이터 유효성 검사
577
+ * @param data - 검사할 데이터 배열
578
+ * @param columns - 컬럼 정의
579
+ * @returns 행별 검사 결과 배열
580
+ */
581
+ static validateAll(e, i) {
582
+ return e.map((s) => this.validateRow(s, i));
583
+ }
584
+ }
585
+ class Ft {
586
+ /**
587
+ * Create an editor element based on type
588
+ */
589
+ static createEditor(e, i, s, o, n) {
590
+ const { type: t } = i;
591
+ switch (t) {
592
+ case "text":
593
+ case "number":
594
+ return this.createTextEditor(e, i, s, o, n);
595
+ case "select":
596
+ return this.createSelectEditor(e, i, s, o, n);
597
+ case "date":
598
+ return this.createDateEditor(e, i, s, o, n);
599
+ case "checkbox":
600
+ return this.createCheckboxEditor(e, i, s, o, n);
601
+ case "custom":
602
+ return this.createCustomEditor(e, i, s, o, n);
603
+ default:
604
+ return this.createTextEditor(e, i, s, o, n);
605
+ }
606
+ }
607
+ /**
608
+ * Create text/number input editor
609
+ */
610
+ static createTextEditor(e, i, s, o, n) {
611
+ const t = document.createElement("input");
612
+ return t.className = "velox-edit-input", t.type = i.type === "number" ? "number" : "text", t.value = e != null ? String(e) : "", i.placeholder && (t.placeholder = i.placeholder), i.type === "number" && (i.min !== void 0 && (t.min = String(i.min)), i.max !== void 0 && (t.max = String(i.max)), i.step !== void 0 && (t.step = String(i.step))), t.addEventListener("blur", () => {
613
+ const l = i.type === "number" ? parseFloat(t.value) : t.value;
614
+ s(l);
615
+ }), t.addEventListener("keydown", (l) => {
616
+ if (l.key === "Enter") {
617
+ l.preventDefault(), l.stopPropagation();
618
+ const a = i.type === "number" ? parseFloat(t.value) : t.value;
619
+ s(a), n && n(l.shiftKey ? "up" : "down");
620
+ } else if (l.key === "Tab") {
621
+ l.preventDefault(), l.stopPropagation();
622
+ const a = i.type === "number" ? parseFloat(t.value) : t.value;
623
+ s(a), n && n(l.shiftKey ? "left" : "right");
624
+ } else l.key === "Escape" && (l.preventDefault(), l.stopPropagation(), o());
625
+ }), t;
626
+ }
627
+ /**
628
+ * Create select dropdown editor
629
+ */
630
+ static createSelectEditor(e, i, s, o, n) {
631
+ const t = document.createElement("select");
632
+ return t.className = "velox-edit-select", i.options && i.options.length > 0 && i.options.forEach((l) => {
633
+ const a = document.createElement("option");
634
+ a.value = String(l.value ?? ""), a.textContent = l.label, l.value === e && (a.selected = !0), t.appendChild(a);
635
+ }), t.addEventListener("change", () => {
636
+ console.log("📦 Select change event", t.value), s(t.value);
637
+ }), t.addEventListener("keydown", (l) => {
638
+ l.key === "Enter" ? (l.preventDefault(), l.stopPropagation(), s(t.value), n && n(l.shiftKey ? "up" : "down")) : l.key === "Tab" ? (l.preventDefault(), l.stopPropagation(), s(t.value), n && n(l.shiftKey ? "left" : "right")) : l.key === "Escape" && (l.preventDefault(), l.stopPropagation(), o());
639
+ }), t;
640
+ }
641
+ /**
642
+ * Create date input editor
643
+ */
644
+ static createDateEditor(e, i, s, o, n) {
645
+ const t = document.createElement("input");
646
+ if (t.className = "velox-edit-input velox-edit-date", t.type = "date", e instanceof Date)
647
+ t.value = e.toISOString().split("T")[0];
648
+ else if (typeof e == "string" && e) {
649
+ const l = new Date(e);
650
+ isNaN(l.getTime()) || (t.value = l.toISOString().split("T")[0]);
651
+ }
652
+ return t.addEventListener("blur", () => {
653
+ s(t.value ? new Date(t.value) : null);
654
+ }), t.addEventListener("keydown", (l) => {
655
+ l.key === "Enter" ? (l.preventDefault(), l.stopPropagation(), s(t.value ? new Date(t.value) : null), n && n(l.shiftKey ? "up" : "down")) : l.key === "Tab" ? (l.preventDefault(), l.stopPropagation(), s(t.value ? new Date(t.value) : null), n && n(l.shiftKey ? "left" : "right")) : l.key === "Escape" && (l.preventDefault(), l.stopPropagation(), o());
656
+ }), t;
657
+ }
658
+ /**
659
+ * Create checkbox editor
660
+ */
661
+ static createCheckboxEditor(e, i, s, o, n) {
662
+ const t = document.createElement("div");
663
+ t.className = "velox-edit-checkbox-container";
664
+ const l = document.createElement("input");
665
+ return l.className = "velox-edit-checkbox", l.type = "checkbox", l.checked = !!e, t.appendChild(l), l.addEventListener("change", () => {
666
+ console.log("📦 Checkbox change event", l.checked), s(l.checked);
667
+ }), l.addEventListener("keydown", (a) => {
668
+ a.key === "Enter" || a.key === " " ? (a.preventDefault(), a.stopPropagation(), l.checked = !l.checked, s(l.checked), a.key === "Enter" && n && n(a.shiftKey ? "up" : "down")) : a.key === "Tab" ? (a.preventDefault(), a.stopPropagation(), s(l.checked), n && n(a.shiftKey ? "left" : "right")) : a.key === "Escape" && (a.preventDefault(), a.stopPropagation(), o());
669
+ }), t;
670
+ }
671
+ /**
672
+ * Create custom editor using renderer function
673
+ */
674
+ static createCustomEditor(e, i, s, o, n) {
675
+ const t = document.createElement("div");
676
+ if (t.className = "velox-edit-custom", i.renderer)
677
+ i.renderer(t, e, s, o);
678
+ else
679
+ return this.createTextEditor(e, { type: "text" }, s, o, n);
680
+ return t;
681
+ }
682
+ }
683
+ class Ot {
684
+ // ms
685
+ constructor(e) {
686
+ this.container = e, this.tooltip = null, this.currentCell = null, this.hideTimeout = null, this.HIDE_DELAY = 100, this.createTooltipElement();
687
+ }
688
+ /**
689
+ * Create tooltip element
690
+ */
691
+ createTooltipElement() {
692
+ this.tooltip = document.createElement("div"), this.tooltip.className = "velox-tooltip", this.tooltip.style.display = "none", this.tooltip.style.position = "absolute", this.tooltip.style.pointerEvents = "none", this.container.appendChild(this.tooltip);
693
+ }
694
+ /**
695
+ * Show tooltip for a cell
696
+ */
697
+ show(e, i, s, o) {
698
+ this.hideTimeout && (clearTimeout(this.hideTimeout), this.hideTimeout = null), this.currentCell = e;
699
+ let n = null;
700
+ if (o.tooltip === !0 ? n = this.getAutoTooltipContent(e, i) : typeof o.tooltip == "function" && (n = o.tooltip(i, s)), !n || !this.tooltip) {
701
+ this.hide();
702
+ return;
703
+ }
704
+ this.tooltip.textContent = n, this.tooltip.style.display = "block", this.positionTooltip(e);
705
+ }
706
+ /**
707
+ * Get auto tooltip content for truncated text
708
+ */
709
+ getAutoTooltipContent(e, i) {
710
+ const s = e.querySelector(".velox-cell-content");
711
+ return s && (s.scrollWidth > s.clientWidth || s.scrollHeight > s.clientHeight) ? String(i ?? "") : null;
712
+ }
713
+ /**
714
+ * Position tooltip relative to cell
715
+ */
716
+ positionTooltip(e) {
717
+ if (!this.tooltip) return;
718
+ const i = e.getBoundingClientRect(), s = this.container.getBoundingClientRect(), o = this.tooltip.getBoundingClientRect();
719
+ let n = i.bottom - s.top + 5, t = i.left - s.left;
720
+ const l = window.innerWidth, a = window.innerHeight;
721
+ i.left + o.width > l && (t = i.right - s.left - o.width), i.bottom + o.height + 5 > a && (n = i.top - s.top - o.height - 5), this.tooltip.style.top = `${n}px`, this.tooltip.style.left = `${t}px`;
722
+ }
723
+ /**
724
+ * Hide tooltip
725
+ */
726
+ hide() {
727
+ this.hideTimeout && clearTimeout(this.hideTimeout), this.hideTimeout = window.setTimeout(() => {
728
+ this.tooltip && (this.tooltip.style.display = "none", this.tooltip.textContent = ""), this.currentCell = null, this.hideTimeout = null;
729
+ }, this.HIDE_DELAY);
730
+ }
731
+ /**
732
+ * Update tooltip position (for scroll events)
733
+ */
734
+ update() {
735
+ this.currentCell && this.tooltip && this.tooltip.style.display !== "none" && this.positionTooltip(this.currentCell);
736
+ }
737
+ /**
738
+ * Destroy tooltip
739
+ */
740
+ destroy() {
741
+ this.hideTimeout && clearTimeout(this.hideTimeout), this.tooltip && (this.tooltip.remove(), this.tooltip = null), this.currentCell = null;
742
+ }
743
+ }
744
+ class Vt {
745
+ constructor(e) {
746
+ this.ctx = e;
747
+ }
748
+ /**
749
+ * 전체 그리드 렌더링
750
+ */
751
+ render() {
752
+ const e = this.ctx.getState();
753
+ console.log("🎨 GridRenderer.render() called", { editing: e.edit.editing }), this.renderHeader(), this.renderBody(), this.renderFooter(), this.updateLoadingState(), console.log("🎨 GridRenderer.render() completed", { editing: e.edit.editing });
754
+ }
755
+ /**
756
+ * 헤더 렌더링 (Phase 14: Fixed Right 지원)
757
+ */
758
+ renderHeader() {
759
+ const e = this.ctx;
760
+ if (e.fixedLeftHeader) {
761
+ e.fixedLeftHeader.innerHTML = "";
762
+ const s = p("div", "velox-header-row");
763
+ e.getFixedLeftColumns().forEach((o) => {
764
+ if (o.field === "__drag") {
765
+ const n = p("div", "velox-row-drag-handle");
766
+ n.style.visibility = "hidden", s.appendChild(n);
767
+ } else if (o.field === "__checkbox")
768
+ s.appendChild(this.createHeaderCheckbarCell());
769
+ else if (o.field === "__rownum") {
770
+ const n = p("div", "velox-header-cell velox-rownumber-cell");
771
+ n.textContent = "#", s.appendChild(n);
772
+ } else
773
+ s.appendChild(this.createHeaderCell(o));
774
+ }), e.fixedLeftHeader.appendChild(s);
775
+ }
776
+ const i = p("div", "velox-header-row");
777
+ if (e.getScrollableColumns().forEach((s) => {
778
+ if (s.field === "__drag") {
779
+ const o = p("div", "velox-row-drag-handle");
780
+ o.style.visibility = "hidden", i.appendChild(o);
781
+ } else if (s.field === "__checkbox")
782
+ i.appendChild(this.createHeaderCheckbarCell());
783
+ else if (s.field === "__rownum") {
784
+ const o = p("div", "velox-header-cell velox-rownumber-cell");
785
+ o.textContent = "#", i.appendChild(o);
786
+ } else
787
+ i.appendChild(this.createHeaderCell(s));
788
+ }), e.headerElement.innerHTML = "", e.headerElement.appendChild(i), e.fixedRightHeader) {
789
+ e.fixedRightHeader.innerHTML = "";
790
+ const s = p("div", "velox-header-row");
791
+ e.getFixedRightColumns().forEach(
792
+ (o) => s.appendChild(this.createHeaderCell(o))
793
+ ), e.fixedRightHeader.appendChild(s), this.updateFixedRightWidth();
794
+ }
795
+ }
796
+ /**
797
+ * CheckBar 헤더 셀 생성
798
+ */
799
+ createHeaderCheckbarCell() {
800
+ const e = this.ctx, i = e.getOptions(), s = e.getState(), o = p("div", "velox-header-cell velox-checkbox-cell"), n = i.checkBar;
801
+ if (n.showAll && !n.exclusive) {
802
+ const t = p("input", "velox-checkbox");
803
+ t.type = "checkbox";
804
+ const l = s.checkBar.checkableRows.size, a = s.checkBar.checkedRows.size, r = l > 0 && a === l, h = a > 0 && !r;
805
+ t.checked = r, t.indeterminate = h, t.addEventListener("change", () => e.checkAll(t.checked)), o.appendChild(t);
806
+ } else if (n.exclusive) {
807
+ const t = p("span", "velox-checkbox-label");
808
+ t.textContent = "선택", o.appendChild(t);
809
+ }
810
+ return o;
811
+ }
812
+ /**
813
+ * 헤더 셀 생성
814
+ */
815
+ createHeaderCell(e) {
816
+ var g;
817
+ const i = this.ctx, s = i.getOptions(), o = i.getState(), n = p("div", "velox-header-cell");
818
+ n.dataset.field = e.field;
819
+ const t = e.headerAlign || e.align || "left";
820
+ if (w(n, `velox-header-cell--align-${t}`), e.width ? (n.style.width = `${e.width}px`, n.style.minWidth = `${e.minWidth || e.width}px`, n.style.maxWidth = `${e.width}px`, n.style.flexShrink = "0") : (n.style.flex = "1", n.style.minWidth = `${e.minWidth || 100}px`), e.headerClass && w(n, e.headerClass), s.sortable && e.sortable !== !1) {
821
+ w(n, "velox-header-cell--sortable");
822
+ const d = o.sort.find((f) => f.field === e.field);
823
+ d != null && d.direction && w(n, "velox-header-cell--sorted");
824
+ }
825
+ const l = p("div", "velox-header-content"), a = p("span", "velox-column-drag-handle");
826
+ a.innerHTML = "⋮⋮", a.title = "드래그하여 컬럼 순서 변경", a.addEventListener("mousedown", (d) => i.startColumnDrag(d, e)), l.appendChild(a);
827
+ const r = p("span", "velox-header-text");
828
+ if (r.textContent = e.header, l.appendChild(r), n.appendChild(l), s.sortable && e.sortable !== !1) {
829
+ const d = p("button", "velox-sort-btn"), f = o.sort.find((C) => C.field === e.field);
830
+ (f == null ? void 0 : f.direction) === "asc" ? (w(d, "velox-sort-btn--asc"), d.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 4.5h14.25M3 9h9.75M3 13.5h5.25m5.25-.75L17.25 9m0 0L21 12.75M17.25 9v12" /></svg>') : ((f == null ? void 0 : f.direction) === "desc" && w(d, "velox-sort-btn--desc"), d.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 4.5h14.25M3 9h9.75M3 13.5h9.75m4.5-4.5v12m0 0-3.75-3.75M17.25 21 21 17.25" /></svg>'), f != null && f.direction && w(d, "velox-sort-btn--active"), d.title = "정렬", d.addEventListener("click", (C) => {
831
+ C.stopPropagation(), i.handleSort(e.field);
832
+ }), n.appendChild(d);
833
+ }
834
+ if (s.filterable && e.filterable !== !1) {
835
+ const d = p("button", "velox-filter-btn");
836
+ d.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 0 1-.659 1.591l-5.432 5.432a2.25 2.25 0 0 0-.659 1.591v2.927a2.25 2.25 0 0 1-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 0 0-.659-1.591L3.659 7.409A2.25 2.25 0 0 1 3 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0 1 12 3Z" /></svg>', ((g = o.filter) == null ? void 0 : g.conditions.some((C) => C.field === e.field)) && w(d, "velox-filter-btn--active"), d.addEventListener("click", (C) => {
837
+ C.stopPropagation(), i.showFilterPopup(e, d);
838
+ }), n.appendChild(d);
839
+ }
840
+ const h = p("button", "velox-column-menu-btn");
841
+ if (h.innerHTML = "⋯", h.title = "컬럼 메뉴", h.addEventListener("click", (d) => {
842
+ d.stopPropagation(), i.showColumnMenu(e, h);
843
+ }), n.appendChild(h), s.resizable && e.resizable !== !1) {
844
+ const d = p("div", "velox-resize-handle");
845
+ d.addEventListener("mousedown", (f) => i.startResize(f, e)), n.appendChild(d);
846
+ }
847
+ return n;
848
+ }
849
+ /**
850
+ * 바디 렌더링 (Phase 14: Fixed Right 지원)
851
+ */
852
+ renderBody() {
853
+ const e = this.ctx, i = e.getOptions(), s = e.getVisibleRows(), o = e.getVirtualState(), n = i.rowHeight || 40;
854
+ if (e.fixedLeftBodyInner && (e.fixedLeftBodyInner.innerHTML = "", i.virtualScroll ? (e.fixedLeftBodyInner.style.height = `${o.totalHeight}px`, e.fixedLeftBodyInner.style.position = "relative") : (e.fixedLeftBodyInner.style.height = "", e.fixedLeftBodyInner.style.position = ""), s.forEach(({ data: t, index: l }) => {
855
+ const a = this.createRowBase(t, l, "fixedLeft");
856
+ i.virtualScroll && (a.style.position = "absolute", a.style.top = `${l * n}px`, a.style.left = "0", a.style.right = "0"), e.fixedLeftBodyInner.appendChild(a);
857
+ })), e.bodyInner.innerHTML = "", i.virtualScroll ? (e.bodyInner.style.height = `${o.totalHeight}px`, e.bodyInner.style.position = "relative") : (e.bodyInner.style.height = "", e.bodyInner.style.position = ""), s.length === 0) {
858
+ const t = p("div", "velox-empty");
859
+ t.textContent = i.emptyMessage || "데이터가 없습니다.", e.bodyInner.appendChild(t);
860
+ return;
861
+ }
862
+ s.forEach(({ data: t, index: l }) => {
863
+ const a = this.createRowBase(t, l, "scrollable");
864
+ i.virtualScroll && (a.style.position = "absolute", a.style.top = `${l * n}px`, a.style.left = "0", a.style.right = "0"), e.bodyInner.appendChild(a);
865
+ }), e.fixedRightBodyInner && (e.fixedRightBodyInner.innerHTML = "", i.virtualScroll ? (e.fixedRightBodyInner.style.height = `${o.totalHeight}px`, e.fixedRightBodyInner.style.position = "relative") : (e.fixedRightBodyInner.style.height = "", e.fixedRightBodyInner.style.position = ""), s.forEach(({ data: t, index: l }) => {
866
+ const a = this.createRowBase(t, l, "fixedRight");
867
+ i.virtualScroll && (a.style.position = "absolute", a.style.top = `${l * n}px`, a.style.left = "0", a.style.right = "0"), e.fixedRightBodyInner.appendChild(a);
868
+ }), this.updateFixedRightWidth());
869
+ }
870
+ /**
871
+ * Update Fixed Right container width based on columns
872
+ * Phase 14: Ensure header and body alignment
873
+ */
874
+ updateFixedRightWidth() {
875
+ const e = this.ctx;
876
+ if (!e.fixedRightContainer) return;
877
+ const i = e.getFixedRightColumns();
878
+ if (i.length === 0) return;
879
+ let s = 0;
880
+ i.forEach((n) => {
881
+ s += n.width || n.minWidth || 100;
882
+ });
883
+ const o = this.getScrollbarWidth(e.fixedRightBody);
884
+ e.fixedRightContainer.style.width = `${s + o}px`, e.fixedRightContainer.style.minWidth = `${s + o}px`, e.fixedRightContainer.style.maxWidth = `${s + o}px`, e.fixedRightHeader && o > 0 && (e.fixedRightHeader.style.paddingRight = `${o}px`), e.fixedRightFooter && o > 0 && (e.fixedRightFooter.style.paddingRight = `${o}px`);
885
+ }
886
+ /**
887
+ * Get scrollbar width of an element
888
+ * Phase 14: For Fixed Right alignment
889
+ */
890
+ getScrollbarWidth(e) {
891
+ return e ? e.offsetWidth - e.clientWidth : 0;
892
+ }
893
+ /**
894
+ * Row 생성 (통합 메서드)
895
+ * @param area - 'fixedLeft' | 'scrollable' | 'fixedRight' (Phase 14)
896
+ */
897
+ createRowBase(e, i, s) {
898
+ const o = this.ctx, n = o.getOptions(), t = o.getState(), l = p("div", "velox-row");
899
+ return l.dataset.rowIndex = String(i), i % 2 === 1 && w(l, "velox-row--alt"), n.selectionStyle === "row" && t.selection.selectedRows.has(i) && w(l, "velox-row--selected"), s === "fixedLeft" && t.checkBar.checkedRows.has(i) && w(l, "velox-row--checked"), l.addEventListener("click", (a) => {
900
+ const r = a.target;
901
+ r.classList.contains("velox-checkbox") || r.classList.contains("velox-row-drag-handle") || o.handleRowClick(i, a);
902
+ }), s !== "fixedLeft" && l.addEventListener("dblclick", (a) => o.handleRowDoubleClick(i, a)), s === "fixedLeft" ? o.getFixedLeftColumns().forEach((a) => {
903
+ if (a.field === "__drag") {
904
+ const r = p("div", "velox-row-drag-handle");
905
+ r.innerHTML = "☰", r.title = "드래그하여 행 순서 변경", r.addEventListener("mousedown", (h) => o.startRowDrag(h, i, l)), l.appendChild(r);
906
+ } else if (a.field === "__checkbox")
907
+ l.appendChild(this.createCheckbarCell(i));
908
+ else if (a.field === "__rownum") {
909
+ const r = p("div", "velox-cell velox-rownumber-cell");
910
+ r.textContent = String(i + 1), l.appendChild(r);
911
+ } else
912
+ l.appendChild(this.createCell(e, i, a));
913
+ }) : s === "scrollable" ? o.getScrollableColumns().forEach((a) => {
914
+ if (a.field === "__drag") {
915
+ const r = p("div", "velox-row-drag-handle");
916
+ r.innerHTML = "☰", r.title = "드래그하여 행 순서 변경", r.addEventListener("mousedown", (h) => o.startRowDrag(h, i, l)), l.appendChild(r);
917
+ } else if (a.field === "__checkbox")
918
+ l.appendChild(this.createCheckbarCell(i));
919
+ else if (a.field === "__rownum") {
920
+ const r = p("div", "velox-cell velox-rownumber-cell");
921
+ r.textContent = String(i + 1), l.appendChild(r);
922
+ } else
923
+ l.appendChild(this.createCell(e, i, a));
924
+ }) : s === "fixedRight" && o.getFixedRightColumns().forEach(
925
+ (a) => l.appendChild(this.createCell(e, i, a))
926
+ ), l;
927
+ }
928
+ /**
929
+ * CheckBar 셀 생성
930
+ */
931
+ createCheckbarCell(e) {
932
+ const i = this.ctx, s = i.getOptions(), o = i.getState(), n = p("div", "velox-cell velox-checkbox-cell"), t = s.checkBar, l = o.checkBar.checkableRows.has(e), a = o.checkBar.checkedRows.has(e), r = p("input", "velox-checkbox");
933
+ return r.type = t.exclusive ? "radio" : "checkbox", r.name = t.exclusive ? `${i.getGridId()}-check` : "", r.checked = a, r.disabled = !l, l || w(n, "velox-checkbox-cell--disabled"), r.addEventListener("click", (h) => {
934
+ console.log("✅ Checkbox clicked", { rowIndex: e, checked: r.checked }), h.stopPropagation();
935
+ }), r.addEventListener("change", () => {
936
+ if (console.log("🔄 Checkbox changed", { rowIndex: e, checked: r.checked }), t.exclusive) {
937
+ const h = { ...i.getState().edit };
938
+ o.checkBar.checkedRows.clear(), r.checked && o.checkBar.checkedRows.add(e), this.render(), h.editing && h.rowIndex !== null && h.field !== null && (i.getState().edit = h, i.renderEditCell(h.rowIndex, h.field, h.originalValue)), i.emitEvent("onCheckChange", e, r.checked);
939
+ } else
940
+ i.checkItem(e, r.checked);
941
+ }), n.appendChild(r), n;
942
+ }
943
+ /**
944
+ * Cell 생성
945
+ */
946
+ createCell(e, i, s) {
947
+ const o = this.ctx, n = o.getOptions(), t = o.getState(), l = p("div", "velox-cell");
948
+ l.dataset.field = s.field, l.dataset.rowIndex = String(i);
949
+ const a = s.align || "left";
950
+ if (w(l, `velox-cell--align-${a}`), s.width ? (l.style.width = `${s.width}px`, l.style.minWidth = `${s.minWidth || s.width}px`, l.style.maxWidth = `${s.width}px`, l.style.flexShrink = "0") : (l.style.flex = "1", l.style.minWidth = `${s.minWidth || 100}px`), s.cellClass) {
951
+ const f = typeof s.cellClass == "function" ? s.cellClass(e[s.field], e) : s.cellClass;
952
+ f && w(l, f);
953
+ }
954
+ const r = `${i}:${s.field}`;
955
+ t.selection.selectedCells.has(r) && w(l, "velox-cell--selected");
956
+ const h = t.selection.focusedCell;
957
+ h && h.rowIndex === i && h.field === s.field && w(l, "velox-cell--focused"), n.editable && s.editable !== !1 && (w(l, "velox-cell--editable"), l.addEventListener("dblclick", (f) => {
958
+ if (l.classList.contains("velox-cell--editing")) {
959
+ console.log("🚫 Double click ignored - already editing"), f.stopPropagation(), f.preventDefault();
960
+ return;
961
+ }
962
+ console.log("🖱️🖱️ Double click detected", { rowIndex: i, field: s.field }), f.stopPropagation(), o.startEdit(i, s.field);
963
+ }));
964
+ const g = e[s.field], d = p("span", "velox-cell-content");
965
+ return s.renderer ? d.innerHTML = s.renderer(g, e, s) : s.formatter ? d.textContent = s.formatter(g, e, s) : d.textContent = H(g, s.type), l.appendChild(d), l.addEventListener("click", (f) => {
966
+ if (l.classList.contains("velox-cell--editing")) {
967
+ const C = f.target;
968
+ if (C.tagName === "INPUT" || C.tagName === "SELECT" || C.tagName === "BUTTON" || C.tagName === "TEXTAREA") {
969
+ console.log("✅ Interactive element click allowed during edit"), f.stopPropagation();
970
+ return;
971
+ }
972
+ console.log("🚫 Cell click ignored - editing mode (cell background)"), f.stopPropagation(), f.preventDefault();
973
+ return;
974
+ }
975
+ o.handleCellClick(i, s.field, g, f);
976
+ }), l.addEventListener("mousedown", (f) => {
977
+ if (l.classList.contains("velox-cell--editing")) {
978
+ console.log("🔒 Cell mousedown - editing mode (ignored in renderer)");
979
+ return;
980
+ }
981
+ n.selectionStyle === "block" && f.button === 0 && o.startBlockSelection(i, s.field);
982
+ }), l.addEventListener("mouseenter", () => {
983
+ o.isBlockSelecting() && o.updateBlockSelection(i, s.field);
984
+ }), s.tooltip && (w(l, "velox-cell--has-tooltip"), l.addEventListener("mouseenter", () => o.showTooltip(l, g, e, s)), l.addEventListener("mouseleave", () => o.hideTooltip())), l;
985
+ }
986
+ /**
987
+ * Footer Summary 렌더링 (Phase 13, Phase 14: Fixed Right 지원)
988
+ */
989
+ renderFooter() {
990
+ var s, o;
991
+ const e = this.ctx, i = e.getOptions();
992
+ if ((s = i.footerSummary) != null && s.visible) {
993
+ if (e.fixedLeftFooter) {
994
+ e.fixedLeftFooter.innerHTML = "";
995
+ const n = p("div", "velox-footer-row");
996
+ if (i.rowDraggable) {
997
+ const t = p("div", "velox-row-drag-handle");
998
+ t.style.visibility = "hidden", n.appendChild(t);
999
+ }
1000
+ if ((o = i.checkBar) != null && o.visible) {
1001
+ const t = p("div", "velox-footer-cell velox-checkbox-cell");
1002
+ n.appendChild(t);
1003
+ }
1004
+ e.getFixedLeftColumns().forEach(
1005
+ (t) => n.appendChild(this.createFooterCell(t))
1006
+ ), e.fixedLeftFooter.appendChild(n);
1007
+ }
1008
+ if (e.footerElement) {
1009
+ e.footerElement.innerHTML = "";
1010
+ const n = p("div", "velox-footer-row");
1011
+ if (i.showRowNumbers) {
1012
+ const t = p("div", "velox-footer-cell velox-rownumber-cell");
1013
+ n.appendChild(t);
1014
+ }
1015
+ e.getScrollableColumns().forEach(
1016
+ (t) => n.appendChild(this.createFooterCell(t))
1017
+ ), e.footerElement.appendChild(n);
1018
+ }
1019
+ if (e.fixedRightFooter) {
1020
+ e.fixedRightFooter.innerHTML = "";
1021
+ const n = p("div", "velox-footer-row");
1022
+ e.getFixedRightColumns().forEach(
1023
+ (t) => n.appendChild(this.createFooterCell(t))
1024
+ ), e.fixedRightFooter.appendChild(n);
1025
+ }
1026
+ }
1027
+ }
1028
+ /**
1029
+ * Footer 셀 생성 (Phase 13)
1030
+ */
1031
+ createFooterCell(e) {
1032
+ var l, a;
1033
+ const i = this.ctx, s = i.getOptions(), o = p("div", "velox-footer-cell");
1034
+ o.dataset.field = e.field;
1035
+ const n = e.align || "left";
1036
+ w(o, `velox-footer-cell--align-${n}`), e.width ? (o.style.width = `${e.width}px`, o.style.minWidth = `${e.minWidth || e.width}px`) : (o.style.flex = "1", o.style.minWidth = `${e.minWidth || 100}px`);
1037
+ const t = ((a = (l = s.footerSummary) == null ? void 0 : l.columns) == null ? void 0 : a[e.field]) || e.summary;
1038
+ if (t) {
1039
+ const r = i.getSummaryValue(e.field), h = p("span", "velox-footer-content");
1040
+ if (t.label) {
1041
+ const d = p("span", "velox-footer-label");
1042
+ d.textContent = t.label, h.appendChild(d);
1043
+ }
1044
+ const g = p("span", "velox-footer-value");
1045
+ t.formatter ? g.textContent = t.formatter(r) : g.textContent = H(r, e.type), h.appendChild(g), o.appendChild(h), t.className && w(o, t.className);
1046
+ }
1047
+ return o;
1048
+ }
1049
+ /**
1050
+ * Loading 상태 업데이트
1051
+ */
1052
+ updateLoadingState() {
1053
+ const e = this.ctx, i = e.getOptions();
1054
+ e.loadingOverlay && (e.loadingOverlay.style.display = i.loading ? "flex" : "none");
1055
+ }
1056
+ /**
1057
+ * Row validation 상태 업데이트
1058
+ */
1059
+ updateRowValidationState(e) {
1060
+ const i = this.ctx, s = i.getState(), o = i.rootElement.querySelector(`[data-row-index="${e}"]`);
1061
+ if (!o) return;
1062
+ o.querySelectorAll(".velox-cell").forEach((t) => {
1063
+ const a = t.dataset.field;
1064
+ if (!a) return;
1065
+ const r = s.columns.find((h) => h.field === a);
1066
+ r != null && r.validation;
1067
+ });
1068
+ }
1069
+ }
1070
+ class At {
1071
+ constructor(e) {
1072
+ this.ctx = e, this.filterPopup = null, this.boundHandleOutsideClick = this.handleOutsideClick.bind(this);
1073
+ }
1074
+ /**
1075
+ * Filter 팝업 표시
1076
+ */
1077
+ showFilterPopup(e, i) {
1078
+ var b;
1079
+ this.closeFilterPopup();
1080
+ const s = this.ctx, o = s.getState(), n = p("div", "velox-filter-popup"), t = i.getBoundingClientRect(), l = s.rootElement.getBoundingClientRect();
1081
+ n.style.top = `${t.bottom - l.top + 5}px`, n.style.left = `${Math.max(0, t.left - l.left - 100)}px`;
1082
+ const a = [...new Set(o.data.map((y) => y[e.field]))].filter((y) => y != null).sort(), r = (b = o.filter) == null ? void 0 : b.conditions.find((y) => y.field === e.field), h = p("select", "velox-filter-operator");
1083
+ [
1084
+ { value: "contains", label: "포함" },
1085
+ { value: "equals", label: "같음" },
1086
+ { value: "notEquals", label: "같지 않음" },
1087
+ { value: "startsWith", label: "시작" },
1088
+ { value: "endsWith", label: "끝" },
1089
+ { value: "greaterThan", label: ">" },
1090
+ { value: "lessThan", label: "<" },
1091
+ { value: "greaterThanOrEqual", label: ">=" },
1092
+ { value: "lessThanOrEqual", label: "<=" },
1093
+ { value: "isEmpty", label: "비어있음" },
1094
+ { value: "isNotEmpty", label: "비어있지 않음" }
1095
+ ].forEach((y) => {
1096
+ const S = p("option");
1097
+ S.value = y.value, S.textContent = y.label, (r == null ? void 0 : r.operator) === y.value && (S.selected = !0), h.appendChild(S);
1098
+ }), n.appendChild(h);
1099
+ const d = p("input", "velox-filter-input");
1100
+ if (d.type = e.type === "number" ? "number" : "text", d.placeholder = "값 입력...", (r == null ? void 0 : r.value) !== void 0 && (d.value = String(r.value)), n.appendChild(d), a.length > 0 && a.length <= 15) {
1101
+ const y = p("div", "velox-filter-list"), S = p("div", "velox-filter-list-label");
1102
+ S.textContent = "빠른 선택:", y.appendChild(S), a.slice(0, 10).forEach((E) => {
1103
+ const R = p("div", "velox-filter-list-item");
1104
+ R.textContent = H(E, e.type), R.addEventListener("click", () => {
1105
+ this.applyColumnFilter(e.field, "equals", E), this.closeFilterPopup();
1106
+ }), y.appendChild(R);
1107
+ }), n.appendChild(y);
1108
+ }
1109
+ const f = p("div", "velox-filter-buttons"), C = p("button", "velox-filter-apply");
1110
+ C.textContent = "적용", C.addEventListener("click", () => {
1111
+ const y = h.value, S = e.type === "number" ? parseFloat(d.value) : d.value;
1112
+ this.applyColumnFilter(e.field, y, S), this.closeFilterPopup();
1113
+ }), f.appendChild(C);
1114
+ const x = p("button", "velox-filter-clear");
1115
+ x.textContent = "해제", x.addEventListener("click", () => {
1116
+ this.removeColumnFilter(e.field), this.closeFilterPopup();
1117
+ }), f.appendChild(x), n.appendChild(f), this.filterPopup = n, s.rootElement.appendChild(n), setTimeout(() => document.addEventListener("click", this.boundHandleOutsideClick), 0), d.focus();
1118
+ }
1119
+ /**
1120
+ * Filter 팝업 닫기
1121
+ */
1122
+ closeFilterPopup() {
1123
+ this.filterPopup && (this.filterPopup.remove(), this.filterPopup = null, document.removeEventListener("click", this.boundHandleOutsideClick));
1124
+ }
1125
+ /**
1126
+ * 외부 클릭 핸들러
1127
+ */
1128
+ handleOutsideClick(e) {
1129
+ this.filterPopup && !this.filterPopup.contains(e.target) && this.closeFilterPopup();
1130
+ }
1131
+ /**
1132
+ * Column filter 적용
1133
+ */
1134
+ applyColumnFilter(e, i, s) {
1135
+ const o = this.ctx, n = o.getState(), t = { field: e, operator: i, value: s };
1136
+ if (n.filter) {
1137
+ const l = n.filter.conditions.filter((a) => a.field !== e);
1138
+ l.push(t), n.filter = { conditions: l, logic: "and" };
1139
+ } else
1140
+ n.filter = { conditions: [t], logic: "and" };
1141
+ o.clearSelectionState(), o.applyDataTransformations(), o.render(), o.emitEvent("onFilter", n.filter);
1142
+ }
1143
+ /**
1144
+ * Column filter 제거
1145
+ */
1146
+ removeColumnFilter(e) {
1147
+ const i = this.ctx, s = i.getState();
1148
+ if (s.filter) {
1149
+ const o = s.filter.conditions.filter((n) => n.field !== e);
1150
+ s.filter = o.length === 0 ? null : { conditions: o, logic: "and" }, i.clearSelectionState(), i.applyDataTransformations(), i.render(), s.filter && i.emitEvent("onFilter", s.filter);
1151
+ }
1152
+ }
1153
+ /**
1154
+ * Filter 팝업이 열려있는지 확인
1155
+ */
1156
+ isOpen() {
1157
+ return this.filterPopup !== null;
1158
+ }
1159
+ }
1160
+ class Nt {
1161
+ constructor(e) {
1162
+ this.ctx = e, this.columnMenuPopup = null, this.boundHandleOutsideClick = this.handleOutsideClick.bind(this);
1163
+ }
1164
+ /**
1165
+ * Column 메뉴 표시
1166
+ */
1167
+ showColumnMenu(e, i) {
1168
+ this.closeColumnMenu();
1169
+ const s = this.ctx, o = s.getOptions(), n = p("div", "velox-column-menu"), t = i.getBoundingClientRect(), l = s.rootElement.getBoundingClientRect();
1170
+ n.style.top = `${t.bottom - l.top + 5}px`, n.style.left = `${t.left - l.left}px`;
1171
+ const a = {
1172
+ field: e.field,
1173
+ column: e,
1174
+ selectedRows: s.getSelectedRows(),
1175
+ selectedCells: s.getSelectedCells(),
1176
+ grid: s
1177
+ }, r = o.contextMenu, h = (r == null ? void 0 : r.showDefaultItems) !== !1, g = (r == null ? void 0 : r.headerItems) || [], d = [
1178
+ {
1179
+ id: "sort-asc",
1180
+ label: "오름차순 정렬",
1181
+ icon: "↑",
1182
+ action: () => s.sort(e.field, "asc")
1183
+ },
1184
+ {
1185
+ id: "sort-desc",
1186
+ label: "내림차순 정렬",
1187
+ icon: "↓",
1188
+ action: () => s.sort(e.field, "desc")
1189
+ },
1190
+ {
1191
+ id: "sort-clear",
1192
+ label: "정렬 해제",
1193
+ icon: "✕",
1194
+ action: () => s.clearSort()
1195
+ },
1196
+ { type: "separator" },
1197
+ {
1198
+ id: "hide",
1199
+ label: "컬럼 숨기기",
1200
+ icon: "👁",
1201
+ action: () => s.hideColumn(e.field)
1202
+ },
1203
+ {
1204
+ id: "autofit",
1205
+ label: "컬럼 너비 자동",
1206
+ icon: "↔",
1207
+ action: () => s.autoFitColumn(e.field)
1208
+ },
1209
+ {
1210
+ id: "autofit-all",
1211
+ label: "모든 컬럼 자동",
1212
+ icon: "⇔",
1213
+ action: () => s.autoFitAllColumns()
1214
+ },
1215
+ { type: "separator" },
1216
+ {
1217
+ id: "fix-left",
1218
+ label: "왼쪽에 고정",
1219
+ icon: "◀",
1220
+ action: () => s.fixColumn(e.field, "left")
1221
+ },
1222
+ {
1223
+ id: "unfix",
1224
+ label: "고정 해제",
1225
+ icon: "◇",
1226
+ action: () => s.fixColumn(e.field, !1)
1227
+ }
1228
+ ];
1229
+ let f = [];
1230
+ h ? (f = [...d], g.length > 0 && (f.push({ type: "separator" }), f.push(...g))) : f = g, f.forEach((C) => {
1231
+ if (typeof C.visible == "function" ? C.visible(a) : C.visible !== !1)
1232
+ if (C.type === "separator") {
1233
+ const b = p("div", "velox-column-menu-separator");
1234
+ n.appendChild(b);
1235
+ } else {
1236
+ const b = p("div", "velox-column-menu-item");
1237
+ C.className && w(b, C.className);
1238
+ const y = typeof C.disabled == "function" ? C.disabled(a) : C.disabled === !0;
1239
+ y && w(b, "velox-column-menu-item--disabled");
1240
+ let S = "";
1241
+ C.icon && (S += `<span class="velox-column-menu-icon">${C.icon}</span>`), S += `<span class="velox-column-menu-label">${C.label || ""}</span>`, C.shortcut && (S += `<span class="velox-column-menu-shortcut">${C.shortcut}</span>`), b.innerHTML = S, y || b.addEventListener("click", () => {
1242
+ var E;
1243
+ (E = C.action) == null || E.call(C, a), this.closeColumnMenu();
1244
+ }), n.appendChild(b);
1245
+ }
1246
+ }), this.columnMenuPopup = n, s.rootElement.appendChild(n), setTimeout(() => document.addEventListener("click", this.boundHandleOutsideClick), 0);
1247
+ }
1248
+ /**
1249
+ * Column 메뉴 닫기
1250
+ */
1251
+ closeColumnMenu() {
1252
+ this.columnMenuPopup && (this.columnMenuPopup.remove(), this.columnMenuPopup = null, document.removeEventListener("click", this.boundHandleOutsideClick));
1253
+ }
1254
+ /**
1255
+ * 외부 클릭 핸들러
1256
+ */
1257
+ handleOutsideClick(e) {
1258
+ this.columnMenuPopup && !this.columnMenuPopup.contains(e.target) && this.closeColumnMenu();
1259
+ }
1260
+ /**
1261
+ * Column 메뉴가 열려있는지 확인
1262
+ */
1263
+ isOpen() {
1264
+ return this.columnMenuPopup !== null;
1265
+ }
1266
+ }
1267
+ class $t {
1268
+ constructor(e) {
1269
+ this.ctx = e, this.columnDragging = null, this.rowDragging = null, this.resizing = null, this.boundHandleColumnDragMove = this.handleColumnDragMove.bind(this), this.boundHandleColumnDragEnd = this.handleColumnDragEnd.bind(this), this.boundHandleRowDragMove = this.handleRowDragMove.bind(this), this.boundHandleRowDragEnd = this.handleRowDragEnd.bind(this), this.boundHandleResizeMove = this.handleResizeMove.bind(this), this.boundHandleResizeEnd = this.handleResizeEnd.bind(this);
1270
+ }
1271
+ // ============================================
1272
+ // Column Drag & Drop
1273
+ // ============================================
1274
+ /**
1275
+ * Column 드래그 시작
1276
+ */
1277
+ startColumnDrag(e, i) {
1278
+ e.preventDefault(), e.stopPropagation(), this.columnDragging = {
1279
+ field: i.field,
1280
+ startX: e.clientX,
1281
+ element: null
1282
+ };
1283
+ const s = p("div", "velox-column-drag-indicator");
1284
+ s.textContent = i.header, s.style.position = "fixed", s.style.left = `${e.clientX}px`, s.style.top = `${e.clientY}px`, document.body.appendChild(s), this.columnDragging.element = s, document.addEventListener("mousemove", this.boundHandleColumnDragMove), document.addEventListener("mouseup", this.boundHandleColumnDragEnd), w(document.body, "velox-no-select");
1285
+ }
1286
+ /**
1287
+ * Column 드래그 이동
1288
+ */
1289
+ handleColumnDragMove(e) {
1290
+ var n;
1291
+ const i = this.ctx;
1292
+ if (!((n = this.columnDragging) != null && n.element)) return;
1293
+ this.columnDragging.element.style.left = `${e.clientX + 10}px`, this.columnDragging.element.style.top = `${e.clientY + 10}px`;
1294
+ const s = document.elementFromPoint(e.clientX, e.clientY), o = s == null ? void 0 : s.closest(".velox-header-cell");
1295
+ i.headerElement.querySelectorAll(".velox-header-cell--drop-target").forEach((t) => {
1296
+ k(t, "velox-header-cell--drop-target");
1297
+ }), o && o.dataset.field !== this.columnDragging.field && w(o, "velox-header-cell--drop-target");
1298
+ }
1299
+ /**
1300
+ * Column 드래그 종료
1301
+ */
1302
+ handleColumnDragEnd(e) {
1303
+ const i = this.ctx;
1304
+ if (!this.columnDragging) return;
1305
+ const s = this.columnDragging.field, o = document.elementFromPoint(e.clientX, e.clientY), n = o == null ? void 0 : o.closest(".velox-header-cell"), t = n == null ? void 0 : n.dataset.field;
1306
+ this.columnDragging.element && this.columnDragging.element.remove(), i.headerElement.querySelectorAll(".velox-header-cell--drop-target").forEach((l) => {
1307
+ k(l, "velox-header-cell--drop-target");
1308
+ }), document.removeEventListener("mousemove", this.boundHandleColumnDragMove), document.removeEventListener("mouseup", this.boundHandleColumnDragEnd), k(document.body, "velox-no-select"), t && t !== s && i.reorderColumn(s, t), this.columnDragging = null;
1309
+ }
1310
+ /**
1311
+ * Column 드래그 중인지 확인
1312
+ */
1313
+ isColumnDragging() {
1314
+ return this.columnDragging !== null;
1315
+ }
1316
+ // ============================================
1317
+ // Row Drag & Drop
1318
+ // ============================================
1319
+ /**
1320
+ * Row 드래그 시작
1321
+ */
1322
+ startRowDrag(e, i, s) {
1323
+ e.preventDefault(), e.stopPropagation(), this.rowDragging = {
1324
+ index: i,
1325
+ startY: e.clientY,
1326
+ element: null
1327
+ };
1328
+ const o = p("div", "velox-row-drag-indicator");
1329
+ o.textContent = `행 ${i + 1}`, o.style.position = "fixed", o.style.left = `${e.clientX}px`, o.style.top = `${e.clientY}px`, document.body.appendChild(o), this.rowDragging.element = o, w(s, "velox-row--dragging"), document.addEventListener("mousemove", this.boundHandleRowDragMove), document.addEventListener("mouseup", this.boundHandleRowDragEnd), w(document.body, "velox-no-select");
1330
+ }
1331
+ /**
1332
+ * Row 드래그 이동
1333
+ */
1334
+ handleRowDragMove(e) {
1335
+ var n, t;
1336
+ const i = this.ctx;
1337
+ if (!((n = this.rowDragging) != null && n.element)) return;
1338
+ this.rowDragging.element.style.left = `${e.clientX + 10}px`, this.rowDragging.element.style.top = `${e.clientY + 10}px`;
1339
+ const s = document.elementFromPoint(e.clientX, e.clientY), o = s == null ? void 0 : s.closest(".velox-row");
1340
+ if (i.bodyInner.querySelectorAll(".velox-row--drop-target").forEach((l) => {
1341
+ k(l, "velox-row--drop-target");
1342
+ }), (t = i.fixedLeftBodyInner) == null || t.querySelectorAll(".velox-row--drop-target").forEach((l) => {
1343
+ k(l, "velox-row--drop-target");
1344
+ }), o) {
1345
+ const l = parseInt(o.dataset.rowIndex || "-1", 10);
1346
+ l !== -1 && l !== this.rowDragging.index && w(o, "velox-row--drop-target");
1347
+ }
1348
+ }
1349
+ /**
1350
+ * Row 드래그 종료
1351
+ */
1352
+ handleRowDragEnd(e) {
1353
+ var l;
1354
+ const i = this.ctx;
1355
+ if (!this.rowDragging) return;
1356
+ const s = this.rowDragging.index, o = document.elementFromPoint(e.clientX, e.clientY), n = o == null ? void 0 : o.closest(".velox-row"), t = n ? parseInt(n.dataset.rowIndex || "-1", 10) : -1;
1357
+ this.rowDragging.element && this.rowDragging.element.remove(), i.bodyInner.querySelectorAll(".velox-row--dragging, .velox-row--drop-target").forEach((a) => {
1358
+ k(a, "velox-row--dragging"), k(a, "velox-row--drop-target");
1359
+ }), (l = i.fixedLeftBodyInner) == null || l.querySelectorAll(".velox-row--dragging, .velox-row--drop-target").forEach((a) => {
1360
+ k(a, "velox-row--dragging"), k(a, "velox-row--drop-target");
1361
+ }), document.removeEventListener("mousemove", this.boundHandleRowDragMove), document.removeEventListener("mouseup", this.boundHandleRowDragEnd), k(document.body, "velox-no-select"), t !== -1 && t !== s && i.moveRow(s, t), this.rowDragging = null;
1362
+ }
1363
+ /**
1364
+ * Row 드래그 중인지 확인
1365
+ */
1366
+ isRowDragging() {
1367
+ return this.rowDragging !== null;
1368
+ }
1369
+ // ============================================
1370
+ // Column Resize
1371
+ // ============================================
1372
+ /**
1373
+ * Column 리사이즈 시작
1374
+ */
1375
+ startResize(e, i) {
1376
+ const s = this.ctx;
1377
+ e.preventDefault(), e.stopPropagation();
1378
+ const o = s.headerElement.querySelector(`[data-field="${i.field}"]`);
1379
+ o && (this.resizing = {
1380
+ column: i,
1381
+ startX: e.clientX,
1382
+ startWidth: o.offsetWidth
1383
+ }, document.addEventListener("mousemove", this.boundHandleResizeMove), document.addEventListener("mouseup", this.boundHandleResizeEnd), w(document.body, "velox-no-select"));
1384
+ }
1385
+ /**
1386
+ * Column 리사이즈 이동
1387
+ */
1388
+ handleResizeMove(e) {
1389
+ const i = this.ctx;
1390
+ if (!this.resizing) return;
1391
+ const s = e.clientX - this.resizing.startX, o = Math.max(50, this.resizing.startWidth + s);
1392
+ this.resizing.column.width = o, i.invalidateColumnCache(), i.render();
1393
+ }
1394
+ /**
1395
+ * Column 리사이즈 종료
1396
+ */
1397
+ handleResizeEnd() {
1398
+ const e = this.ctx;
1399
+ this.resizing && (document.removeEventListener("mousemove", this.boundHandleResizeMove), document.removeEventListener("mouseup", this.boundHandleResizeEnd), k(document.body, "velox-no-select"), e.emitEvent("onColumnResize", this.resizing.column.field, this.resizing.column.width || 0), this.resizing = null);
1400
+ }
1401
+ /**
1402
+ * 리사이즈 중인지 확인
1403
+ */
1404
+ isResizing() {
1405
+ return this.resizing !== null;
1406
+ }
1407
+ /**
1408
+ * 모든 드래그 상태 초기화
1409
+ */
1410
+ cleanup() {
1411
+ this.columnDragging && (this.columnDragging.element && this.columnDragging.element.remove(), document.removeEventListener("mousemove", this.boundHandleColumnDragMove), document.removeEventListener("mouseup", this.boundHandleColumnDragEnd), this.columnDragging = null), this.rowDragging && (this.rowDragging.element && this.rowDragging.element.remove(), document.removeEventListener("mousemove", this.boundHandleRowDragMove), document.removeEventListener("mouseup", this.boundHandleRowDragEnd), this.rowDragging = null), this.resizing && (document.removeEventListener("mousemove", this.boundHandleResizeMove), document.removeEventListener("mouseup", this.boundHandleResizeEnd), this.resizing = null), k(document.body, "velox-no-select");
1412
+ }
1413
+ /**
1414
+ * 리소스 정리 (destroy 별칭)
1415
+ */
1416
+ destroy() {
1417
+ this.cleanup();
1418
+ }
1419
+ }
1420
+ class zt {
1421
+ constructor(e) {
1422
+ this.context = e, this.summaryCache = /* @__PURE__ */ new Map();
1423
+ }
1424
+ /**
1425
+ * Footer Summary 값 계산
1426
+ * @param field 컬럼 필드명
1427
+ * @returns 계산된 집계 값
1428
+ */
1429
+ calculateFooterSummary(e) {
1430
+ var g, d;
1431
+ const i = this.context.getOptions(), s = this.context.getState().columns.find((f) => f.field === e);
1432
+ if (!s) return null;
1433
+ const o = s.summary || ((d = (g = i.footerSummary) == null ? void 0 : g.columns) == null ? void 0 : d[e]);
1434
+ if (!o) return null;
1435
+ const n = `footer:${e}`;
1436
+ if (this.summaryCache.has(n))
1437
+ return this.summaryCache.get(n);
1438
+ const t = this.context.getDisplayData(), l = t.map((f) => f[e]), a = this.executeAggregation(o, l, t), r = this.formatSummaryValue(a, o, s), h = {
1439
+ field: e,
1440
+ function: o.function,
1441
+ value: a,
1442
+ formattedValue: r
1443
+ };
1444
+ return this.summaryCache.set(n, h), h;
1445
+ }
1446
+ /**
1447
+ * 모든 Footer Summary 값 계산
1448
+ * @returns field -> SummaryResult 맵
1449
+ */
1450
+ calculateAllFooterSummaries() {
1451
+ var o;
1452
+ const e = this.context.getOptions(), i = /* @__PURE__ */ new Map();
1453
+ return (o = e.footerSummary) != null && o.visible && this.context.getVisibleColumns().forEach((n) => {
1454
+ const t = this.calculateFooterSummary(n.field);
1455
+ t && i.set(n.field, t);
1456
+ }), i;
1457
+ }
1458
+ /**
1459
+ * Group Summary 값 계산
1460
+ * @param field 컬럼 필드명
1461
+ * @param _groupValue 그룹 값 (reserved for future use)
1462
+ * @param groupData 그룹 데이터
1463
+ * @returns 계산된 집계 값
1464
+ */
1465
+ calculateGroupSummary(e, i, s) {
1466
+ var h, g;
1467
+ const o = this.context.getOptions(), n = this.context.getState().columns.find((d) => d.field === e);
1468
+ if (!n || !((h = o.groupSummary) != null && h.enabled)) return null;
1469
+ const t = (g = o.groupSummary.columns) == null ? void 0 : g[e];
1470
+ if (!t) return null;
1471
+ const l = s.map((d) => d[e]), a = this.executeAggregation(t, l, s), r = this.formatSummaryValue(a, t, n);
1472
+ return {
1473
+ field: e,
1474
+ function: t.function,
1475
+ value: a,
1476
+ formattedValue: r
1477
+ };
1478
+ }
1479
+ /**
1480
+ * 집계 함수 실행
1481
+ * @param config Summary 설정
1482
+ * @param values 값 배열
1483
+ * @param data 원본 데이터 배열
1484
+ * @returns 집계된 값
1485
+ */
1486
+ executeAggregation(e, i, s) {
1487
+ const o = i.filter((n) => n != null);
1488
+ switch (e.function) {
1489
+ case "sum":
1490
+ return this.calculateSum(o);
1491
+ case "avg":
1492
+ return this.calculateAverage(o);
1493
+ case "count":
1494
+ return this.calculateCount(o);
1495
+ case "min":
1496
+ return this.calculateMin(o);
1497
+ case "max":
1498
+ return this.calculateMax(o);
1499
+ case "custom":
1500
+ return e.customFunction ? e.customFunction(i, s) : null;
1501
+ default:
1502
+ return null;
1503
+ }
1504
+ }
1505
+ /**
1506
+ * 합계 계산
1507
+ */
1508
+ calculateSum(e) {
1509
+ return e.reduce((i, s) => {
1510
+ const o = this.toNumber(s);
1511
+ return i + (o !== null ? o : 0);
1512
+ }, 0);
1513
+ }
1514
+ /**
1515
+ * 평균 계산
1516
+ */
1517
+ calculateAverage(e) {
1518
+ if (e.length === 0) return null;
1519
+ const i = this.calculateSum(e), s = e.filter((o) => this.toNumber(o) !== null).length;
1520
+ return s > 0 ? i / s : null;
1521
+ }
1522
+ /**
1523
+ * 개수 계산
1524
+ */
1525
+ calculateCount(e) {
1526
+ return e.length;
1527
+ }
1528
+ /**
1529
+ * 최소값 계산
1530
+ */
1531
+ calculateMin(e) {
1532
+ const i = e.map((s) => this.toNumber(s)).filter((s) => s !== null);
1533
+ return i.length > 0 ? Math.min(...i) : null;
1534
+ }
1535
+ /**
1536
+ * 최대값 계산
1537
+ */
1538
+ calculateMax(e) {
1539
+ const i = e.map((s) => this.toNumber(s)).filter((s) => s !== null);
1540
+ return i.length > 0 ? Math.max(...i) : null;
1541
+ }
1542
+ /**
1543
+ * CellValue를 숫자로 변환
1544
+ */
1545
+ toNumber(e) {
1546
+ if (typeof e == "number") return e;
1547
+ if (typeof e == "string") {
1548
+ const i = e.replace(/,/g, ""), s = parseFloat(i);
1549
+ return isNaN(s) ? null : s;
1550
+ }
1551
+ return typeof e == "boolean" ? e ? 1 : 0 : null;
1552
+ }
1553
+ /**
1554
+ * Summary 값 포맷팅
1555
+ */
1556
+ formatSummaryValue(e, i, s) {
1557
+ return i.formatter ? i.formatter(e) : s.formatter ? s.formatter(e, {}, s) : e == null ? "" : typeof e == "number" ? i.format ? this.applyNumberFormat(e, i.format) : this.formatNumber(e) : String(e);
1558
+ }
1559
+ /**
1560
+ * 숫자 포맷 적용
1561
+ * @param value 숫자 값
1562
+ * @param format 포맷 문자열 (예: '0,0.00')
1563
+ */
1564
+ applyNumberFormat(e, i) {
1565
+ const s = i.includes(","), o = i.match(/\.(\d+)/), n = o ? o[1].length : 0;
1566
+ let t = e.toFixed(n);
1567
+ if (s) {
1568
+ const l = t.split(".");
1569
+ l[0] = l[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","), t = l.join(".");
1570
+ }
1571
+ return t;
1572
+ }
1573
+ /**
1574
+ * 기본 숫자 포맷팅
1575
+ */
1576
+ formatNumber(e) {
1577
+ return Number.isInteger(e) ? e.toLocaleString("en-US") : e.toLocaleString("en-US", {
1578
+ minimumFractionDigits: 0,
1579
+ maximumFractionDigits: 2
1580
+ });
1581
+ }
1582
+ /**
1583
+ * 캐시 무효화
1584
+ */
1585
+ invalidateCache() {
1586
+ this.summaryCache.clear();
1587
+ }
1588
+ /**
1589
+ * 특정 필드의 캐시만 무효화
1590
+ */
1591
+ invalidateFieldCache(e) {
1592
+ this.summaryCache.delete(`footer:${e}`);
1593
+ }
1594
+ /**
1595
+ * Summary 값 가져오기 (캐시 우선)
1596
+ */
1597
+ getSummaryValue(e) {
1598
+ const i = this.calculateFooterSummary(e);
1599
+ return (i == null ? void 0 : i.value) ?? null;
1600
+ }
1601
+ /**
1602
+ * 모든 Summary 값 가져오기
1603
+ */
1604
+ getAllSummaryValues() {
1605
+ const e = this.calculateAllFooterSummaries(), i = {};
1606
+ return e.forEach((s, o) => {
1607
+ i[o] = s.value;
1608
+ }), i;
1609
+ }
1610
+ }
1611
+ const _t = {
1612
+ rowHeight: 40,
1613
+ headerHeight: 44,
1614
+ showRowNumbers: !1,
1615
+ rowDraggable: !1,
1616
+ selectable: !0,
1617
+ selectionMode: "multiple",
1618
+ selectionStyle: "row",
1619
+ showCheckbox: !1,
1620
+ sortable: !0,
1621
+ filterable: !1,
1622
+ editable: !1,
1623
+ resizable: !0,
1624
+ virtualScroll: !1,
1625
+ bufferSize: 5,
1626
+ theme: "default",
1627
+ locale: "ko-KR",
1628
+ emptyMessage: "데이터가 없습니다.",
1629
+ loading: !1,
1630
+ loadingMessage: "로딩 중...",
1631
+ undoable: !0,
1632
+ undoStackSize: 50
1633
+ }, N = {
1634
+ visible: !1,
1635
+ exclusive: !1,
1636
+ showAll: !0
1637
+ };
1638
+ class G {
1639
+ constructor(e, i, s = {}) {
1640
+ var o, n, t, l, a;
1641
+ if (this.footerElement = null, this.fixedLeftFooter = null, this.loadingOverlay = null, this.fixedLeftContainer = null, this.fixedLeftHeader = null, this.fixedLeftBody = null, this.fixedLeftBodyInner = null, this.fixedRightContainer = null, this.fixedRightHeader = null, this.fixedRightBody = null, this.fixedRightBodyInner = null, this.fixedRightFooter = null, this.paginationContainer = null, this.infiniteScrollLoading = !1, this.infiniteScrollAllLoaded = !1, this.blockSelecting = null, this.measureCanvas = null, this.measureContext = null, this.virtualState = {
1642
+ startIndex: 0,
1643
+ endIndex: 0,
1644
+ visibleCount: 0,
1645
+ totalHeight: 0
1646
+ }, this.dataIndexMap = /* @__PURE__ */ new Map(), this.columnCache = {
1647
+ visible: null,
1648
+ fixedLeft: null,
1649
+ scrollable: null,
1650
+ fixedRight: null,
1651
+ // Phase 14: Columns fixed to right
1652
+ dirty: !0
1653
+ }, this.tooltip = null, this.editModeCleanup = null, this.scrollHandlers = [], this.wheelHandler = null, typeof e == "string") {
1654
+ const r = document.querySelector(e);
1655
+ if (!r) throw new Error(`Container not found: ${e}`);
1656
+ this.container = r;
1657
+ } else
1658
+ this.container = e;
1659
+ this.options = { ..._t, ...i }, this.options.checkBar ? this.options.checkBar = { ...N, ...this.options.checkBar } : this.options.showCheckbox && (this.options.checkBar = { ...N, visible: !0 }), this.events = s, this.gridId = vt("velox-grid"), this.boundHandleBlockSelectionEnd = this.handleBlockSelectionEnd.bind(this), this.boundHandleKeyDown = this.handleKeyDown.bind(this), this.history = new Pt({
1660
+ enabled: this.options.undoable ?? !0,
1661
+ maxSize: this.options.undoStackSize ?? 50
1662
+ }), this.renderer = new Vt(this), this.filterPopupManager = new At(this), this.columnMenuManager = new Nt(this), this.dragManager = new $t(this), this.summary = new zt(this), this.state = {
1663
+ data: [],
1664
+ displayData: [],
1665
+ columns: this.options.columns.map((r) => ({ ...r })),
1666
+ selection: {
1667
+ selectedRows: /* @__PURE__ */ new Set(),
1668
+ selectedCells: /* @__PURE__ */ new Set(),
1669
+ focusedCell: null,
1670
+ selections: [],
1671
+ lastSelectedRow: null
1672
+ },
1673
+ checkBar: {
1674
+ checkedRows: /* @__PURE__ */ new Set(),
1675
+ checkableRows: /* @__PURE__ */ new Set()
1676
+ },
1677
+ rowStates: /* @__PURE__ */ new Map(),
1678
+ // Phase 15: Row state tracking
1679
+ sort: [],
1680
+ filter: null,
1681
+ edit: {
1682
+ editing: !1,
1683
+ rowIndex: null,
1684
+ field: null,
1685
+ originalValue: null
1686
+ },
1687
+ pagination: {
1688
+ currentPage: 1,
1689
+ pageSize: ((o = this.options.pagination) == null ? void 0 : o.pageSize) || 20,
1690
+ totalCount: ((n = this.options.dataSource) == null ? void 0 : n.totalCount) || 0,
1691
+ totalPages: 0,
1692
+ loading: !1
1693
+ },
1694
+ scroll: { top: 0, left: 0 }
1695
+ }, this.options.data && (this.state.data = this.options.data.map((r) => ({ ...r })), this.rebuildDataIndexMap(), this.state.displayData = [...this.state.data], this.initCheckableRows(), this.state.data.forEach((r) => {
1696
+ this.state.rowStates.set(r, "none");
1697
+ })), this.build(), this.tooltip = new Ot(this.rootElement), (t = this.options.pagination) != null && t.enabled ? this.isRemoteDataSource() ? (this.render(), this.fetchData()) : (this.state.pagination.totalCount = this.state.data.length, this.updateTotalPages(), this.options.pagination.mode === "infinite" ? this.applyLocalInfiniteScroll() : this.applyLocalPagination(), this.render()) : this.render(), this.attachEvents(), (a = (l = this.events).onReady) == null || a.call(l, this);
1698
+ }
1699
+ // GridContext: Data index methods (public for module access)
1700
+ rebuildDataIndexMap() {
1701
+ this.dataIndexMap.clear(), this.state.data.forEach((e, i) => {
1702
+ this.dataIndexMap.set(e, i);
1703
+ });
1704
+ }
1705
+ initCheckableRows() {
1706
+ this.state.checkBar.checkableRows.clear();
1707
+ const e = this.options.checkBar;
1708
+ this.state.displayData.forEach((i, s) => {
1709
+ e != null && e.checkableCallback ? e.checkableCallback(i, s) && this.state.checkBar.checkableRows.add(s) : this.state.checkBar.checkableRows.add(s);
1710
+ });
1711
+ }
1712
+ // GridContext: Column cache methods (public for module access)
1713
+ invalidateColumnCache() {
1714
+ this.columnCache.dirty = !0, this.columnCache.visible = null, this.columnCache.fixedLeft = null, this.columnCache.scrollable = null, this.columnCache.fixedRight = null;
1715
+ }
1716
+ /**
1717
+ * Get special columns with displayOrder
1718
+ * Phase 14.1: Helper method to generate special columns sorted by displayOrder
1719
+ */
1720
+ getSpecialColumnsWithOrder() {
1721
+ var i;
1722
+ const e = [];
1723
+ if (typeof this.options.rowDraggable == "object" && this.options.rowDraggable.enabled) {
1724
+ const s = this.options.rowDraggable.displayOrder ?? 0;
1725
+ e.push({
1726
+ col: { field: "__drag", header: "", width: 44, visible: !0 },
1727
+ order: s
1728
+ });
1729
+ } else this.options.rowDraggable === !0 && e.push({
1730
+ col: { field: "__drag", header: "", width: 44, visible: !0 },
1731
+ order: 0
1732
+ // default order
1733
+ });
1734
+ if ((i = this.options.checkBar) != null && i.visible) {
1735
+ const s = this.options.checkBar.displayOrder ?? 10;
1736
+ e.push({
1737
+ col: { field: "__checkbox", header: "", width: 44, visible: !0 },
1738
+ order: s
1739
+ });
1740
+ }
1741
+ if (typeof this.options.showRowNumbers == "object" && this.options.showRowNumbers.visible) {
1742
+ const s = this.options.showRowNumbers.displayOrder ?? 20;
1743
+ e.push({
1744
+ col: { field: "__rownum", header: "#", width: 50, visible: !0 },
1745
+ order: s
1746
+ });
1747
+ } else this.options.showRowNumbers === !0 && e.push({
1748
+ col: { field: "__rownum", header: "#", width: 50, visible: !0 },
1749
+ order: 20
1750
+ // default order
1751
+ });
1752
+ return e.sort((s, o) => s.order - o.order), e.map((s) => s.col);
1753
+ }
1754
+ /**
1755
+ * Get fixed left columns
1756
+ * Phase 14: Only include special columns when fixedOptions.colCount > 0
1757
+ * Phase 14.1: Sort special columns by displayOrder
1758
+ *
1759
+ * Logic:
1760
+ * - If colCount = 0: Fixed left is empty (special columns go to scrollable)
1761
+ * - If colCount > 0: Fixed left = special columns (sorted by displayOrder) + first N data columns
1762
+ */
1763
+ getFixedLeftColumns() {
1764
+ if (this.columnCache.dirty || !this.columnCache.fixedLeft) {
1765
+ const { colCount: e = 0 } = this.options.fixedOptions || {};
1766
+ if (e > 0) {
1767
+ const i = this.getSpecialColumnsWithOrder(), o = this.getDataColumns().slice(0, e);
1768
+ this.columnCache.fixedLeft = [...i, ...o];
1769
+ } else
1770
+ this.columnCache.fixedLeft = [];
1771
+ }
1772
+ return this.columnCache.fixedLeft;
1773
+ }
1774
+ /**
1775
+ * Get columns fixed to right (based on fixedOptions.rightCount)
1776
+ * Phase 14: New method for right fixed columns
1777
+ */
1778
+ getFixedRightColumns() {
1779
+ if (this.columnCache.dirty || !this.columnCache.fixedRight) {
1780
+ const { rightCount: e = 0 } = this.options.fixedOptions || {}, i = this.getDataColumns(), s = i.length;
1781
+ this.columnCache.fixedRight = e > 0 ? i.slice(s - e) : [];
1782
+ }
1783
+ return this.columnCache.fixedRight;
1784
+ }
1785
+ /**
1786
+ * Get scrollable columns (middle area between fixed left and fixed right)
1787
+ * Phase 14: Include special columns when colCount = 0
1788
+ * Phase 14.1: Sort special columns by displayOrder
1789
+ *
1790
+ * Logic:
1791
+ * - If colCount = 0: Scrollable = special columns (sorted by displayOrder) + all data columns (except fixed right)
1792
+ * - If colCount > 0: Scrollable = middle data columns only (between fixed left and fixed right)
1793
+ */
1794
+ getScrollableColumns() {
1795
+ if (this.columnCache.dirty || !this.columnCache.scrollable) {
1796
+ const { colCount: e = 0, rightCount: i = 0 } = this.options.fixedOptions || {}, s = this.getDataColumns(), o = s.length;
1797
+ if (e === 0) {
1798
+ const n = this.getSpecialColumnsWithOrder(), t = o - i, l = t > 0 ? s.slice(0, t) : [];
1799
+ this.columnCache.scrollable = [...n, ...l];
1800
+ } else {
1801
+ const n = e, t = o - i;
1802
+ this.columnCache.scrollable = n < t ? s.slice(n, t) : [];
1803
+ }
1804
+ this.columnCache.dirty = !1;
1805
+ }
1806
+ return this.columnCache.scrollable;
1807
+ }
1808
+ /**
1809
+ * Get data columns (exclude special columns)
1810
+ * Phase 14: Helper method to filter out special columns
1811
+ */
1812
+ getDataColumns() {
1813
+ return this.state.columns.filter(
1814
+ (e) => e.visible !== !1 && !this.isSpecialColumn(e)
1815
+ );
1816
+ }
1817
+ /**
1818
+ * Check if column is special (CheckBar, RowNumbers, DragHandle)
1819
+ * Phase 14: Helper method to identify special columns
1820
+ */
1821
+ isSpecialColumn(e) {
1822
+ return e.field === "__checkbox" || e.field === "__rownum" || e.field === "__drag";
1823
+ }
1824
+ getVisibleColumns() {
1825
+ return (this.columnCache.dirty || !this.columnCache.visible) && (this.columnCache.visible = this.state.columns.filter((e) => e.visible !== !1)), this.columnCache.visible;
1826
+ }
1827
+ /**
1828
+ * Check if grid has fixed left columns
1829
+ * Phase 14: Only true when fixedOptions.colCount > 0
1830
+ */
1831
+ hasFixedLeft() {
1832
+ const { colCount: e = 0 } = this.options.fixedOptions || {};
1833
+ return e > 0;
1834
+ }
1835
+ /**
1836
+ * Check if grid has fixed right columns
1837
+ * Phase 14: New method for hasFixedRight
1838
+ */
1839
+ hasFixedRight() {
1840
+ const { rightCount: e = 0 } = this.options.fixedOptions || {};
1841
+ return e > 0;
1842
+ }
1843
+ build() {
1844
+ var s, o, n, t;
1845
+ this.rootElement = p("div", "velox-grid"), this.rootElement.id = this.gridId, this.rootElement.tabIndex = 0, this.options.className && w(this.rootElement, this.options.className), this.hasFixedRight() && w(this.rootElement, "has-fixed-right"), this.options.width && (this.rootElement.style.width = typeof this.options.width == "number" ? `${this.options.width}px` : this.options.width), this.options.height && (this.rootElement.style.height = typeof this.options.height == "number" ? `${this.options.height}px` : this.options.height);
1846
+ const e = p("div", "velox-wrapper");
1847
+ this.hasFixedLeft() && (this.fixedLeftContainer = p("div", "velox-fixed-left"), this.fixedLeftHeader = p("div", "velox-header velox-header--fixed"), this.fixedLeftBody = p("div", "velox-body--fixed"), this.fixedLeftBodyInner = p("div", "velox-body-inner"), this.fixedLeftBody.appendChild(this.fixedLeftBodyInner), this.fixedLeftContainer.appendChild(this.fixedLeftHeader), this.fixedLeftContainer.appendChild(this.fixedLeftBody), (s = this.options.footerSummary) != null && s.visible && (this.fixedLeftFooter = p("div", "velox-footer velox-footer--fixed"), this.fixedLeftContainer.appendChild(this.fixedLeftFooter)), e.appendChild(this.fixedLeftContainer));
1848
+ const i = p("div", "velox-main");
1849
+ this.headerElement = p("div", "velox-header"), this.bodyElement = p("div", "velox-body"), this.bodyInner = p("div", "velox-body-inner"), this.bodyElement.appendChild(this.bodyInner), i.appendChild(this.headerElement), i.appendChild(this.bodyElement), (o = this.options.footerSummary) != null && o.visible && (this.footerElement = p("div", "velox-footer"), i.appendChild(this.footerElement)), e.appendChild(i), this.hasFixedRight() && (this.fixedRightContainer = p("div", "velox-fixed-right"), this.fixedRightHeader = p("div", "velox-header velox-header--fixed-right"), this.fixedRightBody = p("div", "velox-body--fixed"), this.fixedRightBodyInner = p("div", "velox-body-inner"), this.fixedRightBody.appendChild(this.fixedRightBodyInner), this.fixedRightContainer.appendChild(this.fixedRightHeader), this.fixedRightContainer.appendChild(this.fixedRightBody), (n = this.options.footerSummary) != null && n.visible && (this.fixedRightFooter = p("div", "velox-footer velox-footer--fixed-right"), this.fixedRightContainer.appendChild(this.fixedRightFooter)), e.appendChild(this.fixedRightContainer)), this.rootElement.appendChild(e), (t = this.options.pagination) != null && t.enabled && (this.paginationContainer = p("div", "velox-pagination"), this.rootElement.appendChild(this.paginationContainer)), this.container.innerHTML = "", this.container.appendChild(this.rootElement), this.buildLoadingOverlay();
1850
+ }
1851
+ buildLoadingOverlay() {
1852
+ this.loadingOverlay = p("div", "velox-loading-overlay"), this.loadingOverlay.style.display = "none";
1853
+ const e = p("div", "velox-loading-spinner"), i = p("div", "velox-loading-message");
1854
+ i.textContent = this.options.loadingMessage || "로딩 중...", this.loadingOverlay.appendChild(e), this.loadingOverlay.appendChild(i), this.rootElement.appendChild(this.loadingOverlay);
1855
+ }
1856
+ // GridContext: Virtual scroll methods (public for module access)
1857
+ calculateVirtualState() {
1858
+ if (!this.options.virtualScroll) return;
1859
+ const e = this.options.rowHeight || 40, i = this.bodyElement.clientHeight, s = this.bodyElement.scrollTop, o = this.options.bufferSize || 5;
1860
+ this.virtualState.visibleCount = Math.ceil(i / e), this.virtualState.startIndex = Math.max(0, Math.floor(s / e) - o), this.virtualState.endIndex = Math.min(
1861
+ this.state.displayData.length,
1862
+ this.virtualState.startIndex + this.virtualState.visibleCount + o * 2
1863
+ ), this.virtualState.totalHeight = this.state.displayData.length * e;
1864
+ }
1865
+ getVisibleRows() {
1866
+ if (!this.options.virtualScroll)
1867
+ return this.state.displayData.map((i, s) => ({ data: i, index: s }));
1868
+ this.calculateVirtualState();
1869
+ const e = [];
1870
+ for (let i = this.virtualState.startIndex; i < this.virtualState.endIndex; i++)
1871
+ this.state.displayData[i] && e.push({ data: this.state.displayData[i], index: i });
1872
+ return e;
1873
+ }
1874
+ // GridContext: Rendering methods - delegated to GridRenderer
1875
+ render() {
1876
+ console.log("🔄 render() called", { editing: this.state.edit.editing, rowIndex: this.state.edit.rowIndex, field: this.state.edit.field }), this.renderer.render(), this.paginationContainer && this.renderPagination();
1877
+ }
1878
+ renderHeader() {
1879
+ this.renderer.renderHeader();
1880
+ }
1881
+ renderBody() {
1882
+ this.renderer.renderBody();
1883
+ }
1884
+ updateLoadingState() {
1885
+ this.renderer.updateLoadingState();
1886
+ }
1887
+ // GridContext: Filter popup methods - delegated to GridFilterPopup
1888
+ showFilterPopup(e, i) {
1889
+ this.filterPopupManager.showFilterPopup(e, i);
1890
+ }
1891
+ closeFilterPopup() {
1892
+ this.filterPopupManager.closeFilterPopup();
1893
+ }
1894
+ applyColumnFilter(e, i, s) {
1895
+ this.filterPopupManager.applyColumnFilter(e, i, s);
1896
+ }
1897
+ removeColumnFilter(e) {
1898
+ this.filterPopupManager.removeColumnFilter(e);
1899
+ }
1900
+ detachEvents() {
1901
+ this.scrollHandlers.forEach((e) => {
1902
+ this.bodyElement.removeEventListener("scroll", e), this.fixedRightBody && this.fixedRightBody.removeEventListener("scroll", e);
1903
+ }), this.scrollHandlers = [], this.wheelHandler && (this.bodyElement.removeEventListener("wheel", this.wheelHandler), this.wheelHandler = null);
1904
+ }
1905
+ attachEvents() {
1906
+ this.detachEvents();
1907
+ let e = !1, i = null;
1908
+ const s = (n) => {
1909
+ var a, r;
1910
+ if (e || i !== null) return;
1911
+ i = window.setTimeout(() => {
1912
+ i = null;
1913
+ }, 16), e = !0;
1914
+ const t = n === "fixedRight" && this.fixedRightBody ? this.fixedRightBody.scrollTop : this.bodyElement.scrollTop, l = this.bodyElement.scrollLeft;
1915
+ this.state.scroll.top = t, this.state.scroll.left = l, this.fixedLeftBody && this.fixedLeftBody.scrollTop !== t && (this.fixedLeftBody.scrollTop = t), n !== "fixedRight" && this.fixedRightBody && this.fixedRightBody.scrollTop !== t && (this.fixedRightBody.scrollTop = t), n !== "body" && this.bodyElement.scrollTop !== t && (this.bodyElement.scrollTop = t), this.headerElement.scrollLeft !== l && (this.headerElement.scrollLeft = l), this.footerElement && this.footerElement.scrollLeft !== l && (this.footerElement.scrollLeft = l), this.options.virtualScroll && this.renderBody(), (r = (a = this.events).onScroll) == null || r.call(a, this.state.scroll.top, this.state.scroll.left), (n === "body" || n === "fixedRight") && this.checkInfiniteScroll(), e = !1;
1916
+ }, o = yt(() => {
1917
+ const n = this.headerElement.scrollLeft;
1918
+ this.bodyElement.scrollLeft = n, this.footerElement && (this.footerElement.scrollLeft = n);
1919
+ }, 16);
1920
+ if (this.hasFixedRight()) {
1921
+ this.wheelHandler = (l) => {
1922
+ l.preventDefault(), this.fixedRightBody && (this.fixedRightBody.scrollTop += l.deltaY);
1923
+ }, this.bodyElement.addEventListener("wheel", this.wheelHandler, { passive: !1 });
1924
+ const n = () => s("fixedRight");
1925
+ this.fixedRightBody.addEventListener("scroll", n), this.scrollHandlers.push(n);
1926
+ const t = () => s("body");
1927
+ this.bodyElement.addEventListener("scroll", t), this.scrollHandlers.push(t);
1928
+ } else {
1929
+ const n = () => s("body");
1930
+ this.bodyElement.addEventListener("scroll", n), this.scrollHandlers.push(n);
1931
+ }
1932
+ this.headerElement.addEventListener("scroll", o), this.scrollHandlers.push(o), document.addEventListener("mouseup", this.boundHandleBlockSelectionEnd), this.rootElement.addEventListener("keydown", this.boundHandleKeyDown);
1933
+ }
1934
+ handleSort(e) {
1935
+ var o, n, t;
1936
+ const i = this.state.sort.findIndex((l) => l.field === e);
1937
+ let s = "asc";
1938
+ if (i >= 0) {
1939
+ const l = this.state.sort[i].direction;
1940
+ l === "asc" ? s = "desc" : l === "desc" && (s = null);
1941
+ }
1942
+ this.state.sort = s ? [{ field: e, direction: s }] : [], this.clearSelectionState(), this.applyDataTransformations(), (!this.isRemoteDataSource() || !((o = this.options.pagination) != null && o.enabled)) && this.render(), (t = (n = this.events).onSort) == null || t.call(n, this.state.sort);
1943
+ }
1944
+ // GridContext: Event handlers (public for module access)
1945
+ handleRowClick(e, i) {
1946
+ var o, n;
1947
+ if (!this.options.selectable) return;
1948
+ (this.options.selectionStyle || "row") === "row" && this.handleRowSelection(e, i), (n = (o = this.events).onRowClick) == null || n.call(o, e, this.state.displayData[e]);
1949
+ }
1950
+ handleRowSelection(e, i) {
1951
+ var o, n;
1952
+ const s = this.options.selectionMode || "multiple";
1953
+ if (s !== "none")
1954
+ if (s === "multiple" && (i.ctrlKey || i.metaKey)) {
1955
+ const t = this.state.selection.selectedRows.has(e);
1956
+ this.selectRow(e, !t);
1957
+ } else if (s === "multiple" && i.shiftKey) {
1958
+ const t = Array.from(this.state.selection.selectedRows);
1959
+ if (t.length > 0) {
1960
+ const l = t[t.length - 1], a = Math.min(l, e), r = Math.max(l, e);
1961
+ for (let h = a; h <= r; h++) this.state.selection.selectedRows.add(h);
1962
+ this.render(), (n = (o = this.events).onSelectionChange) == null || n.call(o, this.getSelectedRows());
1963
+ } else
1964
+ this.selectRow(e, !0);
1965
+ } else if (s === "extended" && (i.ctrlKey || i.metaKey)) {
1966
+ const t = this.state.selection.selectedRows.has(e);
1967
+ this.selectRow(e, !t);
1968
+ } else
1969
+ this.state.selection.selectedRows.clear(), this.selectRow(e, !0);
1970
+ }
1971
+ handleCellClick(e, i, s, o) {
1972
+ var t, l;
1973
+ if (console.log("🔍 handleCellClick", { rowIndex: e, field: i, editing: this.state.edit.editing, editRow: this.state.edit.rowIndex, editField: this.state.edit.field }), this.state.edit.editing && this.state.edit.rowIndex === e && this.state.edit.field === i) {
1974
+ console.log("✅ Same cell clicked - maintaining edit mode");
1975
+ return;
1976
+ }
1977
+ const n = this.options.selectionStyle || "row";
1978
+ n === "cell" || n === "block" ? this.handleCellSelection(e, i, o) : n === "row" && (this.state.selection.focusedCell = { rowIndex: e, field: i }), (l = (t = this.events).onCellClick) == null || l.call(t, e, i, s);
1979
+ }
1980
+ handleCellSelection(e, i, s) {
1981
+ var t, l;
1982
+ const o = this.options.selectionMode || "multiple", n = `${e}:${i}`;
1983
+ if (o !== "none") {
1984
+ if (this.state.selection.focusedCell = { rowIndex: e, field: i }, o === "multiple" && (s.ctrlKey || s.metaKey))
1985
+ this.state.selection.selectedCells.has(n) ? this.state.selection.selectedCells.delete(n) : this.state.selection.selectedCells.add(n);
1986
+ else if (o === "multiple" && s.shiftKey) {
1987
+ const a = this.state.selection.focusedCell;
1988
+ a && this.selectCellRange(a.rowIndex, a.field, e, i);
1989
+ } else
1990
+ this.state.selection.selectedCells.clear(), this.state.selection.selectedCells.add(n);
1991
+ this.render(), (l = (t = this.events).onCellSelectionChange) == null || l.call(t, this.getSelectedCells());
1992
+ }
1993
+ }
1994
+ selectCellRange(e, i, s, o) {
1995
+ const n = this.getVisibleColumns(), t = n.findIndex((d) => d.field === i), l = n.findIndex((d) => d.field === o), a = Math.min(e, s), r = Math.max(e, s), h = Math.min(t, l), g = Math.max(t, l);
1996
+ this.state.selection.selectedCells.clear();
1997
+ for (let d = a; d <= r; d++)
1998
+ for (let f = h; f <= g; f++) {
1999
+ const C = n[f].field;
2000
+ this.state.selection.selectedCells.add(`${d}:${C}`);
2001
+ }
2002
+ }
2003
+ // GridContext: Block selection methods (public for module access)
2004
+ startBlockSelection(e, i) {
2005
+ this.options.selectionStyle === "block" && (this.blockSelecting = { startRow: e, startField: i }, this.state.selection.focusedCell = { rowIndex: e, field: i }, this.state.selection.selectedCells.clear(), this.state.selection.selectedCells.add(`${e}:${i}`), this.render());
2006
+ }
2007
+ updateBlockSelection(e, i) {
2008
+ this.blockSelecting && (this.selectCellRange(
2009
+ this.blockSelecting.startRow,
2010
+ this.blockSelecting.startField,
2011
+ e,
2012
+ i
2013
+ ), this.render());
2014
+ }
2015
+ handleBlockSelectionEnd() {
2016
+ var e, i;
2017
+ this.blockSelecting && (this.blockSelecting = null, (i = (e = this.events).onCellSelectionChange) == null || i.call(e, this.getSelectedCells()));
2018
+ }
2019
+ handleRowDoubleClick(e, i) {
2020
+ var s, o;
2021
+ (o = (s = this.events).onRowDoubleClick) == null || o.call(s, e, this.state.displayData[e]);
2022
+ }
2023
+ handleKeyDown(e) {
2024
+ var a, r, h, g;
2025
+ if (this.state.edit.editing) {
2026
+ e.key === "Escape" ? this.cancelEdit() : e.key === "Enter" ? (e.preventDefault(), this.endEditAndMove(e.shiftKey ? "up" : "down")) : e.key === "Tab" && (e.preventDefault(), this.endEditAndMove(e.shiftKey ? "left" : "right"));
2027
+ return;
2028
+ }
2029
+ if ((e.ctrlKey || e.metaKey) && e.key === "z") {
2030
+ e.preventDefault(), this.undo();
2031
+ return;
2032
+ }
2033
+ if ((e.ctrlKey || e.metaKey) && e.key === "y") {
2034
+ e.preventDefault(), this.redo();
2035
+ return;
2036
+ }
2037
+ if ((e.ctrlKey || e.metaKey) && e.key === "c") {
2038
+ e.preventDefault(), this.copy();
2039
+ return;
2040
+ }
2041
+ if ((e.ctrlKey || e.metaKey) && e.key === "v") {
2042
+ e.preventDefault(), this.paste();
2043
+ return;
2044
+ }
2045
+ if ((e.ctrlKey || e.metaKey) && e.key === "x") {
2046
+ e.preventDefault(), this.cut();
2047
+ return;
2048
+ }
2049
+ if ((e.key === "Delete" || e.key === "Backspace") && this.options.editable) {
2050
+ e.preventDefault(), this.deleteSelectedCells();
2051
+ return;
2052
+ }
2053
+ const i = this.state.selection.focusedCell;
2054
+ if (!this.state.edit.editing && this.options.editable && i) {
2055
+ const d = this.state.columns.find((f) => f.field === i.field);
2056
+ if ((d == null ? void 0 : d.editable) !== !1 && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
2057
+ e.preventDefault(), this.startEdit(i.rowIndex, i.field), setTimeout(() => {
2058
+ const f = document.querySelector(".velox-edit-input");
2059
+ f && (f.value = e.key, f.setSelectionRange(1, 1));
2060
+ }, 0);
2061
+ return;
2062
+ }
2063
+ }
2064
+ if ((r = (a = this.events).onKeyDown) == null || r.call(a, e, i), !i) return;
2065
+ const s = this.getVisibleColumns(), o = s.findIndex((d) => d.field === i.field);
2066
+ let n = i.rowIndex, t = o, l = !1;
2067
+ switch (e.key) {
2068
+ case "ArrowUp":
2069
+ n > 0 && (n--, l = !0);
2070
+ break;
2071
+ case "ArrowDown":
2072
+ n < this.state.displayData.length - 1 && (n++, l = !0);
2073
+ break;
2074
+ case "ArrowLeft":
2075
+ t > 0 && (t--, l = !0);
2076
+ break;
2077
+ case "ArrowRight":
2078
+ t < s.length - 1 && (t++, l = !0);
2079
+ break;
2080
+ case "Tab":
2081
+ e.shiftKey ? t > 0 ? t-- : n > 0 && (n--, t = s.length - 1) : t < s.length - 1 ? t++ : n < this.state.displayData.length - 1 && (n++, t = 0), l = !0;
2082
+ break;
2083
+ case "Home":
2084
+ e.ctrlKey && (n = 0), t = 0, l = !0;
2085
+ break;
2086
+ case "End":
2087
+ e.ctrlKey && (n = this.state.displayData.length - 1), t = s.length - 1, l = !0;
2088
+ break;
2089
+ case "PageUp":
2090
+ n = Math.max(0, n - this.virtualState.visibleCount), l = !0;
2091
+ break;
2092
+ case "PageDown":
2093
+ n = Math.min(this.state.displayData.length - 1, n + this.virtualState.visibleCount), l = !0;
2094
+ break;
2095
+ case "Enter":
2096
+ case "F2":
2097
+ this.options.editable && (this.startEdit(i.rowIndex, i.field), l = !0);
2098
+ break;
2099
+ case " ":
2100
+ (h = this.options.checkBar) != null && h.visible && (this.checkItem(i.rowIndex, !this.isItemChecked(i.rowIndex)), l = !0);
2101
+ break;
2102
+ case "a":
2103
+ case "A":
2104
+ (e.ctrlKey || e.metaKey) && (this.selectAllCells(), l = !0);
2105
+ break;
2106
+ }
2107
+ if (l) {
2108
+ e.preventDefault();
2109
+ const d = (g = s[t]) == null ? void 0 : g.field;
2110
+ d && (n !== i.rowIndex || d !== i.field) && (this.setFocusedCell(n, d), e.shiftKey && (this.options.selectionStyle === "cell" || this.options.selectionStyle === "block") ? this.selectCellRange(i.rowIndex, i.field, n, d) : !e.shiftKey && !e.ctrlKey && (this.state.selection.selectedCells.clear(), this.state.selection.selectedCells.add(`${n}:${d}`), this.options.selectionStyle === "row" && (this.state.selection.selectedRows.clear(), this.state.selection.selectedRows.add(n))), this.render(), this.scrollToCell(n, d));
2111
+ }
2112
+ }
2113
+ selectAllCells() {
2114
+ var i, s;
2115
+ const e = this.getVisibleColumns();
2116
+ this.state.selection.selectedCells.clear();
2117
+ for (let o = 0; o < this.state.displayData.length; o++)
2118
+ for (const n of e)
2119
+ this.state.selection.selectedCells.add(`${o}:${n.field}`);
2120
+ this.render(), (s = (i = this.events).onCellSelectionChange) == null || s.call(i, this.getSelectedCells());
2121
+ }
2122
+ // GridContext: Resize methods - delegated to GridDragManager
2123
+ startResize(e, i) {
2124
+ this.dragManager.startResize(e, i);
2125
+ }
2126
+ // GridContext: Data transformation (public for module access)
2127
+ applyDataTransformations() {
2128
+ var i;
2129
+ if ((i = this.options.pagination) != null && i.enabled)
2130
+ if (this.infiniteScrollLoading = !1, this.infiniteScrollAllLoaded = !1, this.state.pagination.currentPage = 1, this.isRemoteDataSource()) {
2131
+ this.options.pagination.mode === "infinite" && (this.state.data = [], this.state.displayData = []), this.fetchData();
2132
+ return;
2133
+ } else {
2134
+ this.options.pagination.mode === "infinite" ? this.applyLocalInfiniteScroll() : this.applyLocalPagination();
2135
+ return;
2136
+ }
2137
+ let e = [...this.state.data];
2138
+ if (this.state.filter && (e = A(e, this.state.filter)), this.state.sort.length > 0) {
2139
+ const s = {};
2140
+ this.state.columns.forEach((o) => {
2141
+ s[o.field] = o.type || "text";
2142
+ }), e = V(e, this.state.sort, s);
2143
+ }
2144
+ this.state.displayData = e, this.initCheckableRows();
2145
+ }
2146
+ /**
2147
+ * Clear all selection state (rows, cells, focused cell)
2148
+ * Extracted to reduce code duplication
2149
+ */
2150
+ // GridContext: Selection state clearing (public for module access)
2151
+ clearSelectionState() {
2152
+ this.state.selection.selectedRows.clear(), this.state.selection.selectedCells.clear(), this.state.selection.focusedCell = null;
2153
+ }
2154
+ // --- Public API: Data Methods ---
2155
+ getData() {
2156
+ return this.state.data.map((e) => ({ ...e }));
2157
+ }
2158
+ setData(e) {
2159
+ var i, s, o;
2160
+ this.state.data = e.map((n) => ({ ...n })), this.rebuildDataIndexMap(), this.clearSelectionState(), this.state.checkBar.checkedRows.clear(), this.state.rowStates.clear(), this.state.data.forEach((n) => {
2161
+ this.state.rowStates.set(n, "none");
2162
+ }), (i = this.options.pagination) != null && i.enabled && !this.isRemoteDataSource() && (this.state.pagination.totalCount = this.state.data.length, this.state.pagination.currentPage = 1, this.updateTotalPages()), this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (o = (s = this.events).onDataChange) == null || o.call(s, this.state.data);
2163
+ }
2164
+ getRow(e) {
2165
+ return this.state.displayData[e] ? { ...this.state.displayData[e] } : null;
2166
+ }
2167
+ getRowCount() {
2168
+ return this.state.data.length;
2169
+ }
2170
+ getVisibleRowCount() {
2171
+ return this.state.displayData.length;
2172
+ }
2173
+ addRow(e, i) {
2174
+ var n, t, l, a;
2175
+ const s = { ...e }, o = i !== void 0 ? i : this.state.data.length;
2176
+ this.state.data.splice(o, 0, s), this.rebuildDataIndexMap(), this.state.rowStates.set(s, "created"), this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (t = (n = this.events).onRowAdd) == null || t.call(n, s, o), (a = (l = this.events).onDataChange) == null || a.call(l, this.state.data);
2177
+ }
2178
+ updateRow(e, i) {
2179
+ var n, t, l, a;
2180
+ const s = this.state.displayData[e];
2181
+ if (!s) return;
2182
+ const o = this.state.data.indexOf(s);
2183
+ o >= 0 && (Object.assign(this.state.data[o], i), (this.state.rowStates.get(this.state.data[o]) || "none") === "none" && this.state.rowStates.set(this.state.data[o], "updated"), this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (t = (n = this.events).onRowUpdate) == null || t.call(n, this.state.data[o], e, i), (a = (l = this.events).onDataChange) == null || a.call(l, this.state.data));
2184
+ }
2185
+ removeRow(e) {
2186
+ var o, n, t, l;
2187
+ const i = this.state.displayData[e];
2188
+ if (!i) return;
2189
+ const s = this.state.data.indexOf(i);
2190
+ if (s >= 0) {
2191
+ const a = this.state.data[s];
2192
+ (this.state.rowStates.get(a) || "none") === "created" ? this.state.rowStates.set(a, "createAndDeleted") : this.state.rowStates.set(a, "deleted"), this.state.data.splice(s, 1), this.rebuildDataIndexMap(), this.state.selection.selectedRows.delete(e);
2193
+ const h = /* @__PURE__ */ new Set();
2194
+ this.state.selection.selectedRows.forEach((d) => {
2195
+ d > e ? h.add(d - 1) : d < e && h.add(d);
2196
+ }), this.state.selection.selectedRows = h, this.state.checkBar.checkedRows.delete(e);
2197
+ const g = /* @__PURE__ */ new Set();
2198
+ this.state.checkBar.checkedRows.forEach((d) => {
2199
+ d > e ? g.add(d - 1) : d < e && g.add(d);
2200
+ }), this.state.checkBar.checkedRows = g, this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (n = (o = this.events).onRowRemove) == null || n.call(o, a, e), (l = (t = this.events).onDataChange) == null || l.call(t, this.state.data);
2201
+ }
2202
+ }
2203
+ clearData() {
2204
+ var e, i;
2205
+ this.state.data = [], this.state.displayData = [], this.dataIndexMap.clear(), this.state.selection.selectedRows.clear(), this.state.selection.selectedCells.clear(), this.state.selection.focusedCell = null, this.state.checkBar.checkedRows.clear(), this.state.checkBar.checkableRows.clear(), this.summary.invalidateCache(), this.render(), (i = (e = this.events).onDataChange) == null || i.call(e, []);
2206
+ }
2207
+ // --- Public API: Row Selection ---
2208
+ getSelectedRows() {
2209
+ return Array.from(this.state.selection.selectedRows).sort((e, i) => e - i);
2210
+ }
2211
+ getSelectedData() {
2212
+ return this.getSelectedRows().map((e) => this.state.displayData[e]).filter(Boolean).map((e) => ({ ...e }));
2213
+ }
2214
+ selectRow(e, i = !0) {
2215
+ var s, o, n, t;
2216
+ i ? (this.options.selectionMode === "single" && this.state.selection.selectedRows.clear(), this.state.selection.selectedRows.add(e)) : this.state.selection.selectedRows.delete(e), this.render(), (o = (s = this.events).onRowSelect) == null || o.call(s, e, i), (t = (n = this.events).onSelectionChange) == null || t.call(n, this.getSelectedRows());
2217
+ }
2218
+ selectAll(e = !0) {
2219
+ var i, s, o, n;
2220
+ if (e)
2221
+ for (let t = 0; t < this.state.displayData.length; t++)
2222
+ this.state.selection.selectedRows.add(t);
2223
+ else
2224
+ this.state.selection.selectedRows.clear();
2225
+ this.render(), (s = (i = this.events).onAllSelect) == null || s.call(i, e), (n = (o = this.events).onSelectionChange) == null || n.call(o, this.getSelectedRows());
2226
+ }
2227
+ clearSelection() {
2228
+ var e, i, s, o;
2229
+ this.clearSelectionState(), this.render(), (i = (e = this.events).onSelectionChange) == null || i.call(e, []), (o = (s = this.events).onCellSelectionChange) == null || o.call(s, []);
2230
+ }
2231
+ isRowSelected(e) {
2232
+ return this.state.selection.selectedRows.has(e);
2233
+ }
2234
+ // --- Public API: Cell Selection ---
2235
+ selectCell(e, i, s = !0) {
2236
+ var n, t, l, a;
2237
+ const o = `${e}:${i}`;
2238
+ s ? this.state.selection.selectedCells.add(o) : this.state.selection.selectedCells.delete(o), this.render(), (t = (n = this.events).onCellSelect) == null || t.call(n, { rowIndex: e, field: i }, s), (a = (l = this.events).onCellSelectionChange) == null || a.call(l, this.getSelectedCells());
2239
+ }
2240
+ getSelectedCells() {
2241
+ return Array.from(this.state.selection.selectedCells).map((e) => {
2242
+ const [i, s] = e.split(":");
2243
+ return { rowIndex: parseInt(i, 10), field: s };
2244
+ });
2245
+ }
2246
+ setFocusedCell(e, i) {
2247
+ this.state.selection.focusedCell = { rowIndex: e, field: i }, this.render();
2248
+ }
2249
+ getFocusedCell() {
2250
+ return this.state.selection.focusedCell;
2251
+ }
2252
+ setSelection(e) {
2253
+ if (this.state.selection.selectedCells.clear(), this.state.selection.selectedRows.clear(), e.style === "row")
2254
+ for (let i = e.startRow; i <= e.endRow; i++)
2255
+ this.state.selection.selectedRows.add(i);
2256
+ else (e.style === "cell" || e.style === "block") && e.startColumn && e.endColumn && this.selectCellRange(e.startRow, e.startColumn, e.endRow, e.endColumn);
2257
+ this.state.selection.selections = [e], this.render();
2258
+ }
2259
+ getSelection() {
2260
+ const e = this.state.selection.selections;
2261
+ return e.length > 0 ? e[0] : null;
2262
+ }
2263
+ getSelectionData() {
2264
+ const e = this.getSelectedCells();
2265
+ if (e.length === 0) return [];
2266
+ const i = [...new Set(e.map((l) => l.rowIndex))].sort((l, a) => l - a), s = [...new Set(e.map((l) => l.field))], n = this.getVisibleColumns().filter((l) => s.includes(l.field)).map((l) => l.field), t = [];
2267
+ for (const l of i) {
2268
+ const a = this.state.displayData[l];
2269
+ if (a) {
2270
+ const r = n.map((h) => a[h]);
2271
+ t.push(r);
2272
+ }
2273
+ }
2274
+ return t;
2275
+ }
2276
+ // --- Public API: CheckBar ---
2277
+ checkItem(e, i = !0) {
2278
+ var n, t;
2279
+ if (console.log("🔵 checkItem START", { index: e, checked: i, currentEditState: this.state.edit }), !this.state.checkBar.checkableRows.has(e)) return;
2280
+ const s = this.options.checkBar;
2281
+ s != null && s.exclusive && i && this.state.checkBar.checkedRows.clear(), i ? this.state.checkBar.checkedRows.add(e) : this.state.checkBar.checkedRows.delete(e);
2282
+ const o = { ...this.state.edit };
2283
+ console.log("💾 Saved edit state before render", o), this.render(), console.log("🔄 Render complete, edit state after render", this.state.edit), o.editing && o.rowIndex !== null && o.field !== null && (console.log("♻️ Restoring edit state", o), this.state.edit = o, this.renderEditCell(o.rowIndex, o.field, o.originalValue)), (t = (n = this.events).onCheckChange) == null || t.call(n, e, i), console.log("🔵 checkItem END");
2284
+ }
2285
+ checkItems(e, i = !0) {
2286
+ e.forEach((s) => {
2287
+ this.state.checkBar.checkableRows.has(s) && (i ? this.state.checkBar.checkedRows.add(s) : this.state.checkBar.checkedRows.delete(s));
2288
+ }), this.render();
2289
+ }
2290
+ checkAll(e = !0) {
2291
+ var i, s, o;
2292
+ (i = this.options.checkBar) != null && i.exclusive || (e ? this.state.checkBar.checkableRows.forEach((n) => {
2293
+ this.state.checkBar.checkedRows.add(n);
2294
+ }) : this.state.checkBar.checkedRows.clear(), this.render(), (o = (s = this.events).onCheckAllChange) == null || o.call(s, e));
2295
+ }
2296
+ uncheckAll() {
2297
+ this.checkAll(!1);
2298
+ }
2299
+ getCheckedItems() {
2300
+ return Array.from(this.state.checkBar.checkedRows).sort((e, i) => e - i);
2301
+ }
2302
+ getCheckedData() {
2303
+ return this.getCheckedItems().map((e) => this.state.displayData[e]).filter(Boolean).map((e) => ({ ...e }));
2304
+ }
2305
+ isItemChecked(e) {
2306
+ return this.state.checkBar.checkedRows.has(e);
2307
+ }
2308
+ isItemCheckable(e) {
2309
+ return this.state.checkBar.checkableRows.has(e);
2310
+ }
2311
+ checkRow(e, i = !0) {
2312
+ this.checkItem(e, i);
2313
+ }
2314
+ getCheckedRows() {
2315
+ return this.getCheckedItems();
2316
+ }
2317
+ // --- Public API: Sort ---
2318
+ sort(e, i = "asc") {
2319
+ var s, o;
2320
+ this.state.sort = i ? [{ field: e, direction: i }] : [], this.clearSelectionState(), this.applyDataTransformations(), this.render(), (o = (s = this.events).onSort) == null || o.call(s, this.state.sort);
2321
+ }
2322
+ clearSort() {
2323
+ var e, i;
2324
+ this.state.sort = [], this.applyDataTransformations(), this.render(), (i = (e = this.events).onSort) == null || i.call(e, []);
2325
+ }
2326
+ getSortState() {
2327
+ return [...this.state.sort];
2328
+ }
2329
+ // --- Public API: Filter ---
2330
+ filter(e) {
2331
+ var s, o;
2332
+ const i = Array.isArray(e) ? e : [e];
2333
+ this.state.filter = { conditions: i, logic: "and" }, this.clearSelectionState(), this.applyDataTransformations(), this.render(), (o = (s = this.events).onFilter) == null || o.call(s, this.state.filter);
2334
+ }
2335
+ clearFilter() {
2336
+ this.state.filter = null, this.clearSelectionState(), this.applyDataTransformations(), this.render();
2337
+ }
2338
+ getFilterState() {
2339
+ return this.state.filter ? { ...this.state.filter } : null;
2340
+ }
2341
+ // --- Public API: Edit ---
2342
+ startEdit(e, i) {
2343
+ var n, t, l;
2344
+ if (console.log("🎬 startEdit called", { rowIndex: e, field: i, editable: this.options.editable }), !this.options.editable) return;
2345
+ if (this.state.edit.editing && this.state.edit.rowIndex === e && this.state.edit.field === i) {
2346
+ console.log("⚠️ Already editing this cell - ignoring startEdit");
2347
+ return;
2348
+ }
2349
+ const s = this.state.columns.find((a) => a.field === i);
2350
+ if (console.log("📋 Column found", { column: s == null ? void 0 : s.field, editable: s == null ? void 0 : s.editable }), !s || s.editable === !1) return;
2351
+ this.state.edit.editing && this.endEdit(!0);
2352
+ const o = (n = this.state.displayData[e]) == null ? void 0 : n[i];
2353
+ this.state.edit = { editing: !0, rowIndex: e, field: i, originalValue: o }, console.log("✅ Edit state updated", this.state.edit), (l = (t = this.events).onCellEditStart) == null || l.call(t, e, i, o), this.renderEditCell(e, i, o);
2354
+ }
2355
+ renderEditCell(e, i, s) {
2356
+ console.log("🎨 renderEditCell START", { rowIndex: e, field: i, value: s, currentEditState: this.state.edit }), this.editModeCleanup && (console.log("🧹 Cleaning up previous edit mode listener"), this.editModeCleanup(), this.editModeCleanup = null);
2357
+ const o = this.bodyInner.querySelector(`[data-row-index="${e}"]`), n = o == null ? void 0 : o.querySelector(`[data-field="${i}"]`);
2358
+ if (console.log("🔍 Cell element found", { cell: !!n, hasClass: n == null ? void 0 : n.classList.contains("velox-cell--editing") }), !n) return;
2359
+ const t = this.state.columns.find((a) => a.field === i);
2360
+ if (!t) return;
2361
+ w(n, "velox-cell--editing"), console.log("✅ Added velox-cell--editing class", { classList: Array.from(n.classList) });
2362
+ const l = (a) => {
2363
+ const r = a.target;
2364
+ n.contains(r) ? console.log("📦 Inside cell click - maintaining edit mode") : (console.log("🌍 Outside click detected - ending edit"), this.editModeCleanup = null, document.removeEventListener("mousedown", l), this.endEdit(!0));
2365
+ };
2366
+ if (this.editModeCleanup = () => {
2367
+ document.removeEventListener("mousedown", l);
2368
+ }, setTimeout(() => {
2369
+ document.addEventListener("mousedown", l);
2370
+ }, 0), t.editor) {
2371
+ const a = Ft.createEditor(
2372
+ s,
2373
+ t.editor,
2374
+ (r) => {
2375
+ var g;
2376
+ if (console.log("💾 Editor save callback", { newValue: r, editing: this.state.edit.editing }), this.setCellValue(e, i, r), ((g = t.editor) == null ? void 0 : g.type) === "checkbox") {
2377
+ console.log("✅ Checkbox editor - maintaining edit mode, new value:", r), this.state.edit.originalValue = r;
2378
+ const d = { ...this.state.edit };
2379
+ d.editing && (this.state.edit = d, this.renderEditCell(d.rowIndex, d.field, r));
2380
+ } else
2381
+ console.log("🛑 Other editor - ending edit mode"), this.state.edit.editing = !1, this.applyDataTransformations(), this.render();
2382
+ const h = this.events;
2383
+ h.onCellEditEnd && h.onCellEditEnd({
2384
+ rowIndex: e,
2385
+ field: i,
2386
+ oldValue: s,
2387
+ newValue: r,
2388
+ row: this.state.displayData[e]
2389
+ });
2390
+ },
2391
+ () => {
2392
+ this.cancelEdit();
2393
+ },
2394
+ (r) => {
2395
+ this.endEditAndMove(r);
2396
+ }
2397
+ );
2398
+ n.innerHTML = "", n.appendChild(a), a.addEventListener("mousedown", () => {
2399
+ console.log("🖱️ Editor mousedown");
2400
+ }), setTimeout(() => {
2401
+ (a instanceof HTMLInputElement || a instanceof HTMLSelectElement) && (a.focus(), a instanceof HTMLInputElement && a.type === "text" && a.select());
2402
+ }, 0);
2403
+ } else {
2404
+ const a = p("input", "velox-edit-input");
2405
+ a.type = t.type === "number" ? "number" : "text", a.value = s != null ? String(s) : "", n.innerHTML = "", n.appendChild(a), a.focus(), a.select(), a.addEventListener("mousedown", () => {
2406
+ console.log("🖱️ Input mousedown");
2407
+ }), a.addEventListener("keydown", (r) => {
2408
+ console.log("⌨️ Input keydown:", r.key, { shiftKey: r.shiftKey }), r.key === "Enter" ? (r.preventDefault(), r.stopPropagation(), console.log("✅ Enter detected - calling endEditAndMove"), this.endEditAndMove(r.shiftKey ? "up" : "down")) : r.key === "Tab" ? (r.preventDefault(), r.stopPropagation(), console.log("✅ Tab detected - calling endEditAndMove"), this.endEditAndMove(r.shiftKey ? "left" : "right")) : r.key === "Escape" && (r.preventDefault(), r.stopPropagation(), console.log("✅ Escape detected - calling cancelEdit"), this.cancelEdit());
2409
+ });
2410
+ }
2411
+ }
2412
+ endEdit(e = !0) {
2413
+ var l, a, r, h, g, d;
2414
+ if (console.log("🛑 endEdit called", { save: e, editing: this.state.edit.editing }), this.editModeCleanup && (console.log("🧹 Cleaning up edit mode listener on endEdit"), this.editModeCleanup(), this.editModeCleanup = null), !this.state.edit.editing) return;
2415
+ const { rowIndex: i, field: s, originalValue: o } = this.state.edit;
2416
+ if (i === null || s === null) return;
2417
+ const n = this.bodyInner.querySelector(`[data-row-index="${i}"]`), t = n == null ? void 0 : n.querySelector(`[data-field="${s}"]`);
2418
+ if (e && t) {
2419
+ const f = this.state.columns.find((D) => D.field === s), C = this.state.displayData[i];
2420
+ let x = o;
2421
+ const b = t.querySelector(".velox-edit-input"), y = t.querySelector(".velox-editor--select"), S = t.querySelector('.velox-editor--checkbox input[type="checkbox"]'), E = t.querySelector(".velox-editor--date"), R = t.querySelector(".velox-editor--number");
2422
+ if (S ? x = S.checked : y ? y.multiple ? x = Array.from(y.selectedOptions).map((D) => D.value) : x = y.value : E ? x = E.value : R ? x = R.value === "" ? null : Number(R.value) : b && (x = b.value), JSON.stringify(x) !== JSON.stringify(o)) {
2423
+ if (f != null && f.validation && f.validation.length > 0) {
2424
+ const B = f.type === "number" && typeof x == "string" ? parseFloat(x) : x, L = Ht.validate(B, f.validation, C);
2425
+ if (!L.valid) {
2426
+ if (t) {
2427
+ w(t, "velox-cell--invalid");
2428
+ const T = L.errors.map((F) => F.message).join(", ");
2429
+ t.title = T;
2430
+ }
2431
+ (a = (l = this.events).onValidationError) == null || a.call(l, {
2432
+ rowIndex: i,
2433
+ field: s,
2434
+ value: B,
2435
+ errors: L.errors.map((T) => T.message)
2436
+ }), b ? b.focus() : y ? y.focus() : E ? E.focus() : R && R.focus();
2437
+ return;
2438
+ }
2439
+ }
2440
+ const D = (f == null ? void 0 : f.type) === "number" && typeof x == "string" ? parseFloat(x) : x;
2441
+ this.setCellValue(i, s, D), (h = (r = this.events).onCellEditEnd) == null || h.call(r, {
2442
+ rowIndex: i,
2443
+ field: s,
2444
+ oldValue: o,
2445
+ newValue: D,
2446
+ row: this.state.displayData[i]
2447
+ });
2448
+ }
2449
+ } else
2450
+ (d = (g = this.events).onCellEditCancel) == null || d.call(g, i, s);
2451
+ this.state.edit = { editing: !1, rowIndex: null, field: null, originalValue: null }, this.applyDataTransformations(), this.render();
2452
+ }
2453
+ cancelEdit() {
2454
+ this.endEdit(!1);
2455
+ }
2456
+ isEditing() {
2457
+ return this.state.edit.editing;
2458
+ }
2459
+ /**
2460
+ * End edit and move to adjacent cell (Phase 9)
2461
+ */
2462
+ endEditAndMove(e) {
2463
+ var r;
2464
+ const { rowIndex: i, field: s } = this.state.edit;
2465
+ if (i === null || s === null) return;
2466
+ this.endEdit(!0);
2467
+ const o = this.getVisibleColumns(), n = o.findIndex((h) => h.field === s);
2468
+ let t = i, l = n;
2469
+ switch (e) {
2470
+ case "up":
2471
+ t > 0 && t--;
2472
+ break;
2473
+ case "down":
2474
+ t < this.state.displayData.length - 1 && t++;
2475
+ break;
2476
+ case "left":
2477
+ l > 0 ? l-- : t > 0 && (t--, l = o.length - 1);
2478
+ break;
2479
+ case "right":
2480
+ l < o.length - 1 ? l++ : t < this.state.displayData.length - 1 && (t++, l = 0);
2481
+ break;
2482
+ }
2483
+ const a = (r = o[l]) == null ? void 0 : r.field;
2484
+ a && (this.setFocusedCell(t, a), this.state.selection.selectedCells.clear(), this.state.selection.selectedCells.add(`${t}:${a}`), this.scrollToCell(t, a), this.render(), this.rootElement.focus());
2485
+ }
2486
+ // --- Public API: Column ---
2487
+ getColumn(e) {
2488
+ return this.state.columns.find((i) => i.field === e) || null;
2489
+ }
2490
+ setColumnWidth(e, i) {
2491
+ var o, n;
2492
+ const s = this.state.columns.find((t) => t.field === e);
2493
+ s && (s.width = i, this.invalidateColumnCache(), this.render(), (n = (o = this.events).onColumnResize) == null || n.call(o, e, i));
2494
+ }
2495
+ showColumn(e) {
2496
+ const i = this.state.columns.find((s) => s.field === e);
2497
+ i && (i.visible = !0, this.invalidateColumnCache(), this.render());
2498
+ }
2499
+ hideColumn(e) {
2500
+ const i = this.state.columns.find((s) => s.field === e);
2501
+ i && (i.visible = !1, this.invalidateColumnCache(), this.render());
2502
+ }
2503
+ setColumns(e) {
2504
+ this.state.columns = e.map((i) => ({ ...i })), this.invalidateColumnCache(), this.render();
2505
+ }
2506
+ autoFitColumn(e) {
2507
+ var n, t;
2508
+ const i = this.state.columns.find((l) => l.field === e);
2509
+ if (!i) return;
2510
+ let s = 100;
2511
+ const o = i.header || "";
2512
+ s = Math.max(s, this.measureTextWidth(o) + 40), this.state.displayData.forEach((l) => {
2513
+ const a = l[i.field], r = H(a, i.type), h = this.measureTextWidth(r) + 20;
2514
+ s = Math.max(s, h);
2515
+ }), i.width = Math.min(s, 500), this.invalidateColumnCache(), this.render(), (t = (n = this.events).onColumnResize) == null || t.call(n, e, i.width);
2516
+ }
2517
+ autoFitAllColumns() {
2518
+ this.getVisibleColumns().forEach((e) => this.autoFitColumn(e.field));
2519
+ }
2520
+ // GridContext: Text measurement (public for module access)
2521
+ measureTextWidth(e, i) {
2522
+ return this.measureCanvas || (this.measureCanvas = document.createElement("canvas"), this.measureContext = this.measureCanvas.getContext("2d")), this.measureContext ? (this.measureContext.font = i || "14px sans-serif", this.measureContext.measureText(e).width) : 100;
2523
+ }
2524
+ // --- Public API: Scroll ---
2525
+ scrollToRow(e) {
2526
+ const i = this.options.rowHeight || 40;
2527
+ this.bodyElement.scrollTop = e * i, this.fixedLeftBody && (this.fixedLeftBody.scrollTop = e * i);
2528
+ }
2529
+ scrollToTop() {
2530
+ this.bodyElement.scrollTop = 0, this.fixedLeftBody && (this.fixedLeftBody.scrollTop = 0);
2531
+ }
2532
+ scrollToBottom() {
2533
+ this.bodyElement.scrollTop = this.bodyElement.scrollHeight, this.fixedLeftBody && (this.fixedLeftBody.scrollTop = this.fixedLeftBody.scrollHeight);
2534
+ }
2535
+ scrollToCell(e, i) {
2536
+ const s = this.options.rowHeight || 40, o = this.bodyElement.clientHeight, n = this.bodyElement.scrollTop, t = e * s, l = t + s;
2537
+ t < n ? this.bodyElement.scrollTop = t : l > n + o && (this.bodyElement.scrollTop = l - o), this.fixedLeftBody && (this.fixedLeftBody.scrollTop = this.bodyElement.scrollTop);
2538
+ const a = this.bodyInner.querySelector(`[data-field="${i}"]`);
2539
+ if (a) {
2540
+ const r = a.offsetLeft, h = r + a.offsetWidth, g = this.bodyElement.clientWidth, d = this.bodyElement.scrollLeft;
2541
+ r < d ? this.bodyElement.scrollLeft = r : h > d + g && (this.bodyElement.scrollLeft = h - g);
2542
+ }
2543
+ }
2544
+ // --- Public API: Clipboard ---
2545
+ copy() {
2546
+ const e = this.getSelectionData();
2547
+ if (e.length === 0) return;
2548
+ const i = e.map((s) => s.join(" ")).join(`
2549
+ `);
2550
+ navigator.clipboard.writeText(i).then(() => {
2551
+ var s, o;
2552
+ (o = (s = this.events).onCopy) == null || o.call(s, e.map((n) => n.map((t) => String(t ?? ""))));
2553
+ });
2554
+ }
2555
+ paste() {
2556
+ const e = this.state.selection.focusedCell;
2557
+ e && navigator.clipboard.readText().then((i) => {
2558
+ var t, l, a, r;
2559
+ const s = i.split(`
2560
+ `).map((h) => h.split(" "));
2561
+ (l = (t = this.events).onPaste) == null || l.call(t, s, e);
2562
+ const o = this.getVisibleColumns(), n = o.findIndex((h) => h.field === e.field);
2563
+ s.forEach((h, g) => {
2564
+ const d = e.rowIndex + g;
2565
+ d >= this.state.displayData.length || h.forEach((f, C) => {
2566
+ const x = n + C;
2567
+ if (x >= o.length) return;
2568
+ const b = o[x].field, y = o[x];
2569
+ if (y.editable !== !1) {
2570
+ const S = this.state.displayData[d], E = this.state.data.indexOf(S);
2571
+ E >= 0 && (this.state.data[E][b] = y.type === "number" ? parseFloat(f) : f);
2572
+ }
2573
+ });
2574
+ }), this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (r = (a = this.events).onDataChange) == null || r.call(a, this.state.data);
2575
+ });
2576
+ }
2577
+ cut() {
2578
+ var o, n, t, l;
2579
+ const e = this.getSelectionData();
2580
+ if (e.length === 0) return;
2581
+ this.copy();
2582
+ const i = [];
2583
+ this.getSelectedCells().forEach((a) => {
2584
+ const r = this.state.columns.find((h) => h.field === a.field);
2585
+ if ((r == null ? void 0 : r.editable) !== !1) {
2586
+ const h = this.state.displayData[a.rowIndex], g = this.state.data.indexOf(h);
2587
+ if (g >= 0) {
2588
+ const d = this.state.data[g][a.field];
2589
+ i.push({
2590
+ rowIndex: a.rowIndex,
2591
+ field: a.field,
2592
+ oldValue: d,
2593
+ newValue: ""
2594
+ }), this.state.data[g][a.field] = "";
2595
+ }
2596
+ }
2597
+ }), i.length > 0 && this.pushUndo({ type: "cut", timestamp: Date.now(), data: { changes: i } }), this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (n = (o = this.events).onCut) == null || n.call(o, e.map((a) => a.map((r) => String(r ?? "")))), (l = (t = this.events).onDataChange) == null || l.call(t, this.state.data);
2598
+ }
2599
+ // --- Public API: Undo/Redo ---
2600
+ pushUndo(e) {
2601
+ this.history.push(e);
2602
+ }
2603
+ undo() {
2604
+ var i, s, o, n;
2605
+ const e = this.history.popUndo();
2606
+ if (!e) return !1;
2607
+ switch (e.type) {
2608
+ case "cell_edit": {
2609
+ const t = e.data, l = this.state.displayData[t.rowIndex], a = this.state.data.indexOf(l);
2610
+ a >= 0 && (this.state.data[a][t.field] = t.oldValue);
2611
+ break;
2612
+ }
2613
+ case "bulk_edit":
2614
+ case "paste":
2615
+ case "cut":
2616
+ case "delete": {
2617
+ e.data.changes.forEach((l) => {
2618
+ const a = this.state.displayData[l.rowIndex], r = this.state.data.indexOf(a);
2619
+ r >= 0 && (this.state.data[r][l.field] = l.oldValue);
2620
+ });
2621
+ break;
2622
+ }
2623
+ case "row_add": {
2624
+ const t = e.data;
2625
+ this.state.data.splice(t.index, 1), this.rebuildDataIndexMap();
2626
+ break;
2627
+ }
2628
+ case "row_remove": {
2629
+ const t = e.data;
2630
+ this.state.data.splice(t.index, 0, { ...t.row }), this.rebuildDataIndexMap();
2631
+ break;
2632
+ }
2633
+ }
2634
+ return this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (s = (i = this.events).onUndo) == null || s.call(i, e), (n = (o = this.events).onDataChange) == null || n.call(o, this.state.data), !0;
2635
+ }
2636
+ redo() {
2637
+ var i, s, o, n;
2638
+ const e = this.history.popRedo();
2639
+ if (!e) return !1;
2640
+ switch (e.type) {
2641
+ case "cell_edit": {
2642
+ const t = e.data, l = this.state.displayData[t.rowIndex], a = this.state.data.indexOf(l);
2643
+ a >= 0 && (this.state.data[a][t.field] = t.newValue);
2644
+ break;
2645
+ }
2646
+ case "bulk_edit":
2647
+ case "paste":
2648
+ case "cut":
2649
+ case "delete": {
2650
+ e.data.changes.forEach((l) => {
2651
+ const a = this.state.displayData[l.rowIndex], r = this.state.data.indexOf(a);
2652
+ r >= 0 && (this.state.data[r][l.field] = l.newValue);
2653
+ });
2654
+ break;
2655
+ }
2656
+ case "row_add": {
2657
+ const t = e.data;
2658
+ this.state.data.splice(t.index, 0, { ...t.row }), this.rebuildDataIndexMap();
2659
+ break;
2660
+ }
2661
+ case "row_remove": {
2662
+ const t = e.data;
2663
+ this.state.data.splice(t.index, 1), this.rebuildDataIndexMap();
2664
+ break;
2665
+ }
2666
+ }
2667
+ return this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (s = (i = this.events).onRedo) == null || s.call(i, e), (n = (o = this.events).onDataChange) == null || n.call(o, this.state.data), !0;
2668
+ }
2669
+ canUndo() {
2670
+ return this.history.canUndo();
2671
+ }
2672
+ canRedo() {
2673
+ return this.history.canRedo();
2674
+ }
2675
+ clearHistory() {
2676
+ this.history.clear();
2677
+ }
2678
+ // --- Public API: Delete ---
2679
+ deleteSelectedCells() {
2680
+ var s, o;
2681
+ if (!this.options.editable) return;
2682
+ const e = this.getSelectedCells();
2683
+ if (e.length === 0) return;
2684
+ const i = [];
2685
+ e.forEach((n) => {
2686
+ const t = this.state.columns.find((l) => l.field === n.field);
2687
+ if ((t == null ? void 0 : t.editable) !== !1) {
2688
+ const l = this.state.displayData[n.rowIndex], a = this.state.data.indexOf(l);
2689
+ if (a >= 0) {
2690
+ const r = this.state.data[a][n.field];
2691
+ r !== "" && r !== null && r !== void 0 && (i.push({
2692
+ rowIndex: n.rowIndex,
2693
+ field: n.field,
2694
+ oldValue: r,
2695
+ newValue: ""
2696
+ }), this.state.data[a][n.field] = "");
2697
+ }
2698
+ }
2699
+ }), i.length > 0 && (this.pushUndo({ type: "delete", timestamp: Date.now(), data: { changes: i } }), this.applyDataTransformations(), this.summary.invalidateCache(), this.render(), (o = (s = this.events).onDataChange) == null || o.call(s, this.state.data));
2700
+ }
2701
+ deleteSelectedRows() {
2702
+ const e = this.getSelectedRows();
2703
+ if (e.length === 0) return;
2704
+ [...e].sort((s, o) => o - s).forEach((s) => {
2705
+ this.removeRow(s);
2706
+ });
2707
+ }
2708
+ // --- Public API: Export/Import ---
2709
+ createExportContext(e = {}) {
2710
+ return {
2711
+ data: this.state.data,
2712
+ displayData: this.state.displayData,
2713
+ columns: this.state.columns,
2714
+ selectedRows: this.getSelectedRows(),
2715
+ options: e
2716
+ };
2717
+ }
2718
+ /**
2719
+ * Export grid data to Excel (.xlsx) file
2720
+ * Requires SheetJS library to be loaded via CDN:
2721
+ * <script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"><\/script>
2722
+ */
2723
+ exportToExcel(e = {}) {
2724
+ const i = this.createExportContext(e);
2725
+ St(i);
2726
+ }
2727
+ /**
2728
+ * Export grid data to CSV format
2729
+ * @returns CSV string
2730
+ */
2731
+ exportToCSV(e = {}) {
2732
+ const i = this.createExportContext(e);
2733
+ return K(i);
2734
+ }
2735
+ /**
2736
+ * Export grid data to JSON format
2737
+ * @returns JSON string
2738
+ */
2739
+ exportToJSON(e = {}) {
2740
+ const i = this.createExportContext(e);
2741
+ return q(i);
2742
+ }
2743
+ /**
2744
+ * Download grid data as CSV file
2745
+ */
2746
+ downloadCSV(e = {}) {
2747
+ const i = this.createExportContext(e);
2748
+ Tt(i);
2749
+ }
2750
+ /**
2751
+ * Download grid data as JSON file
2752
+ */
2753
+ downloadJSON(e = {}) {
2754
+ const i = this.createExportContext(e);
2755
+ Bt(i);
2756
+ }
2757
+ /**
2758
+ * Import data from CSV string
2759
+ * @param csvString CSV content
2760
+ * @param hasHeader Whether first row is header (default: true)
2761
+ */
2762
+ importFromCSV(e, i = !0) {
2763
+ const s = Rt(e, i);
2764
+ return s.errors.length === 0 && s.data.length > 0 && this.setData(s.data), s;
2765
+ }
2766
+ /**
2767
+ * Import data from Excel file
2768
+ * Requires SheetJS library to be loaded via CDN
2769
+ * @param file Excel file (File object)
2770
+ * @param sheetIndex Sheet index to import (default: 0)
2771
+ */
2772
+ async importFromExcel(e, i = 0) {
2773
+ const s = await Lt(e, i);
2774
+ return s.errors.length === 0 && s.data.length > 0 && this.setData(s.data), s;
2775
+ }
2776
+ /**
2777
+ * Check if SheetJS library is available for Excel operations
2778
+ */
2779
+ static isExcelSupported() {
2780
+ return U();
2781
+ }
2782
+ // ============================================
2783
+ // Public API - Utility Methods
2784
+ // ============================================
2785
+ getCellValue(e, i) {
2786
+ var s;
2787
+ return (s = this.state.displayData[e]) == null ? void 0 : s[i];
2788
+ }
2789
+ setCellValue(e, i, s) {
2790
+ var t, l;
2791
+ const o = this.state.displayData[e];
2792
+ if (!o) return;
2793
+ const n = this.state.data.indexOf(o);
2794
+ n >= 0 && (this.state.data[n][i] = s, (this.state.rowStates.get(this.state.data[n]) || "none") === "none" && this.state.rowStates.set(this.state.data[n], "updated"), this.summary.invalidateCache(), this.applyDataTransformations(), this.render(), (l = (t = this.events).onDataChange) == null || l.call(t, this.state.data));
2795
+ }
2796
+ // ============================================
2797
+ // Phase 13: Summary Methods
2798
+ // ============================================
2799
+ /**
2800
+ * Get summary value for a specific field
2801
+ * @param field Column field name
2802
+ * @returns Calculated summary value
2803
+ */
2804
+ getSummaryValue(e) {
2805
+ return this.summary.getSummaryValue(e);
2806
+ }
2807
+ /**
2808
+ * Get all summary values
2809
+ * @returns Object with field names as keys and summary values
2810
+ */
2811
+ getSummaryValues() {
2812
+ return this.summary.getAllSummaryValues();
2813
+ }
2814
+ /**
2815
+ * Refresh summary calculations (clear cache)
2816
+ */
2817
+ refreshSummary() {
2818
+ this.summary.invalidateCache(), this.render();
2819
+ }
2820
+ setOptions(e) {
2821
+ this.options = { ...this.options, ...e }, e.checkBar && (this.options.checkBar = { ...N, ...e.checkBar }), e.columns && (this.state.columns = e.columns.map((i) => ({ ...i }))), e.loading !== void 0 && this.updateLoadingState(), this.render();
2822
+ }
2823
+ getOptions() {
2824
+ return { ...this.options };
2825
+ }
2826
+ setLoading(e) {
2827
+ this.options.loading = e, this.updateLoadingState();
2828
+ }
2829
+ refresh() {
2830
+ this.applyDataTransformations(), this.render();
2831
+ }
2832
+ // ============================================
2833
+ // Phase 10: Column Reorder & Menu
2834
+ // ============================================
2835
+ /**
2836
+ * Fix/unfix column to a position
2837
+ */
2838
+ fixColumn(e, i) {
2839
+ const s = this.state.columns.find((o) => o.field === e);
2840
+ s && (s.fixed = i, this.invalidateColumnCache(), this.render());
2841
+ }
2842
+ /**
2843
+ * Reorder column to new position
2844
+ */
2845
+ reorderColumn(e, i) {
2846
+ var t, l;
2847
+ const s = this.state.columns.findIndex((a) => a.field === e), o = this.state.columns.findIndex((a) => a.field === i);
2848
+ if (s === -1 || o === -1) return;
2849
+ const [n] = this.state.columns.splice(s, 1);
2850
+ this.state.columns.splice(o, 0, n), this.invalidateColumnCache(), this.render(), (l = (t = this.events).onColumnReorder) == null || l.call(t, e, s, o);
2851
+ }
2852
+ // GridContext: Column menu methods - delegated to GridColumnMenu
2853
+ showColumnMenu(e, i) {
2854
+ this.closeFilterPopup(), this.columnMenuManager.showColumnMenu(e, i);
2855
+ }
2856
+ closeColumnMenu() {
2857
+ this.columnMenuManager.closeColumnMenu();
2858
+ }
2859
+ // GridContext: Column drag methods - delegated to GridDragManager
2860
+ startColumnDrag(e, i) {
2861
+ this.dragManager.startColumnDrag(e, i);
2862
+ }
2863
+ // ============================================
2864
+ // Phase 11: Row Drag & Drop
2865
+ // ============================================
2866
+ /**
2867
+ * Move row to new position
2868
+ */
2869
+ moveRow(e, i) {
2870
+ var r, h;
2871
+ const s = this.state.displayData[e];
2872
+ if (!s) return;
2873
+ const o = this.state.data.indexOf(s);
2874
+ if (o === -1) return;
2875
+ const n = this.state.displayData[i], t = n ? this.state.data.indexOf(n) : this.state.data.length, [l] = this.state.data.splice(o, 1), a = t > o ? t - 1 : t;
2876
+ this.state.data.splice(a, 0, l), this.rebuildDataIndexMap(), this.applyDataTransformations(), this.render(), (h = (r = this.events).onDataChange) == null || h.call(r, this.state.data);
2877
+ }
2878
+ // GridContext: Row drag methods - delegated to GridDragManager
2879
+ startRowDrag(e, i, s) {
2880
+ this.dragManager.startRowDrag(e, i, s);
2881
+ }
2882
+ // ============================================
2883
+ // GridContext Implementation
2884
+ // ============================================
2885
+ /** GridContext: 그리드 상태 반환 */
2886
+ getState() {
2887
+ return this.state;
2888
+ }
2889
+ /** GridContext: 이벤트 핸들러 반환 */
2890
+ getEvents() {
2891
+ return this.events;
2892
+ }
2893
+ /** GridContext: 그리드 고유 ID 반환 */
2894
+ getGridId() {
2895
+ return this.gridId;
2896
+ }
2897
+ /** GridContext: 표시 데이터 반환 */
2898
+ getDisplayData() {
2899
+ return this.state.displayData;
2900
+ }
2901
+ /** GridContext: 가상 스크롤 상태 반환 */
2902
+ getVirtualState() {
2903
+ return this.virtualState;
2904
+ }
2905
+ /** GridContext: 이벤트 발행 헬퍼 */
2906
+ emitEvent(e, ...i) {
2907
+ const s = this.events[e];
2908
+ s && s(...i);
2909
+ }
2910
+ // ============================================
2911
+ // GridContext: Internal Handlers
2912
+ // ============================================
2913
+ /** GridContext: Block selection 상태 확인 */
2914
+ isBlockSelecting() {
2915
+ return this.blockSelecting !== null;
2916
+ }
2917
+ /** GridContext: Tooltip 표시 */
2918
+ showTooltip(e, i, s, o) {
2919
+ this.tooltip && this.tooltip.show(e, i, s, o);
2920
+ }
2921
+ /** GridContext: Tooltip 숨기기 */
2922
+ hideTooltip() {
2923
+ this.tooltip && this.tooltip.hide();
2924
+ }
2925
+ // ============================================
2926
+ // Phase 14: Fixed Columns
2927
+ // ============================================
2928
+ /**
2929
+ * Set fixed columns options
2930
+ * @param options - Fixed options (colCount, rightCount)
2931
+ */
2932
+ setFixedOptions(e) {
2933
+ var n, t;
2934
+ const i = this.options.fixedOptions || { colCount: 0, rightCount: 0 }, s = {
2935
+ colCount: e.colCount ?? ((n = this.options.fixedOptions) == null ? void 0 : n.colCount) ?? 0,
2936
+ rightCount: e.rightCount ?? ((t = this.options.fixedOptions) == null ? void 0 : t.rightCount) ?? 0
2937
+ }, o = (
2938
+ // Left fixed changes
2939
+ (i.colCount || 0) === 0 && s.colCount > 0 || // Left 추가
2940
+ (i.colCount || 0) > 0 && s.colCount === 0 || // Left 제거
2941
+ // Right fixed changes
2942
+ (i.rightCount || 0) === 0 && s.rightCount > 0 || // Right 추가
2943
+ (i.rightCount || 0) > 0 && s.rightCount === 0
2944
+ );
2945
+ this.options.fixedOptions = s, this.invalidateColumnCache(), o && this.rebuildDOM(), this.render();
2946
+ }
2947
+ /**
2948
+ * Rebuild DOM structure and re-attach events
2949
+ * Phase 14: For dynamic fixed columns
2950
+ */
2951
+ rebuildDOM() {
2952
+ var s, o;
2953
+ const e = ((s = this.bodyElement) == null ? void 0 : s.scrollTop) || 0, i = ((o = this.bodyElement) == null ? void 0 : o.scrollLeft) || 0;
2954
+ this.detachEvents(), this.build(), this.attachEvents(), this.bodyElement && (this.bodyElement.scrollTop = e, this.bodyElement.scrollLeft = i), this.fixedRightBody && (this.fixedRightBody.scrollTop = e);
2955
+ }
2956
+ /**
2957
+ * Get current fixed columns options
2958
+ * @returns Fixed options
2959
+ */
2960
+ getFixedOptions() {
2961
+ return this.options.fixedOptions || { colCount: 0, rightCount: 0 };
2962
+ }
2963
+ // ============================================
2964
+ // Phase 15: Row State Management
2965
+ // ============================================
2966
+ /**
2967
+ * Get row state by display index
2968
+ * @param index - Display index (in displayData array)
2969
+ * @returns Row state type
2970
+ */
2971
+ getRowState(e) {
2972
+ const i = this.state.displayData[e];
2973
+ return i && this.state.rowStates.get(i) || "none";
2974
+ }
2975
+ /**
2976
+ * Get row state by row data object
2977
+ * @param row - Row data object
2978
+ * @returns Row state type
2979
+ */
2980
+ getRowStateByData(e) {
2981
+ return this.state.rowStates.get(e) || "none";
2982
+ }
2983
+ /**
2984
+ * Set row state manually
2985
+ * @param index - Display index
2986
+ * @param state - New state
2987
+ */
2988
+ setRowState(e, i) {
2989
+ const s = this.state.displayData[e];
2990
+ s && (this.state.rowStates.set(s, i), this.render());
2991
+ }
2992
+ /**
2993
+ * Get all changes (created, updated, deleted rows)
2994
+ * @returns Changes result with separated arrays
2995
+ */
2996
+ getChanges() {
2997
+ const e = [], i = [], s = [];
2998
+ return this.state.rowStates.forEach((o, n) => {
2999
+ o === "created" ? e.push(n) : o === "updated" ? i.push(n) : o === "deleted" && s.push(n);
3000
+ }), { created: e, updated: i, deleted: s };
3001
+ }
3002
+ /**
3003
+ * Get newly created rows
3004
+ * @returns Array of created rows
3005
+ */
3006
+ getCreatedRows() {
3007
+ const e = [];
3008
+ return this.state.rowStates.forEach((i, s) => {
3009
+ i === "created" && e.push(s);
3010
+ }), e;
3011
+ }
3012
+ /**
3013
+ * Get updated rows
3014
+ * @returns Array of updated rows
3015
+ */
3016
+ getUpdatedRows() {
3017
+ const e = [];
3018
+ return this.state.rowStates.forEach((i, s) => {
3019
+ i === "updated" && e.push(s);
3020
+ }), e;
3021
+ }
3022
+ /**
3023
+ * Get deleted rows (marked for deletion)
3024
+ * @returns Array of deleted rows
3025
+ */
3026
+ getDeletedRows() {
3027
+ const e = [];
3028
+ return this.state.rowStates.forEach((i, s) => {
3029
+ i === "deleted" && e.push(s);
3030
+ }), e;
3031
+ }
3032
+ /**
3033
+ * Clear all row states (reset to 'none')
3034
+ */
3035
+ clearRowStates() {
3036
+ this.state.rowStates.clear(), this.state.data.forEach((e) => {
3037
+ this.state.rowStates.set(e, "none");
3038
+ }), this.render();
3039
+ }
3040
+ /**
3041
+ * Commit changes (mark all rows as 'none')
3042
+ * This is typically called after successfully saving changes to server
3043
+ */
3044
+ commit() {
3045
+ const e = [];
3046
+ this.state.rowStates.forEach((i, s) => {
3047
+ i === "createAndDeleted" && e.push(s);
3048
+ }), e.forEach((i) => {
3049
+ const s = this.state.data.indexOf(i);
3050
+ s >= 0 && this.state.data.splice(s, 1);
3051
+ }), this.state.rowStates.clear(), this.state.data.forEach((i) => {
3052
+ this.state.rowStates.set(i, "none");
3053
+ }), this.rebuildDataIndexMap(), this.applyDataTransformations(), this.render();
3054
+ }
3055
+ // ============================================
3056
+ // Phase 18: Data Source & Pagination
3057
+ // ============================================
3058
+ /**
3059
+ * Remote 데이터 소스 여부 확인
3060
+ */
3061
+ isRemoteDataSource() {
3062
+ var e;
3063
+ return ((e = this.options.dataSource) == null ? void 0 : e.type) === "remote";
3064
+ }
3065
+ /**
3066
+ * 페이지네이션 상태 조회
3067
+ */
3068
+ getPaginationState() {
3069
+ return { ...this.state.pagination };
3070
+ }
3071
+ /**
3072
+ * 특정 페이지로 이동
3073
+ * @param page - 이동할 페이지 번호 (1-based)
3074
+ */
3075
+ goToPage(e) {
3076
+ var o, n;
3077
+ const { totalPages: i } = this.state.pagination, s = Math.max(1, Math.min(e, i || 1));
3078
+ s === this.state.pagination.currentPage && this.state.displayData.length > 0 || (this.state.pagination.currentPage = s, this.isRemoteDataSource() ? this.fetchData() : (this.applyLocalPagination(), this.render()), (n = (o = this.events).onPageChange) == null || n.call(o, s, this.state.pagination.pageSize));
3079
+ }
3080
+ /**
3081
+ * 페이지 크기 변경
3082
+ * @param pageSize - 새 페이지 크기
3083
+ */
3084
+ setPageSize(e) {
3085
+ var i, s;
3086
+ e < 1 || e === this.state.pagination.pageSize || (this.state.pagination.pageSize = e, this.state.pagination.currentPage = 1, this.updateTotalPages(), this.isRemoteDataSource() ? this.fetchData() : (this.applyLocalPagination(), this.render()), (s = (i = this.events).onPageSizeChange) == null || s.call(i, e));
3087
+ }
3088
+ /**
3089
+ * 서버에서 데이터 가져오기 (remote 모드)
3090
+ */
3091
+ async fetchData() {
3092
+ const e = this.options.dataSource;
3093
+ if (!(e != null && e.fetch)) return;
3094
+ const i = {
3095
+ page: this.state.pagination.currentPage,
3096
+ pageSize: this.state.pagination.pageSize,
3097
+ sort: this.state.sort.length > 0 ? this.state.sort : void 0,
3098
+ filter: this.state.filter
3099
+ };
3100
+ this.state.pagination.loading = !0, this.setLoading(!0);
3101
+ try {
3102
+ const s = await e.fetch(i);
3103
+ this.state.data = s.data.map((o) => ({ ...o })), this.state.displayData = this.state.data, this.state.pagination.totalCount = s.totalCount, this.updateTotalPages(), this.state.rowStates.clear(), this.state.data.forEach((o) => {
3104
+ this.state.rowStates.set(o, "none");
3105
+ }), this.rebuildDataIndexMap(), this.summary.invalidateCache(), this.clearSelectionState();
3106
+ } catch (s) {
3107
+ console.error("VeloxGrid: fetchData error", s);
3108
+ } finally {
3109
+ this.state.pagination.loading = !1, this.setLoading(!1), this.render();
3110
+ }
3111
+ }
3112
+ /**
3113
+ * 전체 페이지 수 재계산
3114
+ */
3115
+ updateTotalPages() {
3116
+ const { pageSize: e, totalCount: i } = this.state.pagination;
3117
+ this.state.pagination.totalPages = Math.max(1, Math.ceil(i / e));
3118
+ }
3119
+ /**
3120
+ * 로컬 데이터에 페이지네이션 적용
3121
+ * sort/filter 적용 후 현재 페이지 데이터만 displayData에 설정
3122
+ */
3123
+ applyLocalPagination() {
3124
+ let e = [...this.state.data];
3125
+ if (this.state.filter && (e = A(e, this.state.filter)), this.state.sort.length > 0) {
3126
+ const n = {};
3127
+ this.state.columns.forEach((t) => {
3128
+ n[t.field] = t.type || "text";
3129
+ }), e = V(e, this.state.sort, n);
3130
+ }
3131
+ this.state.pagination.totalCount = e.length, this.updateTotalPages();
3132
+ const { currentPage: i, pageSize: s } = this.state.pagination, o = (i - 1) * s;
3133
+ this.state.displayData = e.slice(o, o + s), this.initCheckableRows();
3134
+ }
3135
+ /**
3136
+ * Infinite Scroll: 스크롤 바닥 감지 (Phase 18)
3137
+ */
3138
+ checkInfiniteScroll() {
3139
+ const e = this.options.pagination;
3140
+ if (!(e != null && e.enabled) || e.mode !== "infinite" || this.infiniteScrollLoading || this.infiniteScrollAllLoaded) return;
3141
+ const i = e.infiniteScrollThreshold || 100, { scrollTop: s, scrollHeight: o, clientHeight: n } = this.bodyElement;
3142
+ o - s - n <= i && this.loadNextPage();
3143
+ }
3144
+ /**
3145
+ * Infinite Scroll: 다음 페이지 로드 (Phase 18)
3146
+ */
3147
+ async loadNextPage() {
3148
+ const { currentPage: e, totalPages: i } = this.state.pagination;
3149
+ if (e >= i) {
3150
+ this.infiniteScrollAllLoaded = !0, this.renderInfiniteScrollStatus();
3151
+ return;
3152
+ }
3153
+ if (this.infiniteScrollLoading = !0, this.state.pagination.currentPage++, this.renderInfiniteScrollStatus(), this.isRemoteDataSource()) {
3154
+ const s = this.options.dataSource;
3155
+ if (!(s != null && s.fetch)) return;
3156
+ const o = {
3157
+ page: this.state.pagination.currentPage,
3158
+ pageSize: this.state.pagination.pageSize,
3159
+ sort: this.state.sort.length > 0 ? this.state.sort : void 0,
3160
+ filter: this.state.filter
3161
+ };
3162
+ try {
3163
+ const n = await s.fetch(o), t = n.data.map((l) => ({ ...l }));
3164
+ this.state.data.push(...t), this.state.displayData = [...this.state.data], this.state.pagination.totalCount = n.totalCount, this.updateTotalPages(), t.forEach((l) => this.state.rowStates.set(l, "none")), this.rebuildDataIndexMap(), this.summary.invalidateCache(), this.state.pagination.currentPage >= this.state.pagination.totalPages && (this.infiniteScrollAllLoaded = !0);
3165
+ } catch (n) {
3166
+ console.error("VeloxGrid: infinite scroll fetch error", n), this.state.pagination.currentPage--;
3167
+ }
3168
+ } else
3169
+ this.applyLocalInfiniteScroll();
3170
+ this.infiniteScrollLoading = !1, this.render();
3171
+ }
3172
+ /**
3173
+ * Local Infinite Scroll: 다음 페이지 데이터 추가 (Phase 18)
3174
+ */
3175
+ applyLocalInfiniteScroll() {
3176
+ let e = [...this.state.data];
3177
+ if (this.state.filter && (e = A(e, this.state.filter)), this.state.sort.length > 0) {
3178
+ const n = {};
3179
+ this.state.columns.forEach((t) => {
3180
+ n[t.field] = t.type || "text";
3181
+ }), e = V(e, this.state.sort, n);
3182
+ }
3183
+ const { currentPage: i, pageSize: s } = this.state.pagination, o = i * s;
3184
+ this.state.displayData = e.slice(0, o), o >= e.length && (this.infiniteScrollAllLoaded = !0), this.initCheckableRows();
3185
+ }
3186
+ /**
3187
+ * Infinite Scroll 상태 표시 렌더링 (Phase 18)
3188
+ */
3189
+ renderInfiniteScrollStatus() {
3190
+ if (this.paginationContainer) {
3191
+ if (this.paginationContainer.innerHTML = "", this.infiniteScrollLoading) {
3192
+ const e = p("div", "velox-infinite-status");
3193
+ e.textContent = "Loading...", this.paginationContainer.appendChild(e);
3194
+ } else if (this.infiniteScrollAllLoaded) {
3195
+ const e = p("div", "velox-infinite-status velox-infinite-status--done"), { totalCount: i } = this.state.pagination;
3196
+ e.textContent = `All ${i.toLocaleString()} items loaded`, this.paginationContainer.appendChild(e);
3197
+ }
3198
+ }
3199
+ }
3200
+ /**
3201
+ * Pagination UI 렌더링 (Phase 18)
3202
+ */
3203
+ renderPagination() {
3204
+ var g;
3205
+ if (!this.paginationContainer) return;
3206
+ if (((g = this.options.pagination) == null ? void 0 : g.mode) === "infinite") {
3207
+ this.renderInfiniteScrollStatus();
3208
+ return;
3209
+ }
3210
+ const { currentPage: e, totalPages: i, totalCount: s, pageSize: o } = this.state.pagination, n = this.options.pagination, t = (n == null ? void 0 : n.maxPageButtons) || 5;
3211
+ if (this.paginationContainer.innerHTML = "", (n == null ? void 0 : n.showInfo) !== !1) {
3212
+ const d = p("div", "velox-pagination-info"), f = (e - 1) * o + 1, C = Math.min(e * o, s);
3213
+ d.textContent = s > 0 ? `${f}-${C} / ${s.toLocaleString()}` : "0 items", this.paginationContainer.appendChild(d);
3214
+ }
3215
+ const l = p("div", "velox-pagination-nav");
3216
+ l.appendChild(this.createPageButton("«", 1, e === 1)), l.appendChild(this.createPageButton("‹", e - 1, e === 1));
3217
+ const a = Math.floor(t / 2);
3218
+ let r = Math.max(1, e - a);
3219
+ const h = Math.min(i, r + t - 1);
3220
+ if (h - r + 1 < t && (r = Math.max(1, h - t + 1)), r > 1 && (l.appendChild(this.createPageButton("1", 1, !1)), r > 2)) {
3221
+ const d = p("span", "velox-pagination-ellipsis");
3222
+ d.textContent = "…", l.appendChild(d);
3223
+ }
3224
+ for (let d = r; d <= h; d++) {
3225
+ const f = this.createPageButton(String(d), d, !1);
3226
+ d === e && w(f, "velox-pagination-btn--active"), l.appendChild(f);
3227
+ }
3228
+ if (h < i) {
3229
+ if (h < i - 1) {
3230
+ const d = p("span", "velox-pagination-ellipsis");
3231
+ d.textContent = "…", l.appendChild(d);
3232
+ }
3233
+ l.appendChild(this.createPageButton(String(i), i, !1));
3234
+ }
3235
+ if (l.appendChild(this.createPageButton("›", e + 1, e === i)), l.appendChild(this.createPageButton("»", i, e === i)), this.paginationContainer.appendChild(l), n != null && n.showSizeChanger) {
3236
+ const d = p("div", "velox-pagination-sizer"), f = document.createElement("select");
3237
+ f.className = "velox-pagination-select", (n.pageSizeOptions || [10, 20, 50, 100]).forEach((x) => {
3238
+ const b = document.createElement("option");
3239
+ b.value = String(x), b.textContent = `${x} / page`, x === o && (b.selected = !0), f.appendChild(b);
3240
+ }), f.addEventListener("change", () => {
3241
+ this.setPageSize(Number(f.value));
3242
+ }), d.appendChild(f), this.paginationContainer.appendChild(d);
3243
+ }
3244
+ }
3245
+ /**
3246
+ * 페이지 버튼 생성 헬퍼 (Phase 18)
3247
+ */
3248
+ createPageButton(e, i, s) {
3249
+ const o = p("button", "velox-pagination-btn");
3250
+ return o.textContent = e, s ? (o.setAttribute("disabled", "true"), w(o, "velox-pagination-btn--disabled")) : o.addEventListener("click", () => this.goToPage(i)), o;
3251
+ }
3252
+ destroy() {
3253
+ var e, i;
3254
+ this.dragManager.destroy(), this.detachEvents(), document.removeEventListener("mouseup", this.boundHandleBlockSelectionEnd), this.closeFilterPopup(), this.closeColumnMenu(), this.rootElement.removeEventListener("keydown", this.boundHandleKeyDown), this.measureCanvas = null, this.measureContext = null, this.tooltip && (this.tooltip.destroy(), this.tooltip = null), this.container.innerHTML = "", (i = (e = this.events).onDestroy) == null || i.call(e);
3255
+ }
3256
+ }
3257
+ const Kt = /* @__PURE__ */ mt({
3258
+ __name: "VeloxGridVue",
3259
+ props: {
3260
+ columns: {},
3261
+ data: { default: () => [] },
3262
+ width: {},
3263
+ height: {},
3264
+ rowHeight: { default: 40 },
3265
+ headerHeight: { default: 44 },
3266
+ showRowNumbers: { type: [Boolean, Object], default: !1 },
3267
+ rowDraggable: { type: [Boolean, Object], default: !1 },
3268
+ selectable: { type: Boolean, default: !0 },
3269
+ selectionMode: {},
3270
+ selectionStyle: {},
3271
+ showCheckbox: { type: Boolean },
3272
+ checkBar: {},
3273
+ sortable: { type: Boolean, default: !0 },
3274
+ filterable: { type: Boolean, default: !1 },
3275
+ editable: { type: Boolean, default: !1 },
3276
+ resizable: { type: Boolean, default: !0 },
3277
+ virtualScroll: { type: Boolean, default: !0 },
3278
+ bufferSize: { default: 10 },
3279
+ theme: { default: "default" },
3280
+ locale: {},
3281
+ emptyMessage: { default: "No data" },
3282
+ loading: { type: Boolean, default: !1 },
3283
+ loadingMessage: {},
3284
+ className: {},
3285
+ undoable: { type: Boolean },
3286
+ undoStackSize: {},
3287
+ contextMenu: {},
3288
+ footerSummary: {},
3289
+ groupSummary: {},
3290
+ fixedOptions: {},
3291
+ dataSource: {},
3292
+ pagination: {},
3293
+ wrapperClass: {}
3294
+ },
3295
+ emits: ["data-change", "row-add", "row-remove", "row-update", "selection-change", "row-select", "all-select", "cell-click", "cell-double-click", "row-click", "row-double-click", "cell-select", "cell-selection-change", "check-change", "check-all-change", "sort", "filter", "cell-edit-start", "cell-edit-end", "cell-edit-cancel", "validation-error", "copy", "paste", "cut", "key-down", "undo", "redo", "scroll", "column-resize", "column-reorder", "ready", "destroy", "page-change", "page-size-change"],
3296
+ setup(c, { expose: e, emit: i }) {
3297
+ const s = c, o = i, n = P(null);
3298
+ let t = null;
3299
+ function l() {
3300
+ const { wrapperClass: u, ...v } = s;
3301
+ return {
3302
+ ...v,
3303
+ ...{
3304
+ onDataChange: (...m) => o("data-change", ...m),
3305
+ onRowAdd: (...m) => o("row-add", ...m),
3306
+ onRowRemove: (...m) => o("row-remove", ...m),
3307
+ onRowUpdate: (...m) => o("row-update", ...m),
3308
+ onSelectionChange: (...m) => o("selection-change", ...m),
3309
+ onRowSelect: (...m) => o("row-select", ...m),
3310
+ onAllSelect: (...m) => o("all-select", ...m),
3311
+ onCellClick: (...m) => o("cell-click", ...m),
3312
+ onCellDoubleClick: (...m) => o("cell-double-click", ...m),
3313
+ onRowClick: (...m) => o("row-click", ...m),
3314
+ onRowDoubleClick: (...m) => o("row-double-click", ...m),
3315
+ onCellSelect: (...m) => o("cell-select", ...m),
3316
+ onCellSelectionChange: (...m) => o("cell-selection-change", ...m),
3317
+ onCheckChange: (...m) => o("check-change", ...m),
3318
+ onCheckAllChange: (...m) => o("check-all-change", ...m),
3319
+ onSort: (...m) => o("sort", ...m),
3320
+ onFilter: (...m) => o("filter", ...m),
3321
+ onCellEditStart: (...m) => o("cell-edit-start", ...m),
3322
+ onCellEditEnd: (...m) => o("cell-edit-end", ...m),
3323
+ onCellEditCancel: (...m) => o("cell-edit-cancel", ...m),
3324
+ onValidationError: (...m) => o("validation-error", ...m),
3325
+ onCopy: (...m) => o("copy", ...m),
3326
+ onPaste: (...m) => o("paste", ...m),
3327
+ onCut: (...m) => o("cut", ...m),
3328
+ onKeyDown: (...m) => o("key-down", ...m),
3329
+ onUndo: (...m) => o("undo", ...m),
3330
+ onRedo: (...m) => o("redo", ...m),
3331
+ onScroll: (...m) => o("scroll", ...m),
3332
+ onColumnResize: (...m) => o("column-resize", ...m),
3333
+ onColumnReorder: (...m) => o("column-reorder", ...m),
3334
+ onReady: (...m) => o("ready", ...m),
3335
+ onDestroy: () => o("destroy"),
3336
+ onPageChange: (...m) => o("page-change", ...m),
3337
+ onPageSizeChange: (...m) => o("page-size-change", ...m)
3338
+ }
3339
+ };
3340
+ }
3341
+ _(() => {
3342
+ n.value && (t = new G(n.value, l()));
3343
+ }), W(() => {
3344
+ t && (t.destroy(), t = null);
3345
+ }), O(() => s.data, (u) => {
3346
+ t && u && t.setData(u);
3347
+ }), O(() => s.columns, (u) => {
3348
+ t && u && t.setColumns(u);
3349
+ }), O(() => s.loading, (u) => {
3350
+ t && u !== void 0 && t.setOptions({ loading: u });
3351
+ });
3352
+ function a() {
3353
+ return t;
3354
+ }
3355
+ function r() {
3356
+ t == null || t.destroy();
3357
+ }
3358
+ function h() {
3359
+ t == null || t.refresh();
3360
+ }
3361
+ function g() {
3362
+ return (t == null ? void 0 : t.getData()) ?? [];
3363
+ }
3364
+ function d(u) {
3365
+ t == null || t.setData(u);
3366
+ }
3367
+ function f(u) {
3368
+ return (t == null ? void 0 : t.getRow(u)) ?? null;
3369
+ }
3370
+ function C(u, v) {
3371
+ t == null || t.addRow(u, v);
3372
+ }
3373
+ function x(u, v) {
3374
+ t == null || t.updateRow(u, v);
3375
+ }
3376
+ function b(u) {
3377
+ t == null || t.removeRow(u);
3378
+ }
3379
+ function y() {
3380
+ t == null || t.clearData();
3381
+ }
3382
+ function S() {
3383
+ return (t == null ? void 0 : t.getSelectedRows()) ?? [];
3384
+ }
3385
+ function E() {
3386
+ return (t == null ? void 0 : t.getSelectedData()) ?? [];
3387
+ }
3388
+ function R(u, v) {
3389
+ t == null || t.selectRow(u, v);
3390
+ }
3391
+ function $(u) {
3392
+ t == null || t.selectAll(u);
3393
+ }
3394
+ function D() {
3395
+ t == null || t.clearSelection();
3396
+ }
3397
+ function B(u) {
3398
+ return (t == null ? void 0 : t.isRowSelected(u)) ?? !1;
3399
+ }
3400
+ function L(u, v, M) {
3401
+ t == null || t.selectCell(u, v, M);
3402
+ }
3403
+ function T() {
3404
+ return (t == null ? void 0 : t.getSelectedCells()) ?? [];
3405
+ }
3406
+ function F(u, v) {
3407
+ t == null || t.setFocusedCell(u, v);
3408
+ }
3409
+ function J() {
3410
+ return (t == null ? void 0 : t.getFocusedCell()) ?? null;
3411
+ }
3412
+ function Y(u) {
3413
+ t == null || t.setSelection(u);
3414
+ }
3415
+ function Q() {
3416
+ return (t == null ? void 0 : t.getSelection()) ?? null;
3417
+ }
3418
+ function Z() {
3419
+ return (t == null ? void 0 : t.getSelectionData()) ?? [];
3420
+ }
3421
+ function I(u, v) {
3422
+ t == null || t.checkItem(u, v);
3423
+ }
3424
+ function ee(u, v) {
3425
+ t == null || t.checkItems(u, v);
3426
+ }
3427
+ function te(u) {
3428
+ t == null || t.checkAll(u);
3429
+ }
3430
+ function ie() {
3431
+ t == null || t.uncheckAll();
3432
+ }
3433
+ function se() {
3434
+ return (t == null ? void 0 : t.getCheckedItems()) ?? [];
3435
+ }
3436
+ function oe() {
3437
+ return (t == null ? void 0 : t.getCheckedData()) ?? [];
3438
+ }
3439
+ function ne(u) {
3440
+ return (t == null ? void 0 : t.isItemChecked(u)) ?? !1;
3441
+ }
3442
+ function le(u) {
3443
+ return (t == null ? void 0 : t.isItemCheckable(u)) ?? !1;
3444
+ }
3445
+ function ae(u, v) {
3446
+ t == null || t.checkRow(u, v);
3447
+ }
3448
+ function re() {
3449
+ return (t == null ? void 0 : t.getCheckedRows()) ?? [];
3450
+ }
3451
+ function de(u, v) {
3452
+ t == null || t.sort(u, v);
3453
+ }
3454
+ function ce() {
3455
+ t == null || t.clearSort();
3456
+ }
3457
+ function he() {
3458
+ return (t == null ? void 0 : t.getSortState()) ?? [];
3459
+ }
3460
+ function ue(u) {
3461
+ t == null || t.filter(u);
3462
+ }
3463
+ function fe() {
3464
+ t == null || t.clearFilter();
3465
+ }
3466
+ function pe() {
3467
+ return (t == null ? void 0 : t.getFilterState()) ?? null;
3468
+ }
3469
+ function me(u, v) {
3470
+ t == null || t.startEdit(u, v);
3471
+ }
3472
+ function ge(u) {
3473
+ t == null || t.endEdit(u);
3474
+ }
3475
+ function Ce() {
3476
+ t == null || t.cancelEdit();
3477
+ }
3478
+ function xe() {
3479
+ return (t == null ? void 0 : t.isEditing()) ?? !1;
3480
+ }
3481
+ function ye(u) {
3482
+ return (t == null ? void 0 : t.getColumn(u)) ?? null;
3483
+ }
3484
+ function ve(u, v) {
3485
+ t == null || t.setColumnWidth(u, v);
3486
+ }
3487
+ function we(u) {
3488
+ t == null || t.showColumn(u);
3489
+ }
3490
+ function be(u) {
3491
+ t == null || t.hideColumn(u);
3492
+ }
3493
+ function Se(u) {
3494
+ t == null || t.setColumns(u);
3495
+ }
3496
+ function Ee(u) {
3497
+ t == null || t.autoFitColumn(u);
3498
+ }
3499
+ function ke() {
3500
+ t == null || t.autoFitAllColumns();
3501
+ }
3502
+ function Re(u) {
3503
+ t == null || t.scrollToRow(u);
3504
+ }
3505
+ function De() {
3506
+ t == null || t.scrollToTop();
3507
+ }
3508
+ function Le() {
3509
+ t == null || t.scrollToBottom();
3510
+ }
3511
+ function Te(u, v) {
3512
+ t == null || t.scrollToCell(u, v);
3513
+ }
3514
+ function Be() {
3515
+ t == null || t.copy();
3516
+ }
3517
+ function Me() {
3518
+ t == null || t.paste();
3519
+ }
3520
+ function Pe() {
3521
+ t == null || t.cut();
3522
+ }
3523
+ function He() {
3524
+ return (t == null ? void 0 : t.undo()) ?? !1;
3525
+ }
3526
+ function Fe() {
3527
+ return (t == null ? void 0 : t.redo()) ?? !1;
3528
+ }
3529
+ function Oe() {
3530
+ return (t == null ? void 0 : t.canUndo()) ?? !1;
3531
+ }
3532
+ function Ve() {
3533
+ return (t == null ? void 0 : t.canRedo()) ?? !1;
3534
+ }
3535
+ function Ae() {
3536
+ t == null || t.clearHistory();
3537
+ }
3538
+ function Ne() {
3539
+ t == null || t.deleteSelectedCells();
3540
+ }
3541
+ function $e() {
3542
+ t == null || t.deleteSelectedRows();
3543
+ }
3544
+ function ze(u) {
3545
+ t == null || t.exportToExcel(u);
3546
+ }
3547
+ function _e(u) {
3548
+ return (t == null ? void 0 : t.exportToCSV(u)) ?? "";
3549
+ }
3550
+ function We(u) {
3551
+ t == null || t.downloadCSV(u);
3552
+ }
3553
+ function Ke(u) {
3554
+ return (t == null ? void 0 : t.exportToJSON(u)) ?? "[]";
3555
+ }
3556
+ function qe(u) {
3557
+ t == null || t.downloadJSON(u);
3558
+ }
3559
+ function Ue(u, v) {
3560
+ return (t == null ? void 0 : t.importFromCSV(u, v)) ?? { data: [], headers: [], errors: [] };
3561
+ }
3562
+ function je(u, v) {
3563
+ return (t == null ? void 0 : t.importFromExcel(u, v)) ?? Promise.resolve({ data: [], headers: [], errors: [] });
3564
+ }
3565
+ function Xe() {
3566
+ return (t == null ? void 0 : t.getRowCount()) ?? 0;
3567
+ }
3568
+ function Ge() {
3569
+ return (t == null ? void 0 : t.getVisibleRowCount()) ?? 0;
3570
+ }
3571
+ function Je(u, v) {
3572
+ return t == null ? void 0 : t.getCellValue(u, v);
3573
+ }
3574
+ function Ye(u, v, M) {
3575
+ t == null || t.setCellValue(u, v, M);
3576
+ }
3577
+ function Qe(u) {
3578
+ return t == null ? void 0 : t.getSummaryValue(u);
3579
+ }
3580
+ function Ze() {
3581
+ return (t == null ? void 0 : t.getSummaryValues()) ?? {};
3582
+ }
3583
+ function Ie() {
3584
+ t == null || t.refreshSummary();
3585
+ }
3586
+ function et(u) {
3587
+ return (t == null ? void 0 : t.getRowState(u)) ?? "none";
3588
+ }
3589
+ function tt(u) {
3590
+ return (t == null ? void 0 : t.getRowStateByData(u)) ?? "none";
3591
+ }
3592
+ function it(u, v) {
3593
+ t == null || t.setRowState(u, v);
3594
+ }
3595
+ function st() {
3596
+ return (t == null ? void 0 : t.getChanges()) ?? { created: [], updated: [], deleted: [] };
3597
+ }
3598
+ function ot() {
3599
+ return (t == null ? void 0 : t.getCreatedRows()) ?? [];
3600
+ }
3601
+ function nt() {
3602
+ return (t == null ? void 0 : t.getUpdatedRows()) ?? [];
3603
+ }
3604
+ function lt() {
3605
+ return (t == null ? void 0 : t.getDeletedRows()) ?? [];
3606
+ }
3607
+ function at() {
3608
+ t == null || t.clearRowStates();
3609
+ }
3610
+ function rt() {
3611
+ t == null || t.commit();
3612
+ }
3613
+ function dt(u) {
3614
+ t == null || t.setOptions(u);
3615
+ }
3616
+ function ct() {
3617
+ return t == null ? void 0 : t.getOptions();
3618
+ }
3619
+ function ht(u) {
3620
+ t == null || t.goToPage(u);
3621
+ }
3622
+ function ut(u) {
3623
+ t == null || t.setPageSize(u);
3624
+ }
3625
+ function ft() {
3626
+ return (t == null ? void 0 : t.getPaginationState()) ?? {
3627
+ currentPage: 1,
3628
+ pageSize: 20,
3629
+ totalCount: 0,
3630
+ totalPages: 0,
3631
+ loading: !1
3632
+ };
3633
+ }
3634
+ function pt() {
3635
+ return (t == null ? void 0 : t.fetchData()) ?? Promise.resolve();
3636
+ }
3637
+ return e({
3638
+ getGridInstance: a,
3639
+ destroy: r,
3640
+ refresh: h,
3641
+ getData: g,
3642
+ setData: d,
3643
+ getRow: f,
3644
+ addRow: C,
3645
+ updateRow: x,
3646
+ removeRow: b,
3647
+ clearData: y,
3648
+ getSelectedRows: S,
3649
+ getSelectedData: E,
3650
+ selectRow: R,
3651
+ selectAll: $,
3652
+ clearSelection: D,
3653
+ isRowSelected: B,
3654
+ selectCell: L,
3655
+ getSelectedCells: T,
3656
+ setFocusedCell: F,
3657
+ getFocusedCell: J,
3658
+ setSelection: Y,
3659
+ getSelection: Q,
3660
+ getSelectionData: Z,
3661
+ checkItem: I,
3662
+ checkItems: ee,
3663
+ checkAll: te,
3664
+ uncheckAll: ie,
3665
+ getCheckedItems: se,
3666
+ getCheckedData: oe,
3667
+ isItemChecked: ne,
3668
+ isItemCheckable: le,
3669
+ checkRow: ae,
3670
+ getCheckedRows: re,
3671
+ sort: de,
3672
+ clearSort: ce,
3673
+ getSortState: he,
3674
+ filter: ue,
3675
+ clearFilter: fe,
3676
+ getFilterState: pe,
3677
+ startEdit: me,
3678
+ endEdit: ge,
3679
+ cancelEdit: Ce,
3680
+ isEditing: xe,
3681
+ getColumn: ye,
3682
+ setColumnWidth: ve,
3683
+ showColumn: we,
3684
+ hideColumn: be,
3685
+ setColumns: Se,
3686
+ autoFitColumn: Ee,
3687
+ autoFitAllColumns: ke,
3688
+ scrollToRow: Re,
3689
+ scrollToTop: De,
3690
+ scrollToBottom: Le,
3691
+ scrollToCell: Te,
3692
+ copy: Be,
3693
+ paste: Me,
3694
+ cut: Pe,
3695
+ undo: He,
3696
+ redo: Fe,
3697
+ canUndo: Oe,
3698
+ canRedo: Ve,
3699
+ clearHistory: Ae,
3700
+ deleteSelectedCells: Ne,
3701
+ deleteSelectedRows: $e,
3702
+ exportToExcel: ze,
3703
+ exportToCSV: _e,
3704
+ downloadCSV: We,
3705
+ exportToJSON: Ke,
3706
+ downloadJSON: qe,
3707
+ importFromCSV: Ue,
3708
+ importFromExcel: je,
3709
+ getRowCount: Xe,
3710
+ getVisibleRowCount: Ge,
3711
+ getCellValue: Je,
3712
+ setCellValue: Ye,
3713
+ getSummaryValue: Qe,
3714
+ getSummaryValues: Ze,
3715
+ refreshSummary: Ie,
3716
+ getRowState: et,
3717
+ getRowStateByData: tt,
3718
+ setRowState: it,
3719
+ getChanges: st,
3720
+ getCreatedRows: ot,
3721
+ getUpdatedRows: nt,
3722
+ getDeletedRows: lt,
3723
+ clearRowStates: at,
3724
+ commit: rt,
3725
+ setOptions: dt,
3726
+ getOptions: ct,
3727
+ goToPage: ht,
3728
+ setPageSize: ut,
3729
+ getPaginationState: ft,
3730
+ fetchData: pt
3731
+ }), (u, v) => (gt(), Ct("div", {
3732
+ ref_key: "containerRef",
3733
+ ref: n,
3734
+ class: xt(c.wrapperClass)
3735
+ }, null, 2));
3736
+ }
3737
+ });
3738
+ function qt(c) {
3739
+ const e = P(null), i = P(null), s = P(!1);
3740
+ return _(() => {
3741
+ e.value && (i.value = new G(e.value, c), s.value = !0);
3742
+ }), W(() => {
3743
+ i.value && (i.value.destroy(), i.value = null, s.value = !1);
3744
+ }), {
3745
+ containerRef: e,
3746
+ grid: i,
3747
+ isReady: s
3748
+ };
3749
+ }
3750
+ export {
3751
+ Kt as VeloxGridVue,
3752
+ qt as useVeloxGrid
3753
+ };
3754
+ //# sourceMappingURL=index.esm.js.map