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