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