@canvas-components/react-list-table 0.3.20 → 0.3.22
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/README.md +2 -0
- package/dist/index.cjs +138 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +139 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -321,6 +321,8 @@ import {
|
|
|
321
321
|
| `scrollTo` | `(options) => void` | 滚动到指定行 |
|
|
322
322
|
| `getDebugSnapshot` | `() => ListTableDebugSnapshot \| null` | 获取调试快照 |
|
|
323
323
|
|
|
324
|
+
导出文件名弹窗使用 `react-components` 的 `ReactModal`、`ReactInput`,默认开启,文件后缀不可编辑。通过表格 `exportOptions={{ fileName: "报表", promptFileName: false }}` 可配置默认名称并跳过弹窗;工具栏 `toolbar.exportOptions` 或实例 `exportXlsx` 的同名选项可覆盖默认配置。取消不会生成文件。XLSX 默认追加当前已显示的汇总行,传入 `includeSummary: false` 可关闭。
|
|
325
|
+
|
|
324
326
|
## 类型别名
|
|
325
327
|
|
|
326
328
|
| 类型 | 说明 |
|
package/dist/index.cjs
CHANGED
|
@@ -2680,6 +2680,58 @@ var toolButtonStyle = {
|
|
|
2680
2680
|
lineHeight: 1,
|
|
2681
2681
|
cursor: "pointer"
|
|
2682
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
|
+
}
|
|
2683
2735
|
|
|
2684
2736
|
// src/features/editor/utils.ts
|
|
2685
2737
|
function toNumberValue(value) {
|
|
@@ -2781,12 +2833,14 @@ function ReactTableEditorOverlay(props) {
|
|
|
2781
2833
|
if (!input) {
|
|
2782
2834
|
return;
|
|
2783
2835
|
}
|
|
2784
|
-
focusAndSelectEditorInput(input);
|
|
2836
|
+
focusAndSelectEditorInput(input, request.selectOnFocus);
|
|
2785
2837
|
}, [request]);
|
|
2786
2838
|
return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorHostRef, children: renderEditorByType(request, style) }, request.editorKey) });
|
|
2787
2839
|
}
|
|
2788
2840
|
function renderEditorByType(request, style) {
|
|
2789
2841
|
switch (request.config.valueType ?? "text") {
|
|
2842
|
+
case "tree-select":
|
|
2843
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TreeSelectEditor, { request, style });
|
|
2790
2844
|
case "cascader":
|
|
2791
2845
|
return /* @__PURE__ */ jsxRuntime.jsx(CascaderEditor, { request, style });
|
|
2792
2846
|
case "number":
|
|
@@ -2828,7 +2882,7 @@ function TextEditor(props) {
|
|
|
2828
2882
|
const skipBlurCommitRef = react.useRef(false);
|
|
2829
2883
|
react.useLayoutEffect(() => {
|
|
2830
2884
|
const input = hostRef.current?.querySelector("input");
|
|
2831
|
-
focusAndSelectEditorInput(input);
|
|
2885
|
+
focusAndSelectEditorInput(input, request.selectOnFocus);
|
|
2832
2886
|
}, [request]);
|
|
2833
2887
|
react.useEffect(() => {
|
|
2834
2888
|
setValue(String(request.value ?? ""));
|
|
@@ -2868,7 +2922,7 @@ function NumberEditor(props) {
|
|
|
2868
2922
|
const skipBlurCommitRef = react.useRef(false);
|
|
2869
2923
|
react.useLayoutEffect(() => {
|
|
2870
2924
|
const input = hostRef.current?.querySelector("input");
|
|
2871
|
-
focusAndSelectEditorInput(input);
|
|
2925
|
+
focusAndSelectEditorInput(input, request.selectOnFocus);
|
|
2872
2926
|
}, [request]);
|
|
2873
2927
|
react.useEffect(() => {
|
|
2874
2928
|
setValue(toNumberValue(request.value));
|
|
@@ -3077,14 +3131,56 @@ function DateEditor(props) {
|
|
|
3077
3131
|
}
|
|
3078
3132
|
) });
|
|
3079
3133
|
}
|
|
3080
|
-
function
|
|
3134
|
+
function TreeSelectEditor({
|
|
3081
3135
|
request,
|
|
3082
3136
|
style
|
|
3083
3137
|
}) {
|
|
3084
3138
|
const [value, setValue] = react.useState(
|
|
3085
|
-
|
|
3139
|
+
request.value ?? null
|
|
3086
3140
|
);
|
|
3087
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);
|
|
3088
3184
|
react.useEffect(() => {
|
|
3089
3185
|
setValue(Array.isArray(request.value) ? request.value : []);
|
|
3090
3186
|
}, [request.value]);
|
|
@@ -3098,6 +3194,8 @@ function CascaderEditor({
|
|
|
3098
3194
|
showSearch: request.config.showSearch,
|
|
3099
3195
|
allowClear: request.config.allowClear,
|
|
3100
3196
|
changeOnSelect: request.config.changeOnSelect,
|
|
3197
|
+
multiple: request.config.multiple,
|
|
3198
|
+
showCheckedStrategy: request.config.showCheckedStrategy,
|
|
3101
3199
|
expandTrigger: request.config.expandTrigger,
|
|
3102
3200
|
displayRender: request.config.displayRender,
|
|
3103
3201
|
style: getEditorInputStyle(request),
|
|
@@ -3451,13 +3549,14 @@ function handleRangeInputTab(event) {
|
|
|
3451
3549
|
focusAndSelectEditorInput(nextInput);
|
|
3452
3550
|
return true;
|
|
3453
3551
|
}
|
|
3454
|
-
function focusAndSelectEditorInput(input) {
|
|
3552
|
+
function focusAndSelectEditorInput(input, selectOnFocus = true) {
|
|
3455
3553
|
if (!input) {
|
|
3456
3554
|
return;
|
|
3457
3555
|
}
|
|
3458
3556
|
input.focus();
|
|
3459
3557
|
try {
|
|
3460
|
-
input.select();
|
|
3558
|
+
if (selectOnFocus) input.select();
|
|
3559
|
+
else input.setSelectionRange(input.value.length, input.value.length);
|
|
3461
3560
|
} catch {
|
|
3462
3561
|
}
|
|
3463
3562
|
}
|
|
@@ -3768,6 +3867,12 @@ function SettingOutlined() {
|
|
|
3768
3867
|
function HolderOutlined() {
|
|
3769
3868
|
return /* @__PURE__ */ jsxRuntime.jsx(ToolbarIcon, { path: "M300 276.5a56 56 0 1056-97 56 56 0 00-56 97zm0 284a56 56 0 1056-97 56 56 0 00-56 97zM640 228a56 56 0 10112 0 56 56 0 00-112 0zm0 284a56 56 0 10112 0 56 56 0 00-112 0zM300 844.5a56 56 0 1056-97 56 56 0 00-56 97zM640 796a56 56 0 10112 0 56 56 0 00-112 0z" });
|
|
3770
3869
|
}
|
|
3870
|
+
|
|
3871
|
+
// src/components/fullscreen-portal.ts
|
|
3872
|
+
function resolveFullscreenPortalContainer(host) {
|
|
3873
|
+
const fullscreenElement = document.fullscreenElement;
|
|
3874
|
+
return fullscreenElement instanceof HTMLElement && host && fullscreenElement.contains(host) ? fullscreenElement : document.body;
|
|
3875
|
+
}
|
|
3771
3876
|
function SortableList(props) {
|
|
3772
3877
|
const { items, onOrderChange } = props;
|
|
3773
3878
|
const rootRef = react.useRef(null);
|
|
@@ -3892,7 +3997,7 @@ function SortableList(props) {
|
|
|
3892
3997
|
})
|
|
3893
3998
|
}
|
|
3894
3999
|
),
|
|
3895
|
-
|
|
4000
|
+
resolveFullscreenPortalContainer(rootRef.current)
|
|
3896
4001
|
) : null
|
|
3897
4002
|
] });
|
|
3898
4003
|
}
|
|
@@ -4223,9 +4328,14 @@ function useReactListTableState(options) {
|
|
|
4223
4328
|
const [searchRequest, setSearchRequest] = react.useState(null);
|
|
4224
4329
|
const [imagePreviewRequest, setImagePreviewRequest] = react.useState(null);
|
|
4225
4330
|
const [dangerConfirmRequest, setDangerConfirmRequest] = react.useState(null);
|
|
4331
|
+
const [exportNameRequest, setExportNameRequest] = react.useState(null);
|
|
4226
4332
|
const uiOptions = react.useMemo(
|
|
4227
4333
|
() => ({
|
|
4228
4334
|
...options.ui,
|
|
4335
|
+
onExportNameRequest: (request) => {
|
|
4336
|
+
setExportNameRequest(request);
|
|
4337
|
+
options.ui?.onExportNameRequest?.(request);
|
|
4338
|
+
},
|
|
4229
4339
|
onEditorRequest: (request) => {
|
|
4230
4340
|
setEditorRequest(request);
|
|
4231
4341
|
options.ui?.onEditorRequest?.(request);
|
|
@@ -4293,6 +4403,7 @@ function useReactListTableState(options) {
|
|
|
4293
4403
|
setSearchRequest(null);
|
|
4294
4404
|
setImagePreviewRequest(null);
|
|
4295
4405
|
setDangerConfirmRequest(null);
|
|
4406
|
+
setExportNameRequest(null);
|
|
4296
4407
|
};
|
|
4297
4408
|
}, []);
|
|
4298
4409
|
react.useEffect(() => {
|
|
@@ -4314,6 +4425,7 @@ function useReactListTableState(options) {
|
|
|
4314
4425
|
searchRequest,
|
|
4315
4426
|
imagePreviewRequest,
|
|
4316
4427
|
dangerConfirmRequest,
|
|
4428
|
+
exportNameRequest,
|
|
4317
4429
|
closeDangerConfirmRequest: () => {
|
|
4318
4430
|
setDangerConfirmRequest(null);
|
|
4319
4431
|
options.ui?.onDangerConfirmRequest?.(null);
|
|
@@ -4418,7 +4530,8 @@ function ReactListTableInner(props, ref) {
|
|
|
4418
4530
|
rowDrag,
|
|
4419
4531
|
debug,
|
|
4420
4532
|
title,
|
|
4421
|
-
toolbar
|
|
4533
|
+
toolbar,
|
|
4534
|
+
exportOptions
|
|
4422
4535
|
} = props;
|
|
4423
4536
|
const inheritedDebugEnabled = useReactListTableDebugEnabled();
|
|
4424
4537
|
const resolvedDebug = react.useMemo(
|
|
@@ -4459,6 +4572,7 @@ function ReactListTableInner(props, ref) {
|
|
|
4459
4572
|
);
|
|
4460
4573
|
const options = react.useMemo(() => {
|
|
4461
4574
|
const nextOptions = buildListTableOptions({
|
|
4575
|
+
exportOptions,
|
|
4462
4576
|
width,
|
|
4463
4577
|
height,
|
|
4464
4578
|
emptyText,
|
|
@@ -4520,6 +4634,7 @@ function ReactListTableInner(props, ref) {
|
|
|
4520
4634
|
}
|
|
4521
4635
|
};
|
|
4522
4636
|
}, [
|
|
4637
|
+
exportOptions,
|
|
4523
4638
|
width,
|
|
4524
4639
|
height,
|
|
4525
4640
|
emptyText,
|
|
@@ -4575,10 +4690,12 @@ function ReactListTableInner(props, ref) {
|
|
|
4575
4690
|
searchRequest,
|
|
4576
4691
|
imagePreviewRequest,
|
|
4577
4692
|
dangerConfirmRequest,
|
|
4693
|
+
exportNameRequest,
|
|
4578
4694
|
closeDangerConfirmRequest
|
|
4579
4695
|
} = useReactListTableState(options);
|
|
4580
4696
|
const hasPagination = paginationConfig != null;
|
|
4581
4697
|
const paginationLayout = resolveReactListTablePaginationLayout(resolvedRowHeight);
|
|
4698
|
+
const portalContainer = resolveFullscreenPortalContainer(shellRef.current);
|
|
4582
4699
|
react.useImperativeHandle(
|
|
4583
4700
|
ref,
|
|
4584
4701
|
() => ({
|
|
@@ -4736,23 +4853,27 @@ function ReactListTableInner(props, ref) {
|
|
|
4736
4853
|
),
|
|
4737
4854
|
tooltipRequest ? reactDom.createPortal(
|
|
4738
4855
|
/* @__PURE__ */ jsxRuntime.jsx(ReactTableTooltipView, { request: tooltipRequest }),
|
|
4739
|
-
|
|
4856
|
+
portalContainer
|
|
4740
4857
|
) : null,
|
|
4741
4858
|
filterPanelRequest ? reactDom.createPortal(
|
|
4742
4859
|
/* @__PURE__ */ jsxRuntime.jsx(ReactTableFilterPanelView, { request: filterPanelRequest }),
|
|
4743
|
-
|
|
4860
|
+
portalContainer
|
|
4744
4861
|
) : null,
|
|
4745
4862
|
fixedPopupRequest ? reactDom.createPortal(
|
|
4746
4863
|
/* @__PURE__ */ jsxRuntime.jsx(ReactTableFixedPopupView, { request: fixedPopupRequest }),
|
|
4747
|
-
|
|
4864
|
+
portalContainer
|
|
4748
4865
|
) : null,
|
|
4749
4866
|
headerContextMenuRequest ? reactDom.createPortal(
|
|
4750
4867
|
/* @__PURE__ */ jsxRuntime.jsx(ReactTableContextMenuView, { request: headerContextMenuRequest }),
|
|
4751
|
-
|
|
4868
|
+
portalContainer
|
|
4752
4869
|
) : null,
|
|
4753
4870
|
searchRequest ? reactDom.createPortal(
|
|
4754
4871
|
/* @__PURE__ */ jsxRuntime.jsx(ReactListTableSearchDialog, { request: searchRequest }),
|
|
4755
|
-
|
|
4872
|
+
portalContainer
|
|
4873
|
+
) : null,
|
|
4874
|
+
exportNameRequest ? reactDom.createPortal(
|
|
4875
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReactListTableExportNameDialog, { request: exportNameRequest }),
|
|
4876
|
+
portalContainer
|
|
4756
4877
|
) : null,
|
|
4757
4878
|
dangerConfirmRequest ? reactDom.createPortal(
|
|
4758
4879
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4762,11 +4883,11 @@ function ReactListTableInner(props, ref) {
|
|
|
4762
4883
|
onClose: closeDangerConfirmRequest
|
|
4763
4884
|
}
|
|
4764
4885
|
),
|
|
4765
|
-
|
|
4886
|
+
portalContainer
|
|
4766
4887
|
) : null,
|
|
4767
4888
|
editorRequest ? reactDom.createPortal(
|
|
4768
4889
|
/* @__PURE__ */ jsxRuntime.jsx(ReactTableEditorOverlay, { request: editorRequest }),
|
|
4769
|
-
editorRequest.hostElement
|
|
4890
|
+
editorRequest.hostElement && portalContainer.contains(editorRequest.hostElement) ? editorRequest.hostElement : portalContainer
|
|
4770
4891
|
) : null,
|
|
4771
4892
|
imagePreviewRequest ? reactDom.createPortal(
|
|
4772
4893
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4778,7 +4899,7 @@ function ReactListTableInner(props, ref) {
|
|
|
4778
4899
|
onClose: imagePreviewRequest.onClose
|
|
4779
4900
|
}
|
|
4780
4901
|
),
|
|
4781
|
-
|
|
4902
|
+
portalContainer
|
|
4782
4903
|
) : null
|
|
4783
4904
|
] });
|
|
4784
4905
|
}
|