@skygraph/react 0.0.0-placeholder.0 → 0.4.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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Table-BqN2u5ma.d.cts +1015 -0
  3. package/dist/Table-IvijKCyd.d.ts +1015 -0
  4. package/dist/chunk-2OCEO636.js +91 -0
  5. package/dist/chunk-2OCEO636.js.map +1 -0
  6. package/dist/chunk-6SHHUUAE.js +1667 -0
  7. package/dist/chunk-6SHHUUAE.js.map +1 -0
  8. package/dist/chunk-BNMJSYI2.js +54 -0
  9. package/dist/chunk-BNMJSYI2.js.map +1 -0
  10. package/dist/chunk-DRBAZI46.js +57 -0
  11. package/dist/chunk-DRBAZI46.js.map +1 -0
  12. package/dist/chunk-GJDDPZH7.js +226 -0
  13. package/dist/chunk-GJDDPZH7.js.map +1 -0
  14. package/dist/chunk-KCFWFDSP.js +847 -0
  15. package/dist/chunk-KCFWFDSP.js.map +1 -0
  16. package/dist/chunk-MJAEAFPN.js +3791 -0
  17. package/dist/chunk-MJAEAFPN.js.map +1 -0
  18. package/dist/chunk-MLEBVELO.js +1412 -0
  19. package/dist/chunk-MLEBVELO.js.map +1 -0
  20. package/dist/chunk-SEQI65CF.js +61 -0
  21. package/dist/chunk-SEQI65CF.js.map +1 -0
  22. package/dist/chunk-ZJF6SJLP.js +200 -0
  23. package/dist/chunk-ZJF6SJLP.js.map +1 -0
  24. package/dist/common-CdpocIEz.d.cts +27 -0
  25. package/dist/common-CdpocIEz.d.ts +27 -0
  26. package/dist/datagrid-B6hg5yJh.d.cts +200 -0
  27. package/dist/datagrid-B6hg5yJh.d.ts +200 -0
  28. package/dist/datagrid.cjs +1052 -0
  29. package/dist/datagrid.cjs.map +1 -0
  30. package/dist/datagrid.d.cts +2 -0
  31. package/dist/datagrid.d.ts +2 -0
  32. package/dist/datagrid.js +10 -0
  33. package/dist/datagrid.js.map +1 -0
  34. package/dist/devtools.cjs +253 -0
  35. package/dist/devtools.cjs.map +1 -0
  36. package/dist/devtools.d.cts +29 -0
  37. package/dist/devtools.d.ts +29 -0
  38. package/dist/devtools.js +9 -0
  39. package/dist/devtools.js.map +1 -0
  40. package/dist/form.cjs +1723 -0
  41. package/dist/form.cjs.map +1 -0
  42. package/dist/form.d.cts +530 -0
  43. package/dist/form.d.ts +530 -0
  44. package/dist/form.js +49 -0
  45. package/dist/form.js.map +1 -0
  46. package/dist/index.cjs +22419 -0
  47. package/dist/index.cjs.map +1 -0
  48. package/dist/index.d.cts +3671 -0
  49. package/dist/index.d.ts +3671 -0
  50. package/dist/index.js +14087 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/table.cjs +4130 -0
  53. package/dist/table.cjs.map +1 -0
  54. package/dist/table.d.cts +31 -0
  55. package/dist/table.d.ts +31 -0
  56. package/dist/table.js +26 -0
  57. package/dist/table.js.map +1 -0
  58. package/dist/tree.cjs +1821 -0
  59. package/dist/tree.cjs.map +1 -0
  60. package/dist/tree.d.cts +348 -0
  61. package/dist/tree.d.ts +348 -0
  62. package/dist/tree.js +13 -0
  63. package/dist/tree.js.map +1 -0
  64. package/dist/virtual.cjs +145 -0
  65. package/dist/virtual.cjs.map +1 -0
  66. package/dist/virtual.d.cts +50 -0
  67. package/dist/virtual.d.ts +50 -0
  68. package/dist/virtual.js +11 -0
  69. package/dist/virtual.js.map +1 -0
  70. package/package.json +108 -18
  71. package/README.md +0 -12
  72. package/index.js +0 -3
package/dist/table.cjs ADDED
@@ -0,0 +1,4130 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/table.ts
31
+ var table_exports = {};
32
+ __export(table_exports, {
33
+ Table: () => Table,
34
+ copyToClipboard: () => copyToClipboard,
35
+ downloadCSV: () => downloadCSV,
36
+ downloadJSON: () => downloadJSON,
37
+ printTable: () => printTable,
38
+ toCSVString: () => toCSVString,
39
+ toJSONString: () => toJSONString,
40
+ toTSVString: () => toTSVString,
41
+ useTable: () => useTable
42
+ });
43
+ module.exports = __toCommonJS(table_exports);
44
+
45
+ // src/components/complex/Table/Table.tsx
46
+ var import_react13 = __toESM(require("react"), 1);
47
+
48
+ // src/components/ConfigProvider.tsx
49
+ var import_react = require("react");
50
+ var import_jsx_runtime = require("react/jsx-runtime");
51
+ var SgConfigContext = (0, import_react.createContext)({});
52
+ function useConfig() {
53
+ return (0, import_react.useContext)(SgConfigContext);
54
+ }
55
+
56
+ // src/components/ui/Spin.tsx
57
+ var import_react2 = __toESM(require("react"), 1);
58
+ var import_jsx_runtime2 = require("react/jsx-runtime");
59
+ function Spin({
60
+ spinning = true,
61
+ size: sizeProp,
62
+ delay,
63
+ tip,
64
+ fullscreen,
65
+ indicator,
66
+ children,
67
+ className,
68
+ style,
69
+ unstyled
70
+ }) {
71
+ const config = useConfig();
72
+ const resolvedSize = sizeProp ?? config.size ?? "middle";
73
+ const [visible, setVisible] = import_react2.default.useState(delay ? false : spinning);
74
+ import_react2.default.useEffect(() => {
75
+ if (!delay) {
76
+ setVisible(spinning);
77
+ return;
78
+ }
79
+ if (spinning) {
80
+ const timer = setTimeout(() => setVisible(true), delay);
81
+ return () => clearTimeout(timer);
82
+ }
83
+ setVisible(false);
84
+ }, [spinning, delay]);
85
+ if (!visible && !children) return null;
86
+ if (!visible && children) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
87
+ const spinSizeClass = resolvedSize === "middle" ? "default" : resolvedSize;
88
+ const spinClasses = unstyled ? className ?? "" : ["sg-spin", `sg-spin-${spinSizeClass}`, className].filter(Boolean).join(" ");
89
+ const spinElement = indicator ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
90
+ "span",
91
+ {
92
+ className: spinClasses,
93
+ style,
94
+ role: "status",
95
+ "aria-live": "polite",
96
+ "aria-label": config.locale?.spin?.loading ?? "Loading"
97
+ }
98
+ );
99
+ if (fullscreen) {
100
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: unstyled ? "" : "sg-spin-fullscreen", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: unstyled ? "" : "sg-spin-fullscreen-inner", children: [
101
+ spinElement,
102
+ tip && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: unstyled ? "" : "sg-spin-tip", children: tip })
103
+ ] }) });
104
+ }
105
+ if (!children) {
106
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: unstyled ? "" : "sg-spin-standalone", style, children: [
107
+ spinElement,
108
+ tip && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: unstyled ? "" : "sg-spin-tip", children: tip })
109
+ ] });
110
+ }
111
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: unstyled ? "" : "sg-spin-container", style, children: [
112
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: unstyled ? "" : "sg-spin-overlay", children: [
113
+ spinElement,
114
+ tip && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: unstyled ? "" : "sg-spin-tip", children: tip })
115
+ ] }),
116
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: visible ? unstyled ? "" : "sg-spin-blur" : "", children })
117
+ ] });
118
+ }
119
+
120
+ // src/components/ui/Input.tsx
121
+ var import_jsx_runtime3 = require("react/jsx-runtime");
122
+ function Input({
123
+ value,
124
+ defaultValue,
125
+ placeholder,
126
+ type = "text",
127
+ readOnly = false,
128
+ size: sizeProp,
129
+ disabled: disabledProp,
130
+ loading,
131
+ onChange,
132
+ onBlur,
133
+ onFocus,
134
+ "aria-invalid": ariaInvalid,
135
+ "aria-required": ariaRequired,
136
+ "aria-describedby": ariaDescribedBy,
137
+ id,
138
+ className,
139
+ style,
140
+ unstyled
141
+ }) {
142
+ const config = useConfig();
143
+ const size = sizeProp ?? config.size ?? "middle";
144
+ const disabled = disabledProp ?? config.disabled ?? false;
145
+ const wrapperClasses = unstyled ? className ?? "" : [
146
+ "sg-input-wrapper",
147
+ `sg-input-wrapper-${size}`,
148
+ loading ? "sg-input-wrapper-loading" : "",
149
+ readOnly ? "sg-input-wrapper-readonly" : "",
150
+ className
151
+ ].filter(Boolean).join(" ");
152
+ const inputClasses = unstyled ? "" : [
153
+ "sg-input",
154
+ `sg-input-${size}`,
155
+ readOnly ? "sg-input-readonly" : ""
156
+ ].filter(Boolean).join(" ");
157
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: wrapperClasses, style, children: [
158
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
159
+ "input",
160
+ {
161
+ id,
162
+ type,
163
+ className: inputClasses,
164
+ value,
165
+ defaultValue,
166
+ placeholder,
167
+ disabled: disabled || loading,
168
+ readOnly,
169
+ "aria-invalid": ariaInvalid,
170
+ "aria-required": ariaRequired,
171
+ "aria-readonly": readOnly || void 0,
172
+ "aria-describedby": ariaDescribedBy,
173
+ onChange: (e) => onChange?.(e.target.value),
174
+ onBlur,
175
+ onFocus
176
+ }
177
+ ),
178
+ loading && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spin, { size: "small", unstyled })
179
+ ] });
180
+ }
181
+
182
+ // src/components/ui/Pagination.tsx
183
+ var import_react3 = require("react");
184
+ var import_jsx_runtime4 = require("react/jsx-runtime");
185
+ function Pagination({
186
+ current,
187
+ total,
188
+ pageSize = 10,
189
+ onChange,
190
+ onPageSizeChange,
191
+ showTotal,
192
+ disabled: disabledProp,
193
+ simple,
194
+ showSizeChanger,
195
+ pageSizeOptions = [10, 20, 50, 100],
196
+ showQuickJumper,
197
+ className,
198
+ style,
199
+ unstyled
200
+ }) {
201
+ const config = useConfig();
202
+ const disabled = disabledProp ?? config.disabled ?? false;
203
+ const locale = config.locale?.pagination;
204
+ const totalPrefix = locale?.totalPrefix ?? "Total";
205
+ const itemsPerPageLabel = locale?.itemsPerPage ?? "/ page";
206
+ const jumpLabel = locale?.jump ?? "Go to";
207
+ const ariaLabel = locale?.ariaLabel ?? "Pagination";
208
+ const [jumpValue, setJumpValue] = (0, import_react3.useState)("");
209
+ const totalPages = Math.max(1, Math.ceil(total / pageSize));
210
+ const safeCurrentPage = Math.min(Math.max(1, current), totalPages);
211
+ const rangeStart = (safeCurrentPage - 1) * pageSize + 1;
212
+ const rangeEnd = Math.min(safeCurrentPage * pageSize, total);
213
+ const go = (page) => {
214
+ if (disabled || page < 1 || page > totalPages || page === safeCurrentPage) return;
215
+ onChange?.(page);
216
+ };
217
+ const handleJump = () => {
218
+ const num = parseInt(jumpValue, 10);
219
+ if (!isNaN(num)) {
220
+ go(num);
221
+ }
222
+ setJumpValue("");
223
+ };
224
+ const pages = buildPages(safeCurrentPage, totalPages);
225
+ const renderTotal = () => {
226
+ if (!showTotal) return null;
227
+ if (typeof showTotal === "function") {
228
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "sg-pagination-total", children: showTotal(total, [rangeStart, rangeEnd]) });
229
+ }
230
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "sg-pagination-total", children: [
231
+ totalPrefix,
232
+ " ",
233
+ total
234
+ ] });
235
+ };
236
+ const renderSizeChanger = () => {
237
+ if (!showSizeChanger) return null;
238
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
239
+ "select",
240
+ {
241
+ className: "sg-pagination-size-changer",
242
+ value: pageSize,
243
+ onChange: (e) => onPageSizeChange?.(Number(e.target.value)),
244
+ disabled,
245
+ children: pageSizeOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("option", { value: opt, children: [
246
+ opt,
247
+ " ",
248
+ itemsPerPageLabel
249
+ ] }, opt))
250
+ }
251
+ );
252
+ };
253
+ const renderQuickJumper = () => {
254
+ if (!showQuickJumper) return null;
255
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "sg-pagination-quick-jumper", children: [
256
+ jumpLabel,
257
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
258
+ "input",
259
+ {
260
+ type: "text",
261
+ value: jumpValue,
262
+ onChange: (e) => setJumpValue(e.target.value),
263
+ onKeyDown: (e) => {
264
+ if (e.key === "Enter") handleJump();
265
+ },
266
+ onBlur: handleJump,
267
+ disabled,
268
+ className: "sg-pagination-jumper-input"
269
+ }
270
+ )
271
+ ] });
272
+ };
273
+ if (unstyled) {
274
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("nav", { className, style, "aria-label": ariaLabel, children: [
275
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { disabled: safeCurrentPage <= 1, onClick: () => go(safeCurrentPage - 1), children: "\u2039" }),
276
+ pages.map(
277
+ (p, i) => p === "..." ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u2026" }, `e${i}`) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
278
+ "button",
279
+ {
280
+ onClick: () => go(p),
281
+ "aria-current": p === safeCurrentPage ? "page" : void 0,
282
+ children: p
283
+ },
284
+ p
285
+ )
286
+ ),
287
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { disabled: safeCurrentPage >= totalPages, onClick: () => go(safeCurrentPage + 1), children: "\u203A" })
288
+ ] });
289
+ }
290
+ if (simple) {
291
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
292
+ "nav",
293
+ {
294
+ className: [
295
+ "sg-pagination sg-pagination-simple",
296
+ disabled ? "sg-pagination-disabled" : "",
297
+ className
298
+ ].filter(Boolean).join(" "),
299
+ style,
300
+ "aria-label": ariaLabel,
301
+ children: [
302
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
303
+ "button",
304
+ {
305
+ className: "sg-pagination-item sg-pagination-prev",
306
+ disabled: safeCurrentPage <= 1,
307
+ onClick: () => go(safeCurrentPage - 1),
308
+ children: "\u2039"
309
+ }
310
+ ),
311
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "sg-pagination-simple-pager", children: [
312
+ safeCurrentPage,
313
+ " / ",
314
+ totalPages
315
+ ] }),
316
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
317
+ "button",
318
+ {
319
+ className: "sg-pagination-item sg-pagination-next",
320
+ disabled: safeCurrentPage >= totalPages,
321
+ onClick: () => go(safeCurrentPage + 1),
322
+ children: "\u203A"
323
+ }
324
+ )
325
+ ]
326
+ }
327
+ );
328
+ }
329
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
330
+ "nav",
331
+ {
332
+ className: ["sg-pagination", disabled ? "sg-pagination-disabled" : "", className].filter(Boolean).join(" "),
333
+ style,
334
+ "aria-label": ariaLabel,
335
+ children: [
336
+ renderTotal(),
337
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
338
+ "button",
339
+ {
340
+ className: "sg-pagination-item sg-pagination-prev",
341
+ disabled: safeCurrentPage <= 1,
342
+ onClick: () => go(safeCurrentPage - 1),
343
+ children: "\u2039"
344
+ }
345
+ ),
346
+ pages.map(
347
+ (p, i) => p === "..." ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "sg-pagination-ellipsis", children: "\u2026" }, `e${i}`) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
348
+ "button",
349
+ {
350
+ className: `sg-pagination-item${p === safeCurrentPage ? " sg-pagination-item-active" : ""}`,
351
+ onClick: () => go(p),
352
+ "aria-current": p === safeCurrentPage ? "page" : void 0,
353
+ children: p
354
+ },
355
+ p
356
+ )
357
+ ),
358
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
359
+ "button",
360
+ {
361
+ className: "sg-pagination-item sg-pagination-next",
362
+ disabled: safeCurrentPage >= totalPages,
363
+ onClick: () => go(safeCurrentPage + 1),
364
+ children: "\u203A"
365
+ }
366
+ ),
367
+ renderSizeChanger(),
368
+ renderQuickJumper()
369
+ ]
370
+ }
371
+ );
372
+ }
373
+ function buildPages(current, total) {
374
+ if (total <= 7) {
375
+ return Array.from({ length: total }, (_, i) => i + 1);
376
+ }
377
+ if (current <= 4) {
378
+ return [1, 2, 3, 4, 5, "...", total];
379
+ }
380
+ if (current >= total - 3) {
381
+ return [1, "...", total - 4, total - 3, total - 2, total - 1, total];
382
+ }
383
+ return [1, "...", current - 1, current, current + 1, "...", total];
384
+ }
385
+
386
+ // src/components/ui/Checkbox.tsx
387
+ var import_react4 = __toESM(require("react"), 1);
388
+ var import_jsx_runtime5 = require("react/jsx-runtime");
389
+ function Checkbox({
390
+ checked,
391
+ defaultChecked,
392
+ disabled: disabledProp,
393
+ loading,
394
+ indeterminate,
395
+ onChange,
396
+ children,
397
+ className,
398
+ style,
399
+ unstyled
400
+ }) {
401
+ const config = useConfig();
402
+ const disabled = disabledProp ?? config.disabled ?? false;
403
+ const inputRef = import_react4.default.useRef(null);
404
+ import_react4.default.useEffect(() => {
405
+ if (inputRef.current) {
406
+ inputRef.current.indeterminate = indeterminate ?? false;
407
+ }
408
+ }, [indeterminate]);
409
+ const wrapperClass = unstyled ? className ?? "" : [
410
+ "sg-checkbox",
411
+ disabled || loading ? "sg-checkbox-disabled" : "",
412
+ loading ? "sg-checkbox-loading" : "",
413
+ className
414
+ ].filter(Boolean).join(" ");
415
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: wrapperClass, style, children: [
416
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
417
+ "input",
418
+ {
419
+ ref: inputRef,
420
+ type: "checkbox",
421
+ "aria-checked": checked,
422
+ className: unstyled ? "" : "sg-checkbox-input",
423
+ checked,
424
+ defaultChecked,
425
+ disabled: disabled || loading,
426
+ onChange: (e) => onChange?.(e.target.checked)
427
+ }
428
+ ),
429
+ children && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: unstyled ? "" : "sg-checkbox-label", children }),
430
+ loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Spin, { size: "small", unstyled })
431
+ ] });
432
+ }
433
+
434
+ // src/components/complex/Table/FilterDropdown.tsx
435
+ var import_react7 = __toESM(require("react"), 1);
436
+ var import_react_dom = require("react-dom");
437
+
438
+ // src/components/ui/Button.tsx
439
+ var import_jsx_runtime6 = require("react/jsx-runtime");
440
+ function Button({
441
+ type = "default",
442
+ size: sizeProp,
443
+ disabled: disabledProp,
444
+ loading,
445
+ htmlType = "button",
446
+ danger = false,
447
+ block = false,
448
+ onClick,
449
+ children,
450
+ className,
451
+ style,
452
+ unstyled
453
+ }) {
454
+ const config = useConfig();
455
+ const size = sizeProp ?? config.size ?? "middle";
456
+ const disabled = disabledProp ?? config.disabled ?? false;
457
+ const classes = unstyled ? className ?? "" : [
458
+ "sg-button",
459
+ `sg-button-${type}`,
460
+ `sg-button-${size}`,
461
+ danger ? "sg-button-danger" : "",
462
+ block ? "sg-button-block" : "",
463
+ loading ? "sg-button-loading" : "",
464
+ className
465
+ ].filter(Boolean).join(" ");
466
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
467
+ "button",
468
+ {
469
+ type: htmlType,
470
+ className: classes,
471
+ style,
472
+ disabled: disabled || loading,
473
+ "aria-disabled": disabled || loading,
474
+ "aria-busy": loading,
475
+ onClick,
476
+ children: [
477
+ loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Spin, { size: "small", unstyled }),
478
+ children
479
+ ]
480
+ }
481
+ );
482
+ }
483
+
484
+ // src/components/ui/Select.tsx
485
+ var import_react6 = require("react");
486
+
487
+ // src/components/ui/Transition.tsx
488
+ var import_react5 = __toESM(require("react"), 1);
489
+ function Transition({
490
+ visible,
491
+ name = "sg-fade",
492
+ duration = 200,
493
+ enterFrom,
494
+ enterTo,
495
+ leaveFrom,
496
+ leaveTo,
497
+ onAfterEnter,
498
+ onAfterLeave,
499
+ children,
500
+ unmountOnExit = true
501
+ }) {
502
+ const [mounted, setMounted] = (0, import_react5.useState)(visible);
503
+ const [phase, setPhase] = (0, import_react5.useState)(visible ? "idle" : "idle");
504
+ const nodeRef = (0, import_react5.useRef)(null);
505
+ const timerRef = (0, import_react5.useRef)(void 0);
506
+ const prevVisible = (0, import_react5.useRef)(visible);
507
+ const getEnterClasses = (0, import_react5.useCallback)(() => {
508
+ if (enterFrom && enterTo) return { from: enterFrom, active: `${name}-enter-active`, to: enterTo };
509
+ return { from: `${name}-enter-from`, active: `${name}-enter-active`, to: `${name}-enter-to` };
510
+ }, [name, enterFrom, enterTo]);
511
+ const getLeaveClasses = (0, import_react5.useCallback)(() => {
512
+ if (leaveFrom && leaveTo) return { from: leaveFrom, active: `${name}-leave-active`, to: leaveTo };
513
+ return { from: `${name}-leave-from`, active: `${name}-leave-active`, to: `${name}-leave-to` };
514
+ }, [name, leaveFrom, leaveTo]);
515
+ (0, import_react5.useEffect)(() => {
516
+ if (visible === prevVisible.current) return;
517
+ prevVisible.current = visible;
518
+ clearTimeout(timerRef.current);
519
+ if (visible) {
520
+ setMounted(true);
521
+ setPhase("enter");
522
+ requestAnimationFrame(() => {
523
+ requestAnimationFrame(() => setPhase("enter-active"));
524
+ });
525
+ timerRef.current = setTimeout(() => {
526
+ setPhase("idle");
527
+ onAfterEnter?.();
528
+ }, duration);
529
+ } else {
530
+ setPhase("leave");
531
+ requestAnimationFrame(() => {
532
+ requestAnimationFrame(() => setPhase("leave-active"));
533
+ });
534
+ timerRef.current = setTimeout(() => {
535
+ setPhase("idle");
536
+ if (unmountOnExit) setMounted(false);
537
+ onAfterLeave?.();
538
+ }, duration);
539
+ }
540
+ }, [visible, duration, unmountOnExit, onAfterEnter, onAfterLeave]);
541
+ (0, import_react5.useEffect)(() => {
542
+ return () => clearTimeout(timerRef.current);
543
+ }, []);
544
+ if (!mounted && unmountOnExit) return null;
545
+ const enterC = getEnterClasses();
546
+ const leaveC = getLeaveClasses();
547
+ let transitionClass = "";
548
+ switch (phase) {
549
+ case "enter":
550
+ transitionClass = `${enterC.from} ${enterC.active}`;
551
+ break;
552
+ case "enter-active":
553
+ transitionClass = `${enterC.to} ${enterC.active}`;
554
+ break;
555
+ case "leave":
556
+ transitionClass = `${leaveC.from} ${leaveC.active}`;
557
+ break;
558
+ case "leave-active":
559
+ transitionClass = `${leaveC.to} ${leaveC.active}`;
560
+ break;
561
+ }
562
+ return import_react5.default.cloneElement(children, {
563
+ ref: nodeRef,
564
+ className: [children.props.className, transitionClass].filter(Boolean).join(" ")
565
+ });
566
+ }
567
+
568
+ // src/components/ui/Select.tsx
569
+ var import_jsx_runtime7 = require("react/jsx-runtime");
570
+ function Select(props) {
571
+ const {
572
+ options,
573
+ placeholder = "Select...",
574
+ disabled: disabledProp,
575
+ loading,
576
+ size: sizeProp,
577
+ onBlur,
578
+ className,
579
+ style,
580
+ unstyled,
581
+ "aria-label": ariaLabel,
582
+ "aria-labelledby": ariaLabelledBy
583
+ } = props;
584
+ const isMultiple = props.multiple === true;
585
+ const config = useConfig();
586
+ const size = sizeProp ?? config.size ?? "middle";
587
+ const disabled = disabledProp ?? config.disabled ?? false;
588
+ const initialSingle = isMultiple ? void 0 : props.value ?? props.defaultValue;
589
+ const initialMultiple = isMultiple ? props.value ?? props.defaultValue ?? [] : [];
590
+ const [internalSingle, setInternalSingle] = (0, import_react6.useState)(initialSingle);
591
+ const [internalMultiple, setInternalMultiple] = (0, import_react6.useState)(initialMultiple);
592
+ const [open, setOpen] = (0, import_react6.useState)(false);
593
+ const [focusedIndex, setFocusedIndex] = (0, import_react6.useState)(-1);
594
+ const ref = (0, import_react6.useRef)(null);
595
+ const listboxId = (0, import_react6.useId)();
596
+ const currentSingle = isMultiple ? void 0 : props.value ?? internalSingle;
597
+ const currentMultiple = isMultiple ? props.value ?? internalMultiple : [];
598
+ const selectedOption = isMultiple ? void 0 : options.find((o) => o.value === currentSingle);
599
+ const selectedOptions = isMultiple ? options.filter((o) => currentMultiple.includes(o.value)) : [];
600
+ (0, import_react6.useEffect)(() => {
601
+ const handleClickOutside = (e) => {
602
+ if (ref.current && !ref.current.contains(e.target)) {
603
+ setOpen(false);
604
+ }
605
+ };
606
+ document.addEventListener("mousedown", handleClickOutside);
607
+ return () => document.removeEventListener("mousedown", handleClickOutside);
608
+ }, []);
609
+ (0, import_react6.useEffect)(() => {
610
+ if (!open) setFocusedIndex(-1);
611
+ }, [open]);
612
+ const emitSingle = (val) => {
613
+ setInternalSingle(val);
614
+ if (!isMultiple) props.onChange?.(val);
615
+ };
616
+ const emitMultiple = (vals) => {
617
+ setInternalMultiple(vals);
618
+ if (isMultiple) props.onChange?.(vals);
619
+ };
620
+ const handleSelect = (opt) => {
621
+ if (opt.disabled || opt.loading) return;
622
+ if (isMultiple) {
623
+ const exists = currentMultiple.includes(opt.value);
624
+ const next = exists ? currentMultiple.filter((v) => v !== opt.value) : [...currentMultiple, opt.value];
625
+ emitMultiple(next);
626
+ } else {
627
+ emitSingle(opt.value);
628
+ setOpen(false);
629
+ }
630
+ };
631
+ const handleRemoveTag = (val, e) => {
632
+ e.stopPropagation();
633
+ if (disabled || loading) return;
634
+ emitMultiple(currentMultiple.filter((v) => v !== val));
635
+ };
636
+ if (unstyled) {
637
+ if (isMultiple) {
638
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
639
+ "select",
640
+ {
641
+ className,
642
+ style,
643
+ multiple: true,
644
+ value: currentMultiple.map(String),
645
+ disabled: disabled || loading,
646
+ "aria-label": ariaLabel,
647
+ "aria-labelledby": ariaLabelledBy,
648
+ onChange: (e) => {
649
+ const picked = Array.from(e.target.selectedOptions).map((o) => {
650
+ const v = o.value;
651
+ const numVal = Number(v);
652
+ return options.some((opt) => opt.value === numVal) ? numVal : v;
653
+ });
654
+ emitMultiple(picked);
655
+ },
656
+ onBlur,
657
+ children: options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: opt.value, disabled: opt.disabled, children: opt.label }, opt.value))
658
+ }
659
+ );
660
+ }
661
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
662
+ "select",
663
+ {
664
+ className,
665
+ style,
666
+ value: currentSingle,
667
+ disabled: disabled || loading,
668
+ "aria-label": ariaLabel,
669
+ "aria-labelledby": ariaLabelledBy,
670
+ onChange: (e) => {
671
+ const v = e.target.value;
672
+ const numVal = Number(v);
673
+ const finalVal = options.some((o) => o.value === numVal) ? numVal : v;
674
+ emitSingle(finalVal);
675
+ },
676
+ onBlur,
677
+ children: [
678
+ !selectedOption && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: placeholder }),
679
+ options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: opt.value, disabled: opt.disabled, children: opt.label }, opt.value))
680
+ ]
681
+ }
682
+ );
683
+ }
684
+ const wrapperClass = [
685
+ "sg-select",
686
+ `sg-select-${size}`,
687
+ isMultiple ? "sg-select-multiple" : "",
688
+ open ? "sg-select-open" : "",
689
+ disabled || loading ? "sg-select-disabled" : "",
690
+ loading ? "sg-select-loading" : "",
691
+ className
692
+ ].filter(Boolean).join(" ");
693
+ const isOptionSelected = (opt) => isMultiple ? currentMultiple.includes(opt.value) : opt.value === currentSingle;
694
+ const renderTrigger = () => {
695
+ if (isMultiple) {
696
+ if (selectedOptions.length === 0) {
697
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "sg-select-placeholder", children: placeholder });
698
+ }
699
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "sg-select-tags", children: selectedOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "sg-select-tag", children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "sg-select-tag-label", children: opt.label }),
701
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
702
+ "button",
703
+ {
704
+ type: "button",
705
+ className: "sg-select-tag-remove",
706
+ "aria-label": `Remove ${opt.label}`,
707
+ tabIndex: -1,
708
+ onClick: (e) => handleRemoveTag(opt.value, e),
709
+ children: "\xD7"
710
+ }
711
+ )
712
+ ] }, opt.value)) });
713
+ }
714
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
715
+ "span",
716
+ {
717
+ className: selectedOption ? "sg-select-selection-item" : "sg-select-placeholder",
718
+ children: selectedOption?.label ?? placeholder
719
+ }
720
+ );
721
+ };
722
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: wrapperClass, ref, style, onBlur, children: [
723
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
724
+ "div",
725
+ {
726
+ className: "sg-select-selector",
727
+ role: "combobox",
728
+ "aria-expanded": open,
729
+ "aria-haspopup": "listbox",
730
+ "aria-controls": listboxId,
731
+ "aria-multiselectable": isMultiple || void 0,
732
+ "aria-label": ariaLabel,
733
+ "aria-labelledby": ariaLabelledBy,
734
+ "aria-disabled": disabled || loading || void 0,
735
+ tabIndex: disabled || loading ? -1 : 0,
736
+ onClick: () => !disabled && !loading && setOpen(!open),
737
+ onKeyDown: (e) => {
738
+ if (disabled || loading) return;
739
+ switch (e.key) {
740
+ case "Enter":
741
+ case " ":
742
+ e.preventDefault();
743
+ if (open && focusedIndex >= 0) {
744
+ handleSelect(options[focusedIndex]);
745
+ } else {
746
+ setOpen(!open);
747
+ }
748
+ break;
749
+ case "Escape":
750
+ e.preventDefault();
751
+ setOpen(false);
752
+ break;
753
+ case "ArrowDown":
754
+ e.preventDefault();
755
+ if (!open) setOpen(true);
756
+ else setFocusedIndex((i) => (i + 1) % options.length);
757
+ break;
758
+ case "ArrowUp":
759
+ e.preventDefault();
760
+ if (!open) setOpen(true);
761
+ else
762
+ setFocusedIndex(
763
+ (i) => (i - 1 + options.length) % options.length
764
+ );
765
+ break;
766
+ case "Backspace":
767
+ if (isMultiple && currentMultiple.length > 0) {
768
+ emitMultiple(currentMultiple.slice(0, -1));
769
+ }
770
+ break;
771
+ }
772
+ },
773
+ children: [
774
+ renderTrigger(),
775
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Spin, { size: "small", unstyled }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "sg-select-arrow", children: open ? "\u25B2" : "\u25BC" })
776
+ ]
777
+ }
778
+ ),
779
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Transition, { visible: open, name: "sg-slide-up", unmountOnExit: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "sg-select-dropdown", role: "listbox", id: listboxId, "aria-multiselectable": isMultiple || void 0, children: options.map((opt, idx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
780
+ "div",
781
+ {
782
+ role: "option",
783
+ "aria-selected": isOptionSelected(opt),
784
+ className: [
785
+ "sg-select-option",
786
+ isOptionSelected(opt) ? "sg-select-option-selected" : "",
787
+ idx === focusedIndex ? "sg-select-option-focused" : "",
788
+ opt.disabled || opt.loading ? "sg-select-option-disabled" : "",
789
+ opt.loading ? "sg-select-option-loading" : ""
790
+ ].filter(Boolean).join(" "),
791
+ onClick: () => handleSelect(opt),
792
+ children: [
793
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: opt.label }),
794
+ opt.loading && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Spin, { size: "small", unstyled })
795
+ ]
796
+ },
797
+ opt.value
798
+ )) }) })
799
+ ] });
800
+ }
801
+
802
+ // src/components/complex/Table/FilterDropdown.tsx
803
+ var import_jsx_runtime8 = require("react/jsx-runtime");
804
+ var TEXT_OPS = [
805
+ "eq",
806
+ "neq",
807
+ "contains",
808
+ "startsWith",
809
+ "endsWith",
810
+ "in",
811
+ "notIn",
812
+ "isEmpty",
813
+ "isNotEmpty"
814
+ ];
815
+ var NUMBER_OPS = [
816
+ "eq",
817
+ "neq",
818
+ "lt",
819
+ "lte",
820
+ "gt",
821
+ "gte",
822
+ "between",
823
+ "in",
824
+ "notIn",
825
+ "isEmpty",
826
+ "isNotEmpty"
827
+ ];
828
+ var NO_VALUE_OPS = /* @__PURE__ */ new Set(["isEmpty", "isNotEmpty"]);
829
+ function FilterTrigger({ col, t, state, actions }) {
830
+ const hasFilter = col.filterDropdown || col.filterMode === "search" || col.filterMode === "advanced" || col.filters && col.filters.length > 0;
831
+ if (!hasFilter) return null;
832
+ const filtered = col.filterMode === "advanced" ? state.advancedFilters[col.key] != null : (state.activeFilters[col.key]?.length ?? 0) > 0;
833
+ const iconNode = col.filterIcon ? typeof col.filterIcon === "function" ? col.filterIcon(filtered) : col.filterIcon : col.filterMode === "search" ? t.searchIcon : t.filterIcon;
834
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
835
+ "span",
836
+ {
837
+ className: `sg-table-filter-trigger${filtered ? " sg-table-filter-active" : ""}`,
838
+ onClick: (e) => {
839
+ e.stopPropagation();
840
+ const isOpen = state.openFilterDropdown === col.key;
841
+ if (isOpen) {
842
+ actions.setOpenFilterDropdown(null);
843
+ actions.setFilterAnchor(null);
844
+ } else {
845
+ actions.setFilterAnchor(e.currentTarget);
846
+ actions.setOpenFilterDropdown(col.key);
847
+ }
848
+ },
849
+ children: iconNode
850
+ }
851
+ );
852
+ }
853
+ function FilterPortal({
854
+ anchor,
855
+ children
856
+ }) {
857
+ const [coords, setCoords] = import_react7.default.useState(null);
858
+ import_react7.default.useLayoutEffect(() => {
859
+ if (!anchor) return;
860
+ const update = () => {
861
+ const r = anchor.getBoundingClientRect();
862
+ setCoords({ top: r.bottom + 4, left: r.left });
863
+ };
864
+ update();
865
+ window.addEventListener("scroll", update, true);
866
+ window.addEventListener("resize", update);
867
+ return () => {
868
+ window.removeEventListener("scroll", update, true);
869
+ window.removeEventListener("resize", update);
870
+ };
871
+ }, [anchor]);
872
+ if (!anchor || !coords || typeof document === "undefined") return null;
873
+ return (0, import_react_dom.createPortal)(
874
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
875
+ "div",
876
+ {
877
+ className: "sg-table-filter-portal",
878
+ style: { position: "fixed", top: coords.top, left: coords.left, zIndex: 1100 },
879
+ children
880
+ }
881
+ ),
882
+ document.body
883
+ );
884
+ }
885
+ function FilterDropdownContent({ col, t, state, actions, filterRef }) {
886
+ if (state.openFilterDropdown !== col.key) return null;
887
+ if (col.filterDropdown) {
888
+ const props = actions.getFilterDropdownProps(col);
889
+ const content = typeof col.filterDropdown === "function" ? col.filterDropdown(props) : col.filterDropdown;
890
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FilterPortal, { anchor: state.filterAnchor, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
891
+ "div",
892
+ {
893
+ className: "sg-table-filter-dropdown",
894
+ ref: filterRef,
895
+ onClick: (e) => e.stopPropagation(),
896
+ children: content
897
+ }
898
+ ) });
899
+ }
900
+ if (col.filterMode === "advanced") {
901
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FilterPortal, { anchor: state.filterAnchor, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
902
+ AdvancedFilterPanel,
903
+ {
904
+ col,
905
+ t,
906
+ state,
907
+ actions,
908
+ filterRef
909
+ }
910
+ ) });
911
+ }
912
+ if (col.filterMode === "search") {
913
+ const searchVal = state.activeFilters[col.key]?.[0] ?? "";
914
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FilterPortal, { anchor: state.filterAnchor, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
915
+ "div",
916
+ {
917
+ className: "sg-table-filter-dropdown sg-table-filter-search-mode",
918
+ ref: filterRef,
919
+ onClick: (e) => e.stopPropagation(),
920
+ children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
922
+ Input,
923
+ {
924
+ placeholder: `${t.searchPlaceholder.replace("...", "")} ${typeof col.title === "string" ? col.title : ""}...`,
925
+ size: "small",
926
+ value: searchVal,
927
+ onChange: (v) => actions.handleSearchFilterChange(col.key, v)
928
+ }
929
+ ),
930
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "sg-table-filter-actions", children: [
931
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
932
+ Button,
933
+ {
934
+ size: "small",
935
+ onClick: () => {
936
+ actions.handleFilterReset(col.key);
937
+ actions.handleFilterClose(col.key);
938
+ },
939
+ children: t.filterReset
940
+ }
941
+ ),
942
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
943
+ Button,
944
+ {
945
+ size: "small",
946
+ type: "primary",
947
+ onClick: () => actions.handleFilterConfirm(col.key),
948
+ children: t.filterConfirm
949
+ }
950
+ )
951
+ ] })
952
+ ]
953
+ }
954
+ ) });
955
+ }
956
+ if (!col.filters || col.filters.length === 0) return null;
957
+ const multiple = col.filterMultiple !== false;
958
+ const currentVals = state.activeFilters[col.key] ?? [];
959
+ const searchTxt = state.filterSearchText[col.key] ?? "";
960
+ let visibleFilters = col.filters;
961
+ if (col.filterSearch && searchTxt) {
962
+ visibleFilters = col.filters.filter((f) => {
963
+ if (typeof col.filterSearch === "function") {
964
+ return col.filterSearch(searchTxt, f);
965
+ }
966
+ return f.text.toLowerCase().includes(searchTxt.toLowerCase());
967
+ });
968
+ }
969
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FilterPortal, { anchor: state.filterAnchor, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
970
+ "div",
971
+ {
972
+ className: "sg-table-filter-dropdown",
973
+ ref: filterRef,
974
+ onClick: (e) => e.stopPropagation(),
975
+ children: [
976
+ col.filterSearch !== void 0 && col.filterSearch !== false && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "sg-table-filter-search", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
977
+ Input,
978
+ {
979
+ placeholder: t.filterSearchPlaceholder,
980
+ size: "small",
981
+ value: searchTxt,
982
+ onChange: (v) => actions.setFilterSearchText((prev) => ({ ...prev, [col.key]: v }))
983
+ }
984
+ ) }),
985
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "sg-table-filter-list", children: [
986
+ visibleFilters.map((f) => {
987
+ const checked = currentVals.includes(f.value);
988
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "sg-table-filter-item", children: [
989
+ multiple ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
990
+ Checkbox,
991
+ {
992
+ checked,
993
+ onChange: () => actions.handleFilterToggle(col.key, f.value, true)
994
+ }
995
+ ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
996
+ "input",
997
+ {
998
+ type: "radio",
999
+ checked,
1000
+ onChange: () => actions.handleFilterToggle(col.key, f.value, false)
1001
+ }
1002
+ ),
1003
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: f.text })
1004
+ ] }, String(f.value));
1005
+ }),
1006
+ visibleFilters.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "sg-table-filter-empty", children: t.filterEmptyText })
1007
+ ] }),
1008
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "sg-table-filter-actions", children: [
1009
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1010
+ Button,
1011
+ {
1012
+ size: "small",
1013
+ onClick: () => {
1014
+ actions.handleFilterReset(col.key);
1015
+ actions.handleFilterClose(col.key);
1016
+ },
1017
+ children: t.filterReset
1018
+ }
1019
+ ),
1020
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { size: "small", type: "primary", onClick: () => actions.handleFilterConfirm(col.key), children: t.filterConfirm })
1021
+ ] })
1022
+ ]
1023
+ }
1024
+ ) });
1025
+ }
1026
+ function AdvancedFilterPanel({ col, t, state, actions, filterRef }) {
1027
+ const isNumeric = col.advancedFilterType === "number";
1028
+ const defaultOps = isNumeric ? NUMBER_OPS : TEXT_OPS;
1029
+ const ops = col.advancedFilterOperators ?? defaultOps;
1030
+ const current = state.advancedFilters[col.key];
1031
+ const [draftOp, setDraftOp] = import_react7.default.useState(current?.op ?? ops[0]);
1032
+ const [draftValue, setDraftValue] = import_react7.default.useState(() => formatDraftValue(current?.value));
1033
+ const [draftValue2, setDraftValue2] = import_react7.default.useState(() => {
1034
+ const v = current?.value;
1035
+ if (Array.isArray(v) && v.length === 2) return String(v[1] ?? "");
1036
+ return "";
1037
+ });
1038
+ import_react7.default.useEffect(() => {
1039
+ if (current) {
1040
+ setDraftOp(current.op);
1041
+ setDraftValue(formatDraftValue(current.value));
1042
+ if (Array.isArray(current.value) && current.value.length === 2) {
1043
+ setDraftValue2(String(current.value[1] ?? ""));
1044
+ }
1045
+ }
1046
+ }, [state.openFilterDropdown]);
1047
+ const reset = () => {
1048
+ setDraftOp(ops[0]);
1049
+ setDraftValue("");
1050
+ setDraftValue2("");
1051
+ actions.setAdvancedFilter(col.key, null);
1052
+ actions.handleFilterClose(col.key);
1053
+ };
1054
+ const confirm = () => {
1055
+ if (NO_VALUE_OPS.has(draftOp)) {
1056
+ actions.setAdvancedFilter(col.key, { op: draftOp });
1057
+ } else if (draftOp === "between") {
1058
+ const a = parseValue(draftValue, isNumeric);
1059
+ const b = parseValue(draftValue2, isNumeric);
1060
+ actions.setAdvancedFilter(col.key, { op: "between", value: [a, b] });
1061
+ } else if (draftOp === "in" || draftOp === "notIn") {
1062
+ const list = draftValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => parseValue(s, isNumeric));
1063
+ actions.setAdvancedFilter(col.key, { op: draftOp, value: list });
1064
+ } else {
1065
+ actions.setAdvancedFilter(col.key, {
1066
+ op: draftOp,
1067
+ value: parseValue(draftValue, isNumeric)
1068
+ });
1069
+ }
1070
+ actions.setOpenFilterDropdown(null);
1071
+ };
1072
+ const showValueInput = !NO_VALUE_OPS.has(draftOp);
1073
+ const showSecondInput = draftOp === "between";
1074
+ const isValueRequired = showValueInput;
1075
+ const valueIsEmpty = isValueRequired && draftValue.trim() === "";
1076
+ const secondValueIsEmpty = showSecondInput && draftValue2.trim() === "";
1077
+ const confirmDisabled = valueIsEmpty || secondValueIsEmpty;
1078
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1079
+ "div",
1080
+ {
1081
+ className: "sg-table-filter-dropdown sg-table-filter-advanced-mode",
1082
+ ref: filterRef,
1083
+ onClick: (e) => e.stopPropagation(),
1084
+ children: [
1085
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "sg-table-filter-advanced-row", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1086
+ Select,
1087
+ {
1088
+ size: "small",
1089
+ value: draftOp,
1090
+ onChange: (v) => setDraftOp(v),
1091
+ options: ops.map((op) => ({ label: operatorLabel(op, t), value: op })),
1092
+ "aria-label": "Filter operator"
1093
+ }
1094
+ ) }),
1095
+ showValueInput && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "sg-table-filter-advanced-row", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1096
+ Input,
1097
+ {
1098
+ size: "small",
1099
+ type: isNumeric && draftOp !== "in" && draftOp !== "notIn" && draftOp !== "between" ? "number" : "text",
1100
+ value: draftValue,
1101
+ onChange: setDraftValue,
1102
+ placeholder: draftOp === "in" || draftOp === "notIn" ? t.filterAdvancedInPlaceholder : t.filterAdvancedValuePlaceholder
1103
+ }
1104
+ ) }),
1105
+ showSecondInput && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "sg-table-filter-advanced-row", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1106
+ Input,
1107
+ {
1108
+ size: "small",
1109
+ type: isNumeric ? "number" : "text",
1110
+ value: draftValue2,
1111
+ onChange: setDraftValue2,
1112
+ placeholder: t.filterAdvancedBetweenMaxPlaceholder
1113
+ }
1114
+ ) }),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "sg-table-filter-actions", children: [
1116
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { size: "small", onClick: reset, children: t.filterReset }),
1117
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { size: "small", type: "primary", disabled: confirmDisabled, onClick: confirm, children: t.filterConfirm })
1118
+ ] })
1119
+ ]
1120
+ }
1121
+ );
1122
+ }
1123
+ function formatDraftValue(value) {
1124
+ if (value == null) return "";
1125
+ if (Array.isArray(value)) return value.map((v) => String(v ?? "")).join(", ");
1126
+ return String(value);
1127
+ }
1128
+ function parseValue(raw, numeric) {
1129
+ const trimmed = raw.trim();
1130
+ if (trimmed === "") return "";
1131
+ if (numeric) {
1132
+ const n = Number(trimmed);
1133
+ return Number.isNaN(n) ? trimmed : n;
1134
+ }
1135
+ return trimmed;
1136
+ }
1137
+ function operatorLabel(op, t) {
1138
+ const map = {
1139
+ eq: t.filterOpEq,
1140
+ neq: t.filterOpNeq,
1141
+ lt: t.filterOpLt,
1142
+ lte: t.filterOpLte,
1143
+ gt: t.filterOpGt,
1144
+ gte: t.filterOpGte,
1145
+ between: t.filterOpBetween,
1146
+ in: t.filterOpIn,
1147
+ notIn: t.filterOpNotIn,
1148
+ contains: t.filterOpContains,
1149
+ startsWith: t.filterOpStartsWith,
1150
+ endsWith: t.filterOpEndsWith,
1151
+ isEmpty: t.filterOpIsEmpty,
1152
+ isNotEmpty: t.filterOpIsNotEmpty
1153
+ };
1154
+ return map[op];
1155
+ }
1156
+
1157
+ // src/components/complex/Table/TableHeader.tsx
1158
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1159
+ function SortIndicator({
1160
+ col,
1161
+ sorts,
1162
+ getSortIndex,
1163
+ getSortDirection,
1164
+ t
1165
+ }) {
1166
+ if (!col.sortable) return null;
1167
+ const dir = getSortDirection(col.key);
1168
+ const idx = getSortIndex(col.key);
1169
+ const isActive = dir !== null;
1170
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: `sg-table-sort-arrows${isActive ? " sg-table-sort-active" : ""}`, children: [
1171
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: `sg-table-sort-asc${dir === "asc" ? " sg-table-sort-current" : ""}`, children: t.sortAsc }),
1172
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: `sg-table-sort-desc${dir === "desc" ? " sg-table-sort-current" : ""}`, children: t.sortDesc }),
1173
+ idx >= 0 && sorts.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "sg-table-sort-index", children: idx + 1 })
1174
+ ] });
1175
+ }
1176
+ function ColumnTooltip({ content }) {
1177
+ if (!content) return null;
1178
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "sg-table-th-tooltip", title: typeof content === "string" ? content : void 0, children: "\u24D8" });
1179
+ }
1180
+ function TableHeader(props) {
1181
+ const {
1182
+ columns,
1183
+ headerRows,
1184
+ hasColumnGroups,
1185
+ rowSelection,
1186
+ expandable,
1187
+ draggable,
1188
+ allSelected,
1189
+ someSelected,
1190
+ dragOver,
1191
+ t,
1192
+ fixedStyle,
1193
+ onSort,
1194
+ onSelectAll,
1195
+ onDragStart,
1196
+ onDragOver,
1197
+ onDragLeave,
1198
+ onDrop,
1199
+ onDragEnd,
1200
+ onResizeStart,
1201
+ filterState,
1202
+ filterActions,
1203
+ filterRef,
1204
+ sorts,
1205
+ getSortIndex,
1206
+ getSortDirection,
1207
+ headerContextMenu,
1208
+ onContextMenu,
1209
+ showRowNumber,
1210
+ rowDraggable,
1211
+ columnPinning,
1212
+ onPinColumn,
1213
+ onAutoResize,
1214
+ slotClassNames,
1215
+ slotStyles
1216
+ } = props;
1217
+ const sCls = slotClassNames ?? {};
1218
+ const sSty = slotStyles ?? {};
1219
+ const filterProps = (col) => ({
1220
+ col,
1221
+ t,
1222
+ state: filterState,
1223
+ actions: filterActions,
1224
+ filterRef
1225
+ });
1226
+ const sortProps = {
1227
+ sorts,
1228
+ getSortIndex,
1229
+ getSortDirection,
1230
+ t
1231
+ };
1232
+ const buildContextMenu = (col, e) => {
1233
+ e.preventDefault();
1234
+ const items = [];
1235
+ if (headerContextMenu) {
1236
+ items.push(...headerContextMenu(col));
1237
+ }
1238
+ if (columnPinning && onPinColumn) {
1239
+ if (items.length > 0) {
1240
+ items.push({ key: "pin-divider", label: "", divider: true });
1241
+ }
1242
+ if (col.fixed !== "left") {
1243
+ items.push({
1244
+ key: "pin-left",
1245
+ label: t.pinLeft,
1246
+ onClick: () => onPinColumn(col.key, "left")
1247
+ });
1248
+ }
1249
+ if (col.fixed !== "right") {
1250
+ items.push({
1251
+ key: "pin-right",
1252
+ label: t.pinRight,
1253
+ onClick: () => onPinColumn(col.key, "right")
1254
+ });
1255
+ }
1256
+ if (col.fixed) {
1257
+ items.push({
1258
+ key: "unpin",
1259
+ label: t.unpin,
1260
+ onClick: () => onPinColumn(col.key, void 0)
1261
+ });
1262
+ }
1263
+ }
1264
+ if (items.length > 0) {
1265
+ onContextMenu({ x: e.clientX, y: e.clientY, items });
1266
+ }
1267
+ };
1268
+ if (hasColumnGroups && headerRows) {
1269
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: headerRows.map((row, ri) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1270
+ "div",
1271
+ {
1272
+ className: ["sg-table-header-row", sCls.headerRow].filter(Boolean).join(" "),
1273
+ role: "row",
1274
+ style: { display: "contents", ...sSty.headerRow },
1275
+ children: [
1276
+ ri === 0 && rowDraggable && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1277
+ "div",
1278
+ {
1279
+ className: "sg-table-th",
1280
+ role: "columnheader",
1281
+ style: { gridRow: `span ${headerRows.length}` }
1282
+ }
1283
+ ),
1284
+ ri === 0 && showRowNumber && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1285
+ "div",
1286
+ {
1287
+ className: "sg-table-th sg-table-cell-row-number",
1288
+ role: "columnheader",
1289
+ style: { gridRow: `span ${headerRows.length}` },
1290
+ children: t.rowNumber
1291
+ }
1292
+ ),
1293
+ ri === 0 && rowSelection && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1294
+ "div",
1295
+ {
1296
+ className: "sg-table-th sg-table-cell-selection",
1297
+ role: "columnheader",
1298
+ style: { gridRow: `span ${headerRows.length}` },
1299
+ children: rowSelection.type !== "radio" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1300
+ Checkbox,
1301
+ {
1302
+ checked: allSelected,
1303
+ indeterminate: someSelected,
1304
+ onChange: onSelectAll
1305
+ }
1306
+ )
1307
+ }
1308
+ ),
1309
+ ri === 0 && expandable && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1310
+ "div",
1311
+ {
1312
+ className: "sg-table-th sg-table-cell-expand",
1313
+ role: "columnheader",
1314
+ style: { gridRow: `span ${headerRows.length}` }
1315
+ }
1316
+ ),
1317
+ row.map((cell, ci) => {
1318
+ const isLeaf = !cell.col.children || cell.col.children.length === 0;
1319
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1320
+ "div",
1321
+ {
1322
+ className: [
1323
+ "sg-table-th",
1324
+ isLeaf && cell.col.sortable ? "sg-table-th-sortable" : "",
1325
+ cell.col.fixed ? "sg-table-cell-fixed" : "",
1326
+ cell.col.fixed ? `sg-table-cell-fixed-${cell.col.fixed}` : "",
1327
+ cell.colSpan > 1 ? "sg-table-th-group" : "",
1328
+ sCls.headerCell,
1329
+ cell.col.headerClassName
1330
+ ].filter(Boolean).join(" "),
1331
+ style: {
1332
+ ...isLeaf ? fixedStyle(cell.col, true) : {},
1333
+ gridColumn: cell.colSpan > 1 ? `span ${cell.colSpan}` : void 0,
1334
+ gridRow: cell.rowSpan > 1 ? `span ${cell.rowSpan}` : void 0,
1335
+ justifyContent: cell.colSpan > 1 ? "center" : void 0,
1336
+ ...sSty.headerCell
1337
+ },
1338
+ role: "columnheader",
1339
+ onClick: isLeaf ? (e) => onSort(cell.col, e.shiftKey) : void 0,
1340
+ onContextMenu: isLeaf ? (e) => buildContextMenu(cell.col, e) : void 0,
1341
+ children: [
1342
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1343
+ "span",
1344
+ {
1345
+ className: ["sg-table-th-content", sCls.headerCellContent].filter(Boolean).join(" "),
1346
+ style: sSty.headerCellContent,
1347
+ children: [
1348
+ cell.col.title,
1349
+ isLeaf && cell.col.tooltip && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ColumnTooltip, { content: cell.col.tooltip }),
1350
+ isLeaf && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SortIndicator, { col: cell.col, ...sortProps })
1351
+ ]
1352
+ }
1353
+ ),
1354
+ isLeaf && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterTrigger, { ...filterProps(cell.col) }),
1355
+ isLeaf && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterDropdownContent, { ...filterProps(cell.col) }),
1356
+ isLeaf && cell.col.resizable && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1357
+ "div",
1358
+ {
1359
+ className: "sg-table-resize-handle",
1360
+ onMouseDown: (e) => onResizeStart(e, cell.col.key),
1361
+ onDoubleClick: onAutoResize ? (e) => {
1362
+ e.stopPropagation();
1363
+ onAutoResize(cell.col.key);
1364
+ } : void 0
1365
+ }
1366
+ )
1367
+ ]
1368
+ },
1369
+ cell.col.key ?? `g-${ri}-${ci}`
1370
+ );
1371
+ })
1372
+ ]
1373
+ },
1374
+ `hdr-${ri}`
1375
+ )) });
1376
+ }
1377
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1378
+ "div",
1379
+ {
1380
+ className: ["sg-table-header-row", sCls.headerRow].filter(Boolean).join(" "),
1381
+ role: "row",
1382
+ style: { display: "contents", ...sSty.headerRow },
1383
+ children: [
1384
+ rowDraggable && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "sg-table-th", role: "columnheader" }),
1385
+ showRowNumber && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "sg-table-th sg-table-cell-row-number", role: "columnheader", children: t.rowNumber }),
1386
+ rowSelection && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "sg-table-th sg-table-cell-selection", role: "columnheader", children: rowSelection.type !== "radio" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Checkbox, { checked: allSelected, indeterminate: someSelected, onChange: onSelectAll }) }),
1387
+ expandable && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "sg-table-th sg-table-cell-expand", role: "columnheader" }),
1388
+ columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1389
+ "div",
1390
+ {
1391
+ className: [
1392
+ "sg-table-th",
1393
+ col.sortable ? "sg-table-th-sortable" : "",
1394
+ dragOver === col.key ? "sg-table-th-drag-over" : "",
1395
+ col.fixed ? "sg-table-cell-fixed" : "",
1396
+ col.fixed ? `sg-table-cell-fixed-${col.fixed}` : "",
1397
+ sCls.headerCell,
1398
+ col.headerClassName
1399
+ ].filter(Boolean).join(" "),
1400
+ style: { ...fixedStyle(col, true), ...sSty.headerCell },
1401
+ role: "columnheader",
1402
+ onClick: (e) => onSort(col, e.shiftKey),
1403
+ onContextMenu: (e) => buildContextMenu(col, e),
1404
+ draggable: draggable && !col.fixed,
1405
+ onDragStart: draggable ? (e) => onDragStart(e, col.key) : void 0,
1406
+ onDragOver: draggable ? (e) => onDragOver(e, col.key) : void 0,
1407
+ onDragLeave: draggable ? () => onDragLeave() : void 0,
1408
+ onDrop: draggable ? (e) => onDrop(e, col.key) : void 0,
1409
+ onDragEnd: draggable ? () => onDragEnd() : void 0,
1410
+ children: [
1411
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1412
+ "span",
1413
+ {
1414
+ className: ["sg-table-th-content", sCls.headerCellContent].filter(Boolean).join(" "),
1415
+ style: sSty.headerCellContent,
1416
+ children: [
1417
+ col.title,
1418
+ col.tooltip && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ColumnTooltip, { content: col.tooltip }),
1419
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SortIndicator, { col, ...sortProps })
1420
+ ]
1421
+ }
1422
+ ),
1423
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterTrigger, { ...filterProps(col) }),
1424
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterDropdownContent, { ...filterProps(col) }),
1425
+ col.resizable && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1426
+ "div",
1427
+ {
1428
+ className: "sg-table-resize-handle",
1429
+ onMouseDown: (e) => onResizeStart(e, col.key),
1430
+ onDoubleClick: onAutoResize ? (e) => {
1431
+ e.stopPropagation();
1432
+ onAutoResize(col.key);
1433
+ } : void 0
1434
+ }
1435
+ )
1436
+ ]
1437
+ },
1438
+ col.key
1439
+ ))
1440
+ ]
1441
+ }
1442
+ );
1443
+ }
1444
+
1445
+ // src/components/complex/Table/TableBody.tsx
1446
+ var import_react8 = __toESM(require("react"), 1);
1447
+
1448
+ // src/components/complex/Table/export.ts
1449
+ function toCSVString(data) {
1450
+ return data.map(
1451
+ (row) => row.map((cell) => {
1452
+ if (cell.includes(",") || cell.includes('"') || cell.includes("\n")) {
1453
+ return `"${cell.replace(/"/g, '""')}"`;
1454
+ }
1455
+ return cell;
1456
+ }).join(",")
1457
+ ).join("\n");
1458
+ }
1459
+ function toTSVString(data) {
1460
+ return data.map((row) => row.join(" ")).join("\n");
1461
+ }
1462
+ function toJSONString(headers, rows, pretty = true) {
1463
+ const objects = rows.map((row) => {
1464
+ const obj = {};
1465
+ headers.forEach((h, i) => {
1466
+ obj[h] = row[i] ?? "";
1467
+ });
1468
+ return obj;
1469
+ });
1470
+ return pretty ? JSON.stringify(objects, null, 2) : JSON.stringify(objects);
1471
+ }
1472
+ function downloadCSV(content, filename = "export.csv") {
1473
+ const blob = new Blob([content], { type: "text/csv;charset=utf-8;" });
1474
+ const url = URL.createObjectURL(blob);
1475
+ const a = document.createElement("a");
1476
+ a.href = url;
1477
+ a.download = filename;
1478
+ a.click();
1479
+ URL.revokeObjectURL(url);
1480
+ }
1481
+ function downloadJSON(content, filename = "export.json") {
1482
+ const blob = new Blob([content], { type: "application/json;charset=utf-8;" });
1483
+ const url = URL.createObjectURL(blob);
1484
+ const a = document.createElement("a");
1485
+ a.href = url;
1486
+ a.download = filename;
1487
+ a.click();
1488
+ URL.revokeObjectURL(url);
1489
+ }
1490
+ async function copyToClipboard(text) {
1491
+ if (navigator.clipboard) {
1492
+ await navigator.clipboard.writeText(text);
1493
+ }
1494
+ }
1495
+ function printTable(tableEl) {
1496
+ if (!tableEl) return;
1497
+ const printWindow = window.open("", "_blank");
1498
+ if (!printWindow) return;
1499
+ const styles = Array.from(document.querySelectorAll('style, link[rel="stylesheet"]')).map((el) => el.outerHTML).join("\n");
1500
+ printWindow.document.write(`<!DOCTYPE html><html><head>${styles}
1501
+ <style>
1502
+ body { padding: 20px; }
1503
+ .sg-table-toolbar, .sg-table-pagination, .sg-table-selection-bar { display: none !important; }
1504
+ .sg-table-wrapper { overflow: visible !important; }
1505
+ .sg-table-scroll { overflow: visible !important; max-height: none !important; }
1506
+ @media print { @page { size: landscape; margin: 1cm; } }
1507
+ </style>
1508
+ </head><body>${tableEl.outerHTML}</body></html>`);
1509
+ printWindow.document.close();
1510
+ printWindow.focus();
1511
+ setTimeout(() => {
1512
+ printWindow.print();
1513
+ printWindow.close();
1514
+ }, 300);
1515
+ }
1516
+
1517
+ // src/components/complex/Table/TableGroupRow.tsx
1518
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1519
+ function TableGroupRow({ group, groupBy, totalCols, t, onToggle }) {
1520
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1521
+ "div",
1522
+ {
1523
+ className: "sg-table-group-row",
1524
+ role: "row",
1525
+ style: { display: "contents" },
1526
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1527
+ "div",
1528
+ {
1529
+ className: "sg-table-td sg-table-group-cell",
1530
+ role: "cell",
1531
+ style: { gridColumn: `1 / ${totalCols + 1}` },
1532
+ onClick: () => onToggle(group.groupKey),
1533
+ children: [
1534
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1535
+ "button",
1536
+ {
1537
+ type: "button",
1538
+ className: `sg-table-expand-btn${group.expanded ? " sg-table-expand-open" : ""}`,
1539
+ "aria-label": group.expanded ? t.groupCollapse : t.groupExpand,
1540
+ "aria-expanded": group.expanded,
1541
+ onClick: (e) => {
1542
+ e.stopPropagation();
1543
+ onToggle(group.groupKey);
1544
+ },
1545
+ children: t.expandIcon
1546
+ }
1547
+ ),
1548
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "sg-table-group-title", children: [
1549
+ groupBy ? `${groupBy}: ` : null,
1550
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: String(group.groupValue) })
1551
+ ] }),
1552
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "sg-table-group-count", children: [
1553
+ "(",
1554
+ group.count,
1555
+ ")"
1556
+ ] }),
1557
+ Object.keys(group.aggregates).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "sg-table-group-aggregates", children: Object.entries(group.aggregates).map(([key, val]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "sg-table-group-agg-item", children: [
1558
+ key,
1559
+ ": ",
1560
+ String(val)
1561
+ ] }, key)) })
1562
+ ]
1563
+ }
1564
+ )
1565
+ }
1566
+ );
1567
+ }
1568
+
1569
+ // src/components/complex/Table/TableBody.tsx
1570
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1571
+ function TableBody(props) {
1572
+ const {
1573
+ columns,
1574
+ flatRows,
1575
+ rowSelection,
1576
+ expandable,
1577
+ isTreeMode,
1578
+ indentSize,
1579
+ treeExpanded,
1580
+ expandedKeys,
1581
+ totalCols,
1582
+ spanMap,
1583
+ hiddenCells,
1584
+ t,
1585
+ rowClassName,
1586
+ fixedStyle,
1587
+ onRowClick,
1588
+ onCellEdit,
1589
+ onSelectRow,
1590
+ onToggleExpand,
1591
+ onToggleTreeExpand,
1592
+ rowDraggable,
1593
+ onRowOrderChange,
1594
+ cellContextMenu,
1595
+ onContextMenu,
1596
+ striped,
1597
+ showRowNumber,
1598
+ groupBy,
1599
+ onToggleGroup,
1600
+ focusedCell,
1601
+ onFocusCell,
1602
+ keyboardNavigation,
1603
+ emptyContent,
1604
+ slotClassNames,
1605
+ slotStyles,
1606
+ isPinnedSection,
1607
+ rowIndexOffset
1608
+ } = props;
1609
+ const sCls = slotClassNames ?? {};
1610
+ const sSty = slotStyles ?? {};
1611
+ const [editingCell, setEditingCell] = (0, import_react8.useState)(null);
1612
+ const [editValue, setEditValue] = (0, import_react8.useState)("");
1613
+ const editRef = (0, import_react8.useRef)(null);
1614
+ const [dragRowIdx, setDragRowIdx] = (0, import_react8.useState)(null);
1615
+ const [dragOverRowIdx, setDragOverRowIdx] = (0, import_react8.useState)(null);
1616
+ const [copiedCell, setCopiedCell] = (0, import_react8.useState)(null);
1617
+ (0, import_react8.useEffect)(() => {
1618
+ if (editingCell && editRef.current) editRef.current.focus();
1619
+ }, [editingCell]);
1620
+ const handleEditStart = (rowId, col, val) => {
1621
+ setEditingCell({ rowId, col });
1622
+ setEditValue(String(val ?? ""));
1623
+ };
1624
+ const handleEditSave = () => {
1625
+ if (editingCell && onCellEdit) {
1626
+ onCellEdit(editingCell.rowId, editingCell.col, editValue);
1627
+ }
1628
+ setEditingCell(null);
1629
+ };
1630
+ const handleEditCancel = () => setEditingCell(null);
1631
+ const handleRowDragStart = (e, idx) => {
1632
+ setDragRowIdx(idx);
1633
+ e.dataTransfer.effectAllowed = "move";
1634
+ e.dataTransfer.setData("text/plain", String(idx));
1635
+ };
1636
+ const handleRowDragOver = (e, idx) => {
1637
+ e.preventDefault();
1638
+ e.dataTransfer.dropEffect = "move";
1639
+ setDragOverRowIdx(idx);
1640
+ };
1641
+ const handleRowDrop = (_e, toIdx) => {
1642
+ if (dragRowIdx !== null && dragRowIdx !== toIdx) {
1643
+ onRowOrderChange?.(dragRowIdx, toIdx);
1644
+ }
1645
+ setDragRowIdx(null);
1646
+ setDragOverRowIdx(null);
1647
+ };
1648
+ const handleRowDragEnd = () => {
1649
+ setDragRowIdx(null);
1650
+ setDragOverRowIdx(null);
1651
+ };
1652
+ const handleCellContext = (e, id, colKey, data) => {
1653
+ if (!cellContextMenu) return;
1654
+ e.preventDefault();
1655
+ const items = cellContextMenu(id, colKey, data);
1656
+ if (items.length > 0) {
1657
+ onContextMenu({ x: e.clientX, y: e.clientY, items });
1658
+ }
1659
+ };
1660
+ const handleCellCopy = (0, import_react8.useCallback)(
1661
+ async (rowId, colKey, value) => {
1662
+ await copyToClipboard(String(value ?? ""));
1663
+ setCopiedCell(`${rowId}:${colKey}`);
1664
+ setTimeout(() => setCopiedCell(null), 1500);
1665
+ },
1666
+ []
1667
+ );
1668
+ if (flatRows.length === 0) {
1669
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1670
+ "div",
1671
+ {
1672
+ className: ["sg-table-empty", sCls.empty].filter(Boolean).join(" "),
1673
+ style: { gridColumn: `1 / ${totalCols + 1}`, ...sSty.empty },
1674
+ role: "row",
1675
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { role: "cell", children: emptyContent ?? t.emptyText })
1676
+ }
1677
+ );
1678
+ }
1679
+ let dataRowIndex = 0;
1680
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: flatRows.map((row, rowIdx) => {
1681
+ if (row.__groupRow) {
1682
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1683
+ TableGroupRow,
1684
+ {
1685
+ group: row.__groupRow,
1686
+ groupBy,
1687
+ totalCols,
1688
+ t,
1689
+ onToggle: onToggleGroup ?? (() => {
1690
+ })
1691
+ },
1692
+ row.id
1693
+ );
1694
+ }
1695
+ const currentDataIdx = dataRowIndex++;
1696
+ const isExpanded = expandedKeys.has(row.id);
1697
+ const isSelected = rowSelection?.selectedKeys.includes(row.id);
1698
+ const canExpand = expandable?.rowExpandable ? expandable.rowExpandable(row.data) : !!expandable;
1699
+ const rowCls = typeof rowClassName === "function" ? rowClassName(row.data, row.id) : rowClassName ?? "";
1700
+ const isZebra = striped && currentDataIdx % 2 === 1;
1701
+ const isDragOver = dragOverRowIdx === rowIdx && dragRowIdx !== rowIdx;
1702
+ const isPinned = isPinnedSection;
1703
+ const virtualIndexAttr = rowIndexOffset !== void 0 ? rowIndexOffset + rowIdx : void 0;
1704
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react8.default.Fragment, { children: [
1705
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1706
+ "div",
1707
+ {
1708
+ className: [
1709
+ "sg-table-row",
1710
+ isSelected ? "sg-table-row-selected" : "",
1711
+ onRowClick ? "sg-table-row-clickable" : "",
1712
+ isZebra ? "sg-table-row-striped" : "",
1713
+ isDragOver ? "sg-table-row-drag-over" : "",
1714
+ isPinned ? "sg-table-row-pinned" : "",
1715
+ sCls.row,
1716
+ rowCls
1717
+ ].filter(Boolean).join(" "),
1718
+ role: "row",
1719
+ style: { display: "contents", ...sSty.row },
1720
+ "data-sg-virtual-row-index": virtualIndexAttr,
1721
+ draggable: rowDraggable,
1722
+ onDragStart: rowDraggable ? (e) => handleRowDragStart(e, rowIdx) : void 0,
1723
+ onDragOver: rowDraggable ? (e) => handleRowDragOver(e, rowIdx) : void 0,
1724
+ onDrop: rowDraggable ? (e) => handleRowDrop(e, rowIdx) : void 0,
1725
+ onDragEnd: rowDraggable ? handleRowDragEnd : void 0,
1726
+ children: [
1727
+ rowDraggable && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1728
+ "div",
1729
+ {
1730
+ className: "sg-table-td sg-table-cell-drag-handle",
1731
+ role: "cell",
1732
+ style: { cursor: "grab", userSelect: "none", display: "flex", alignItems: "center", justifyContent: "center" },
1733
+ children: "\u283F"
1734
+ }
1735
+ ),
1736
+ showRowNumber && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "sg-table-td sg-table-cell-row-number", role: "cell", children: currentDataIdx + 1 }),
1737
+ rowSelection && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1738
+ "div",
1739
+ {
1740
+ className: "sg-table-td sg-table-cell-selection",
1741
+ role: "cell",
1742
+ onClick: (e) => {
1743
+ e.stopPropagation();
1744
+ onSelectRow(row.id, row.data);
1745
+ },
1746
+ children: rowSelection.type === "radio" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { type: "radio", checked: !!isSelected, readOnly: true }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Checkbox, { checked: !!isSelected, onChange: () => {
1747
+ } })
1748
+ }
1749
+ ),
1750
+ expandable && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "sg-table-td sg-table-cell-expand", role: "cell", children: canExpand && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1751
+ "button",
1752
+ {
1753
+ className: `sg-table-expand-btn${isExpanded ? " sg-table-expand-open" : ""}`,
1754
+ onClick: (e) => {
1755
+ e.stopPropagation();
1756
+ onToggleExpand(row.id);
1757
+ },
1758
+ children: t.expandIcon
1759
+ }
1760
+ ) }),
1761
+ columns.map((col, colIndex) => {
1762
+ const cellKey = `${row.id}:${col.key}`;
1763
+ if (hiddenCells.has(cellKey)) return null;
1764
+ const span = spanMap.get(cellKey);
1765
+ const val = row.data[col.key];
1766
+ const isEditing = editingCell?.rowId === row.id && editingCell?.col === col.key;
1767
+ const isFocused = keyboardNavigation && focusedCell?.row === rowIdx && focusedCell?.col === colIndex;
1768
+ const isCopied = copiedCell === cellKey;
1769
+ const cellStyle = { ...fixedStyle(col) };
1770
+ if (span?.colSpan && span.colSpan > 1)
1771
+ cellStyle.gridColumn = `span ${span.colSpan}`;
1772
+ if (span?.rowSpan && span.rowSpan > 1)
1773
+ cellStyle.gridRow = `span ${span.rowSpan}`;
1774
+ const isFirstCol = colIndex === 0;
1775
+ const treeIndent = isTreeMode && isFirstCol ? row.depth * indentSize : 0;
1776
+ const cellClsExtra = typeof col.cellClassName === "function" ? col.cellClassName(val, row.data, row.id) : col.cellClassName ?? "";
1777
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1778
+ "div",
1779
+ {
1780
+ className: [
1781
+ "sg-table-td",
1782
+ col.fixed ? "sg-table-cell-fixed" : "",
1783
+ col.fixed ? `sg-table-cell-fixed-${col.fixed}` : "",
1784
+ col.editable ? "sg-table-td-editable" : "",
1785
+ isFocused ? "sg-table-cell-focused" : "",
1786
+ isCopied ? "sg-table-cell-copied" : "",
1787
+ col.copyable ? "sg-table-cell-copyable" : "",
1788
+ sCls.bodyCell,
1789
+ cellClsExtra
1790
+ ].filter(Boolean).join(" "),
1791
+ style: { ...cellStyle, ...sSty.bodyCell },
1792
+ role: "cell",
1793
+ tabIndex: keyboardNavigation ? -1 : void 0,
1794
+ onClick: () => {
1795
+ onRowClick?.(row.id, row.data);
1796
+ if (keyboardNavigation) {
1797
+ onFocusCell?.({ row: rowIdx, col: colIndex });
1798
+ }
1799
+ },
1800
+ onContextMenu: (e) => handleCellContext(e, row.id, col.key, row.data),
1801
+ onDoubleClick: col.editable && onCellEdit ? (e) => {
1802
+ e.stopPropagation();
1803
+ handleEditStart(row.id, col.key, val);
1804
+ } : void 0,
1805
+ children: [
1806
+ isTreeMode && isFirstCol && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1807
+ "span",
1808
+ {
1809
+ style: {
1810
+ display: "inline-flex",
1811
+ alignItems: "center",
1812
+ minWidth: treeIndent + 20,
1813
+ flexShrink: 0
1814
+ },
1815
+ children: [
1816
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { width: treeIndent } }),
1817
+ row.hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1818
+ "button",
1819
+ {
1820
+ className: `sg-table-expand-btn${treeExpanded.has(row.id) ? " sg-table-expand-open" : ""}`,
1821
+ onClick: (e) => {
1822
+ e.stopPropagation();
1823
+ onToggleTreeExpand(row.id);
1824
+ },
1825
+ children: t.expandIcon
1826
+ }
1827
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { width: 20 } })
1828
+ ]
1829
+ }
1830
+ ),
1831
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sg-table-cell-content", children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1832
+ "input",
1833
+ {
1834
+ ref: editRef,
1835
+ className: "sg-table-edit-input",
1836
+ value: editValue,
1837
+ onChange: (e) => setEditValue(e.target.value),
1838
+ onBlur: handleEditSave,
1839
+ onKeyDown: (e) => {
1840
+ if (e.key === "Enter") handleEditSave();
1841
+ if (e.key === "Escape") handleEditCancel();
1842
+ }
1843
+ }
1844
+ ) : col.render ? col.render(val, row.data, row.id) : String(val ?? "") }),
1845
+ col.copyable && !isEditing && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1846
+ "button",
1847
+ {
1848
+ className: "sg-table-copy-btn",
1849
+ onClick: (e) => {
1850
+ e.stopPropagation();
1851
+ handleCellCopy(row.id, col.key, val);
1852
+ },
1853
+ title: "Copy",
1854
+ children: isCopied ? "\u2713" : "\u2398"
1855
+ }
1856
+ )
1857
+ ]
1858
+ },
1859
+ col.key
1860
+ );
1861
+ })
1862
+ ]
1863
+ }
1864
+ ),
1865
+ expandable && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1866
+ "div",
1867
+ {
1868
+ className: "sg-table-expanded-row",
1869
+ style: { gridColumn: `1 / ${totalCols + 1}` },
1870
+ role: "row",
1871
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "cell", children: expandable.expandedRowRender(row.data, row.id) })
1872
+ }
1873
+ )
1874
+ ] }, row.id);
1875
+ }) });
1876
+ }
1877
+
1878
+ // src/components/complex/Table/VirtualTableBody.tsx
1879
+ var import_react9 = require("react");
1880
+ var import_core = require("@skygraph/core");
1881
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1882
+ var DEFAULT_ROW_HEIGHT = 40;
1883
+ function buildEstimate(rowHeight, estimate, flatRows) {
1884
+ if (typeof rowHeight === "number" && estimate == null) {
1885
+ return rowHeight;
1886
+ }
1887
+ const fallback = typeof rowHeight === "number" ? rowHeight : DEFAULT_ROW_HEIGHT;
1888
+ const fn = estimate ?? (typeof rowHeight === "function" ? rowHeight : void 0);
1889
+ if (!fn) return fallback;
1890
+ return (index) => {
1891
+ const row = flatRows[index];
1892
+ if (!row) return fallback;
1893
+ const v = fn(row.data, row.id);
1894
+ return Number.isFinite(v) && v >= 0 ? v : fallback;
1895
+ };
1896
+ }
1897
+ function VirtualTableBody(props) {
1898
+ const {
1899
+ rowHeight,
1900
+ estimateRowHeight,
1901
+ overscan,
1902
+ scrollContainerRef,
1903
+ flatRows,
1904
+ totalCols,
1905
+ ...bodyProps
1906
+ } = props;
1907
+ const isDeclarative = typeof rowHeight === "function";
1908
+ const isDynamic = isDeclarative || estimateRowHeight != null;
1909
+ const virtual = (0, import_react9.useMemo)(
1910
+ () => (0, import_core.createVirtual)({
1911
+ itemCount: flatRows.length,
1912
+ itemHeight: buildEstimate(rowHeight, estimateRowHeight, flatRows),
1913
+ overscan
1914
+ }),
1915
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1916
+ []
1917
+ );
1918
+ const [, forceUpdate] = (0, import_react9.useReducer)((n) => n + 1, 0);
1919
+ (0, import_react9.useEffect)(() => virtual.subscribe(() => forceUpdate()), [virtual]);
1920
+ (0, import_react9.useEffect)(() => {
1921
+ virtual.setItemCount(flatRows.length);
1922
+ virtual.setItemHeight(buildEstimate(rowHeight, estimateRowHeight, flatRows));
1923
+ }, [virtual, flatRows, rowHeight, estimateRowHeight]);
1924
+ (0, import_react9.useEffect)(() => {
1925
+ if (!isDeclarative) return;
1926
+ const fn = rowHeight;
1927
+ for (let i = 0; i < flatRows.length; i++) {
1928
+ const row = flatRows[i];
1929
+ if (!row) continue;
1930
+ const h = fn(row.data, row.id);
1931
+ if (Number.isFinite(h) && h >= 0) {
1932
+ virtual.setMeasuredHeight(i, Math.round(h));
1933
+ }
1934
+ }
1935
+ }, [virtual, flatRows, rowHeight, isDeclarative]);
1936
+ const [scrollTop, setScrollTop] = (0, import_react9.useState)(0);
1937
+ const [viewportHeight, setViewportHeight] = (0, import_react9.useState)(0);
1938
+ (0, import_react9.useEffect)(() => {
1939
+ const el = scrollContainerRef.current;
1940
+ if (!el) return;
1941
+ setViewportHeight(el.clientHeight);
1942
+ setScrollTop(el.scrollTop);
1943
+ const onScroll = () => setScrollTop(el.scrollTop);
1944
+ el.addEventListener("scroll", onScroll, { passive: true });
1945
+ let ro = null;
1946
+ if (typeof ResizeObserver !== "undefined") {
1947
+ ro = new ResizeObserver(() => setViewportHeight(el.clientHeight));
1948
+ ro.observe(el);
1949
+ }
1950
+ return () => {
1951
+ el.removeEventListener("scroll", onScroll);
1952
+ ro?.disconnect();
1953
+ };
1954
+ }, [scrollContainerRef]);
1955
+ const range = virtual.getRange(scrollTop, viewportHeight || 400);
1956
+ const visibleRows = flatRows.slice(range.startIndex, range.endIndex + 1);
1957
+ const totalHeight = range.totalHeight;
1958
+ const topPad = range.offsetTop;
1959
+ const visibleSize = visibleRows.reduce(
1960
+ (sum, _row, idx) => sum + virtual.getItemSize(range.startIndex + idx),
1961
+ 0
1962
+ );
1963
+ const bottomPad = Math.max(0, totalHeight - topPad - visibleSize);
1964
+ const normalizeHeight = (h) => Math.round(h);
1965
+ const roRef = (0, import_react9.useRef)(null);
1966
+ const observedCellsRef = (0, import_react9.useRef)(/* @__PURE__ */ new Set());
1967
+ (0, import_react9.useEffect)(() => {
1968
+ if (!isDynamic) return;
1969
+ if (isDeclarative) return;
1970
+ if (typeof ResizeObserver === "undefined") return;
1971
+ const ro = new ResizeObserver((entries) => {
1972
+ for (const entry of entries) {
1973
+ const target = entry.target;
1974
+ const rowEl = target.closest("[data-sg-virtual-row-index]");
1975
+ if (!rowEl) continue;
1976
+ const idx = Number(rowEl.getAttribute("data-sg-virtual-row-index"));
1977
+ virtual.setMeasuredHeight(idx, normalizeHeight(entry.contentRect.height));
1978
+ }
1979
+ });
1980
+ roRef.current = ro;
1981
+ return () => {
1982
+ ro.disconnect();
1983
+ roRef.current = null;
1984
+ observedCellsRef.current.clear();
1985
+ };
1986
+ }, [isDynamic, isDeclarative, virtual]);
1987
+ (0, import_react9.useLayoutEffect)(() => {
1988
+ if (!isDynamic) return;
1989
+ const grid = scrollContainerRef.current?.querySelector(".sg-table-grid");
1990
+ if (!grid) return;
1991
+ const rowEls = grid.querySelectorAll("[data-sg-virtual-row-index]");
1992
+ const ro = roRef.current;
1993
+ const currentCells = /* @__PURE__ */ new Set();
1994
+ rowEls.forEach((rowEl) => {
1995
+ const firstCell = rowEl.firstElementChild;
1996
+ if (!firstCell) return;
1997
+ const idx = Number(rowEl.getAttribute("data-sg-virtual-row-index"));
1998
+ currentCells.add(firstCell);
1999
+ if (isDeclarative) {
2000
+ const row = flatRows[idx];
2001
+ if (row) {
2002
+ const declared = rowHeight(row.data, row.id);
2003
+ if (Number.isFinite(declared) && declared >= 0) {
2004
+ virtual.setMeasuredHeight(idx, Math.round(declared));
2005
+ }
2006
+ }
2007
+ } else if (!virtual.hasMeasured(idx)) {
2008
+ virtual.setMeasuredHeight(idx, normalizeHeight(firstCell.getBoundingClientRect().height));
2009
+ }
2010
+ if (isDeclarative || virtual.hasMeasured(idx)) {
2011
+ const h = virtual.getItemSize(idx);
2012
+ const px = `${h}px`;
2013
+ const children = rowEl.children;
2014
+ for (let c = 0; c < children.length; c++) {
2015
+ const cell = children[c];
2016
+ if (cell.style.height !== px) cell.style.height = px;
2017
+ if (cell.style.minHeight !== "0px") cell.style.minHeight = "0px";
2018
+ if (cell.style.overflow !== "hidden") cell.style.overflow = "hidden";
2019
+ }
2020
+ }
2021
+ if (ro && !observedCellsRef.current.has(firstCell)) {
2022
+ ro.observe(firstCell);
2023
+ }
2024
+ });
2025
+ if (ro) {
2026
+ for (const cell of observedCellsRef.current) {
2027
+ if (!currentCells.has(cell)) ro.unobserve(cell);
2028
+ }
2029
+ }
2030
+ observedCellsRef.current = currentCells;
2031
+ if (!isDeclarative && typeof ResizeObserver === "undefined") {
2032
+ rowEls.forEach((rowEl) => {
2033
+ const firstCell = rowEl.firstElementChild;
2034
+ if (!firstCell) return;
2035
+ const idx = Number(rowEl.getAttribute("data-sg-virtual-row-index"));
2036
+ virtual.setMeasuredHeight(idx, normalizeHeight(firstCell.getBoundingClientRect().height));
2037
+ });
2038
+ }
2039
+ }, [isDynamic, isDeclarative, virtual, scrollContainerRef, visibleRows, flatRows, rowHeight]);
2040
+ const spacerColumn = `1 / ${totalCols + 1}`;
2041
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2042
+ topPad > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { gridColumn: spacerColumn, height: topPad }, role: "presentation", "aria-hidden": true }),
2043
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2044
+ TableBody,
2045
+ {
2046
+ ...bodyProps,
2047
+ flatRows: visibleRows,
2048
+ totalCols,
2049
+ rowIndexOffset: range.startIndex
2050
+ }
2051
+ ),
2052
+ bottomPad > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2053
+ "div",
2054
+ {
2055
+ style: { gridColumn: spacerColumn, height: bottomPad },
2056
+ role: "presentation",
2057
+ "aria-hidden": true
2058
+ }
2059
+ )
2060
+ ] });
2061
+ }
2062
+
2063
+ // src/components/complex/Table/ContextMenu.tsx
2064
+ var import_react10 = require("react");
2065
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2066
+ function ContextMenu({ state, onClose }) {
2067
+ const ref = (0, import_react10.useRef)(null);
2068
+ const [subMenu, setSubMenu] = (0, import_react10.useState)(null);
2069
+ (0, import_react10.useEffect)(() => {
2070
+ if (!state) return;
2071
+ const handle = (e) => {
2072
+ if (ref.current && !ref.current.contains(e.target)) {
2073
+ onClose();
2074
+ }
2075
+ };
2076
+ const handleKey = (e) => {
2077
+ if (e.key === "Escape") onClose();
2078
+ };
2079
+ const handleScroll = () => onClose();
2080
+ document.addEventListener("mousedown", handle);
2081
+ document.addEventListener("keydown", handleKey);
2082
+ window.addEventListener("scroll", handleScroll, true);
2083
+ return () => {
2084
+ document.removeEventListener("mousedown", handle);
2085
+ document.removeEventListener("keydown", handleKey);
2086
+ window.removeEventListener("scroll", handleScroll, true);
2087
+ };
2088
+ }, [state, onClose]);
2089
+ if (!state) return null;
2090
+ const rootStyle = {
2091
+ position: "fixed",
2092
+ top: state.y,
2093
+ left: state.x
2094
+ };
2095
+ const submenuStyle = {
2096
+ position: "absolute",
2097
+ top: 0,
2098
+ left: "100%"
2099
+ };
2100
+ const itemClass = (item) => {
2101
+ const classes = ["sg-context-menu-item"];
2102
+ if (item.danger) classes.push("sg-context-menu-item--danger");
2103
+ if (item.disabled) classes.push("sg-context-menu-item--disabled");
2104
+ return classes.join(" ");
2105
+ };
2106
+ const renderItems = (items, isSubmenu = false) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2107
+ "div",
2108
+ {
2109
+ ref: isSubmenu ? void 0 : ref,
2110
+ className: "sg-context-menu",
2111
+ style: isSubmenu ? submenuStyle : rootStyle,
2112
+ role: "menu",
2113
+ children: items.map((item) => {
2114
+ if (item.divider) {
2115
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "sg-context-menu-divider" }, item.key);
2116
+ }
2117
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2118
+ "div",
2119
+ {
2120
+ className: itemClass(item),
2121
+ role: "menuitem",
2122
+ onClick: () => {
2123
+ if (item.disabled) return;
2124
+ item.onClick?.();
2125
+ if (!item.children) onClose();
2126
+ },
2127
+ onMouseEnter: (e) => {
2128
+ if (item.children) {
2129
+ const rect = e.currentTarget.getBoundingClientRect();
2130
+ setSubMenu({ key: item.key, x: rect.right, y: rect.top, items: item.children });
2131
+ } else {
2132
+ setSubMenu(null);
2133
+ }
2134
+ },
2135
+ children: [
2136
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "sg-context-menu-icon", children: item.icon }),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "sg-context-menu-label", children: item.label }),
2138
+ item.children && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "sg-context-menu-submenu-arrow", children: "\u203A" }),
2139
+ subMenu?.key === item.key && item.children && renderItems(item.children, true)
2140
+ ]
2141
+ },
2142
+ item.key
2143
+ );
2144
+ })
2145
+ }
2146
+ );
2147
+ return renderItems(state.items);
2148
+ }
2149
+
2150
+ // src/components/complex/Table/useTableState.ts
2151
+ var import_react12 = require("react");
2152
+
2153
+ // src/hooks/useTable.ts
2154
+ var import_react11 = require("react");
2155
+ var import_core2 = require("@skygraph/core");
2156
+ function useTable(options) {
2157
+ const [{ core, table }] = (0, import_react11.useState)(() => {
2158
+ const c = (0, import_core2.createCore)();
2159
+ const t = (0, import_core2.createTable)(c, options);
2160
+ if (options?.data) {
2161
+ t.addRows(options.data);
2162
+ }
2163
+ return { core: c, table: t };
2164
+ });
2165
+ const [visibleRows, setVisibleRows] = (0, import_react11.useState)(() => table.getVisibleRows());
2166
+ const [tableState, setTableState] = (0, import_react11.useState)(() => table.getTableState());
2167
+ const [pinnedColumns, setPinnedColumns] = (0, import_react11.useState)(() => table.getPinnedColumns());
2168
+ const [columnWidths, setColumnWidthsState] = (0, import_react11.useState)(
2169
+ () => table.getColumnWidths()
2170
+ );
2171
+ const prevDataRef = (0, import_react11.useRef)(options?.data);
2172
+ (0, import_react11.useEffect)(() => {
2173
+ const newData = options?.data;
2174
+ if (newData === prevDataRef.current) return;
2175
+ prevDataRef.current = newData;
2176
+ table.reset();
2177
+ if (newData) {
2178
+ table.addRows(newData);
2179
+ }
2180
+ setVisibleRows(table.getVisibleRows());
2181
+ setTableState(table.getTableState());
2182
+ }, [options?.data, table]);
2183
+ const refresh = (0, import_react11.useCallback)(() => {
2184
+ setVisibleRows(table.getVisibleRows());
2185
+ setTableState(table.getTableState());
2186
+ setPinnedColumns(table.getPinnedColumns());
2187
+ setColumnWidthsState(table.getColumnWidths());
2188
+ }, [table]);
2189
+ const pinColumn = (0, import_react11.useCallback)(
2190
+ (column, side) => {
2191
+ table.pinColumn(column, side);
2192
+ setPinnedColumns(table.getPinnedColumns());
2193
+ },
2194
+ [table]
2195
+ );
2196
+ const clearPinned = (0, import_react11.useCallback)(() => {
2197
+ table.clearPinned();
2198
+ setPinnedColumns(table.getPinnedColumns());
2199
+ }, [table]);
2200
+ const setColumnWidth = (0, import_react11.useCallback)(
2201
+ (column, width) => {
2202
+ table.setColumnWidth(column, width);
2203
+ setColumnWidthsState(table.getColumnWidths());
2204
+ },
2205
+ [table]
2206
+ );
2207
+ const clearColumnWidths = (0, import_react11.useCallback)(() => {
2208
+ table.clearColumnWidths();
2209
+ setColumnWidthsState(table.getColumnWidths());
2210
+ }, [table]);
2211
+ const setSort = (0, import_react11.useCallback)(
2212
+ (column, direction) => {
2213
+ table.setSort(column, direction);
2214
+ refresh();
2215
+ },
2216
+ [table, refresh]
2217
+ );
2218
+ const setSorts = (0, import_react11.useCallback)(
2219
+ (sorts) => {
2220
+ table.setSorts(sorts);
2221
+ refresh();
2222
+ },
2223
+ [table, refresh]
2224
+ );
2225
+ const clearSort = (0, import_react11.useCallback)(() => {
2226
+ table.clearSort();
2227
+ refresh();
2228
+ }, [table, refresh]);
2229
+ const addFilter = (0, import_react11.useCallback)(
2230
+ (filter) => {
2231
+ table.addFilter(filter);
2232
+ refresh();
2233
+ },
2234
+ [table, refresh]
2235
+ );
2236
+ const removeFilter = (0, import_react11.useCallback)(
2237
+ (column) => {
2238
+ table.removeFilter(column);
2239
+ refresh();
2240
+ },
2241
+ [table, refresh]
2242
+ );
2243
+ const clearFilters = (0, import_react11.useCallback)(() => {
2244
+ table.clearFilters();
2245
+ refresh();
2246
+ }, [table, refresh]);
2247
+ const setFilterFn = (0, import_react11.useCallback)(
2248
+ (fn) => {
2249
+ table.setFilterFn(fn);
2250
+ refresh();
2251
+ },
2252
+ [table, refresh]
2253
+ );
2254
+ const setPage = (0, import_react11.useCallback)(
2255
+ (page) => {
2256
+ table.setPage(page);
2257
+ refresh();
2258
+ },
2259
+ [table, refresh]
2260
+ );
2261
+ const nextPage = (0, import_react11.useCallback)(() => {
2262
+ table.nextPage();
2263
+ refresh();
2264
+ }, [table, refresh]);
2265
+ const prevPage = (0, import_react11.useCallback)(() => {
2266
+ table.prevPage();
2267
+ refresh();
2268
+ }, [table, refresh]);
2269
+ return (0, import_react11.useMemo)(
2270
+ () => ({
2271
+ core,
2272
+ table,
2273
+ visibleRows,
2274
+ tableState,
2275
+ pinnedColumns,
2276
+ columnWidths,
2277
+ setSort,
2278
+ setSorts,
2279
+ clearSort,
2280
+ addFilter,
2281
+ removeFilter,
2282
+ clearFilters,
2283
+ setFilterFn,
2284
+ setPage,
2285
+ nextPage,
2286
+ prevPage,
2287
+ pinColumn,
2288
+ clearPinned,
2289
+ setColumnWidth,
2290
+ clearColumnWidths,
2291
+ refresh
2292
+ }),
2293
+ [
2294
+ core,
2295
+ table,
2296
+ visibleRows,
2297
+ tableState,
2298
+ pinnedColumns,
2299
+ columnWidths,
2300
+ setSort,
2301
+ setSorts,
2302
+ clearSort,
2303
+ addFilter,
2304
+ removeFilter,
2305
+ clearFilters,
2306
+ setFilterFn,
2307
+ setPage,
2308
+ nextPage,
2309
+ prevPage,
2310
+ pinColumn,
2311
+ clearPinned,
2312
+ setColumnWidth,
2313
+ clearColumnWidths,
2314
+ refresh
2315
+ ]
2316
+ );
2317
+ }
2318
+
2319
+ // src/components/complex/Table/helpers.ts
2320
+ function flattenLeafColumns(cols) {
2321
+ const result = [];
2322
+ for (const col of cols) {
2323
+ if (col.children && col.children.length > 0) {
2324
+ result.push(...flattenLeafColumns(col.children));
2325
+ } else {
2326
+ result.push(col);
2327
+ }
2328
+ }
2329
+ return result;
2330
+ }
2331
+ function buildHeaderRows(cols) {
2332
+ function getDepth(c) {
2333
+ if (!c.children || c.children.length === 0) return 1;
2334
+ return 1 + Math.max(...c.children.map(getDepth));
2335
+ }
2336
+ const maxDepth = cols.length > 0 ? Math.max(...cols.map(getDepth)) : 1;
2337
+ function getLeafCount(c) {
2338
+ if (!c.children || c.children.length === 0) return 1;
2339
+ return c.children.reduce((sum, ch) => sum + getLeafCount(ch), 0);
2340
+ }
2341
+ const rows = Array.from({ length: maxDepth }, () => []);
2342
+ function fill(list, depth) {
2343
+ for (const c of list) {
2344
+ if (c.children && c.children.length > 0) {
2345
+ rows[depth].push({ col: c, colSpan: getLeafCount(c), rowSpan: 1 });
2346
+ fill(c.children, depth + 1);
2347
+ } else {
2348
+ rows[depth].push({ col: c, colSpan: 1, rowSpan: maxDepth - depth });
2349
+ }
2350
+ }
2351
+ }
2352
+ fill(cols, 0);
2353
+ return rows;
2354
+ }
2355
+ function flattenTreeRows(rows, childrenKey, expandedSet, depth = 0) {
2356
+ const result = [];
2357
+ for (const row of rows) {
2358
+ const children = row.data[childrenKey];
2359
+ const hasChildren = Array.isArray(children) && children.length > 0;
2360
+ result.push({ id: row.id, data: row.data, depth, hasChildren });
2361
+ if (hasChildren && expandedSet.has(row.id)) {
2362
+ result.push(...flattenTreeRows(children, childrenKey, expandedSet, depth + 1));
2363
+ }
2364
+ }
2365
+ return result;
2366
+ }
2367
+ function collectAllTreeIds(rows, childrenKey) {
2368
+ const ids = [];
2369
+ for (const row of rows) {
2370
+ const children = row.data[childrenKey];
2371
+ if (Array.isArray(children) && children.length > 0) {
2372
+ ids.push(row.id);
2373
+ ids.push(...collectAllTreeIds(children, childrenKey));
2374
+ }
2375
+ }
2376
+ return ids;
2377
+ }
2378
+ function computeSpanMap(columns, flatRows) {
2379
+ const map = /* @__PURE__ */ new Map();
2380
+ const hasOnCell = columns.some((c) => c.onCell);
2381
+ if (!hasOnCell) return map;
2382
+ flatRows.forEach((row, rowIndex) => {
2383
+ for (const col of columns) {
2384
+ if (col.onCell) {
2385
+ const span = col.onCell(row.data, rowIndex);
2386
+ if (span && (span.rowSpan !== void 0 || span.colSpan !== void 0)) {
2387
+ map.set(`${row.id}:${col.key}`, span);
2388
+ }
2389
+ }
2390
+ }
2391
+ });
2392
+ return map;
2393
+ }
2394
+ function computeHiddenCells(columns, flatRows, spanMap) {
2395
+ const hidden = /* @__PURE__ */ new Set();
2396
+ const hasOnCell = columns.some((c) => c.onCell);
2397
+ if (!hasOnCell) return hidden;
2398
+ flatRows.forEach((row, rowIndex) => {
2399
+ for (let ci = 0; ci < columns.length; ci++) {
2400
+ const key = `${row.id}:${columns[ci].key}`;
2401
+ const span = spanMap.get(key);
2402
+ if (!span) continue;
2403
+ if (span.rowSpan === 0 || span.colSpan === 0) {
2404
+ hidden.add(key);
2405
+ continue;
2406
+ }
2407
+ const rs = span.rowSpan ?? 1;
2408
+ const cs = span.colSpan ?? 1;
2409
+ for (let dr = 0; dr < rs; dr++) {
2410
+ for (let dc = 0; dc < cs; dc++) {
2411
+ if (dr === 0 && dc === 0) continue;
2412
+ const targetRow = flatRows[rowIndex + dr];
2413
+ const targetCol = columns[ci + dc];
2414
+ if (targetRow && targetCol) {
2415
+ hidden.add(`${targetRow.id}:${targetCol.key}`);
2416
+ }
2417
+ }
2418
+ }
2419
+ }
2420
+ });
2421
+ return hidden;
2422
+ }
2423
+ function getFixedStyle(col, fixedLeftOffsets, fixedRightOffsets, isHeader) {
2424
+ const s = {};
2425
+ if (col.align) s.textAlign = col.align;
2426
+ if (col.ellipsis) {
2427
+ s.overflow = "hidden";
2428
+ s.textOverflow = "ellipsis";
2429
+ s.whiteSpace = "nowrap";
2430
+ }
2431
+ if (col.fixed === "left") {
2432
+ s.position = "sticky";
2433
+ s.left = fixedLeftOffsets[col.key];
2434
+ s.zIndex = isHeader ? 4 : 2;
2435
+ }
2436
+ if (col.fixed === "right") {
2437
+ s.position = "sticky";
2438
+ s.right = fixedRightOffsets[col.key];
2439
+ s.zIndex = isHeader ? 4 : 2;
2440
+ }
2441
+ return s;
2442
+ }
2443
+ function computeAggregate(values, type) {
2444
+ const nums = values.map(Number).filter((n) => !isNaN(n));
2445
+ if (nums.length === 0) return type === "count" ? values.length : "-";
2446
+ switch (type) {
2447
+ case "sum":
2448
+ return Math.round(nums.reduce((a, b) => a + b, 0) * 100) / 100;
2449
+ case "avg":
2450
+ return Math.round(nums.reduce((a, b) => a + b, 0) / nums.length * 100) / 100;
2451
+ case "count":
2452
+ return values.length;
2453
+ case "min":
2454
+ return Math.min(...nums);
2455
+ case "max":
2456
+ return Math.max(...nums);
2457
+ }
2458
+ }
2459
+ function groupByColumn(flatRows, groupByKey, columns, expandedGroups) {
2460
+ const groups = /* @__PURE__ */ new Map();
2461
+ const groupOrder = [];
2462
+ for (const row of flatRows) {
2463
+ const val = String(row.data[groupByKey] ?? "Other");
2464
+ if (!groups.has(val)) {
2465
+ groups.set(val, []);
2466
+ groupOrder.push(val);
2467
+ }
2468
+ groups.get(val).push(row);
2469
+ }
2470
+ const result = [];
2471
+ for (const gKey of groupOrder) {
2472
+ const rows = groups.get(gKey);
2473
+ const expanded = expandedGroups.has(gKey);
2474
+ const aggregates = {};
2475
+ for (const col of columns) {
2476
+ if (col.aggregate) {
2477
+ const values = rows.map((r) => r.data[col.key]);
2478
+ if (typeof col.aggregate === "function") {
2479
+ aggregates[col.key] = col.aggregate(values);
2480
+ } else {
2481
+ aggregates[col.key] = computeAggregate(values, col.aggregate);
2482
+ }
2483
+ }
2484
+ }
2485
+ const groupRow = {
2486
+ __isGroup: true,
2487
+ groupKey: gKey,
2488
+ groupValue: gKey,
2489
+ count: rows.length,
2490
+ expanded,
2491
+ aggregates
2492
+ };
2493
+ result.push({
2494
+ id: `__group_${gKey}`,
2495
+ data: {},
2496
+ depth: 0,
2497
+ hasChildren: false,
2498
+ __groupRow: groupRow
2499
+ });
2500
+ if (expanded) {
2501
+ result.push(...rows);
2502
+ }
2503
+ }
2504
+ return result;
2505
+ }
2506
+ function separatePinnedRows(flatRows, topIds, bottomIds) {
2507
+ const topSet = new Set(topIds ?? []);
2508
+ const bottomSet = new Set(bottomIds ?? []);
2509
+ const top = [];
2510
+ const middle = [];
2511
+ const bottom = [];
2512
+ for (const row of flatRows) {
2513
+ if (topSet.has(row.id)) top.push(row);
2514
+ else if (bottomSet.has(row.id)) bottom.push(row);
2515
+ else middle.push(row);
2516
+ }
2517
+ if (topIds) {
2518
+ top.sort((a, b) => topIds.indexOf(a.id) - topIds.indexOf(b.id));
2519
+ }
2520
+ if (bottomIds) {
2521
+ bottom.sort((a, b) => bottomIds.indexOf(a.id) - bottomIds.indexOf(b.id));
2522
+ }
2523
+ return { top, middle, bottom };
2524
+ }
2525
+ function computeColumnAggregates(columns, flatRows) {
2526
+ const hasAny = columns.some((c) => c.aggregate);
2527
+ if (!hasAny) return null;
2528
+ const result = {};
2529
+ for (const col of columns) {
2530
+ if (!col.aggregate) continue;
2531
+ const values = flatRows.filter((r) => !r.__groupRow).map((r) => r.data[col.key]);
2532
+ if (typeof col.aggregate === "function") {
2533
+ result[col.key] = col.aggregate(values);
2534
+ } else {
2535
+ result[col.key] = computeAggregate(values, col.aggregate);
2536
+ }
2537
+ }
2538
+ return result;
2539
+ }
2540
+
2541
+ // src/components/complex/Table/defaultIcons.tsx
2542
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2543
+ var FilterIcon = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2544
+ "svg",
2545
+ {
2546
+ width: "12",
2547
+ height: "12",
2548
+ viewBox: "0 0 16 16",
2549
+ fill: "none",
2550
+ stroke: "currentColor",
2551
+ strokeWidth: "1.5",
2552
+ strokeLinejoin: "round",
2553
+ strokeLinecap: "round",
2554
+ "aria-hidden": "true",
2555
+ focusable: "false",
2556
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M2 3h12l-5 6.5V14l-2 1V9.5L2 3z" })
2557
+ }
2558
+ );
2559
+ var SearchIcon = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2560
+ "svg",
2561
+ {
2562
+ width: "12",
2563
+ height: "12",
2564
+ viewBox: "0 0 16 16",
2565
+ fill: "none",
2566
+ stroke: "currentColor",
2567
+ strokeWidth: "1.5",
2568
+ strokeLinecap: "round",
2569
+ "aria-hidden": "true",
2570
+ focusable: "false",
2571
+ children: [
2572
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("circle", { cx: "7", cy: "7", r: "4.5" }),
2573
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M10.5 10.5L14 14" })
2574
+ ]
2575
+ }
2576
+ );
2577
+
2578
+ // src/components/complex/Table/types.ts
2579
+ var DEFAULT_LOCALE = {
2580
+ emptyText: "No data",
2581
+ filterReset: "Reset",
2582
+ filterConfirm: "OK",
2583
+ filterSearchPlaceholder: "Search filters...",
2584
+ filterEmptyText: "No filters",
2585
+ searchPlaceholder: "Search...",
2586
+ sortAsc: "\u25B2",
2587
+ sortDesc: "\u25BC",
2588
+ expandIcon: "\u203A",
2589
+ filterIcon: FilterIcon,
2590
+ searchIcon: SearchIcon,
2591
+ totalRows: (count) => `${count} rows`,
2592
+ selectedRows: (count) => `${count} selected`,
2593
+ exportCSV: "Export CSV",
2594
+ exportJSON: "Export JSON",
2595
+ copyTable: "Copy",
2596
+ pinLeft: "Pin Left",
2597
+ pinRight: "Pin Right",
2598
+ unpin: "Unpin",
2599
+ showColumns: "Show Columns",
2600
+ print: "Print",
2601
+ fullscreen: "Fullscreen",
2602
+ exitFullscreen: "Exit Fullscreen",
2603
+ density: "Density",
2604
+ densitySmall: "Compact",
2605
+ densityMiddle: "Default",
2606
+ densityLarge: "Comfortable",
2607
+ groupCollapse: "Collapse All",
2608
+ groupExpand: "Expand All",
2609
+ sum: "Sum",
2610
+ avg: "Avg",
2611
+ count: "Count",
2612
+ min: "Min",
2613
+ max: "Max",
2614
+ copiedToClipboard: "Copied!",
2615
+ rowNumber: "#",
2616
+ groupByLabel: "Group by",
2617
+ groupByNone: "No grouping",
2618
+ filterAdvancedValuePlaceholder: "Value",
2619
+ filterAdvancedInPlaceholder: "value1, value2, ...",
2620
+ filterAdvancedBetweenMaxPlaceholder: "Max",
2621
+ filterOpEq: "=",
2622
+ filterOpNeq: "!=",
2623
+ filterOpLt: "<",
2624
+ filterOpLte: "<=",
2625
+ filterOpGt: ">",
2626
+ filterOpGte: ">=",
2627
+ filterOpBetween: "between",
2628
+ filterOpIn: "in",
2629
+ filterOpNotIn: "not in",
2630
+ filterOpContains: "contains",
2631
+ filterOpStartsWith: "starts with",
2632
+ filterOpEndsWith: "ends with",
2633
+ filterOpIsEmpty: "is empty",
2634
+ filterOpIsNotEmpty: "is not empty"
2635
+ };
2636
+ var DEFAULT_COL_WIDTH = 150;
2637
+ var MIN_COL_WIDTH = 50;
2638
+ var SELECTION_COL_WIDTH = "40px";
2639
+
2640
+ // src/components/complex/Table/useTableState.ts
2641
+ function useTableState(props) {
2642
+ const {
2643
+ columns: columnsProp,
2644
+ rowSelection,
2645
+ expandable,
2646
+ tree,
2647
+ draggable: _draggable,
2648
+ searchable,
2649
+ locale,
2650
+ onColumnOrderChange,
2651
+ onCellEdit: _onCellEdit,
2652
+ multiSort,
2653
+ sorts: controlledSorts,
2654
+ onSortsChange,
2655
+ hiddenColumns: hiddenColumnsProp,
2656
+ onHiddenColumnsChange,
2657
+ onColumnPinChange,
2658
+ groupBy,
2659
+ defaultGroupExpanded,
2660
+ onGroupExpandChange,
2661
+ pinnedRows: pinnedRowsConfig,
2662
+ keyboardNavigation,
2663
+ scroll,
2664
+ footer: _footer,
2665
+ showRowNumber: _showRowNumber,
2666
+ fullscreenable: _fullscreenable,
2667
+ densityToggle: _densityToggle,
2668
+ emptyContent: _emptyContent,
2669
+ printable: _printable,
2670
+ exportJSON: _exportJSON,
2671
+ highlightOnHover: _highlightOnHover,
2672
+ columnAutoResize: _columnAutoResize,
2673
+ ...tableOptions
2674
+ } = props;
2675
+ const hasScrollX = scroll?.x != null;
2676
+ const {
2677
+ table,
2678
+ visibleRows,
2679
+ tableState,
2680
+ columnWidths: persistedColWidths,
2681
+ setSort,
2682
+ setSorts,
2683
+ clearSort,
2684
+ setPage,
2685
+ setFilterFn,
2686
+ setColumnWidth: persistColumnWidth,
2687
+ refresh
2688
+ } = useTable(tableOptions);
2689
+ const t = (0, import_react12.useMemo)(() => ({ ...DEFAULT_LOCALE, ...locale }), [locale]);
2690
+ const hasColumnGroups = columnsProp.some((c) => c.children && c.children.length > 0);
2691
+ const leafColumns = (0, import_react12.useMemo)(() => flattenLeafColumns(columnsProp), [columnsProp]);
2692
+ const headerRows = (0, import_react12.useMemo)(
2693
+ () => hasColumnGroups ? buildHeaderRows(columnsProp) : null,
2694
+ [columnsProp, hasColumnGroups]
2695
+ );
2696
+ const [internalSorts, setInternalSorts] = (0, import_react12.useState)([]);
2697
+ const sorts = controlledSorts ?? internalSorts;
2698
+ const [colWidths, setColWidths] = (0, import_react12.useState)(() => {
2699
+ const w = {};
2700
+ for (const c of leafColumns) {
2701
+ w[c.key] = persistedColWidths[c.key] ?? c.width ?? DEFAULT_COL_WIDTH;
2702
+ }
2703
+ return w;
2704
+ });
2705
+ const [userResizedCols, setUserResizedCols] = (0, import_react12.useState)(
2706
+ () => new Set(Object.keys(persistedColWidths))
2707
+ );
2708
+ const [colOrder, setColOrder] = (0, import_react12.useState)(() => leafColumns.map((c) => c.key));
2709
+ const [dragCol, setDragCol] = (0, import_react12.useState)(null);
2710
+ const [dragOver, setDragOver] = (0, import_react12.useState)(null);
2711
+ const [internalHidden, setInternalHidden] = (0, import_react12.useState)(
2712
+ () => new Set(hiddenColumnsProp ?? [])
2713
+ );
2714
+ const hiddenSet = (0, import_react12.useMemo)(
2715
+ () => hiddenColumnsProp ? new Set(hiddenColumnsProp) : internalHidden,
2716
+ [hiddenColumnsProp, internalHidden]
2717
+ );
2718
+ const toggleColumnVisibility = (0, import_react12.useCallback)(
2719
+ (key) => {
2720
+ if (onHiddenColumnsChange) {
2721
+ const current = hiddenColumnsProp ?? [];
2722
+ const next = current.includes(key) ? current.filter((k) => k !== key) : [...current, key];
2723
+ onHiddenColumnsChange(next);
2724
+ } else {
2725
+ setInternalHidden((prev) => {
2726
+ const next = new Set(prev);
2727
+ if (next.has(key)) {
2728
+ next.delete(key);
2729
+ } else {
2730
+ next.add(key);
2731
+ }
2732
+ return next;
2733
+ });
2734
+ }
2735
+ },
2736
+ [hiddenColumnsProp, onHiddenColumnsChange]
2737
+ );
2738
+ const [internalExpanded, setInternalExpanded] = (0, import_react12.useState)(() => {
2739
+ if (tree?.defaultExpandAllRows) {
2740
+ const childrenKey2 = tree.childrenColumnName ?? "children";
2741
+ return new Set(collectAllTreeIds(props.data ?? [], childrenKey2));
2742
+ }
2743
+ return new Set(expandable?.defaultExpandedRowKeys ?? []);
2744
+ });
2745
+ const expandedKeys = expandable?.expandedKeys ? new Set(expandable.expandedKeys) : internalExpanded;
2746
+ const [treeExpanded, setTreeExpanded] = (0, import_react12.useState)(() => {
2747
+ if (tree?.defaultExpandAllRows) {
2748
+ const childrenKey2 = tree.childrenColumnName ?? "children";
2749
+ return new Set(collectAllTreeIds(props.data ?? [], childrenKey2));
2750
+ }
2751
+ return /* @__PURE__ */ new Set();
2752
+ });
2753
+ const [searchText, setSearchText] = (0, import_react12.useState)("");
2754
+ const [activeFilters, setActiveFilters] = (0, import_react12.useState)(() => {
2755
+ const init = {};
2756
+ for (const col of leafColumns) {
2757
+ if (col.filteredValue) {
2758
+ init[col.key] = [...col.filteredValue];
2759
+ } else if (col.defaultFilteredValue) {
2760
+ init[col.key] = [...col.defaultFilteredValue];
2761
+ }
2762
+ }
2763
+ return init;
2764
+ });
2765
+ const [filterSearchText, setFilterSearchText] = (0, import_react12.useState)({});
2766
+ const [openFilterDropdown, setOpenFilterDropdown] = (0, import_react12.useState)(null);
2767
+ const [advancedFilters, setAdvancedFiltersState] = (0, import_react12.useState)({});
2768
+ const filterRef = (0, import_react12.useRef)(null);
2769
+ const [filterAnchor, setFilterAnchor] = (0, import_react12.useState)(null);
2770
+ const setAdvancedFilter = (0, import_react12.useCallback)(
2771
+ (colKey, filter) => {
2772
+ setAdvancedFiltersState((prev) => {
2773
+ const next = { ...prev };
2774
+ if (filter == null) delete next[colKey];
2775
+ else next[colKey] = filter;
2776
+ return next;
2777
+ });
2778
+ table.setColumnFilter(colKey, filter);
2779
+ refresh();
2780
+ },
2781
+ [table, refresh]
2782
+ );
2783
+ const resizeRef = (0, import_react12.useRef)(null);
2784
+ const [contextMenu, setContextMenu] = (0, import_react12.useState)(null);
2785
+ const columns = (0, import_react12.useMemo)(() => {
2786
+ const base = hasColumnGroups ? leafColumns : (() => {
2787
+ const map = new Map(leafColumns.map((c) => [c.key, c]));
2788
+ return colOrder.filter((k) => map.has(k)).map((k) => map.get(k));
2789
+ })();
2790
+ return base.filter((c) => !hiddenSet.has(c.key) && !c.hidden);
2791
+ }, [leafColumns, colOrder, hasColumnGroups, hiddenSet]);
2792
+ (0, import_react12.useEffect)(() => {
2793
+ const keys = leafColumns.map((c) => c.key);
2794
+ setColOrder((prev) => {
2795
+ const prevSet = new Set(prev);
2796
+ const added = keys.filter((k) => !prevSet.has(k));
2797
+ const valid = prev.filter((k) => keys.includes(k));
2798
+ return [...valid, ...added];
2799
+ });
2800
+ }, [leafColumns]);
2801
+ (0, import_react12.useEffect)(() => {
2802
+ for (const col of leafColumns) {
2803
+ if (col.filteredValue !== void 0) {
2804
+ setActiveFilters((prev) => {
2805
+ if (JSON.stringify(prev[col.key]) === JSON.stringify(col.filteredValue)) return prev;
2806
+ return { ...prev, [col.key]: [...col.filteredValue] };
2807
+ });
2808
+ }
2809
+ }
2810
+ }, [leafColumns]);
2811
+ (0, import_react12.useEffect)(() => {
2812
+ const colFilters = columns.filter((c) => c.onFilter && activeFilters[c.key]?.length);
2813
+ const hasSearch = searchable && searchText.length > 0;
2814
+ if (colFilters.length === 0 && !hasSearch) {
2815
+ setFilterFn(null);
2816
+ return;
2817
+ }
2818
+ const lower = hasSearch ? searchText.toLowerCase() : "";
2819
+ setFilterFn((row) => {
2820
+ for (const col of colFilters) {
2821
+ const vals = activeFilters[col.key];
2822
+ const fn = col.onFilter;
2823
+ if (!vals.some((v) => fn(v, row))) return false;
2824
+ }
2825
+ if (hasSearch) {
2826
+ const match = Object.values(row).some(
2827
+ (v) => v != null && String(v).toLowerCase().includes(lower)
2828
+ );
2829
+ if (!match) return false;
2830
+ }
2831
+ return true;
2832
+ });
2833
+ }, [activeFilters, searchText, searchable, setFilterFn, columns]);
2834
+ (0, import_react12.useEffect)(() => {
2835
+ if (!openFilterDropdown) return;
2836
+ const handle = (e) => {
2837
+ if (filterRef.current && !filterRef.current.contains(e.target)) {
2838
+ setOpenFilterDropdown(null);
2839
+ }
2840
+ };
2841
+ document.addEventListener("mousedown", handle);
2842
+ return () => document.removeEventListener("mousedown", handle);
2843
+ }, [openFilterDropdown]);
2844
+ const handleSort = (0, import_react12.useCallback)(
2845
+ (col, shiftKey) => {
2846
+ if (!col.sortable) return;
2847
+ if (multiSort && shiftKey) {
2848
+ const existing = sorts.find((s) => s.column === col.key);
2849
+ let next;
2850
+ if (!existing) {
2851
+ next = [...sorts, { column: col.key, direction: "asc" }];
2852
+ } else if (existing.direction === "asc") {
2853
+ next = sorts.map(
2854
+ (s) => s.column === col.key ? { ...s, direction: "desc" } : s
2855
+ );
2856
+ } else {
2857
+ next = sorts.filter((s) => s.column !== col.key);
2858
+ }
2859
+ if (onSortsChange) {
2860
+ onSortsChange(next);
2861
+ } else {
2862
+ setInternalSorts(next);
2863
+ }
2864
+ if (next.length === 0) {
2865
+ clearSort();
2866
+ } else {
2867
+ setSorts(next);
2868
+ }
2869
+ } else {
2870
+ const current = sorts.length === 1 ? sorts[0] : null;
2871
+ let next;
2872
+ if (!current || current.column !== col.key) {
2873
+ next = [{ column: col.key, direction: "asc" }];
2874
+ } else if (current.direction === "asc") {
2875
+ next = [{ column: col.key, direction: "desc" }];
2876
+ } else {
2877
+ next = [];
2878
+ }
2879
+ if (onSortsChange) {
2880
+ onSortsChange(next);
2881
+ } else {
2882
+ setInternalSorts(next);
2883
+ }
2884
+ if (next.length === 0) {
2885
+ clearSort();
2886
+ } else {
2887
+ setSort(next[0].column, next[0].direction);
2888
+ }
2889
+ }
2890
+ },
2891
+ [multiSort, sorts, onSortsChange, setSort, setSorts, clearSort]
2892
+ );
2893
+ const getSortIndex = (0, import_react12.useCallback)(
2894
+ (colKey) => {
2895
+ if (!multiSort || sorts.length <= 1) return -1;
2896
+ return sorts.findIndex((s) => s.column === colKey);
2897
+ },
2898
+ [multiSort, sorts]
2899
+ );
2900
+ const getSortDirection = (0, import_react12.useCallback)(
2901
+ (colKey) => {
2902
+ const found = sorts.find((s) => s.column === colKey);
2903
+ return found?.direction ?? null;
2904
+ },
2905
+ [sorts]
2906
+ );
2907
+ const handleToggleExpand = (id) => {
2908
+ const open = expandedKeys.has(id);
2909
+ if (expandable?.onExpand) {
2910
+ expandable.onExpand(!open, id);
2911
+ } else {
2912
+ setInternalExpanded((prev) => {
2913
+ const next = new Set(prev);
2914
+ if (open) {
2915
+ next.delete(id);
2916
+ } else {
2917
+ next.add(id);
2918
+ }
2919
+ return next;
2920
+ });
2921
+ }
2922
+ };
2923
+ const handleToggleTreeExpand = (id) => {
2924
+ setTreeExpanded((prev) => {
2925
+ const next = new Set(prev);
2926
+ if (next.has(id)) {
2927
+ next.delete(id);
2928
+ } else {
2929
+ next.add(id);
2930
+ }
2931
+ return next;
2932
+ });
2933
+ };
2934
+ const handleSelectRow = (id, row) => {
2935
+ if (!rowSelection) return;
2936
+ const { selectedKeys, onChange, type = "checkbox" } = rowSelection;
2937
+ if (type === "radio") {
2938
+ onChange([id], [row]);
2939
+ return;
2940
+ }
2941
+ const next = selectedKeys.includes(id) ? selectedKeys.filter((k) => k !== id) : [...selectedKeys, id];
2942
+ onChange(
2943
+ next,
2944
+ visibleRows.filter((r) => next.includes(r.id)).map((r) => r.data)
2945
+ );
2946
+ };
2947
+ const handleSelectAll = () => {
2948
+ if (!rowSelection) return;
2949
+ const ids = visibleRows.map((r) => r.id);
2950
+ const all = ids.every((id) => rowSelection.selectedKeys.includes(id));
2951
+ rowSelection.onChange(all ? [] : ids, all ? [] : visibleRows.map((r) => r.data));
2952
+ };
2953
+ const handleFilterToggle = (colKey, value, multiple) => {
2954
+ setActiveFilters((prev) => {
2955
+ const current = prev[colKey] ?? [];
2956
+ if (!multiple) return { ...prev, [colKey]: [value] };
2957
+ const idx = current.indexOf(value);
2958
+ const next = idx >= 0 ? current.filter((_, i) => i !== idx) : [...current, value];
2959
+ return { ...prev, [colKey]: next };
2960
+ });
2961
+ };
2962
+ const handleFilterConfirm = (colKey) => {
2963
+ setOpenFilterDropdown(null);
2964
+ setFilterSearchText((prev) => ({ ...prev, [colKey]: "" }));
2965
+ };
2966
+ const handleFilterReset = (colKey) => {
2967
+ setActiveFilters((prev) => ({ ...prev, [colKey]: [] }));
2968
+ setFilterSearchText((prev) => ({ ...prev, [colKey]: "" }));
2969
+ };
2970
+ const handleFilterClose = (colKey) => {
2971
+ setOpenFilterDropdown(null);
2972
+ setFilterSearchText((prev) => ({ ...prev, [colKey]: "" }));
2973
+ };
2974
+ const handleSearchFilterChange = (colKey, text) => {
2975
+ setActiveFilters((prev) => ({ ...prev, [colKey]: text ? [text] : [] }));
2976
+ };
2977
+ const getFilterDropdownProps = (col) => ({
2978
+ selectedKeys: activeFilters[col.key] ?? [],
2979
+ setSelectedKeys: (keys) => setActiveFilters((prev) => ({ ...prev, [col.key]: keys })),
2980
+ confirm: () => handleFilterConfirm(col.key),
2981
+ clearFilters: () => handleFilterReset(col.key),
2982
+ close: () => handleFilterClose(col.key)
2983
+ });
2984
+ const handleResizeStart = (e, colKey) => {
2985
+ e.preventDefault();
2986
+ e.stopPropagation();
2987
+ resizeRef.current = {
2988
+ col: colKey,
2989
+ startX: e.clientX,
2990
+ startW: colWidths[colKey] ?? DEFAULT_COL_WIDTH
2991
+ };
2992
+ const onMove = (ev) => {
2993
+ if (!resizeRef.current) return;
2994
+ const diff = ev.clientX - resizeRef.current.startX;
2995
+ const min = leafColumns.find((c) => c.key === resizeRef.current.col)?.minWidth ?? MIN_COL_WIDTH;
2996
+ setColWidths((prev) => ({
2997
+ ...prev,
2998
+ [resizeRef.current.col]: Math.max(min, resizeRef.current.startW + diff)
2999
+ }));
3000
+ setUserResizedCols(
3001
+ (prev) => prev.has(resizeRef.current.col) ? prev : new Set(prev).add(resizeRef.current.col)
3002
+ );
3003
+ };
3004
+ const onUp = () => {
3005
+ const ref = resizeRef.current;
3006
+ resizeRef.current = null;
3007
+ document.removeEventListener("mousemove", onMove);
3008
+ document.removeEventListener("mouseup", onUp);
3009
+ if (!ref) return;
3010
+ setColWidths((prev) => {
3011
+ const w = prev[ref.col];
3012
+ if (typeof w === "number") persistColumnWidth(ref.col, w);
3013
+ return prev;
3014
+ });
3015
+ };
3016
+ document.addEventListener("mousemove", onMove);
3017
+ document.addEventListener("mouseup", onUp);
3018
+ };
3019
+ const handleDragStart = (e, key) => {
3020
+ setDragCol(key);
3021
+ e.dataTransfer.effectAllowed = "move";
3022
+ e.dataTransfer.setData("text/plain", key);
3023
+ };
3024
+ const handleDragOver = (e, key) => {
3025
+ e.preventDefault();
3026
+ e.dataTransfer.dropEffect = "move";
3027
+ setDragOver(key);
3028
+ };
3029
+ const handleDrop = (e, targetKey) => {
3030
+ e.preventDefault();
3031
+ if (!dragCol || dragCol === targetKey) {
3032
+ setDragCol(null);
3033
+ setDragOver(null);
3034
+ return;
3035
+ }
3036
+ setColOrder((prev) => {
3037
+ const next = prev.filter((k) => k !== dragCol);
3038
+ const idx = next.indexOf(targetKey);
3039
+ next.splice(idx, 0, dragCol);
3040
+ onColumnOrderChange?.(next);
3041
+ return next;
3042
+ });
3043
+ setDragCol(null);
3044
+ setDragOver(null);
3045
+ };
3046
+ const handleDragEnd = () => {
3047
+ setDragCol(null);
3048
+ setDragOver(null);
3049
+ };
3050
+ const handlePinColumn = (0, import_react12.useCallback)(
3051
+ (key, fixed) => {
3052
+ onColumnPinChange?.(key, fixed);
3053
+ },
3054
+ [onColumnPinChange]
3055
+ );
3056
+ const [isFullscreen, setIsFullscreen] = (0, import_react12.useState)(false);
3057
+ const wrapperRef = (0, import_react12.useRef)(null);
3058
+ const toggleFullscreen = (0, import_react12.useCallback)(() => {
3059
+ setIsFullscreen((prev) => !prev);
3060
+ }, []);
3061
+ const [density, setDensity] = (0, import_react12.useState)("middle");
3062
+ (0, import_react12.useEffect)(() => {
3063
+ if (!groupBy) {
3064
+ table.clearGroupBy();
3065
+ return;
3066
+ }
3067
+ const aggregates2 = leafColumns.filter((c) => c.aggregate).map((c) => ({
3068
+ column: c.key,
3069
+ type: typeof c.aggregate === "function" ? c.aggregate : c.aggregate
3070
+ }));
3071
+ table.groupBy(groupBy, aggregates2);
3072
+ }, [groupBy, leafColumns, table]);
3073
+ const [expandedGroups, setExpandedGroups] = (0, import_react12.useState)(() => {
3074
+ return defaultGroupExpanded ? /* @__PURE__ */ new Set(["__all__"]) : /* @__PURE__ */ new Set();
3075
+ });
3076
+ const toggleGroupExpand = (0, import_react12.useCallback)(
3077
+ (groupKey) => {
3078
+ setExpandedGroups((prev) => {
3079
+ const next = new Set(prev);
3080
+ const wasExpanded = next.has(groupKey);
3081
+ if (wasExpanded) {
3082
+ next.delete(groupKey);
3083
+ } else {
3084
+ next.add(groupKey);
3085
+ }
3086
+ onGroupExpandChange?.(groupKey, !wasExpanded);
3087
+ return next;
3088
+ });
3089
+ },
3090
+ [onGroupExpandChange]
3091
+ );
3092
+ const expandAllGroups = (0, import_react12.useCallback)(() => {
3093
+ setExpandedGroups((prev) => {
3094
+ const next = new Set(prev);
3095
+ next.add("__all__");
3096
+ return next;
3097
+ });
3098
+ }, []);
3099
+ const collapseAllGroups = (0, import_react12.useCallback)(() => {
3100
+ setExpandedGroups(/* @__PURE__ */ new Set());
3101
+ }, []);
3102
+ const [focusedCell, setFocusedCell] = (0, import_react12.useState)(null);
3103
+ const handleKeyNav = (0, import_react12.useCallback)(
3104
+ (e) => {
3105
+ if (!keyboardNavigation || !focusedCell) return;
3106
+ const maxRow = visibleRows.length - 1;
3107
+ const maxCol = columns.length - 1;
3108
+ let { row, col } = focusedCell;
3109
+ switch (e.key) {
3110
+ case "ArrowUp":
3111
+ e.preventDefault();
3112
+ row = Math.max(0, row - 1);
3113
+ break;
3114
+ case "ArrowDown":
3115
+ e.preventDefault();
3116
+ row = Math.min(maxRow, row + 1);
3117
+ break;
3118
+ case "ArrowLeft":
3119
+ e.preventDefault();
3120
+ col = Math.max(0, col - 1);
3121
+ break;
3122
+ case "ArrowRight":
3123
+ e.preventDefault();
3124
+ col = Math.min(maxCol, col + 1);
3125
+ break;
3126
+ case "Tab":
3127
+ e.preventDefault();
3128
+ if (e.shiftKey) {
3129
+ col -= 1;
3130
+ if (col < 0) {
3131
+ col = maxCol;
3132
+ row = Math.max(0, row - 1);
3133
+ }
3134
+ } else {
3135
+ col += 1;
3136
+ if (col > maxCol) {
3137
+ col = 0;
3138
+ row = Math.min(maxRow, row + 1);
3139
+ }
3140
+ }
3141
+ break;
3142
+ case "Home":
3143
+ e.preventDefault();
3144
+ col = 0;
3145
+ if (e.ctrlKey) row = 0;
3146
+ break;
3147
+ case "End":
3148
+ e.preventDefault();
3149
+ col = maxCol;
3150
+ if (e.ctrlKey) row = maxRow;
3151
+ break;
3152
+ default:
3153
+ return;
3154
+ }
3155
+ setFocusedCell({ row, col });
3156
+ },
3157
+ [keyboardNavigation, focusedCell, visibleRows.length, columns.length]
3158
+ );
3159
+ const handleAutoResize = (0, import_react12.useCallback)(
3160
+ (colKey) => {
3161
+ const maxLen = visibleRows.reduce((max, row) => {
3162
+ const val = String(row.data[colKey] ?? "");
3163
+ return Math.max(max, val.length);
3164
+ }, 0);
3165
+ const headerCol = leafColumns.find((c) => c.key === colKey);
3166
+ const headerLen = typeof headerCol?.title === "string" ? headerCol.title.length : 6;
3167
+ const charWidth = 8;
3168
+ const padding = 32;
3169
+ const min = headerCol?.minWidth ?? MIN_COL_WIDTH;
3170
+ const optimal = Math.max(min, Math.max(maxLen, headerLen) * charWidth + padding);
3171
+ setColWidths((prev) => ({ ...prev, [colKey]: optimal }));
3172
+ setUserResizedCols((prev) => prev.has(colKey) ? prev : new Set(prev).add(colKey));
3173
+ },
3174
+ [visibleRows, leafColumns]
3175
+ );
3176
+ const isTreeMode = !!tree;
3177
+ const childrenKey = tree?.childrenColumnName ?? "children";
3178
+ const indentSize = tree?.indentSize ?? 20;
3179
+ const baseFlatRows = (0, import_react12.useMemo)(() => {
3180
+ if (!isTreeMode) {
3181
+ return visibleRows.map((r) => ({
3182
+ id: r.id,
3183
+ data: r.data,
3184
+ depth: 0,
3185
+ hasChildren: false
3186
+ }));
3187
+ }
3188
+ return flattenTreeRows(visibleRows, childrenKey, treeExpanded);
3189
+ }, [visibleRows, isTreeMode, childrenKey, treeExpanded]);
3190
+ const groupedRows = (0, import_react12.useMemo)(() => {
3191
+ if (!groupBy) return baseFlatRows;
3192
+ const allExpanded = expandedGroups.has("__all__");
3193
+ const effectiveExpanded = allExpanded ? /* @__PURE__ */ new Set([...expandedGroups, ...baseFlatRows.map((r) => String(r.data[groupBy] ?? "Other"))]) : expandedGroups;
3194
+ return groupByColumn(baseFlatRows, groupBy, columns, effectiveExpanded);
3195
+ }, [baseFlatRows, groupBy, columns, expandedGroups]);
3196
+ const {
3197
+ top: pinnedTop,
3198
+ middle: middleRows,
3199
+ bottom: pinnedBottom
3200
+ } = (0, import_react12.useMemo)(
3201
+ () => separatePinnedRows(groupedRows, pinnedRowsConfig?.top, pinnedRowsConfig?.bottom),
3202
+ [groupedRows, pinnedRowsConfig]
3203
+ );
3204
+ const flatRows = groupedRows;
3205
+ const aggregates = (0, import_react12.useMemo)(
3206
+ () => computeColumnAggregates(columns, baseFlatRows),
3207
+ [columns, baseFlatRows]
3208
+ );
3209
+ const extraBefore = [];
3210
+ if (rowSelection) extraBefore.push(SELECTION_COL_WIDTH);
3211
+ if (expandable) extraBefore.push(SELECTION_COL_WIDTH);
3212
+ const hasAutoColumns = columns.some(
3213
+ (c) => !c.fixed && !userResizedCols.has(c.key) && c.width == null
3214
+ );
3215
+ const shouldFlexExplicitWidths = !hasScrollX && !hasAutoColumns;
3216
+ const scrollXMinWidth = typeof scroll?.x === "number" ? scroll.x : typeof scroll?.x === "string" && scroll.x.trim().endsWith("px") ? Number.parseFloat(scroll.x) : null;
3217
+ const declaredGridWidth = extraBefore.reduce((sum, w) => sum + Number.parseFloat(w), 0) + columns.reduce((sum, c) => sum + (colWidths[c.key] ?? c.width ?? DEFAULT_COL_WIDTH), 0);
3218
+ const shouldFillScrollX = hasScrollX && scrollXMinWidth !== null && Number.isFinite(scrollXMinWidth) && scrollXMinWidth > declaredGridWidth;
3219
+ const colTemplates = columns.map((c) => {
3220
+ const resized = userResizedCols.has(c.key);
3221
+ const w = colWidths[c.key] ?? c.width ?? DEFAULT_COL_WIDTH;
3222
+ if (hasScrollX) {
3223
+ if (c.fixed || resized) {
3224
+ return `${w}px`;
3225
+ }
3226
+ return shouldFillScrollX ? `minmax(${w}px, ${w}fr)` : `${w}px`;
3227
+ }
3228
+ if (c.fixed || resized) {
3229
+ return `${w}px`;
3230
+ }
3231
+ if (c.width == null) {
3232
+ return `minmax(${MIN_COL_WIDTH}px, 1fr)`;
3233
+ }
3234
+ if (shouldFlexExplicitWidths) {
3235
+ return `minmax(${MIN_COL_WIDTH}px, ${w}fr)`;
3236
+ }
3237
+ return `minmax(${MIN_COL_WIDTH}px, ${w}px)`;
3238
+ });
3239
+ const gridTemplate = [...extraBefore, ...colTemplates].join(" ");
3240
+ const totalCols = extraBefore.length + columns.length;
3241
+ const fixedLeftOffsets = (0, import_react12.useMemo)(() => {
3242
+ const o = {};
3243
+ const selW = parseInt(SELECTION_COL_WIDTH);
3244
+ let left = (rowSelection ? selW : 0) + (expandable ? selW : 0);
3245
+ for (const col of columns) {
3246
+ if (col.fixed === "left") {
3247
+ o[col.key] = left;
3248
+ left += colWidths[col.key] ?? col.width ?? DEFAULT_COL_WIDTH;
3249
+ }
3250
+ }
3251
+ return o;
3252
+ }, [columns, colWidths, rowSelection, expandable]);
3253
+ const fixedRightOffsets = (0, import_react12.useMemo)(() => {
3254
+ const o = {};
3255
+ let right = 0;
3256
+ for (let i = columns.length - 1; i >= 0; i--) {
3257
+ if (columns[i].fixed === "right") {
3258
+ o[columns[i].key] = right;
3259
+ right += colWidths[columns[i].key] ?? columns[i].width ?? DEFAULT_COL_WIDTH;
3260
+ }
3261
+ }
3262
+ return o;
3263
+ }, [columns, colWidths]);
3264
+ const fixedStyle = (col, isHeader) => getFixedStyle(col, fixedLeftOffsets, fixedRightOffsets, isHeader);
3265
+ const allSelected = rowSelection ? visibleRows.length > 0 && visibleRows.every((r) => rowSelection.selectedKeys.includes(r.id)) : false;
3266
+ const someSelected = rowSelection ? visibleRows.some((r) => rowSelection.selectedKeys.includes(r.id)) && !allSelected : false;
3267
+ const spanMap = (0, import_react12.useMemo)(() => computeSpanMap(columns, flatRows), [columns, flatRows]);
3268
+ const hiddenCells = (0, import_react12.useMemo)(
3269
+ () => computeHiddenCells(columns, flatRows, spanMap),
3270
+ [columns, flatRows, spanMap]
3271
+ );
3272
+ return {
3273
+ visibleRows,
3274
+ tableState,
3275
+ columns,
3276
+ leafColumns,
3277
+ flatRows,
3278
+ headerRows,
3279
+ hasColumnGroups,
3280
+ t,
3281
+ // Multi-sort
3282
+ sorts,
3283
+ getSortIndex,
3284
+ getSortDirection,
3285
+ handleSort,
3286
+ // Selection
3287
+ allSelected,
3288
+ someSelected,
3289
+ handleSelectAll,
3290
+ handleSelectRow,
3291
+ // Expand
3292
+ expandedKeys,
3293
+ handleToggleExpand,
3294
+ // Tree
3295
+ isTreeMode,
3296
+ indentSize,
3297
+ treeExpanded,
3298
+ handleToggleTreeExpand,
3299
+ // Filters
3300
+ filterState: {
3301
+ activeFilters,
3302
+ filterSearchText,
3303
+ openFilterDropdown,
3304
+ advancedFilters,
3305
+ filterAnchor
3306
+ },
3307
+ filterActions: {
3308
+ setOpenFilterDropdown,
3309
+ handleFilterToggle,
3310
+ handleFilterConfirm,
3311
+ handleFilterReset,
3312
+ handleFilterClose,
3313
+ handleSearchFilterChange,
3314
+ setFilterSearchText,
3315
+ getFilterDropdownProps,
3316
+ setAdvancedFilter,
3317
+ setFilterAnchor
3318
+ },
3319
+ filterRef,
3320
+ // Drag columns
3321
+ dragOver,
3322
+ handleDragStart,
3323
+ handleDragOver,
3324
+ handleDragEnd,
3325
+ handleDrop,
3326
+ setDragOver: () => setDragOver(null),
3327
+ // Resize
3328
+ colWidths,
3329
+ handleResizeStart,
3330
+ // Grid
3331
+ gridTemplate,
3332
+ totalCols,
3333
+ // Fixed
3334
+ fixedStyle,
3335
+ // Span
3336
+ spanMap,
3337
+ hiddenCells,
3338
+ // Search
3339
+ searchText,
3340
+ setSearchText,
3341
+ // Pagination
3342
+ setPage,
3343
+ // Column visibility
3344
+ hiddenSet,
3345
+ toggleColumnVisibility,
3346
+ // Column pin
3347
+ handlePinColumn,
3348
+ // Context menu
3349
+ contextMenu,
3350
+ setContextMenu,
3351
+ // Fullscreen
3352
+ isFullscreen,
3353
+ toggleFullscreen,
3354
+ wrapperRef,
3355
+ // Density
3356
+ density,
3357
+ setDensity,
3358
+ // Group by
3359
+ expandedGroups,
3360
+ toggleGroupExpand,
3361
+ expandAllGroups,
3362
+ collapseAllGroups,
3363
+ // Keyboard
3364
+ focusedCell,
3365
+ setFocusedCell,
3366
+ handleKeyNav,
3367
+ // Auto-resize
3368
+ handleAutoResize,
3369
+ // Aggregation
3370
+ aggregates,
3371
+ // Pinned
3372
+ pinnedTop,
3373
+ pinnedBottom,
3374
+ middleRows
3375
+ };
3376
+ }
3377
+
3378
+ // src/utils/print/printElement.ts
3379
+ function buildPageRule(opts = {}) {
3380
+ const orientation = opts.orientation ?? "portrait";
3381
+ const pageSize = opts.pageSize ?? "A4";
3382
+ const margins = opts.margins ?? "1cm";
3383
+ return `@page { size: ${pageSize} ${orientation}; margin: ${margins}; }`;
3384
+ }
3385
+ function buildPrintHtml(fragment, opts = {}, documentRef = typeof document !== "undefined" ? document : null) {
3386
+ const styles = documentRef === null ? "" : Array.from(documentRef.querySelectorAll('style, link[rel="stylesheet"]')).map((el) => el.outerHTML).join("\n");
3387
+ const pageRule = buildPageRule(opts);
3388
+ const scale = opts.scale && opts.scale !== 1 ? opts.scale : null;
3389
+ const title = escapeHtml(opts.fileName ?? "SkyGraph print");
3390
+ const customStyles = opts.customStyles ?? "";
3391
+ const wrapperOpen = scale ? `<div class="sg-print-root" style="transform: scale(${scale}); transform-origin: 0 0;">` : `<div class="sg-print-root">`;
3392
+ return `<!DOCTYPE html>
3393
+ <html>
3394
+ <head>
3395
+ <meta charset="utf-8" />
3396
+ <title>${title}</title>
3397
+ ${styles}
3398
+ <style>
3399
+ ${pageRule}
3400
+ html, body { margin: 0; padding: 0; background: #fff; }
3401
+ body { padding: 0; }
3402
+ .sg-print-root { width: 100%; }
3403
+ ${customStyles}
3404
+ </style>
3405
+ </head>
3406
+ <body>
3407
+ ${wrapperOpen}
3408
+ ${fragment}
3409
+ </div>
3410
+ </body>
3411
+ </html>`;
3412
+ }
3413
+ function escapeHtml(s) {
3414
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
3415
+ }
3416
+ function printElement(node, opts = {}) {
3417
+ if (!node) return null;
3418
+ if (typeof window === "undefined") return null;
3419
+ const popup = window.open("", "_blank");
3420
+ if (!popup) return null;
3421
+ const html = buildPrintHtml(node.outerHTML, opts);
3422
+ popup.document.open();
3423
+ popup.document.write(html);
3424
+ popup.document.close();
3425
+ popup.focus();
3426
+ if (opts.skipPrint) return popup;
3427
+ const trigger = () => {
3428
+ try {
3429
+ popup.print();
3430
+ } catch {
3431
+ }
3432
+ if (!opts.keepOpen) {
3433
+ try {
3434
+ popup.close();
3435
+ } catch {
3436
+ }
3437
+ }
3438
+ };
3439
+ if (popup.document.readyState === "complete") {
3440
+ setTimeout(trigger, 0);
3441
+ } else {
3442
+ popup.addEventListener("load", () => setTimeout(trigger, 0), { once: true });
3443
+ setTimeout(trigger, 300);
3444
+ }
3445
+ return popup;
3446
+ }
3447
+
3448
+ // src/types/slots.ts
3449
+ function slotClass(...parts) {
3450
+ const filtered = parts.filter((p) => typeof p === "string" && p.length > 0);
3451
+ return filtered.length ? filtered.join(" ") : void 0;
3452
+ }
3453
+ function slotStyle(base, custom) {
3454
+ if (!base && !custom) return void 0;
3455
+ if (!base) return custom;
3456
+ if (!custom) return base;
3457
+ return { ...base, ...custom };
3458
+ }
3459
+
3460
+ // src/components/complex/Table/Table.tsx
3461
+ var import_jsx_runtime15 = require("react/jsx-runtime");
3462
+ var DRAG_HANDLE_WIDTH = "32px";
3463
+ var ROW_NUMBER_WIDTH = "48px";
3464
+ function TableInner(props, forwardedRef) {
3465
+ const {
3466
+ rowSelection,
3467
+ expandable,
3468
+ sticky,
3469
+ draggable,
3470
+ searchable,
3471
+ showPagination = true,
3472
+ bordered: borderedProp,
3473
+ size: sizeProp,
3474
+ scroll,
3475
+ summary,
3476
+ onRowClick,
3477
+ onCellEdit,
3478
+ loading: loadingProp,
3479
+ rowClassName,
3480
+ className,
3481
+ style,
3482
+ unstyled,
3483
+ rowDraggable,
3484
+ onRowOrderChange,
3485
+ headerContextMenu,
3486
+ cellContextMenu,
3487
+ columnVisibility,
3488
+ virtual: virtualProp,
3489
+ exportable,
3490
+ onExport,
3491
+ selectionSummary,
3492
+ selectionActions,
3493
+ striped,
3494
+ showSizeChanger,
3495
+ pageSizeOptions,
3496
+ showQuickJumper,
3497
+ showTotal,
3498
+ onPageSizeChange,
3499
+ showRowNumber,
3500
+ footer,
3501
+ fullscreenable,
3502
+ densityToggle,
3503
+ groupBy,
3504
+ groupByOptions,
3505
+ onGroupByChange,
3506
+ keyboardNavigation,
3507
+ emptyContent,
3508
+ printable,
3509
+ exportJSON,
3510
+ highlightOnHover,
3511
+ columnAutoResize,
3512
+ columnPinning,
3513
+ classNames: slotCls,
3514
+ styles: slotSty
3515
+ } = props;
3516
+ const sCls = slotCls ?? {};
3517
+ const sSty = slotSty ?? {};
3518
+ const config = useConfig();
3519
+ const sizeFromProp = sizeProp ?? config.size ?? "middle";
3520
+ const bordered = borderedProp ?? config.bordered ?? false;
3521
+ const loading = loadingProp ?? false;
3522
+ const state = useTableState(props);
3523
+ const tableRef = (0, import_react13.useRef)(null);
3524
+ const scrollRef = (0, import_react13.useRef)(null);
3525
+ const effectiveSize = densityToggle ? state.density : sizeFromProp;
3526
+ const rowNumConfig = (0, import_react13.useMemo)(
3527
+ () => showRowNumber ? typeof showRowNumber === "object" ? showRowNumber : {} : null,
3528
+ [showRowNumber]
3529
+ );
3530
+ const getExportData = (0, import_react13.useCallback)(() => {
3531
+ const cols = state.columns.map((c) => c.key);
3532
+ const headers = state.columns.map((c) => typeof c.title === "string" ? c.title : c.key);
3533
+ const rows = state.flatRows.filter((r) => !r.__groupRow).map(
3534
+ (row) => cols.map((k) => {
3535
+ const v = row.data[k];
3536
+ return v == null ? "" : String(v);
3537
+ })
3538
+ );
3539
+ return { cols, headers, rows };
3540
+ }, [state.columns, state.flatRows]);
3541
+ const handleExportCSV = (0, import_react13.useCallback)(() => {
3542
+ const { headers, rows } = getExportData();
3543
+ const data = [headers, ...rows];
3544
+ if (onExport) {
3545
+ onExport(data);
3546
+ } else {
3547
+ downloadCSV(toCSVString(data));
3548
+ }
3549
+ }, [getExportData, onExport]);
3550
+ const handleExportJSON = (0, import_react13.useCallback)(() => {
3551
+ const { headers, rows } = getExportData();
3552
+ downloadJSON(toJSONString(headers, rows));
3553
+ }, [getExportData]);
3554
+ const handleCopy = (0, import_react13.useCallback)(async () => {
3555
+ const { headers, rows } = getExportData();
3556
+ await copyToClipboard(toTSVString([headers, ...rows]));
3557
+ }, [getExportData]);
3558
+ const printOptionsFromProp = (0, import_react13.useMemo)(() => {
3559
+ if (typeof printable === "object" && printable !== null) {
3560
+ return { fileName: printable.fileName };
3561
+ }
3562
+ return {};
3563
+ }, [printable]);
3564
+ const doPrint = (0, import_react13.useCallback)(
3565
+ (opts) => {
3566
+ printElement(tableRef.current, { ...printOptionsFromProp, ...opts ?? {} });
3567
+ },
3568
+ [printOptionsFromProp]
3569
+ );
3570
+ const handlePrint = (0, import_react13.useCallback)(() => {
3571
+ doPrint();
3572
+ }, [doPrint]);
3573
+ (0, import_react13.useImperativeHandle)(forwardedRef, () => ({ print: doPrint }), [doPrint]);
3574
+ const gridTemplate = (0, import_react13.useMemo)(() => {
3575
+ const parts = [];
3576
+ if (rowDraggable) parts.push(DRAG_HANDLE_WIDTH);
3577
+ if (rowNumConfig) parts.push(rowNumConfig.width ? `${rowNumConfig.width}px` : ROW_NUMBER_WIDTH);
3578
+ parts.push(state.gridTemplate);
3579
+ return parts.join(" ");
3580
+ }, [rowDraggable, rowNumConfig, state.gridTemplate]);
3581
+ const totalCols = state.totalCols + (rowDraggable ? 1 : 0) + (rowNumConfig ? 1 : 0);
3582
+ const virtualConfig = virtualProp ? {
3583
+ rowHeight: typeof virtualProp === "object" ? virtualProp.rowHeight ?? 40 : 40,
3584
+ estimateRowHeight: typeof virtualProp === "object" ? virtualProp.estimateRowHeight : void 0,
3585
+ overscan: typeof virtualProp === "object" ? virtualProp.overscan ?? 5 : 5,
3586
+ height: typeof virtualProp === "object" ? virtualProp.height : void 0
3587
+ } : null;
3588
+ const virtualFixedRowHeight = virtualConfig && typeof virtualConfig.rowHeight === "number" && virtualConfig.estimateRowHeight == null ? virtualConfig.rowHeight : null;
3589
+ if (unstyled) {
3590
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className, style, role: "table", children: [
3591
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { role: "rowgroup", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { role: "row", children: state.columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3592
+ "span",
3593
+ {
3594
+ role: "columnheader",
3595
+ onClick: (e) => state.handleSort(col, e.shiftKey),
3596
+ children: col.title
3597
+ },
3598
+ col.key
3599
+ )) }) }),
3600
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { role: "rowgroup", children: state.flatRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { role: "row", children: state.columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { role: "cell", children: col.render ? col.render(row.data[col.key], row.data, row.id) : String(row.data[col.key] ?? "") }, col.key)) }, row.id)) })
3601
+ ] });
3602
+ }
3603
+ const hasToolbar = searchable || columnVisibility || exportable || exportJSON || fullscreenable || densityToggle || printable || groupBy || groupByOptions && groupByOptions.length > 0;
3604
+ const wrapperCls = [
3605
+ "sg-table-wrapper",
3606
+ `sg-table-${effectiveSize}`,
3607
+ bordered ? "sg-table-bordered" : "",
3608
+ sticky || virtualConfig ? "sg-table-sticky" : "",
3609
+ loading ? "sg-table-loading" : "",
3610
+ striped ? "sg-table-striped" : "",
3611
+ state.isFullscreen ? "sg-table-fullscreen" : "",
3612
+ highlightOnHover === false ? "" : "sg-table-hoverable",
3613
+ sCls.root,
3614
+ className
3615
+ ].filter(Boolean).join(" ");
3616
+ const scrollStyle = {};
3617
+ if (scroll?.x) scrollStyle.overflowX = "auto";
3618
+ if (virtualConfig) {
3619
+ scrollStyle.overflowY = "auto";
3620
+ scrollStyle.height = virtualConfig.height ?? scroll?.y ?? 400;
3621
+ } else if (scroll?.y) {
3622
+ scrollStyle.overflowY = "auto";
3623
+ scrollStyle.maxHeight = scroll.y;
3624
+ }
3625
+ const selectedCount = rowSelection?.selectedKeys.length ?? 0;
3626
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3627
+ "div",
3628
+ {
3629
+ className: wrapperCls,
3630
+ style: slotStyle(sSty.root, style),
3631
+ ref: (el) => {
3632
+ ;
3633
+ tableRef.current = el;
3634
+ state.wrapperRef.current = el;
3635
+ },
3636
+ onKeyDown: keyboardNavigation ? state.handleKeyNav : void 0,
3637
+ tabIndex: keyboardNavigation ? 0 : void 0,
3638
+ children: [
3639
+ hasToolbar && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: slotClass("sg-table-toolbar", sCls.toolbar), style: sSty.toolbar, children: [
3640
+ searchable && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3641
+ Input,
3642
+ {
3643
+ placeholder: state.t.searchPlaceholder,
3644
+ size: "small",
3645
+ value: state.searchText,
3646
+ onChange: state.setSearchText,
3647
+ style: { maxWidth: 240 }
3648
+ }
3649
+ ),
3650
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "sg-table-toolbar-right", children: [
3651
+ groupByOptions && groupByOptions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3652
+ GroupByDropdown,
3653
+ {
3654
+ value: groupBy ?? null,
3655
+ options: groupByOptions,
3656
+ onChange: onGroupByChange ?? (() => {
3657
+ }),
3658
+ t: state.t
3659
+ }
3660
+ ),
3661
+ groupBy && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "sg-table-toolbar-group", children: [
3662
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: state.expandAllGroups, children: state.t.groupExpand }),
3663
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: state.collapseAllGroups, children: state.t.groupCollapse })
3664
+ ] }),
3665
+ densityToggle && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DensityDropdown, { value: state.density, onChange: state.setDensity, t: state.t }),
3666
+ columnVisibility && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3667
+ ColumnVisibilityDropdown,
3668
+ {
3669
+ leafColumns: state.leafColumns,
3670
+ hiddenSet: state.hiddenSet,
3671
+ onToggle: state.toggleColumnVisibility,
3672
+ label: state.t.showColumns
3673
+ }
3674
+ ),
3675
+ exportable && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3676
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: handleExportCSV, children: state.t.exportCSV }),
3677
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: handleCopy, children: state.t.copyTable })
3678
+ ] }),
3679
+ exportJSON && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: handleExportJSON, children: state.t.exportJSON }),
3680
+ printable && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: handlePrint, children: state.t.print }),
3681
+ fullscreenable && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: state.toggleFullscreen, children: state.isFullscreen ? state.t.exitFullscreen : state.t.fullscreen })
3682
+ ] })
3683
+ ] }),
3684
+ selectionSummary && selectedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "sg-table-selection-bar", children: [
3685
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "sg-table-selection-count", children: state.t.selectedRows(selectedCount) }),
3686
+ selectionActions?.map((action) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3687
+ "button",
3688
+ {
3689
+ className: `sg-table-selection-action${action.danger ? " sg-table-selection-action-danger" : ""}`,
3690
+ onClick: () => action.onClick(
3691
+ rowSelection.selectedKeys,
3692
+ state.visibleRows.filter((r) => rowSelection.selectedKeys.includes(r.id)).map((r) => r.data)
3693
+ ),
3694
+ children: action.label
3695
+ },
3696
+ action.key
3697
+ )),
3698
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3699
+ "button",
3700
+ {
3701
+ className: "sg-table-selection-clear",
3702
+ onClick: () => rowSelection?.onChange([], []),
3703
+ children: "\u2715"
3704
+ }
3705
+ )
3706
+ ] }),
3707
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3708
+ "div",
3709
+ {
3710
+ ref: scrollRef,
3711
+ className: slotClass("sg-table-scroll", scroll?.x ? "sg-table-scroll-x" : "", sCls.scroll),
3712
+ style: slotStyle(
3713
+ Object.keys(scrollStyle).length > 0 ? scrollStyle : void 0,
3714
+ sSty.scroll
3715
+ ),
3716
+ children: [
3717
+ state.pinnedTop.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3718
+ "div",
3719
+ {
3720
+ className: "sg-table-pinned-top",
3721
+ style: { gridTemplateColumns: gridTemplate, minWidth: scroll?.x },
3722
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3723
+ TableBody,
3724
+ {
3725
+ columns: state.columns,
3726
+ flatRows: state.pinnedTop,
3727
+ rowSelection,
3728
+ expandable,
3729
+ isTreeMode: state.isTreeMode,
3730
+ indentSize: state.indentSize,
3731
+ treeExpanded: state.treeExpanded,
3732
+ expandedKeys: state.expandedKeys,
3733
+ totalCols,
3734
+ spanMap: state.spanMap,
3735
+ hiddenCells: state.hiddenCells,
3736
+ t: state.t,
3737
+ rowClassName,
3738
+ fixedStyle: state.fixedStyle,
3739
+ onRowClick,
3740
+ onCellEdit,
3741
+ onSelectRow: state.handleSelectRow,
3742
+ onToggleExpand: state.handleToggleExpand,
3743
+ onToggleTreeExpand: state.handleToggleTreeExpand,
3744
+ onContextMenu: state.setContextMenu,
3745
+ striped: false,
3746
+ isPinnedSection: true,
3747
+ slotClassNames: sCls,
3748
+ slotStyles: sSty
3749
+ }
3750
+ )
3751
+ }
3752
+ ),
3753
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3754
+ "div",
3755
+ {
3756
+ className: slotClass(
3757
+ "sg-table-grid",
3758
+ virtualFixedRowHeight != null ? "sg-table-grid-virtual-fixed" : "",
3759
+ sCls.grid
3760
+ ),
3761
+ style: slotStyle(
3762
+ {
3763
+ gridTemplateColumns: gridTemplate,
3764
+ minWidth: scroll?.x,
3765
+ ...virtualFixedRowHeight != null ? {
3766
+ ["--sg-virtual-row-height"]: `${virtualFixedRowHeight}px`
3767
+ } : null
3768
+ },
3769
+ sSty.grid
3770
+ ),
3771
+ role: "table",
3772
+ children: [
3773
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3774
+ TableHeader,
3775
+ {
3776
+ columns: state.columns,
3777
+ headerRows: state.headerRows,
3778
+ hasColumnGroups: state.hasColumnGroups,
3779
+ rowSelection,
3780
+ expandable,
3781
+ draggable,
3782
+ allSelected: state.allSelected,
3783
+ someSelected: state.someSelected,
3784
+ dragOver: state.dragOver,
3785
+ t: state.t,
3786
+ fixedStyle: state.fixedStyle,
3787
+ onSort: state.handleSort,
3788
+ onSelectAll: state.handleSelectAll,
3789
+ onDragStart: state.handleDragStart,
3790
+ onDragOver: state.handleDragOver,
3791
+ onDragLeave: state.setDragOver,
3792
+ onDrop: state.handleDrop,
3793
+ onDragEnd: state.handleDragEnd,
3794
+ onResizeStart: state.handleResizeStart,
3795
+ filterState: state.filterState,
3796
+ filterActions: state.filterActions,
3797
+ filterRef: state.filterRef,
3798
+ sorts: state.sorts,
3799
+ getSortIndex: state.getSortIndex,
3800
+ getSortDirection: state.getSortDirection,
3801
+ headerContextMenu,
3802
+ onContextMenu: state.setContextMenu,
3803
+ showRowNumber: !!rowNumConfig,
3804
+ rowDraggable,
3805
+ columnPinning,
3806
+ onPinColumn: state.handlePinColumn,
3807
+ onAutoResize: columnAutoResize ? state.handleAutoResize : void 0,
3808
+ slotClassNames: sCls,
3809
+ slotStyles: sSty
3810
+ }
3811
+ ),
3812
+ virtualConfig ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3813
+ VirtualTableBody,
3814
+ {
3815
+ columns: state.columns,
3816
+ flatRows: state.flatRows,
3817
+ rowHeight: virtualConfig.rowHeight,
3818
+ estimateRowHeight: virtualConfig.estimateRowHeight,
3819
+ overscan: virtualConfig.overscan,
3820
+ scrollContainerRef: scrollRef,
3821
+ rowSelection,
3822
+ expandable,
3823
+ isTreeMode: state.isTreeMode,
3824
+ indentSize: state.indentSize,
3825
+ treeExpanded: state.treeExpanded,
3826
+ expandedKeys: state.expandedKeys,
3827
+ totalCols,
3828
+ spanMap: state.spanMap,
3829
+ hiddenCells: state.hiddenCells,
3830
+ t: state.t,
3831
+ rowClassName,
3832
+ fixedStyle: state.fixedStyle,
3833
+ onRowClick,
3834
+ onCellEdit,
3835
+ onSelectRow: state.handleSelectRow,
3836
+ onToggleExpand: state.handleToggleExpand,
3837
+ onToggleTreeExpand: state.handleToggleTreeExpand,
3838
+ rowDraggable,
3839
+ showRowNumber: !!rowNumConfig,
3840
+ cellContextMenu,
3841
+ onContextMenu: state.setContextMenu,
3842
+ striped,
3843
+ groupBy,
3844
+ onToggleGroup: state.toggleGroupExpand,
3845
+ focusedCell: state.focusedCell,
3846
+ onFocusCell: state.setFocusedCell,
3847
+ keyboardNavigation,
3848
+ emptyContent,
3849
+ slotClassNames: sCls,
3850
+ slotStyles: sSty
3851
+ }
3852
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3853
+ TableBody,
3854
+ {
3855
+ columns: state.columns,
3856
+ flatRows: state.flatRows,
3857
+ rowSelection,
3858
+ expandable,
3859
+ isTreeMode: state.isTreeMode,
3860
+ indentSize: state.indentSize,
3861
+ treeExpanded: state.treeExpanded,
3862
+ expandedKeys: state.expandedKeys,
3863
+ totalCols,
3864
+ spanMap: state.spanMap,
3865
+ hiddenCells: state.hiddenCells,
3866
+ t: state.t,
3867
+ rowClassName,
3868
+ fixedStyle: state.fixedStyle,
3869
+ onRowClick,
3870
+ onCellEdit,
3871
+ onSelectRow: state.handleSelectRow,
3872
+ onToggleExpand: state.handleToggleExpand,
3873
+ onToggleTreeExpand: state.handleToggleTreeExpand,
3874
+ rowDraggable,
3875
+ onRowOrderChange,
3876
+ cellContextMenu,
3877
+ onContextMenu: state.setContextMenu,
3878
+ striped,
3879
+ showRowNumber: !!rowNumConfig,
3880
+ groupBy,
3881
+ onToggleGroup: state.toggleGroupExpand,
3882
+ focusedCell: state.focusedCell,
3883
+ onFocusCell: state.setFocusedCell,
3884
+ keyboardNavigation,
3885
+ emptyContent,
3886
+ slotClassNames: sCls,
3887
+ slotStyles: sSty
3888
+ }
3889
+ ),
3890
+ footer && state.aggregates && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3891
+ "div",
3892
+ {
3893
+ className: ["sg-table-footer-row", sCls.footer].filter(Boolean).join(" "),
3894
+ role: "row",
3895
+ style: { display: "contents", ...sSty.footer },
3896
+ children: [
3897
+ rowDraggable && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "sg-table-td sg-table-footer-cell", role: "cell" }),
3898
+ rowNumConfig && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "sg-table-td sg-table-footer-cell", role: "cell" }),
3899
+ rowSelection && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "sg-table-td sg-table-footer-cell", role: "cell" }),
3900
+ expandable && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "sg-table-td sg-table-footer-cell", role: "cell" }),
3901
+ state.columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3902
+ "div",
3903
+ {
3904
+ className: "sg-table-td sg-table-footer-cell",
3905
+ role: "cell",
3906
+ style: state.fixedStyle(col),
3907
+ children: state.aggregates[col.key] != null ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "sg-table-aggregate-value", children: [
3908
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "sg-table-aggregate-label", children: typeof col.aggregate === "string" ? state.t[col.aggregate] : "" }),
3909
+ " ",
3910
+ String(state.aggregates[col.key])
3911
+ ] }) : null
3912
+ },
3913
+ col.key
3914
+ ))
3915
+ ]
3916
+ }
3917
+ ),
3918
+ summary && state.visibleRows && summary(state.visibleRows).map((cells, ri) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3919
+ "div",
3920
+ {
3921
+ className: "sg-table-summary-row",
3922
+ role: "row",
3923
+ style: { display: "contents" },
3924
+ children: cells.map((cell, ci) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3925
+ "div",
3926
+ {
3927
+ className: "sg-table-td sg-table-summary-cell",
3928
+ role: "cell",
3929
+ style: {
3930
+ gridColumn: cell.colSpan ? `span ${cell.colSpan}` : void 0,
3931
+ textAlign: cell.align
3932
+ },
3933
+ children: cell.content
3934
+ },
3935
+ ci
3936
+ ))
3937
+ },
3938
+ `sum-${ri}`
3939
+ ))
3940
+ ]
3941
+ }
3942
+ ),
3943
+ state.pinnedBottom.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3944
+ "div",
3945
+ {
3946
+ className: "sg-table-pinned-bottom",
3947
+ style: { gridTemplateColumns: gridTemplate, minWidth: scroll?.x },
3948
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3949
+ TableBody,
3950
+ {
3951
+ columns: state.columns,
3952
+ flatRows: state.pinnedBottom,
3953
+ rowSelection,
3954
+ expandable,
3955
+ isTreeMode: state.isTreeMode,
3956
+ indentSize: state.indentSize,
3957
+ treeExpanded: state.treeExpanded,
3958
+ expandedKeys: state.expandedKeys,
3959
+ totalCols,
3960
+ spanMap: state.spanMap,
3961
+ hiddenCells: state.hiddenCells,
3962
+ t: state.t,
3963
+ rowClassName,
3964
+ fixedStyle: state.fixedStyle,
3965
+ onRowClick,
3966
+ onCellEdit,
3967
+ onSelectRow: state.handleSelectRow,
3968
+ onToggleExpand: state.handleToggleExpand,
3969
+ onToggleTreeExpand: state.handleToggleTreeExpand,
3970
+ onContextMenu: state.setContextMenu,
3971
+ striped: false,
3972
+ isPinnedSection: true,
3973
+ slotClassNames: sCls,
3974
+ slotStyles: sSty
3975
+ }
3976
+ )
3977
+ }
3978
+ )
3979
+ ]
3980
+ }
3981
+ ),
3982
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ContextMenu, { state: state.contextMenu, onClose: () => state.setContextMenu(null) }),
3983
+ loading && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "sg-table-loading-mask", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Spin, { size: "large" }) }),
3984
+ showPagination && state.tableState.totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: slotClass("sg-table-pagination", sCls.pagination), style: sSty.pagination, children: [
3985
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "sg-table-pagination-total", children: state.t.totalRows(state.tableState.filteredRows) }),
3986
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3987
+ Pagination,
3988
+ {
3989
+ current: state.tableState.page,
3990
+ total: state.tableState.filteredRows,
3991
+ pageSize: state.tableState.pageSize,
3992
+ onChange: state.setPage,
3993
+ showSizeChanger,
3994
+ pageSizeOptions,
3995
+ showQuickJumper,
3996
+ showTotal,
3997
+ onPageSizeChange
3998
+ }
3999
+ )
4000
+ ] })
4001
+ ]
4002
+ }
4003
+ );
4004
+ }
4005
+ var Table = (0, import_react13.forwardRef)(TableInner);
4006
+ Table.displayName = "Table";
4007
+ function ColumnVisibilityDropdown({
4008
+ leafColumns,
4009
+ hiddenSet,
4010
+ onToggle,
4011
+ label
4012
+ }) {
4013
+ const [open, setOpen] = import_react13.default.useState(false);
4014
+ const ref = import_react13.default.useRef(null);
4015
+ import_react13.default.useEffect(() => {
4016
+ if (!open) return;
4017
+ const h = (e) => {
4018
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
4019
+ };
4020
+ document.addEventListener("mousedown", h);
4021
+ return () => document.removeEventListener("mousedown", h);
4022
+ }, [open]);
4023
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { ref, style: { position: "relative" }, children: [
4024
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: () => setOpen(!open), children: label }),
4025
+ open && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "sg-table-col-visibility-dropdown", children: leafColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "sg-table-col-visibility-item", children: [
4026
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Checkbox, { checked: !hiddenSet.has(col.key), onChange: () => onToggle(col.key) }),
4027
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: typeof col.title === "string" ? col.title : col.key })
4028
+ ] }, col.key)) })
4029
+ ] });
4030
+ }
4031
+ function GroupByDropdown({
4032
+ value,
4033
+ options,
4034
+ onChange,
4035
+ t
4036
+ }) {
4037
+ const [open, setOpen] = import_react13.default.useState(false);
4038
+ const ref = import_react13.default.useRef(null);
4039
+ import_react13.default.useEffect(() => {
4040
+ if (!open) return;
4041
+ const h = (e) => {
4042
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
4043
+ };
4044
+ document.addEventListener("mousedown", h);
4045
+ return () => document.removeEventListener("mousedown", h);
4046
+ }, [open]);
4047
+ const current = value ? options.find((o) => o.key === value) : null;
4048
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { ref, style: { position: "relative" }, children: [
4049
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { className: "sg-table-toolbar-btn", onClick: () => setOpen(!open), children: [
4050
+ t.groupByLabel,
4051
+ current ? `: ${typeof current.label === "string" ? current.label : current.key}` : ""
4052
+ ] }),
4053
+ open && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "sg-table-group-by-dropdown", role: "menu", children: [
4054
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4055
+ "button",
4056
+ {
4057
+ type: "button",
4058
+ className: `sg-table-group-by-option${value === null ? " sg-table-group-by-active" : ""}`,
4059
+ onClick: () => {
4060
+ onChange(null);
4061
+ setOpen(false);
4062
+ },
4063
+ children: t.groupByNone
4064
+ }
4065
+ ),
4066
+ options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4067
+ "button",
4068
+ {
4069
+ type: "button",
4070
+ className: `sg-table-group-by-option${value === opt.key ? " sg-table-group-by-active" : ""}`,
4071
+ onClick: () => {
4072
+ onChange(opt.key);
4073
+ setOpen(false);
4074
+ },
4075
+ children: opt.label
4076
+ },
4077
+ opt.key
4078
+ ))
4079
+ ] })
4080
+ ] });
4081
+ }
4082
+ function DensityDropdown({
4083
+ value,
4084
+ onChange,
4085
+ t
4086
+ }) {
4087
+ const [open, setOpen] = import_react13.default.useState(false);
4088
+ const ref = import_react13.default.useRef(null);
4089
+ import_react13.default.useEffect(() => {
4090
+ if (!open) return;
4091
+ const h = (e) => {
4092
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
4093
+ };
4094
+ document.addEventListener("mousedown", h);
4095
+ return () => document.removeEventListener("mousedown", h);
4096
+ }, [open]);
4097
+ const options = [
4098
+ { key: "small", label: t.densitySmall },
4099
+ { key: "middle", label: t.densityMiddle },
4100
+ { key: "large", label: t.densityLarge }
4101
+ ];
4102
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { ref, style: { position: "relative" }, children: [
4103
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "sg-table-toolbar-btn", onClick: () => setOpen(!open), children: t.density }),
4104
+ open && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "sg-table-density-dropdown", children: options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4105
+ "button",
4106
+ {
4107
+ className: `sg-table-density-option${value === opt.key ? " sg-table-density-active" : ""}`,
4108
+ onClick: () => {
4109
+ onChange(opt.key);
4110
+ setOpen(false);
4111
+ },
4112
+ children: opt.label
4113
+ },
4114
+ opt.key
4115
+ )) })
4116
+ ] });
4117
+ }
4118
+ // Annotate the CommonJS export names for ESM import in node:
4119
+ 0 && (module.exports = {
4120
+ Table,
4121
+ copyToClipboard,
4122
+ downloadCSV,
4123
+ downloadJSON,
4124
+ printTable,
4125
+ toCSVString,
4126
+ toJSONString,
4127
+ toTSVString,
4128
+ useTable
4129
+ });
4130
+ //# sourceMappingURL=table.cjs.map