@canvas-components/react-list-table 0.3.19 → 0.3.21

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.
package/dist/index.cjs CHANGED
@@ -4,9 +4,9 @@ var react = require('react');
4
4
  var reactDom = require('react-dom');
5
5
  var reactComponents = require('@canvas-components/react-components');
6
6
  var listTable = require('@canvas-components/list-table');
7
+ var jsxRuntime = require('react/jsx-runtime');
7
8
  var date = require('@canvas-components/utils/date');
8
9
  var number = require('@canvas-components/utils/number');
9
- var jsxRuntime = require('react/jsx-runtime');
10
10
 
11
11
  // #style-inject:#style-inject
12
12
  function styleInject(css, { insertAt } = {}) {
@@ -32,6 +32,328 @@ function styleInject(css, { insertAt } = {}) {
32
32
 
33
33
  // src/styles/table-overrides.css
34
34
  styleInject(".react-list-table-filter-option {\n transition: background-color 0.2s ease;\n}\n.react-list-table-filter-option:hover {\n background: #f3f4f6;\n}\n.react-list-table-menu-action,\n.react-list-table-menu-row {\n transition: background-color 0.2s ease, color 0.2s ease;\n}\n.react-list-table-menu-action:hover,\n.react-list-table-menu-row:hover {\n background: #f3f4f6 !important;\n}\n.react-list-table-custom-selection-copy {\n transition: background-color 0.2s ease;\n}\n.react-list-table-custom-selection-copy:hover {\n background: #4096ff !important;\n}\n.react-list-table-custom-selection-input > .canvas-react-input-number-handler-down {\n display: none;\n}\n.react-list-table-menu-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.react-list-table-menu-action:hover .react-list-table-menu-chevron,\n.react-list-table-menu-row:hover .react-list-table-menu-chevron {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n.react-list-table-menu-chevron-active {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n");
35
+ var conditionalOperators = {
36
+ eq: "\u7B49\u4E8E",
37
+ neq: "\u4E0D\u7B49\u4E8E",
38
+ gt: "\u5927\u4E8E",
39
+ gte: "\u5927\u4E8E\u7B49\u4E8E",
40
+ lt: "\u5C0F\u4E8E",
41
+ lte: "\u5C0F\u4E8E\u7B49\u4E8E",
42
+ between: "\u4ECB\u4E8E\uFF08\u542B\u8FB9\u754C\uFF09",
43
+ contains: "\u5305\u542B\u6587\u672C",
44
+ empty: "\u4E3A\u7A7A",
45
+ notEmpty: "\u4E0D\u4E3A\u7A7A"
46
+ };
47
+ function describeConditionalRule(rule) {
48
+ return resolveConditions(rule).map(
49
+ (condition, index) => `${index === 0 ? "" : (condition.relation ?? rule.conditionRelation ?? "and") === "or" ? " \u6216 " : " \u4E14 "}${conditionalOperators[condition.operator]}${condition.operator === "empty" || condition.operator === "notEmpty" ? "" : ` ${condition.value ?? ""}`}${condition.operator === "between" ? ` \uFF5E ${condition.endValue ?? ""}` : ""}`
50
+ ).join("");
51
+ }
52
+ function resolveConditions(rule) {
53
+ return rule.conditions ?? (rule.operator ? [
54
+ {
55
+ operator: rule.operator,
56
+ value: rule.value,
57
+ endValue: rule.endValue
58
+ }
59
+ ] : []);
60
+ }
61
+ function validateConditionalRule(rule) {
62
+ const conditions = resolveConditions(rule);
63
+ if (!conditions.length) return "\u8BF7\u81F3\u5C11\u6DFB\u52A0\u4E00\u4E2A\u6761\u4EF6\u3002";
64
+ for (const [index, condition] of conditions.entries()) {
65
+ const error = validateCondition(condition);
66
+ if (error) return `\u6761\u4EF6 ${index + 1}\uFF1A${error}`;
67
+ }
68
+ return null;
69
+ }
70
+ function validateCondition(rule) {
71
+ if (rule.operator === "empty" || rule.operator === "notEmpty") return null;
72
+ if (String(rule.value ?? "").trim() === "")
73
+ return "\u8BF7\u8F93\u5165\u6BD4\u8F83\u503C\uFF1B\u7A7A\u503C\u8BF7\u4F7F\u7528\u201C\u4E3A\u7A7A\u201D\u6761\u4EF6\u3002";
74
+ if (["gt", "gte", "lt", "lte", "between"].includes(rule.operator)) {
75
+ if (!Number.isFinite(Number(rule.value))) return "\u8BF7\u8F93\u5165\u6709\u6548\u6570\u503C\u3002";
76
+ if (rule.operator === "between" && (String(rule.endValue ?? "").trim() === "" || !Number.isFinite(Number(rule.endValue)) || Number(rule.endValue) < Number(rule.value)))
77
+ return "\u8BF7\u8F93\u5165\u4E0D\u5C0F\u4E8E\u8D77\u59CB\u503C\u7684\u7ED3\u675F\u6570\u503C\u3002";
78
+ }
79
+ return null;
80
+ }
81
+ function ConditionalFormatDialog(props) {
82
+ const rules = props.request.conditionalFormats ?? [];
83
+ const [rule, setRule] = react.useState(
84
+ () => props.index == null ? {
85
+ id: `rule-${Date.now()}-${Math.random().toString(36).slice(2)}`,
86
+ operator: "gt",
87
+ value: "",
88
+ backgroundColor: "#fff1b8",
89
+ textColor: "#1f2329"
90
+ } : { ...rules[props.index] }
91
+ );
92
+ const [error, setError] = react.useState(null);
93
+ const conditions = resolveConditions(rule);
94
+ const patch = (value) => {
95
+ setRule((current) => ({ ...current, ...value }));
96
+ setError(null);
97
+ };
98
+ const apply = (next) => {
99
+ props.request.onChangeConditionalFormats?.(next);
100
+ props.onClose();
101
+ };
102
+ const patchCondition = (index, value) => {
103
+ patch({
104
+ conditions: conditions.map(
105
+ (condition, i) => i === index ? { ...condition, ...value } : condition
106
+ )
107
+ });
108
+ };
109
+ return /* @__PURE__ */ jsxRuntime.jsx(
110
+ reactComponents.ReactModal,
111
+ {
112
+ open: true,
113
+ title: props.index == null ? "\u65B0\u589E\u6761\u4EF6\u683C\u5F0F\u89C4\u5219" : "\u7F16\u8F91\u6761\u4EF6\u683C\u5F0F\u89C4\u5219",
114
+ width: 460,
115
+ onCancel: props.onClose,
116
+ onOk: () => {
117
+ const message = validateConditionalRule(rule);
118
+ if (message) {
119
+ setError(message);
120
+ return;
121
+ }
122
+ const next = rules.map((item) => ({ ...item }));
123
+ if (props.index == null) next.push(rule);
124
+ else next[props.index] = rule;
125
+ apply(next);
126
+ },
127
+ okText: "\u4FDD\u5B58\u89C4\u5219",
128
+ cancelText: "\u53D6\u6D88",
129
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gap: 14, fontSize: 14 }, children: [
130
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#64748b" }, children: "\u4EC5\u5F53\u524D\u5217\u751F\u6548\uFF1B\u4ECE\u4E0A\u5230\u4E0B\u5339\u914D\uFF0C\u9996\u6761\u547D\u4E2D\u7684\u80CC\u666F\u751F\u6548\u3002 \u6761\u4EF6\u4E4B\u95F4\u53EF\u5206\u522B\u8BBE\u7F6E\u201C\u4E14 / \u6216\u201D\uFF0C\u4E14\u4F18\u5148\u4E8E\u6216\u3002" }),
131
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
132
+ "\u89C4\u5219\u540D\u79F0\uFF08\u53EF\u9009\uFF09",
133
+ /* @__PURE__ */ jsxRuntime.jsx(
134
+ reactComponents.ReactInput,
135
+ {
136
+ value: rule.name ?? "",
137
+ onChange: (event) => patch({ name: event.target.value })
138
+ }
139
+ )
140
+ ] }),
141
+ /* @__PURE__ */ jsxRuntime.jsx(
142
+ "div",
143
+ {
144
+ style: {
145
+ display: "grid",
146
+ gap: 12,
147
+ maxHeight: "35vh",
148
+ overflowY: "auto"
149
+ },
150
+ children: conditions.map((condition, index) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
151
+ index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
152
+ reactComponents.ReactSelect,
153
+ {
154
+ "aria-label": `\u6761\u4EF6 ${index} \u4E0E\u6761\u4EF6 ${index + 1} \u7684\u5173\u7CFB`,
155
+ value: condition.relation ?? rule.conditionRelation ?? "and",
156
+ options: [
157
+ { value: "and", label: "\u4E14" },
158
+ { value: "or", label: "\u6216" }
159
+ ],
160
+ onChange: (value) => patchCondition(index, { relation: value }),
161
+ style: { width: 88, justifySelf: "center" }
162
+ }
163
+ ),
164
+ /* @__PURE__ */ jsxRuntime.jsxs(
165
+ "div",
166
+ {
167
+ style: {
168
+ display: "grid",
169
+ gap: 8,
170
+ padding: 12,
171
+ border: "1px solid #d9e1ec"
172
+ },
173
+ children: [
174
+ /* @__PURE__ */ jsxRuntime.jsxs(
175
+ "div",
176
+ {
177
+ style: {
178
+ display: "flex",
179
+ justifyContent: "space-between",
180
+ alignItems: "center"
181
+ },
182
+ children: [
183
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
184
+ "\u6761\u4EF6 ",
185
+ index + 1
186
+ ] }),
187
+ /* @__PURE__ */ jsxRuntime.jsx(
188
+ reactComponents.ReactButton,
189
+ {
190
+ type: "text",
191
+ size: "small",
192
+ disabled: conditions.length === 1,
193
+ "aria-label": `\u5220\u9664\u6761\u4EF6 ${index + 1}`,
194
+ onClick: () => patch({
195
+ conditions: conditions.filter((_, i) => i !== index)
196
+ }),
197
+ children: "\u5220\u9664\u6761\u4EF6"
198
+ }
199
+ )
200
+ ]
201
+ }
202
+ ),
203
+ /* @__PURE__ */ jsxRuntime.jsx(
204
+ reactComponents.ReactSelect,
205
+ {
206
+ "aria-label": `\u6761\u4EF6 ${index + 1} \u6BD4\u8F83\u65B9\u5F0F`,
207
+ value: condition.operator,
208
+ options: Object.entries(conditionalOperators).map(
209
+ ([value, label]) => ({ value, label })
210
+ ),
211
+ onChange: (value) => patchCondition(index, {
212
+ operator: value
213
+ })
214
+ }
215
+ ),
216
+ condition.operator !== "empty" && condition.operator !== "notEmpty" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
217
+ "\u6BD4\u8F83\u503C",
218
+ /* @__PURE__ */ jsxRuntime.jsx(
219
+ reactComponents.ReactInput,
220
+ {
221
+ value: String(condition.value ?? ""),
222
+ onChange: (event) => patchCondition(index, { value: event.target.value })
223
+ }
224
+ )
225
+ ] }),
226
+ condition.operator === "between" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
227
+ "\u7ED3\u675F\u503C",
228
+ /* @__PURE__ */ jsxRuntime.jsx(
229
+ reactComponents.ReactInput,
230
+ {
231
+ value: String(condition.endValue ?? ""),
232
+ onChange: (event) => patchCondition(index, { endValue: event.target.value })
233
+ }
234
+ )
235
+ ] })
236
+ ]
237
+ }
238
+ )
239
+ ] }, index))
240
+ }
241
+ ),
242
+ /* @__PURE__ */ jsxRuntime.jsx(
243
+ reactComponents.ReactButton,
244
+ {
245
+ onClick: () => patch({
246
+ conditions: [
247
+ ...conditions,
248
+ { operator: "gt", value: "", relation: "and" }
249
+ ]
250
+ }),
251
+ children: "\u65B0\u589E\u6761\u4EF6"
252
+ }
253
+ ),
254
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "grid", gap: 4 }, children: [
255
+ "\u5355\u5143\u683C\u80CC\u666F",
256
+ /* @__PURE__ */ jsxRuntime.jsx(
257
+ reactComponents.ReactColorPicker,
258
+ {
259
+ "aria-label": "\u5355\u5143\u683C\u80CC\u666F",
260
+ value: rule.backgroundColor,
261
+ onChange: (backgroundColor) => patch({ backgroundColor })
262
+ }
263
+ )
264
+ ] }),
265
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "grid", gap: 4 }, children: [
266
+ "\u6587\u672C\u989C\u8272",
267
+ /* @__PURE__ */ jsxRuntime.jsx(
268
+ reactComponents.ReactColorPicker,
269
+ {
270
+ "aria-label": "\u6587\u672C\u989C\u8272",
271
+ value: rule.textColor,
272
+ onChange: (textColor) => patch({ textColor })
273
+ }
274
+ )
275
+ ] }),
276
+ /* @__PURE__ */ jsxRuntime.jsxs(
277
+ "div",
278
+ {
279
+ style: {
280
+ padding: "8px 12px",
281
+ backgroundColor: rule.backgroundColor,
282
+ color: rule.textColor,
283
+ border: "1px solid #d9e1ec"
284
+ },
285
+ children: [
286
+ "\u6837\u5F0F\u9884\u89C8\uFF1A",
287
+ describeConditionalRule(rule)
288
+ ]
289
+ }
290
+ ),
291
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", style: { color: "#cf1322" }, children: error }),
292
+ props.index != null && /* @__PURE__ */ jsxRuntime.jsx(
293
+ reactComponents.ReactButton,
294
+ {
295
+ type: "text",
296
+ danger: true,
297
+ onClick: () => apply(rules.filter((_, index) => index !== props.index)),
298
+ children: "\u5220\u9664\u6B64\u89C4\u5219"
299
+ }
300
+ )
301
+ ] })
302
+ }
303
+ );
304
+ }
305
+
306
+ // src/features/context-menu/cache-menu.ts
307
+ function buildCacheMenuItems(request) {
308
+ const available = request.columnSettingsCacheAvailable === true;
309
+ const items = [];
310
+ const state = {
311
+ disabled: !available,
312
+ title: available ? void 0 : "\u914D\u7F6E storageKey \u540E\u53EF\u7F13\u5B58\u914D\u7F6E"
313
+ };
314
+ if (request.onChangeColumnSettingsCache)
315
+ items.push({
316
+ ...state,
317
+ key: "cache-columns",
318
+ label: "\u5217\u8BBE\u7F6E",
319
+ selected: available && request.cacheColumnSettings === true,
320
+ onClick: () => request.onChangeColumnSettingsCache?.(!request.cacheColumnSettings)
321
+ });
322
+ if (request.onChangeCachePreference) {
323
+ const categories = [
324
+ ["sort", "\u6392\u5E8F"],
325
+ ["filter", "\u7B5B\u9009"],
326
+ ["summary", "\u6C47\u603B"],
327
+ ["alignment", "\u5BF9\u9F50"],
328
+ ["dataFormat", "\u683C\u5F0F"],
329
+ ["density", "\u8868\u683C\u5BC6\u5EA6"],
330
+ ["zoom", "\u7F29\u653E"]
331
+ ];
332
+ for (const [category, label] of categories)
333
+ items.push({
334
+ ...state,
335
+ key: `cache-${category}`,
336
+ label,
337
+ selected: available && request.cachePreferences?.[category] !== false,
338
+ onClick: () => request.onChangeCachePreference?.(
339
+ category,
340
+ request.cachePreferences?.[category] === false
341
+ )
342
+ });
343
+ }
344
+ if (request.onChangeConditionalFormats)
345
+ items.push({
346
+ ...state,
347
+ key: "cache-conditional",
348
+ label: "\u5F53\u524D\u5217\u6761\u4EF6\u683C\u5F0F",
349
+ selected: available && request.cacheConditionalFormats !== false,
350
+ onClick: () => request.onChangeConditionalFormats?.(
351
+ request.conditionalFormats ?? [],
352
+ request.cacheConditionalFormats === false
353
+ )
354
+ });
355
+ return items;
356
+ }
35
357
  var CONTEXT_MENU_SURFACE_STYLE = {
36
358
  padding: 8,
37
359
  background: "#ffffff",
@@ -40,10 +362,22 @@ var CONTEXT_MENU_SURFACE_STYLE = {
40
362
  function ReactTableContextMenuView(props) {
41
363
  const { request } = props;
42
364
  const [menuOpen, setMenuOpen] = react.useState(true);
365
+ const [conditionalEditor, setConditionalEditor] = react.useState(null);
366
+ const conditionalDialog = conditionalEditor ? /* @__PURE__ */ jsxRuntime.jsx(
367
+ ConditionalFormatDialog,
368
+ {
369
+ ...conditionalEditor,
370
+ onClose: () => {
371
+ setConditionalEditor(null);
372
+ conditionalEditor.request.onClose();
373
+ }
374
+ }
375
+ ) : null;
43
376
  const [moreFormatRequest, setMoreFormatRequest] = react.useState(null);
44
377
  const [customSelectionRequest, setCustomSelectionRequest] = react.useState(null);
45
378
  if (!request) {
46
379
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
380
+ conditionalDialog,
47
381
  moreFormatRequest ? /* @__PURE__ */ jsxRuntime.jsx(
48
382
  MoreFormatDialog,
49
383
  {
@@ -68,6 +402,7 @@ function ReactTableContextMenuView(props) {
68
402
  width: 260
69
403
  };
70
404
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
405
+ conditionalDialog,
71
406
  /* @__PURE__ */ jsxRuntime.jsx(
72
407
  reactComponents.ReactPopup,
73
408
  {
@@ -77,7 +412,7 @@ function ReactTableContextMenuView(props) {
77
412
  minWidth: 260,
78
413
  onOpenChange: (open) => {
79
414
  setMenuOpen(open);
80
- if (!open && !moreFormatRequest && !customSelectionRequest) {
415
+ if (!open && !moreFormatRequest && !customSelectionRequest && !conditionalEditor) {
81
416
  request.onClose();
82
417
  }
83
418
  },
@@ -112,7 +447,28 @@ function ReactTableContextMenuView(props) {
112
447
  key: "copy-selection",
113
448
  label: "\u590D\u5236\u9009\u533A",
114
449
  onClick: request.onCopySelection
115
- }
450
+ },
451
+ ...request.onCopyImage ? [
452
+ {
453
+ key: "copy-image-all",
454
+ label: "\u590D\u5236\u4E3A\u56FE\u7247 \xB7 \u6240\u6709\u533A\u57DF",
455
+ separatorBefore: true,
456
+ title: "\u5F53\u524D\u5DF2\u52A0\u8F7D\u5E76\u7ECF\u8FC7\u6392\u5E8F\u8FC7\u6EE4\u7684\u5168\u90E8\u6570\u636E\uFF0C\u4E0D\u8BF7\u6C42\u672A\u52A0\u8F7D\u7684\u670D\u52A1\u7AEF\u6570\u636E",
457
+ onClick: () => request.onCopyImage?.("all")
458
+ },
459
+ {
460
+ key: "copy-image-selection",
461
+ label: "\u590D\u5236\u4E3A\u56FE\u7247 \xB7 \u9009\u4E2D\u533A\u57DF",
462
+ disabled: !request.canCopySelectionImage,
463
+ onClick: () => request.onCopyImage?.("selection")
464
+ },
465
+ {
466
+ key: "copy-image-viewport",
467
+ label: "\u590D\u5236\u4E3A\u56FE\u7247 \xB7 \u89C6\u53E3\u533A\u57DF",
468
+ title: "\u5F53\u524D\u53EF\u89C1\u8868\u683C\uFF0C\u5305\u542B\u8868\u5934\u548C\u6C47\u603B\u884C\uFF0C\u4E0D\u5305\u542B\u5206\u9875\u5668\u548C\u83DC\u5355",
469
+ onClick: () => request.onCopyImage?.("viewport")
470
+ }
471
+ ] : []
116
472
  ],
117
473
  children: /* @__PURE__ */ jsxRuntime.jsx(
118
474
  CustomSelectionMenu,
@@ -151,7 +507,26 @@ function ReactTableContextMenuView(props) {
151
507
  key: "export-json",
152
508
  label: "\u5BFC\u51FA JSON",
153
509
  onClick: request.onExportJson
154
- }
510
+ },
511
+ ...request.onExportImage ? [
512
+ {
513
+ key: "export-image-all",
514
+ label: "\u5BFC\u51FA\u56FE\u7247 \xB7 \u6240\u6709\u533A\u57DF",
515
+ separatorBefore: true,
516
+ onClick: () => request.onExportImage?.("all")
517
+ },
518
+ {
519
+ key: "export-image-selection",
520
+ label: "\u5BFC\u51FA\u56FE\u7247 \xB7 \u9009\u4E2D\u533A\u57DF",
521
+ disabled: !request.canCopySelectionImage,
522
+ onClick: () => request.onExportImage?.("selection")
523
+ },
524
+ {
525
+ key: "export-image-viewport",
526
+ label: "\u5BFC\u51FA\u56FE\u7247 \xB7 \u89C6\u53E3\u533A\u57DF",
527
+ onClick: () => request.onExportImage?.("viewport")
528
+ }
529
+ ] : []
155
530
  ]
156
531
  }
157
532
  ),
@@ -224,6 +599,41 @@ function ReactTableContextMenuView(props) {
224
599
  ),
225
600
  /* @__PURE__ */ jsxRuntime.jsx(SummaryMenu, { request }),
226
601
  /* @__PURE__ */ jsxRuntime.jsx(AlignmentMenu, { request }),
602
+ request.onChangeConditionalFormats && /* @__PURE__ */ jsxRuntime.jsx(
603
+ MenuSubmenu,
604
+ {
605
+ label: "\u6761\u4EF6\u683C\u5F0F",
606
+ items: [
607
+ {
608
+ key: "add-rule",
609
+ label: "\u65B0\u589E\u89C4\u5219",
610
+ onClick: () => {
611
+ setConditionalEditor({ request, index: null });
612
+ setMenuOpen(false);
613
+ }
614
+ },
615
+ {
616
+ key: "reset-rules",
617
+ label: "\u91CD\u7F6E\u6761\u4EF6\u683C\u5F0F",
618
+ disabled: !request.conditionalFormats?.length,
619
+ onClick: () => request.onChangeConditionalFormats?.([])
620
+ }
621
+ ],
622
+ header: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gap: 4, paddingBottom: 8 }, children: request.conditionalFormats?.length ? request.conditionalFormats.map((rule, index) => /* @__PURE__ */ jsxRuntime.jsx(
623
+ MenuAction,
624
+ {
625
+ label: rule.name?.trim() || `\u89C4\u5219 ${index + 1}`,
626
+ colorSwatch: rule.backgroundColor,
627
+ title: `${rule.name?.trim() || `\u89C4\u5219 ${index + 1}`}\uFF1A${describeConditionalRule(rule)}`,
628
+ onClick: () => {
629
+ setConditionalEditor({ request, index });
630
+ setMenuOpen(false);
631
+ }
632
+ },
633
+ rule.id
634
+ )) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#64748b", padding: 8 }, children: "\u6682\u65E0\u89C4\u5219" }) })
635
+ }
636
+ ),
227
637
  /* @__PURE__ */ jsxRuntime.jsx(
228
638
  DataFormatMenu,
229
639
  {
@@ -354,6 +764,13 @@ function ReactTableContextMenuView(props) {
354
764
  }
355
765
  ),
356
766
  /* @__PURE__ */ jsxRuntime.jsx(ZoomMenu, { value: request.zoom ?? 1, onChange: request.onChangeZoom }),
767
+ /* @__PURE__ */ jsxRuntime.jsx(
768
+ MenuSubmenu,
769
+ {
770
+ label: "\u7F13\u5B58\u5230\u672C\u5730",
771
+ items: buildCacheMenuItems(request)
772
+ }
773
+ ),
357
774
  request.columns?.length && request.onToggleColumn ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
358
775
  /* @__PURE__ */ jsxRuntime.jsx(MenuDivider, {}),
359
776
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -400,6 +817,7 @@ function MenuAction(props) {
400
817
  type: "button",
401
818
  onClick: disabled ? void 0 : onClick,
402
819
  disabled,
820
+ title: props.title,
403
821
  className: "react-list-table-menu-action",
404
822
  style: {
405
823
  display: "flex",
@@ -428,7 +846,36 @@ function MenuAction(props) {
428
846
  children: selected ? "\u2713" : ""
429
847
  }
430
848
  ) : null,
431
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1, whiteSpace: "nowrap" }, children: label }),
849
+ props.colorSwatch ? /* @__PURE__ */ jsxRuntime.jsx(
850
+ "span",
851
+ {
852
+ "aria-hidden": "true",
853
+ style: {
854
+ width: 14,
855
+ height: 14,
856
+ flex: "0 0 14px",
857
+ marginRight: 8,
858
+ borderRadius: 2,
859
+ backgroundColor: props.colorSwatch,
860
+ boxShadow: "inset 0 0 0 1px rgba(0, 0, 0, 0.12)"
861
+ }
862
+ }
863
+ ) : null,
864
+ /* @__PURE__ */ jsxRuntime.jsx(
865
+ "span",
866
+ {
867
+ style: {
868
+ flex: 1,
869
+ whiteSpace: "nowrap",
870
+ ...props.colorSwatch ? {
871
+ minWidth: 0,
872
+ overflow: "hidden",
873
+ textOverflow: "ellipsis"
874
+ } : null
875
+ },
876
+ children: label
877
+ }
878
+ ),
432
879
  preview ? /* @__PURE__ */ jsxRuntime.jsx(
433
880
  "span",
434
881
  {
@@ -539,6 +986,7 @@ function MenuSubmenu(props) {
539
986
  MenuAction,
540
987
  {
541
988
  label: item.label,
989
+ title: item.title,
542
990
  preview: item.preview,
543
991
  onClick: item.onClick,
544
992
  selected: item.selected,
@@ -1028,13 +1476,7 @@ function CustomSelectionMenu(props) {
1028
1476
  if (!request.onCopyCustomSelection || !request.customSelection) {
1029
1477
  return null;
1030
1478
  }
1031
- return /* @__PURE__ */ jsxRuntime.jsx(
1032
- MenuAction,
1033
- {
1034
- label: "\u590D\u5236\u81EA\u5B9A\u4E49\u9009\u533A",
1035
- onClick: props.onOpen
1036
- }
1037
- );
1479
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuAction, { label: "\u590D\u5236\u81EA\u5B9A\u4E49\u9009\u533A", onClick: props.onOpen });
1038
1480
  }
1039
1481
  function CustomSelectionDialog(props) {
1040
1482
  const { request } = props;
@@ -1247,6 +1689,16 @@ function SummaryMenu(props) {
1247
1689
  selected: request.summaryType === item.value,
1248
1690
  onClick: () => request.onChangeSummaryType?.(item.value)
1249
1691
  })),
1692
+ {
1693
+ key: "show-summary-type-prefix",
1694
+ label: "\u5C55\u793A\u6C47\u603B\u65B9\u5F0F\u524D\u7F00",
1695
+ separatorBefore: true,
1696
+ selected: request.summaryShowTypePrefix !== false,
1697
+ disabled: !request.summaryType,
1698
+ onClick: request.onChangeSummaryShowTypePrefix ? () => request.onChangeSummaryShowTypePrefix?.(
1699
+ request.summaryShowTypePrefix === false
1700
+ ) : void 0
1701
+ },
1250
1702
  {
1251
1703
  key: "clear-summary",
1252
1704
  label: "\u53D6\u6D88\u6C47\u603B",
@@ -2228,6 +2680,58 @@ var toolButtonStyle = {
2228
2680
  lineHeight: 1,
2229
2681
  cursor: "pointer"
2230
2682
  };
2683
+ function ReactListTableExportNameDialog({
2684
+ request
2685
+ }) {
2686
+ const extension = request.fileName.match(/\.(xlsx|csv|txt|json)$/i)?.[0] ?? "";
2687
+ const [fileName, setFileName] = react.useState(
2688
+ extension ? request.fileName.slice(0, -extension.length) : request.fileName
2689
+ );
2690
+ const [invalid, setInvalid] = react.useState(false);
2691
+ const confirm = () => {
2692
+ if (!fileName.trim()) {
2693
+ setInvalid(true);
2694
+ return;
2695
+ }
2696
+ request.onConfirm(`${fileName.trim()}${extension}`);
2697
+ };
2698
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2699
+ reactComponents.ReactModal,
2700
+ {
2701
+ open: true,
2702
+ title: "\u5BFC\u51FA\u6587\u4EF6",
2703
+ width: 420,
2704
+ fullscreenable: false,
2705
+ onCancel: request.onCancel,
2706
+ onOk: confirm,
2707
+ okText: "\u5BFC\u51FA",
2708
+ cancelText: "\u53D6\u6D88",
2709
+ children: [
2710
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2711
+ "\u6587\u4EF6\u540D\u79F0",
2712
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
2713
+ /* @__PURE__ */ jsxRuntime.jsx(
2714
+ reactComponents.ReactInput,
2715
+ {
2716
+ autoFocus: true,
2717
+ value: fileName,
2718
+ placeholder: "\u8BF7\u8F93\u5165\u6587\u4EF6\u540D\u79F0",
2719
+ onFocus: (event) => event.target.select(),
2720
+ onChange: (event) => {
2721
+ setFileName(event.target.value);
2722
+ setInvalid(false);
2723
+ },
2724
+ onPressEnter: confirm
2725
+ }
2726
+ ),
2727
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-label": "\u6587\u4EF6\u540E\u7F00", style: { flexShrink: 0 }, children: extension })
2728
+ ] })
2729
+ ] }),
2730
+ invalid ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", style: { color: "#ff4d4f", marginTop: 8 }, children: "\u8BF7\u8F93\u5165\u6587\u4EF6\u540D\u79F0" }) : null
2731
+ ]
2732
+ }
2733
+ );
2734
+ }
2231
2735
 
2232
2736
  // src/features/editor/utils.ts
2233
2737
  function toNumberValue(value) {
@@ -2329,12 +2833,16 @@ function ReactTableEditorOverlay(props) {
2329
2833
  if (!input) {
2330
2834
  return;
2331
2835
  }
2332
- focusAndSelectEditorInput(input);
2836
+ focusAndSelectEditorInput(input, request.selectOnFocus);
2333
2837
  }, [request]);
2334
2838
  return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorHostRef, children: renderEditorByType(request, style) }, request.editorKey) });
2335
2839
  }
2336
2840
  function renderEditorByType(request, style) {
2337
2841
  switch (request.config.valueType ?? "text") {
2842
+ case "tree-select":
2843
+ return /* @__PURE__ */ jsxRuntime.jsx(TreeSelectEditor, { request, style });
2844
+ case "cascader":
2845
+ return /* @__PURE__ */ jsxRuntime.jsx(CascaderEditor, { request, style });
2338
2846
  case "number":
2339
2847
  return /* @__PURE__ */ jsxRuntime.jsx(NumberEditor, { request, style });
2340
2848
  case "input-range":
@@ -2374,7 +2882,7 @@ function TextEditor(props) {
2374
2882
  const skipBlurCommitRef = react.useRef(false);
2375
2883
  react.useLayoutEffect(() => {
2376
2884
  const input = hostRef.current?.querySelector("input");
2377
- focusAndSelectEditorInput(input);
2885
+ focusAndSelectEditorInput(input, request.selectOnFocus);
2378
2886
  }, [request]);
2379
2887
  react.useEffect(() => {
2380
2888
  setValue(String(request.value ?? ""));
@@ -2414,7 +2922,7 @@ function NumberEditor(props) {
2414
2922
  const skipBlurCommitRef = react.useRef(false);
2415
2923
  react.useLayoutEffect(() => {
2416
2924
  const input = hostRef.current?.querySelector("input");
2417
- focusAndSelectEditorInput(input);
2925
+ focusAndSelectEditorInput(input, request.selectOnFocus);
2418
2926
  }, [request]);
2419
2927
  react.useEffect(() => {
2420
2928
  setValue(toNumberValue(request.value));
@@ -2623,6 +3131,94 @@ function DateEditor(props) {
2623
3131
  }
2624
3132
  ) });
2625
3133
  }
3134
+ function TreeSelectEditor({
3135
+ request,
3136
+ style
3137
+ }) {
3138
+ const [value, setValue] = react.useState(
3139
+ request.value ?? null
3140
+ );
3141
+ const skipBlurCommitRef = react.useRef(false);
3142
+ react.useEffect(() => {
3143
+ setValue(request.value ?? null);
3144
+ }, [request.value]);
3145
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style, children: /* @__PURE__ */ jsxRuntime.jsx(
3146
+ reactComponents.ReactTreeSelect,
3147
+ {
3148
+ autoFocus: true,
3149
+ value,
3150
+ treeData: request.config.treeData,
3151
+ multiple: request.config.multiple,
3152
+ showSearch: request.config.showSearch,
3153
+ treeDefaultExpandAll: request.config.treeDefaultExpandAll,
3154
+ treeDefaultExpandedKeys: request.config.treeDefaultExpandedKeys,
3155
+ allowClear: request.config.allowClear,
3156
+ placeholder: request.config.placeholder,
3157
+ style: getEditorInputStyle(request),
3158
+ onChange: (next, _nodes, info) => {
3159
+ setValue(next);
3160
+ request.onChange(next);
3161
+ if (info.complete && info.trigger !== "clear") {
3162
+ skipBlurCommitRef.current = true;
3163
+ request.onCommit();
3164
+ }
3165
+ },
3166
+ onBlur: (event) => handleEditorBlur(event, skipBlurCommitRef, request),
3167
+ onKeyDown: (event) => {
3168
+ if (event.key === "Tab")
3169
+ handleEditorNavigationKey(event, request, skipBlurCommitRef);
3170
+ if (event.key === "Escape") {
3171
+ skipBlurCommitRef.current = true;
3172
+ handleEditorEscapeKey(event, request);
3173
+ }
3174
+ }
3175
+ }
3176
+ ) });
3177
+ }
3178
+ function CascaderEditor({
3179
+ request,
3180
+ style
3181
+ }) {
3182
+ const [value, setValue] = react.useState(Array.isArray(request.value) ? request.value : []);
3183
+ const skipBlurCommitRef = react.useRef(false);
3184
+ react.useEffect(() => {
3185
+ setValue(Array.isArray(request.value) ? request.value : []);
3186
+ }, [request.value]);
3187
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style, children: /* @__PURE__ */ jsxRuntime.jsx(
3188
+ reactComponents.ReactCascader,
3189
+ {
3190
+ value,
3191
+ options: request.config.options,
3192
+ autoFocus: true,
3193
+ placeholder: request.config.placeholder,
3194
+ showSearch: request.config.showSearch,
3195
+ allowClear: request.config.allowClear,
3196
+ changeOnSelect: request.config.changeOnSelect,
3197
+ multiple: request.config.multiple,
3198
+ showCheckedStrategy: request.config.showCheckedStrategy,
3199
+ expandTrigger: request.config.expandTrigger,
3200
+ displayRender: request.config.displayRender,
3201
+ style: getEditorInputStyle(request),
3202
+ onChange: (next, _options, info) => {
3203
+ setValue(next);
3204
+ request.onChange(next);
3205
+ if (info.complete && info.trigger !== "clear") {
3206
+ skipBlurCommitRef.current = true;
3207
+ request.onCommit();
3208
+ }
3209
+ },
3210
+ onBlur: (event) => handleEditorBlur(event, skipBlurCommitRef, request),
3211
+ onKeyDown: (event) => {
3212
+ if (event.key === "Tab")
3213
+ handleEditorNavigationKey(event, request, skipBlurCommitRef);
3214
+ if (event.key === "Escape") {
3215
+ skipBlurCommitRef.current = true;
3216
+ handleEditorEscapeKey(event, request);
3217
+ }
3218
+ }
3219
+ }
3220
+ ) });
3221
+ }
2626
3222
  function SelectEditor(props) {
2627
3223
  const { request, style } = props;
2628
3224
  const options = request.config.options ?? [];
@@ -2953,13 +3549,14 @@ function handleRangeInputTab(event) {
2953
3549
  focusAndSelectEditorInput(nextInput);
2954
3550
  return true;
2955
3551
  }
2956
- function focusAndSelectEditorInput(input) {
3552
+ function focusAndSelectEditorInput(input, selectOnFocus = true) {
2957
3553
  if (!input) {
2958
3554
  return;
2959
3555
  }
2960
3556
  input.focus();
2961
3557
  try {
2962
- input.select();
3558
+ if (selectOnFocus) input.select();
3559
+ else input.setSelectionRange(input.value.length, input.value.length);
2963
3560
  } catch {
2964
3561
  }
2965
3562
  }
@@ -3449,7 +4046,7 @@ function resolveSortableTransform(index, sourceIndex, targetIndex, height) {
3449
4046
  }
3450
4047
 
3451
4048
  // src/features/toolbar/style.css
3452
- styleInject('.react-list-table-shell {\n background: #fff;\n font-size: 14px;\n}\n.react-list-table-titlebar {\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0;\n box-sizing: border-box;\n background: #fff;\n}\n.react-list-table-shell-fullscreen {\n width: 100% !important;\n height: 100% !important;\n}\n.react-list-table-shell-fullscreen .canvas-list-table-root {\n height: 100% !important;\n}\n.react-list-table-title {\n min-width: 0;\n color: #1f2937;\n font-size: 14px;\n font-weight: 600;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-tools {\n display: flex;\n align-items: center;\n gap: 14px;\n color: #475569;\n}\n.react-list-table-tool-wrap {\n position: relative;\n display: inline-flex;\n}\n.react-list-table-tool {\n width: 20px;\n height: 24px;\n padding: 0;\n border: 0;\n color: inherit;\n background: transparent;\n font: 16px/24px sans-serif;\n cursor: pointer;\n}\n.react-list-table-tool:hover {\n color: #1677ff;\n}\n.react-list-table-tool-menu,\n.react-list-table-column-setting {\n position: absolute;\n z-index: 120;\n top: 28px;\n right: 0;\n min-width: 112px;\n padding: 6px;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n background: #fff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, .14);\n}\n.react-list-table-tool-menu button {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 6px 10px;\n border: 0;\n border-radius: 4px;\n background: transparent;\n text-align: left;\n cursor: pointer;\n}\n.react-list-table-tool-menu button.active::after {\n content: "\\2713";\n margin-left: 12px;\n font-size: 14px;\n}\n.react-list-table-tool-menu button:hover,\n.react-list-table-tool-menu button.active {\n color: #1677ff;\n background: #e6f4ff;\n}\n.react-list-table-column-setting {\n width: 328px;\n max-height: 360px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n.react-list-table-column-setting-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 6px 8px;\n border-bottom: 1px solid #f0f0f0;\n flex: 0 0 auto;\n}\n.react-list-table-column-setting-head button {\n border: 0;\n color: #1677ff;\n background: transparent;\n cursor: pointer;\n}\n.react-list-table-column-setting-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n.react-list-table-column-item {\n display: flex;\n align-items: center;\n gap: 8px;\n justify-content: space-between;\n padding: 7px 6px;\n box-sizing: border-box;\n cursor: pointer;\n}\n.react-list-table-column-main,\n.react-list-table-column-actions {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.react-list-table-column-main {\n min-width: 0;\n}\n.react-list-table-column-actions {\n flex: 0 0 auto;\n}\n.react-list-table-column-actions > .canvas-react-select-wrap {\n flex: 0 0 96px;\n width: 96px;\n height: 24px;\n}\n.react-list-table-column-label {\n min-width: 64px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-column-width-input {\n height: 22px;\n padding-inline: 5px;\n}\n.react-list-table-column-fixed-input {\n height: 22px;\n padding-inline: 6px;\n font-size: 14px;\n}\n.react-list-table-column-setting label.dragging {\n opacity: 0.45;\n background: #e6f4ff;\n}\n.react-list-table-column-setting [data-sortable-key].dragging {\n opacity: 0.28;\n}\n.react-list-table-column-drag {\n color: #94a3b8;\n display: inline-flex;\n font-size: 14px;\n cursor: grab;\n user-select: none;\n}\nbody.react-list-table-sorting,\nbody.react-list-table-sorting * {\n cursor: grabbing !important;\n}\n.react-list-table-sort-overlay {\n position: fixed;\n z-index: 1400;\n display: block;\n padding: 0;\n box-sizing: border-box;\n color: #334155;\n background: #fff;\n border: 1px solid #91caff;\n border-radius: 6px;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);\n pointer-events: none;\n}\n.react-list-table-sort-overlay .react-list-table-column-item {\n width: 100%;\n height: 100%;\n}\n');
4049
+ styleInject('.react-list-table-shell {\n background: #fff;\n font-size: 14px;\n}\n.react-list-table-titlebar {\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0;\n box-sizing: border-box;\n background: #fff;\n}\n.react-list-table-shell-fullscreen {\n width: 100% !important;\n height: 100% !important;\n}\n.react-list-table-shell-fullscreen .canvas-list-table-root {\n height: 100% !important;\n}\n.react-list-table-title {\n min-width: 0;\n color: #1f2937;\n font-size: 14px;\n font-weight: 600;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-tools {\n display: flex;\n align-items: center;\n gap: 14px;\n color: #475569;\n}\n.react-list-table-tool-wrap {\n position: relative;\n display: inline-flex;\n}\n.react-list-table-tool {\n width: 20px;\n height: 24px;\n padding: 0;\n border: 0;\n color: inherit;\n background: transparent;\n font: 16px/24px sans-serif;\n cursor: pointer;\n}\n.react-list-table-tool:hover {\n color: #1677ff;\n}\n.react-list-table-tool-menu,\n.react-list-table-column-setting {\n position: absolute;\n z-index: 120;\n top: 28px;\n right: 0;\n min-width: 112px;\n padding: 6px;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n background: #fff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, .14);\n}\n.react-list-table-tool-menu button {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 6px 10px;\n border: 0;\n border-radius: 4px;\n background: transparent;\n text-align: left;\n cursor: pointer;\n}\n.react-list-table-tool-menu button.active::after {\n content: "\\2713";\n margin-left: 12px;\n font-size: 14px;\n}\n.react-list-table-tool-menu button:hover,\n.react-list-table-tool-menu button.active {\n color: #1677ff;\n background: #e6f4ff;\n}\n.react-list-table-column-setting {\n width: 328px;\n max-height: 360px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n.react-list-table-column-setting-head {\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: 4px 6px 8px;\n border-bottom: 1px solid #f0f0f0;\n flex: 0 0 auto;\n}\n.react-list-table-column-setting-head button {\n border: 0;\n color: #1677ff;\n background: transparent;\n cursor: pointer;\n}\n.react-list-table-column-setting-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n.react-list-table-column-item {\n display: flex;\n align-items: center;\n gap: 8px;\n justify-content: space-between;\n padding: 7px 6px;\n box-sizing: border-box;\n cursor: pointer;\n}\n.react-list-table-column-main,\n.react-list-table-column-actions {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.react-list-table-column-main {\n min-width: 0;\n}\n.react-list-table-column-actions {\n flex: 0 0 auto;\n}\n.react-list-table-column-actions > .canvas-react-select-wrap {\n flex: 0 0 96px;\n width: 96px;\n height: 24px;\n}\n.react-list-table-column-label {\n min-width: 64px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-column-width-input {\n height: 22px;\n padding-inline: 5px;\n}\n.react-list-table-column-fixed-input {\n height: 22px;\n padding-inline: 6px;\n font-size: 14px;\n}\n.react-list-table-column-setting label.dragging {\n opacity: 0.45;\n background: #e6f4ff;\n}\n.react-list-table-column-setting [data-sortable-key].dragging {\n opacity: 0.28;\n}\n.react-list-table-column-drag {\n color: #94a3b8;\n display: inline-flex;\n font-size: 14px;\n cursor: grab;\n user-select: none;\n}\nbody.react-list-table-sorting,\nbody.react-list-table-sorting * {\n cursor: grabbing !important;\n}\n.react-list-table-sort-overlay {\n position: fixed;\n z-index: 1400;\n display: block;\n padding: 0;\n box-sizing: border-box;\n color: #334155;\n background: #fff;\n border: 1px solid #91caff;\n border-radius: 6px;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);\n pointer-events: none;\n}\n.react-list-table-sort-overlay .react-list-table-column-item {\n width: 100%;\n height: 100%;\n}\n');
3453
4050
  function ReactTableToolbar(props) {
3454
4051
  const { toolbar, title } = props;
3455
4052
  const [densityOpen, setDensityOpen] = react.useState(false);
@@ -3566,6 +4163,18 @@ function ReactTableToolbar(props) {
3566
4163
  children: [
3567
4164
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-list-table-column-setting-head", children: [
3568
4165
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "\u5217\u8BBE\u7F6E" }),
4166
+ /* @__PURE__ */ jsxRuntime.jsx(
4167
+ reactComponents.ReactCheckbox,
4168
+ {
4169
+ checked: props.cacheColumnSettings === true,
4170
+ disabled: !props.columnSettingsCacheAvailable,
4171
+ title: props.columnSettingsCacheAvailable ? "\u7F13\u5B58\u5217\u5BBD\u3001\u663E\u9690\u3001\u56FA\u5B9A\u548C\u987A\u5E8F" : "\u914D\u7F6E storageKey \u540E\u53EF\u7F13\u5B58\u5217\u8BBE\u7F6E",
4172
+ onChange: (event) => props.onColumnSettingsCacheChange?.(
4173
+ event.target.checked
4174
+ ),
4175
+ children: "\u7F13\u5B58\u5230\u672C\u5730"
4176
+ }
4177
+ ),
3569
4178
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: "auto" }, children: config.columnSettingHeaderExtra }),
3570
4179
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: props.onResetColumns, children: "\u91CD\u7F6E" })
3571
4180
  ] }),
@@ -3713,9 +4322,14 @@ function useReactListTableState(options) {
3713
4322
  const [searchRequest, setSearchRequest] = react.useState(null);
3714
4323
  const [imagePreviewRequest, setImagePreviewRequest] = react.useState(null);
3715
4324
  const [dangerConfirmRequest, setDangerConfirmRequest] = react.useState(null);
4325
+ const [exportNameRequest, setExportNameRequest] = react.useState(null);
3716
4326
  const uiOptions = react.useMemo(
3717
4327
  () => ({
3718
4328
  ...options.ui,
4329
+ onExportNameRequest: (request) => {
4330
+ setExportNameRequest(request);
4331
+ options.ui?.onExportNameRequest?.(request);
4332
+ },
3719
4333
  onEditorRequest: (request) => {
3720
4334
  setEditorRequest(request);
3721
4335
  options.ui?.onEditorRequest?.(request);
@@ -3783,6 +4397,7 @@ function useReactListTableState(options) {
3783
4397
  setSearchRequest(null);
3784
4398
  setImagePreviewRequest(null);
3785
4399
  setDangerConfirmRequest(null);
4400
+ setExportNameRequest(null);
3786
4401
  };
3787
4402
  }, []);
3788
4403
  react.useEffect(() => {
@@ -3804,6 +4419,7 @@ function useReactListTableState(options) {
3804
4419
  searchRequest,
3805
4420
  imagePreviewRequest,
3806
4421
  dangerConfirmRequest,
4422
+ exportNameRequest,
3807
4423
  closeDangerConfirmRequest: () => {
3808
4424
  setDangerConfirmRequest(null);
3809
4425
  options.ui?.onDangerConfirmRequest?.(null);
@@ -3901,12 +4517,15 @@ function ReactListTableInner(props, ref) {
3901
4517
  stretchColumns,
3902
4518
  resizable,
3903
4519
  storageKey,
4520
+ cacheColumnSettings,
4521
+ cachePreferences,
3904
4522
  draggable,
3905
4523
  tableId,
3906
4524
  rowDrag,
3907
4525
  debug,
3908
4526
  title,
3909
- toolbar
4527
+ toolbar,
4528
+ exportOptions
3910
4529
  } = props;
3911
4530
  const inheritedDebugEnabled = useReactListTableDebugEnabled();
3912
4531
  const resolvedDebug = react.useMemo(
@@ -3922,6 +4541,10 @@ function ReactListTableInner(props, ref) {
3922
4541
  );
3923
4542
  const [columnConfig, setColumnConfig] = react.useState(() => /* @__PURE__ */ new Map());
3924
4543
  const [columnConfigRevision, setColumnConfigRevision] = react.useState(0);
4544
+ const [columnSettingsCacheOverride, setColumnSettingsCacheOverride] = react.useState(null);
4545
+ const resolvedColumnSettingsCache = (columnSettingsCacheOverride?.storageKey === storageKey ? columnSettingsCacheOverride?.value : void 0) ?? cacheColumnSettings ?? true;
4546
+ const [cachePreferencesOverride, setCachePreferencesOverride] = react.useState();
4547
+ const resolvedCachePreferences = (cachePreferencesOverride?.storageKey === storageKey ? cachePreferencesOverride?.value : void 0) ?? cachePreferences;
3925
4548
  const [columnConfigResetRevision, setColumnConfigResetRevision] = react.useState(0);
3926
4549
  const resolvedColumns = react.useMemo(
3927
4550
  () => applyColumnManagerState(
@@ -3943,6 +4566,7 @@ function ReactListTableInner(props, ref) {
3943
4566
  );
3944
4567
  const options = react.useMemo(() => {
3945
4568
  const nextOptions = buildListTableOptions({
4569
+ exportOptions,
3946
4570
  width,
3947
4571
  height,
3948
4572
  emptyText,
@@ -3975,6 +4599,8 @@ function ReactListTableInner(props, ref) {
3975
4599
  stretchColumns,
3976
4600
  resizable,
3977
4601
  storageKey,
4602
+ cacheColumnSettings: resolvedColumnSettingsCache,
4603
+ cachePreferences: resolvedCachePreferences,
3978
4604
  draggable,
3979
4605
  tableId,
3980
4606
  rowDrag,
@@ -3992,10 +4618,17 @@ function ReactListTableInner(props, ref) {
3992
4618
  columnConfigResetRevision,
3993
4619
  ui: {
3994
4620
  ...nextOptions.ui,
3995
- onDensityChange: setDensityOverride
4621
+ onDensityChange: setDensityOverride,
4622
+ onColumnSettingsCacheChange: (value) => setColumnSettingsCacheOverride(
4623
+ (current) => current?.storageKey === storageKey && current?.value === value ? current : { storageKey, value }
4624
+ ),
4625
+ onCachePreferencesChange: (next) => setCachePreferencesOverride(
4626
+ (current) => current?.storageKey === storageKey && JSON.stringify(current?.value ?? {}) === JSON.stringify(next) ? current : { storageKey, value: next }
4627
+ )
3996
4628
  }
3997
4629
  };
3998
4630
  }, [
4631
+ exportOptions,
3999
4632
  width,
4000
4633
  height,
4001
4634
  emptyText,
@@ -4028,6 +4661,8 @@ function ReactListTableInner(props, ref) {
4028
4661
  stretchColumns,
4029
4662
  resizable,
4030
4663
  storageKey,
4664
+ resolvedColumnSettingsCache,
4665
+ resolvedCachePreferences,
4031
4666
  draggable,
4032
4667
  tableId,
4033
4668
  rowDrag,
@@ -4049,6 +4684,7 @@ function ReactListTableInner(props, ref) {
4049
4684
  searchRequest,
4050
4685
  imagePreviewRequest,
4051
4686
  dangerConfirmRequest,
4687
+ exportNameRequest,
4052
4688
  closeDangerConfirmRequest
4053
4689
  } = useReactListTableState(options);
4054
4690
  const hasPagination = paginationConfig != null;
@@ -4096,6 +4732,9 @@ function ReactListTableInner(props, ref) {
4096
4732
  {
4097
4733
  title,
4098
4734
  toolbar,
4735
+ cacheColumnSettings: Boolean(storageKey) && resolvedColumnSettingsCache,
4736
+ columnSettingsCacheAvailable: Boolean(storageKey),
4737
+ onColumnSettingsCacheChange: (enabled) => tableRef.current?.setColumnSettingsCache(enabled),
4099
4738
  columns: resolvedColumns,
4100
4739
  density: resolvedRowHeight ?? 32,
4101
4740
  hostRef: shellRef,
@@ -4225,6 +4864,10 @@ function ReactListTableInner(props, ref) {
4225
4864
  /* @__PURE__ */ jsxRuntime.jsx(ReactListTableSearchDialog, { request: searchRequest }),
4226
4865
  document.body
4227
4866
  ) : null,
4867
+ exportNameRequest ? reactDom.createPortal(
4868
+ /* @__PURE__ */ jsxRuntime.jsx(ReactListTableExportNameDialog, { request: exportNameRequest }),
4869
+ document.body
4870
+ ) : null,
4228
4871
  dangerConfirmRequest ? reactDom.createPortal(
4229
4872
  /* @__PURE__ */ jsxRuntime.jsx(
4230
4873
  ReactTableDangerConfirmView,