@_tc/template-core 0.0.1-bate.37 → 0.0.1-bate.39
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/cjs/bundler/utils.js +13 -5
- package/cjs/packages/core/index.js +1 -1
- package/cjs/packages/core/loader/config.js +4 -2
- package/cjs/packages/core/loader/controller.js +2 -3
- package/cjs/packages/core/loader/extend.js +1 -2
- package/cjs/packages/core/loader/middleware.js +2 -3
- package/cjs/packages/core/loader/model.js +7 -3
- package/cjs/packages/core/loader/router-schema.js +4 -2
- package/cjs/packages/core/loader/router.js +10 -6
- package/cjs/packages/core/loader/service.js +2 -2
- package/cjs/packages/utils/runFileFn.js +46 -1
- package/esm/bundler/utils.js +13 -5
- package/esm/packages/core/index.js +1 -2
- package/esm/packages/core/loader/config.js +4 -3
- package/esm/packages/core/loader/controller.js +2 -4
- package/esm/packages/core/loader/extend.js +1 -3
- package/esm/packages/core/loader/middleware.js +2 -4
- package/esm/packages/core/loader/model.js +7 -4
- package/esm/packages/core/loader/router-schema.js +4 -3
- package/esm/packages/core/loader/router.js +10 -7
- package/esm/packages/core/loader/service.js +2 -3
- package/esm/packages/utils/runFileFn.js +47 -1
- package/fe/frontend/dash/Dashboard.js +11 -1
- package/fe/frontend/dash/dash.entry.js +19 -1
- package/fe/frontend/main.js +2 -0
- package/fe/frontend/widgets/common/CRUD/CRUD.js +1 -0
- package/fe/frontend/widgets/common/importComponent.js +1 -0
- package/fe/frontend/widgets/common/language.js +1 -0
- package/fe/frontend/widgets/common/menu.d.ts +12 -0
- package/fe/frontend/widgets/common/menu.js +21 -0
- package/fe/frontend/widgets/common/request.d.ts +3 -0
- package/fe/frontend/widgets/common/request.js +6 -0
- package/fe/frontend/widgets/components/BasePage/HeaderView.js +3 -1
- package/fe/frontend/widgets/defaultPages/Schema/components/CallCom/PopFrom.js +15 -0
- package/fe/frontend/widgets/defaultPages/Schema/components/SchemaSearch/index.js +5 -0
- package/fe/frontend/widgets/defaultPages/Schema/components/SchemaTable/index.js +13 -1
- package/fe/frontend/widgets/defaultPages/Schema/data/eventInfo.js +4 -4
- package/fe/frontend/widgets/defaultPages/Schema/index.js +7 -0
- package/fe/frontend/widgets/defaultPages/Schema/schemaType.d.ts +9 -0
- package/fe/frontend/widgets/defaultPages/Schema/stores/schemaEventBus.d.ts +19 -0
- package/fe/frontend/widgets/defaultPages/Schema/stores/schemaEventBus.js +4 -0
- package/fe/frontend/widgets/defaultPages/Schema/stores/schemaStore.d.ts +14 -0
- package/fe/frontend/widgets/defaultPages/Schema/stores/schemaStore.js +2 -0
- package/fe/frontend/widgets/defaultPages/Schema/utils/schemaConversion.js +43 -0
- package/fe/frontend/widgets/defaultPages/Schema/utils/validator.d.ts +3 -0
- package/fe/frontend/widgets/defaultPages/Schema/utils/validator.js +5 -0
- package/fe/frontend/widgets/defaultPages/SidebarSlotPage/SidebarSlotContainer.js +7 -0
- package/fe/frontend/widgets/defaultPages/SidebarSlotPage/index.js +1 -0
- package/fe/frontend/widgets/defaultPages/SlotPage/index.js +2 -0
- package/fe/frontend/widgets/hooks/useCurrentMenuData.d.ts +8 -0
- package/fe/frontend/widgets/hooks/useCurrentMenuData.js +8 -0
- package/fe/frontend/widgets/store/mode.d.ts +3 -0
- package/fe/frontend/widgets/store/mode.js +1 -0
- package/fe/model/types/data/button.d.ts +9 -0
- package/fe/model/types/data/button.js +15 -0
- package/fe/model/types/data/component.d.ts +24 -0
- package/fe/model/types/data/component.js +10 -0
- package/fe/model/types/data/fetchInfo.d.ts +12 -0
- package/fe/model/types/data/schema.d.ts +51 -0
- package/fe/model/types/menuType.d.ts +29 -0
- package/fe/model/types/model.d.ts +13 -0
- package/fe/packages/common/i18n/default.d.ts +5 -0
- package/fe/packages/common/i18n/default.js +5 -0
- package/fe/packages/common/i18n/en-US.d.ts +5 -0
- package/fe/packages/common/i18n/en-US.js +5 -0
- package/fe/packages/common/i18n/index.d.ts +24 -0
- package/fe/packages/common/i18n/index.js +31 -0
- package/fe/packages/common/i18n/types.d.ts +24 -0
- package/fe/packages/ui/react/components/Button/Button.d.ts +33 -0
- package/fe/packages/ui/react/components/Button/Button.js +3 -0
- package/fe/packages/ui/react/components/Button/SumbitButton.d.ts +4 -0
- package/fe/packages/ui/react/components/Button/SumbitButton.js +4 -0
- package/fe/packages/ui/react/components/ConfirmDialog/ConfirmDialog.d.ts +8 -0
- package/fe/packages/ui/react/components/DataTable/index.d.ts +19 -0
- package/fe/packages/ui/react/components/DataTable/index.js +4 -0
- package/fe/packages/ui/react/components/Date/Calendar.d.ts +13 -0
- package/fe/packages/ui/react/components/Date/Calendar.js +10 -1
- package/fe/packages/ui/react/components/Date/Date.d.ts +11 -0
- package/fe/packages/ui/react/components/Date/Date.js +19 -0
- package/fe/packages/ui/react/components/Date/LocaleContext.d.ts +4 -0
- package/fe/packages/ui/react/components/Date/LocaleContext.js +4 -0
- package/fe/packages/ui/react/components/Date/LocaleProvider.d.ts +11 -0
- package/fe/packages/ui/react/components/Date/LocaleProvider.js +11 -0
- package/fe/packages/ui/react/components/Date/TimePicker.js +1 -0
- package/fe/packages/ui/react/components/Date/dateLocaleStore.d.ts +6 -0
- package/fe/packages/ui/react/components/Date/locales.d.ts +19 -0
- package/fe/packages/ui/react/components/Date/locales.js +9 -0
- package/fe/packages/ui/react/components/Drawer/Drawer.d.ts +6 -0
- package/fe/packages/ui/react/components/Dropdown/Dropdown.d.ts +1 -0
- package/fe/packages/ui/react/components/Form/Form.d.ts +6 -0
- package/fe/packages/ui/react/components/Form/FormItem.d.ts +21 -0
- package/fe/packages/ui/react/components/Form/FormItem.js +8 -1
- package/fe/packages/ui/react/components/Form/SchemaForm/data.js +1 -0
- package/fe/packages/ui/react/components/Form/SchemaForm/index.d.ts +93 -0
- package/fe/packages/ui/react/components/Form/SchemaForm/index.js +5 -1
- package/fe/packages/ui/react/components/ImagePreview/ImagePreview.js +8 -0
- package/fe/packages/ui/react/components/ImagePreview/PreviewImage.d.ts +3 -0
- package/fe/packages/ui/react/components/Input/Input.d.ts +22 -0
- package/fe/packages/ui/react/components/Input/Input.js +3 -0
- package/fe/packages/ui/react/components/InputNumber/InputNumber.d.ts +2 -0
- package/fe/packages/ui/react/components/Label/Label.d.ts +29 -0
- package/fe/packages/ui/react/components/Label/Label.js +2 -0
- package/fe/packages/ui/react/components/Menu/Menu.js +4 -0
- package/fe/packages/ui/react/components/Menu/SubMenu.d.ts +7 -0
- package/fe/packages/ui/react/components/Menu/SubMenu.js +46 -1
- package/fe/packages/ui/react/components/Menu/menuTypes.d.ts +1 -0
- package/fe/packages/ui/react/components/Message/Message.d.ts +7 -0
- package/fe/packages/ui/react/components/Message/Message.js +3 -0
- package/fe/packages/ui/react/components/Message/MessageManager.js +8 -0
- package/fe/packages/ui/react/components/Modal/Modal.d.ts +6 -0
- package/fe/packages/ui/react/components/Modal/Modal.js +1 -0
- package/fe/packages/ui/react/components/Modal/ModalManager.d.ts +12 -0
- package/fe/packages/ui/react/components/Modal/ModalManager.js +4 -1
- package/fe/packages/ui/react/components/Overlay/Overlay.d.ts +3 -0
- package/fe/packages/ui/react/components/Pagination/Pagination.d.ts +7 -0
- package/fe/packages/ui/react/components/Pagination/Pagination.js +8 -1
- package/fe/packages/ui/react/components/Popup/Popup.js +14 -2
- package/fe/packages/ui/react/components/Search/Search.d.ts +3 -0
- package/fe/packages/ui/react/components/Select/Select.d.ts +5 -0
- package/fe/packages/ui/react/components/Select/Select.js +4 -0
- package/fe/packages/ui/react/components/Skeleton/Skeleton.d.ts +15 -0
- package/fe/packages/ui/react/components/Skeleton/Skeleton.js +1 -1
- package/fe/packages/ui/react/components/TableSearch/TableSearch.d.ts +37 -0
- package/fe/packages/ui/react/components/TableSearch/TableSearch.js +4 -1
- package/fe/packages/ui/react/components/Textarea/Textarea.d.ts +46 -0
- package/fe/packages/ui/react/components/Textarea/Textarea.js +1 -0
- package/fe/packages/ui/react/components/Tooltip/Tooltip.d.ts +16 -0
- package/fe/packages/ui/react/components/Tooltip/Tooltip.js +8 -0
- package/fe/packages/ui/react/components/TreeSelect/TreeSelect.d.ts +6 -0
- package/fe/packages/ui/react/components/TreeSelect/TreeSelect.js +6 -0
- package/fe/packages/ui/react/components/Upload/Upload.d.ts +27 -0
- package/fe/packages/ui/react/components/breadcrumb/breadcrumb.js +9 -0
- package/fe/packages/ui/react/components/hooks/useDropdownPositioning.d.ts +6 -0
- package/fe/packages/ui/react/components/hooks/useDropdownPositioning.js +14 -0
- package/fe/packages/ui/react/components/hooks/useInputController.d.ts +3 -0
- package/fe/packages/ui/react/components/hooks/useInputController.js +7 -0
- package/fe/packages/ui/react/components/testPage/MenuTestPage.js +3 -0
- package/fe/packages/ui/react/components/testPage/index.js +26 -0
- package/fe/packages/ui/react/hooks/useExecuteOnce.d.ts +19 -1
- package/fe/packages/ui/react/hooks/useExecuteOnce.js +22 -1
- package/fe/packages/ui/react/hooks/useRefState.d.ts +12 -0
- package/fe/packages/ui/react/hooks/useRefState.js +1 -0
- package/fe/packages/ui/react/hooks/useWatch.d.ts +8 -0
- package/fe/packages/ui/react/i18n/I18nProvider.d.ts +18 -0
- package/fe/packages/ui/react/i18n/useI18n.d.ts +4 -0
- package/fe/packages/ui/react/i18n/useI18n.js +4 -0
- package/fe/packages/ui/react/index.js +2 -0
- package/fe/packages/ui/react/lib/export.d.ts +44 -0
- package/fe/packages/ui/react/lib/export.js +40 -0
- package/fe/packages/ui/react/lib/utils.d.ts +24 -0
- package/fe/packages/ui/react/lib/utils.js +25 -0
- package/fe/packages/ui/react/stores/breadcrumb.js +2 -0
- package/model/index.d.ts +2 -0
- package/model/types/data/button.d.ts +32 -0
- package/model/types/data/component.d.ts +61 -0
- package/model/types/data/fetchInfo.d.ts +20 -0
- package/model/types/data/schema.d.ts +98 -0
- package/model/types/data/search.d.ts +7 -0
- package/model/types/index.d.ts +2 -0
- package/model/types/menuType.d.ts +73 -0
- package/model/types/model.d.ts +33 -0
- package/model/types/test.d.ts +2 -0
- package/package.json +10 -7
- package/types/packages/utils/runFileFn.d.ts +5 -3
|
@@ -10,19 +10,52 @@ export type { FieldProps, SchemaFormComponentPropsMap, SchemaFormFieldType, Sche
|
|
|
10
10
|
export type FormFieldType = SchemaFormAllFieldType;
|
|
11
11
|
type BaseField<T> = {
|
|
12
12
|
[K in keyof T]: {
|
|
13
|
+
/**
|
|
14
|
+
* 字段名
|
|
15
|
+
*/
|
|
13
16
|
key: K | number | (K | number)[];
|
|
17
|
+
/**
|
|
18
|
+
* 标签文本
|
|
19
|
+
*/
|
|
14
20
|
label?: ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* 验证规则
|
|
23
|
+
*/
|
|
15
24
|
rules?: Rule[];
|
|
25
|
+
/**
|
|
26
|
+
* 是否必填(仅用于显示,实际验证通过 rules 配置)
|
|
27
|
+
*/
|
|
16
28
|
required?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 表单项类名
|
|
31
|
+
*/
|
|
17
32
|
className?: string;
|
|
33
|
+
/**
|
|
34
|
+
* 标签类名
|
|
35
|
+
*/
|
|
18
36
|
labelClassName?: string;
|
|
37
|
+
/**
|
|
38
|
+
* 错误信息类名
|
|
39
|
+
*/
|
|
19
40
|
errorClassName?: string;
|
|
41
|
+
/**
|
|
42
|
+
* 是否显示错误信息
|
|
43
|
+
*/
|
|
20
44
|
showError?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* 自定义渲染函数
|
|
47
|
+
*/
|
|
21
48
|
render?: (value: T[K], onChange: (value: T[K]) => void, meta: {
|
|
22
49
|
errors: string[];
|
|
23
50
|
warnings: string[];
|
|
24
51
|
}) => ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* field label 布局方向
|
|
54
|
+
*/
|
|
25
55
|
layout?: Required<LabelLayout>['layout'];
|
|
56
|
+
/**
|
|
57
|
+
* 插入到控件后边
|
|
58
|
+
*/
|
|
26
59
|
affterNode?: ReactNode;
|
|
27
60
|
};
|
|
28
61
|
}[keyof T];
|
|
@@ -34,22 +67,82 @@ type GroupField<T> = {
|
|
|
34
67
|
type NotGroupField<T> = FieldProps & BaseField<T>;
|
|
35
68
|
export type FormFieldSchema<T> = GroupField<T> | NotGroupField<T>;
|
|
36
69
|
export interface SchemaFormProps<T = object> extends MOmit<FormProps<T>, 'initialValues' | 'children' | 'preserve'> {
|
|
70
|
+
/**
|
|
71
|
+
* 表单实例
|
|
72
|
+
*/
|
|
37
73
|
form?: FormInstance<T>;
|
|
74
|
+
/**
|
|
75
|
+
* 获取当前使用的form实例 只有挂载后会调用一次
|
|
76
|
+
*/
|
|
38
77
|
getForm?: (formInstance: FormInstance<T>) => void;
|
|
78
|
+
/**
|
|
79
|
+
* 表单配置方案
|
|
80
|
+
*/
|
|
39
81
|
schemas: FormFieldSchema<T>[];
|
|
82
|
+
/**
|
|
83
|
+
* 表单类名
|
|
84
|
+
*/
|
|
40
85
|
className?: string;
|
|
86
|
+
/**
|
|
87
|
+
* 提交回调
|
|
88
|
+
*/
|
|
41
89
|
onFinish?: (values: T) => void;
|
|
90
|
+
/**
|
|
91
|
+
* 提交失败回调
|
|
92
|
+
*/
|
|
42
93
|
onFinishFailed?: (errorInfo: any) => void;
|
|
94
|
+
/**
|
|
95
|
+
* 初始值
|
|
96
|
+
*/
|
|
43
97
|
initialValues?: T;
|
|
98
|
+
/**
|
|
99
|
+
* form 布局方向
|
|
100
|
+
*
|
|
101
|
+
* tips: horizontal 需自行实现提交按钮
|
|
102
|
+
*/
|
|
44
103
|
layout?: Required<LabelLayout>['layout'];
|
|
104
|
+
/**
|
|
105
|
+
* 统一配置 field layout
|
|
106
|
+
*/
|
|
45
107
|
fieldLayout?: Required<LabelLayout>['layout'];
|
|
108
|
+
/**
|
|
109
|
+
* - 是否显示提交和取消按钮
|
|
110
|
+
* - 或自定义按钮
|
|
111
|
+
* - tips button type submit 可直接触发提交
|
|
112
|
+
* @default true
|
|
113
|
+
*/
|
|
46
114
|
footerButtons?: boolean | ReactNode;
|
|
115
|
+
/**
|
|
116
|
+
* 提交按钮文本
|
|
117
|
+
* @default '提交'
|
|
118
|
+
*/
|
|
47
119
|
submitText?: ReactNode;
|
|
120
|
+
/**
|
|
121
|
+
* 取消按钮文本
|
|
122
|
+
* @default '取消'
|
|
123
|
+
*/
|
|
48
124
|
cancelText?: ReactNode;
|
|
125
|
+
/**
|
|
126
|
+
* 取消按钮回调
|
|
127
|
+
*/
|
|
49
128
|
onCancel?: () => void;
|
|
129
|
+
/**
|
|
130
|
+
* 按钮容器类名
|
|
131
|
+
*/
|
|
50
132
|
buttonClassName?: string;
|
|
133
|
+
/**
|
|
134
|
+
* 提交按钮属性
|
|
135
|
+
*/
|
|
51
136
|
submitButtonProps?: Omit<ButtonElementProps, 'type' | 'onClick' | 'children'>;
|
|
137
|
+
/**
|
|
138
|
+
* 取消按钮属性
|
|
139
|
+
*/
|
|
52
140
|
cancelButtonProps?: Omit<ButtonElementProps, 'onClick' | 'children'>;
|
|
141
|
+
/**
|
|
142
|
+
* 移除字段时保留值
|
|
143
|
+
*
|
|
144
|
+
* @default false
|
|
145
|
+
*/
|
|
53
146
|
preserve?: boolean;
|
|
54
147
|
}
|
|
55
148
|
export declare const SchemaForm: {
|
|
@@ -8,6 +8,7 @@ import { Skeleton } from '../../Skeleton';
|
|
|
8
8
|
import { componentsMap } from './data';
|
|
9
9
|
const renderField = (schema) => {
|
|
10
10
|
return (value, onChange, meta) => {
|
|
11
|
+
// 如果提供了自定义渲染函数,优先使用
|
|
11
12
|
if (schema.render) {
|
|
12
13
|
return schema.render(value, onChange, meta);
|
|
13
14
|
}
|
|
@@ -22,7 +23,9 @@ const renderField = (schema) => {
|
|
|
22
23
|
return (_jsxs(Suspense, { fallback: _jsx(Skeleton, { mode: "componentsloading", rows: 2 }), children: [_jsx(ComponentRenderer, { value: value, onChange: onChange, ...fieldProps }), schema.affterNode] }));
|
|
23
24
|
};
|
|
24
25
|
};
|
|
25
|
-
export const SchemaForm = ({ form, getForm, schemas, className, onFinish, onFinishFailed, initialValues, footerButtons = true, submitText, cancelText, onCancel, buttonClassName, submitButtonProps, layout = 'vertical', fieldLayout = 'vertical', cancelButtonProps,
|
|
26
|
+
export const SchemaForm = ({ form, getForm, schemas, className, onFinish, onFinishFailed, initialValues, footerButtons = true, submitText, cancelText, onCancel, buttonClassName, submitButtonProps, layout = 'vertical', fieldLayout = 'vertical', cancelButtonProps,
|
|
27
|
+
// preserve = false,
|
|
28
|
+
...formProps }) => {
|
|
26
29
|
const t = useI18n();
|
|
27
30
|
const [f] = useForm();
|
|
28
31
|
const getFormRef = useRef(getForm);
|
|
@@ -36,6 +39,7 @@ export const SchemaForm = ({ form, getForm, schemas, className, onFinish, onFini
|
|
|
36
39
|
onCancel();
|
|
37
40
|
}
|
|
38
41
|
else {
|
|
42
|
+
// 如果没有提供 onCancel,默认重置表单
|
|
39
43
|
usedForm?.resetFields();
|
|
40
44
|
}
|
|
41
45
|
};
|
|
@@ -126,12 +126,20 @@ function PreviewCore({ images, initialIndex, onClose }) {
|
|
|
126
126
|
if (!imgRef.current)
|
|
127
127
|
return;
|
|
128
128
|
const { naturalWidth, naturalHeight, clientWidth, clientHeight } = imgRef.current;
|
|
129
|
+
// 如果 lastScaleBeforeNatural 无值
|
|
130
|
+
// 第一次点击
|
|
131
|
+
// 将 scaleRef 复制给 lastScaleBeforeNatural
|
|
132
|
+
// 正常赋值
|
|
133
|
+
// 如果 lastScaleBeforeNatural 有值
|
|
134
|
+
// 则使用 lastScaleBeforeNatural
|
|
135
|
+
// 再清除 lastScaleBeforeNatural
|
|
129
136
|
if (lastScaleBeforeNatural.current === null) {
|
|
130
137
|
const scaleToNatural = Math.max(naturalWidth / Math.max(clientWidth, 1), naturalHeight / Math.max(clientHeight, 1), 1);
|
|
131
138
|
lastScaleBeforeNatural.current = scaleRef.current;
|
|
132
139
|
setScale(scaleToNatural);
|
|
133
140
|
}
|
|
134
141
|
else {
|
|
142
|
+
//
|
|
135
143
|
setScale(lastScaleBeforeNatural.current);
|
|
136
144
|
lastScaleBeforeNatural.current = null;
|
|
137
145
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { MOmit } from '../../types';
|
|
2
2
|
import { type ImagePreviewControllerProps } from './ImagePreview';
|
|
3
3
|
export type PreviewImageProps = MOmit<ImagePreviewControllerProps, 'open' | 'onClose'> & Pick<Partial<ImagePreviewControllerProps>, 'onClose'> & {
|
|
4
|
+
/**
|
|
5
|
+
* 缩略图边长,默认 80px
|
|
6
|
+
*/
|
|
4
7
|
thumbSize?: number | string;
|
|
5
8
|
direction?: 'horizontal' | 'vertical';
|
|
6
9
|
};
|
|
@@ -1,22 +1,44 @@
|
|
|
1
1
|
import type { ChangeEvent, InputHTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
export type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'defaultValue'> & {
|
|
3
3
|
value?: string;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param v input value
|
|
7
|
+
* @param e changeEvent
|
|
8
|
+
*/
|
|
4
9
|
onChange?: (v: string, e: ChangeEvent<HTMLInputElement>) => void;
|
|
10
|
+
/**
|
|
11
|
+
* 只有初始化时会使用
|
|
12
|
+
* 如果会改变请使用value
|
|
13
|
+
*/
|
|
5
14
|
defaultValue?: string;
|
|
6
15
|
allowClear?: boolean | {
|
|
7
16
|
clearIcon: ReactNode;
|
|
8
17
|
};
|
|
18
|
+
/** 输入框内部右侧按钮 */
|
|
9
19
|
addonAfter?: ReactNode;
|
|
20
|
+
/** 原生 input 节点的自定义 className */
|
|
10
21
|
inputClassName?: string;
|
|
11
22
|
};
|
|
12
23
|
declare const Input: import("react").ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange"> & {
|
|
13
24
|
value?: string;
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @param v input value
|
|
28
|
+
* @param e changeEvent
|
|
29
|
+
*/
|
|
14
30
|
onChange?: (v: string, e: ChangeEvent<HTMLInputElement>) => void;
|
|
31
|
+
/**
|
|
32
|
+
* 只有初始化时会使用
|
|
33
|
+
* 如果会改变请使用value
|
|
34
|
+
*/
|
|
15
35
|
defaultValue?: string;
|
|
16
36
|
allowClear?: boolean | {
|
|
17
37
|
clearIcon: ReactNode;
|
|
18
38
|
};
|
|
39
|
+
/** 输入框内部右侧按钮 */
|
|
19
40
|
addonAfter?: ReactNode;
|
|
41
|
+
/** 原生 input 节点的自定义 className */
|
|
20
42
|
inputClassName?: string;
|
|
21
43
|
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
22
44
|
export { Input };
|
|
@@ -10,6 +10,8 @@ const Input = forwardRef(({ className, inputClassName, type, value: controlledVa
|
|
|
10
10
|
ref,
|
|
11
11
|
});
|
|
12
12
|
const isFileInput = type === 'file';
|
|
13
|
+
// 在change恒定时 不重复生成 fn
|
|
14
|
+
// isControlledRef setInternalValue 都是不会变的值
|
|
13
15
|
const handleChange = useCallback((e) => {
|
|
14
16
|
const newValue = e.target.value;
|
|
15
17
|
if (!isFileInput && !isControlledRef.current) {
|
|
@@ -20,6 +22,7 @@ const Input = forwardRef(({ className, inputClassName, type, value: controlledVa
|
|
|
20
22
|
const handleClear = useCallback((e) => {
|
|
21
23
|
e.preventDefault();
|
|
22
24
|
e.stopPropagation();
|
|
25
|
+
// 非受控时更新内部状态
|
|
23
26
|
if (!isControlledRef.current) {
|
|
24
27
|
setInternalValue('');
|
|
25
28
|
}
|
|
@@ -9,6 +9,7 @@ export type InputNumberProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'defa
|
|
|
9
9
|
};
|
|
10
10
|
addonAfter?: ReactNode;
|
|
11
11
|
allowStep?: boolean;
|
|
12
|
+
/** 原生 input 节点的自定义 className */
|
|
12
13
|
inputClassName?: string;
|
|
13
14
|
};
|
|
14
15
|
declare const InputNumber: import("react").ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "type" | "defaultValue" | "onChange" | "step"> & InputNumberConstraints & {
|
|
@@ -20,6 +21,7 @@ declare const InputNumber: import("react").ForwardRefExoticComponent<Omit<InputH
|
|
|
20
21
|
};
|
|
21
22
|
addonAfter?: ReactNode;
|
|
22
23
|
allowStep?: boolean;
|
|
24
|
+
/** 原生 input 节点的自定义 className */
|
|
23
25
|
inputClassName?: string;
|
|
24
26
|
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
25
27
|
export { InputNumber };
|
|
@@ -4,17 +4,46 @@ type VerticalLayout = {
|
|
|
4
4
|
};
|
|
5
5
|
type HorizontalLayout = {
|
|
6
6
|
layout?: 'horizontal';
|
|
7
|
+
/**
|
|
8
|
+
* 标签宽度
|
|
9
|
+
* @default 'auto'
|
|
10
|
+
*/
|
|
7
11
|
labelWidth?: string | number;
|
|
12
|
+
/**
|
|
13
|
+
* 标签对齐方式
|
|
14
|
+
* @default 'left'
|
|
15
|
+
*/
|
|
8
16
|
labelAlign?: 'left' | 'right' | 'center';
|
|
9
17
|
};
|
|
10
18
|
export type LabelLayout = HorizontalLayout | VerticalLayout;
|
|
11
19
|
export type LabelProps = {
|
|
20
|
+
/**
|
|
21
|
+
* 标签文本
|
|
22
|
+
*/
|
|
12
23
|
label: ReactNode;
|
|
24
|
+
/**
|
|
25
|
+
* 标签内容
|
|
26
|
+
*/
|
|
13
27
|
children: ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* 是否必填(显示红色星号)
|
|
30
|
+
*/
|
|
14
31
|
required?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* 标签的 htmlFor 属性
|
|
34
|
+
*/
|
|
15
35
|
htmlFor?: string;
|
|
36
|
+
/**
|
|
37
|
+
* 容器类名
|
|
38
|
+
*/
|
|
16
39
|
className?: string;
|
|
40
|
+
/**
|
|
41
|
+
* 标签类名
|
|
42
|
+
*/
|
|
17
43
|
labelClassName?: string;
|
|
44
|
+
/**
|
|
45
|
+
* 内容区域类名
|
|
46
|
+
*/
|
|
18
47
|
contentClassName?: string;
|
|
19
48
|
} & LabelLayout;
|
|
20
49
|
declare const Label: import("react").ForwardRefExoticComponent<LabelProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from '../../lib/utils';
|
|
3
3
|
import { forwardRef, useMemo } from 'react';
|
|
4
|
+
// 标签对齐样式
|
|
4
5
|
const labelAlignStyles = {
|
|
5
6
|
left: 'text-left',
|
|
6
7
|
right: 'text-right',
|
|
@@ -9,6 +10,7 @@ const labelAlignStyles = {
|
|
|
9
10
|
const Label = forwardRef((props, ref) => {
|
|
10
11
|
const { label, children, layout = 'vertical', required = false, htmlFor, className, labelClassName, contentClassName, } = props;
|
|
11
12
|
const isVertical = layout === 'vertical';
|
|
13
|
+
// 标签样式
|
|
12
14
|
const labelStyles = cn('text-sm font-medium text-foreground', required && "before:content-['*'] before:pt-1 before:mr-0.5 before:text-destructive", labelClassName);
|
|
13
15
|
const { usedClassName, labelWidth } = useMemo(() => {
|
|
14
16
|
let usedLabelWidth;
|
|
@@ -19,6 +19,10 @@ export const CollapseToggle = forwardRef(({ className }, ref) => {
|
|
|
19
19
|
const onCollapse = useMenuStore((s) => s.onCollapse);
|
|
20
20
|
const propsCollapsed = useMenuStore((s) => s.propsCollapsed);
|
|
21
21
|
const shouldShowCollapseToggle = () => {
|
|
22
|
+
/**
|
|
23
|
+
* 传入 collapsed 且没有 onCollapse 时,表示折叠状态完全由外部控制。
|
|
24
|
+
* 内部控制器无法改变状态,因此不渲染。
|
|
25
|
+
*/
|
|
22
26
|
if (typeof propsCollapsed !== "undefined" &&
|
|
23
27
|
typeof onCollapse === "undefined") {
|
|
24
28
|
return false;
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type { SubMenuProps } from "./menuTypes";
|
|
2
|
+
/**
|
|
3
|
+
* 渲染带子菜单的 Menu 项。
|
|
4
|
+
*
|
|
5
|
+
* 根据当前 menu mode、收起状态、是否在弹出层内,决定子菜单是内嵌展开还是 Popup 弹出。
|
|
6
|
+
*
|
|
7
|
+
* @returns SubMenu 完整节点,包含触发区域和子菜单内容。
|
|
8
|
+
*/
|
|
2
9
|
export declare function SubMenu({ eventKey, label, icon, disabled, popup: forcePopup, parentKey, children, }: SubMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
3
10
|
//# sourceMappingURL=SubMenu.d.ts.map
|
|
@@ -7,6 +7,11 @@ import { CollapsedContext, useMenuStore } from "./MenuContext";
|
|
|
7
7
|
import { getFirstChar } from "./utils";
|
|
8
8
|
const SUBMENU_POPUP_OFFSET = 12;
|
|
9
9
|
const SubMenuLevelContext = createContext(0);
|
|
10
|
+
/**
|
|
11
|
+
* 计算 top 模式下,二级及更深层 submenu 的弹出位置。
|
|
12
|
+
*
|
|
13
|
+
* @returns 优先放在右侧;右侧空间不够时,改放到左侧。
|
|
14
|
+
*/
|
|
10
15
|
const getTopNestedSubMenuPosition = ({ anchorRect, contentRect, viewportWidth, offset, matchAnchorWidth, }) => {
|
|
11
16
|
const width = contentRect?.width ?? 0;
|
|
12
17
|
const rightLeft = anchorRect.right + offset;
|
|
@@ -19,11 +24,25 @@ const getTopNestedSubMenuPosition = ({ anchorRect, contentRect, viewportWidth, o
|
|
|
19
24
|
width: matchAnchorWidth ? anchorRect.width : undefined,
|
|
20
25
|
};
|
|
21
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* 判断当前 SubMenu 的子节点里,有没有选中的菜单项。
|
|
29
|
+
*
|
|
30
|
+
* @param children SubMenu 下面渲染出来的菜单节点。
|
|
31
|
+
* @param targetKey 当前选中的 key。
|
|
32
|
+
* @returns 子孙节点里命中选中 key 时返回 true。
|
|
33
|
+
*/
|
|
22
34
|
function hasDescendantSelected(children, targetKey) {
|
|
23
35
|
if (!targetKey)
|
|
24
36
|
return false;
|
|
25
37
|
return walkReactChildren(children, targetKey);
|
|
26
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* 递归遍历 React children,查找指定 eventKey。
|
|
41
|
+
*
|
|
42
|
+
* @param node 当前要检查的 React 节点。
|
|
43
|
+
* @param targetKey 要查找的 eventKey。
|
|
44
|
+
* @returns 当前节点或子孙节点命中时返回 true。
|
|
45
|
+
*/
|
|
27
46
|
function walkReactChildren(node, targetKey) {
|
|
28
47
|
if (!node)
|
|
29
48
|
return false;
|
|
@@ -38,6 +57,11 @@ function walkReactChildren(node, targetKey) {
|
|
|
38
57
|
}
|
|
39
58
|
return false;
|
|
40
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* 渲染 SubMenu 的触发区域,也就是能点击/hover 的那一行。
|
|
62
|
+
*
|
|
63
|
+
* @returns SubMenu trigger 节点。
|
|
64
|
+
*/
|
|
41
65
|
function SubMenuItem({ triggerRef, onClick, icon, label, disabled, collapsed, descendantSelected, ArrowIcon, showArrow, setPopupContentRef, mode, }) {
|
|
42
66
|
const collapsedLabelTooltip = useMenuStore((s) => s.collapsedLabelTooltip);
|
|
43
67
|
return (_jsxs("div", { ref: triggerRef, onClick: onClick, className: cn("subMenuItem group relative flex items-center rounded-lg text-sm transition-all", "select-none", mode === "top" &&
|
|
@@ -50,6 +74,13 @@ function SubMenuItem({ triggerRef, onClick, icon, label, disabled, collapsed, de
|
|
|
50
74
|
? "bg-theme/10 text-theme"
|
|
51
75
|
: "text-muted-foreground group-hover:text-foreground"), children: icon })), !collapsed && _jsx("span", { className: "min-w-0 flex-1 truncate", children: label }), collapsed && !icon && collapsedLabelTooltip && (_jsx("span", { className: "absolute left-0 right-0 top-0 flex h-full items-center justify-center text-[10px]", children: getFirstChar(label) })), !collapsed && showArrow && (_jsx(ArrowIcon, { className: "h-4 w-4 flex-shrink-0 text-muted-foreground transition-transform group-hover:text-foreground" })), _jsx("div", { ref: setPopupContentRef })] }));
|
|
52
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* 渲染带子菜单的 Menu 项。
|
|
79
|
+
*
|
|
80
|
+
* 根据当前 menu mode、收起状态、是否在弹出层内,决定子菜单是内嵌展开还是 Popup 弹出。
|
|
81
|
+
*
|
|
82
|
+
* @returns SubMenu 完整节点,包含触发区域和子菜单内容。
|
|
83
|
+
*/
|
|
53
84
|
export function SubMenu({ eventKey, label, icon, disabled, popup: forcePopup, parentKey, children, }) {
|
|
54
85
|
const mode = useMenuStore((s) => s.mode);
|
|
55
86
|
const expandTrigger = useMenuStore((s) => s.expandTrigger);
|
|
@@ -64,7 +95,9 @@ export function SubMenu({ eventKey, label, icon, disabled, popup: forcePopup, pa
|
|
|
64
95
|
const popupContentRef = useRef(null);
|
|
65
96
|
const [popupContainer, setPopupContainer] = useState(undefined);
|
|
66
97
|
const [popupOpen, setPopupOpen] = useState(false);
|
|
98
|
+
// 处于弹出层内:store 已收起但 context 被覆盖为 false
|
|
67
99
|
const isInsidePopup = storeCollapsed && !collapsed;
|
|
100
|
+
// mode=top always popup; left+collapsed always popup; inside popup -> popup; else check popup flag
|
|
68
101
|
const usePopup = mode === "top" ||
|
|
69
102
|
(mode === "left" && collapsed) ||
|
|
70
103
|
isInsidePopup ||
|
|
@@ -119,6 +152,18 @@ export function SubMenu({ eventKey, label, icon, disabled, popup: forcePopup, pa
|
|
|
119
152
|
const popupPlacement = mode === "top" && level === 0 ? "bottom-start" : "right-start";
|
|
120
153
|
const popupStrategy = mode === "top" && level > 0 ? getTopNestedSubMenuPosition : undefined;
|
|
121
154
|
const hoverBridgePlacement = mode === "top" && level > 0 ? "horizontal" : "auto";
|
|
122
|
-
const subMenuContent = (_jsx("div", { className: cn(
|
|
155
|
+
const subMenuContent = (_jsx("div", { className: cn(
|
|
156
|
+
// "min-w-[180px]",
|
|
157
|
+
" rounded-xl bg-muted p-2 shadow-[0_18px_44px_rgba(15,23,42,0.14),0_4px_12px_rgba(15,23,42,0.08)]"), children: _jsx(SubMenuLevelContext.Provider, { value: level + 1, children: _jsx("div", { className: "flex flex-col gap-1", children: children }) }) }));
|
|
158
|
+
/**
|
|
159
|
+
*
|
|
160
|
+
* submenu 生成的节点是 1 menuItem
|
|
161
|
+
* submenu「
|
|
162
|
+
* 1-1
|
|
163
|
+
* 1-2
|
|
164
|
+
* 」
|
|
165
|
+
*
|
|
166
|
+
* 所以判断鼠标是否在区域内应该是 监听 submenu 的根节点
|
|
167
|
+
*/
|
|
123
168
|
return (_jsxs("div", { className: "submenu", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [_jsx(SubMenuItem, { triggerRef: triggerRef, onClick: handleTriggerClick, icon: icon, label: label, disabled: disabled, collapsed: collapsed, descendantSelected: descendantSelected, ArrowIcon: ArrowIcon, showArrow: showArrow, setPopupContentRef: setPopupContentRef, mode: mode }), usePopup ? (_jsx(Popup, { open: popupOpen, anchorRef: triggerRef, placement: popupPlacement, offset: SUBMENU_POPUP_OFFSET, hoverBridge: SUBMENU_POPUP_OFFSET, onOpenChange: setPopupOpen, container: popupContainer, strategy: popupStrategy, hoverBridgePlacement: hoverBridgePlacement, className: "border-0 bg-transparent p-0 shadow-none", children: _jsx(CollapsedContext.Provider, { value: false, children: subMenuContent }) })) : (isOpen && (_jsx("div", { className: "ml-4 pl-2 pt-1", children: _jsx(SubMenuLevelContext.Provider, { value: level + 1, children: _jsx("div", { className: "flex flex-col gap-1", children: children }) }) })))] }));
|
|
124
169
|
}
|
|
@@ -4,8 +4,15 @@ export type MessageProps = {
|
|
|
4
4
|
type?: MessageType;
|
|
5
5
|
content?: ReactNode;
|
|
6
6
|
children?: ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* 存在时间
|
|
9
|
+
* @default 3000ms
|
|
10
|
+
*/
|
|
7
11
|
duration?: number;
|
|
8
12
|
onClose?: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* 可手动关闭
|
|
15
|
+
*/
|
|
9
16
|
closable?: boolean;
|
|
10
17
|
className?: string;
|
|
11
18
|
};
|
|
@@ -33,10 +33,12 @@ export function Message({ type = 'info', content, children, duration = DEFAULT_D
|
|
|
33
33
|
const iconColor = typeConfig[type].color;
|
|
34
34
|
const handleClose = () => {
|
|
35
35
|
setVisible(false);
|
|
36
|
+
// 等待动画完成后再调用 onClose
|
|
36
37
|
setTimeout(() => {
|
|
37
38
|
onClose?.();
|
|
38
39
|
}, 200);
|
|
39
40
|
};
|
|
41
|
+
// 自动关闭
|
|
40
42
|
useEffect(() => {
|
|
41
43
|
if (duration > 0) {
|
|
42
44
|
timerRef.current = setTimeout(() => {
|
|
@@ -48,6 +50,7 @@ export function Message({ type = 'info', content, children, duration = DEFAULT_D
|
|
|
48
50
|
clearTimeout(timerRef.current);
|
|
49
51
|
}
|
|
50
52
|
};
|
|
53
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
51
54
|
}, [duration]);
|
|
52
55
|
if (!visible)
|
|
53
56
|
return null;
|
|
@@ -12,17 +12,20 @@ class MessageManagerClass {
|
|
|
12
12
|
init() {
|
|
13
13
|
if (typeof document === 'undefined' || this.container)
|
|
14
14
|
return;
|
|
15
|
+
// 可见消息容器
|
|
15
16
|
this.container = document.createElement('div');
|
|
16
17
|
this.container.id = 'message-container';
|
|
17
18
|
this.container.className = 'fixed top-4 left-1/2 z-[10000] flex flex-col items-center gap-2 pointer-events-none';
|
|
18
19
|
this.container.style.transform = 'translateX(-50%)';
|
|
19
20
|
document.body.appendChild(this.container);
|
|
21
|
+
// 屏幕外消息容器 保留回调触发
|
|
20
22
|
this.offScreenContainer = document.createElement('div');
|
|
21
23
|
this.offScreenContainer.id = 'message-offscreen-container';
|
|
22
24
|
this.offScreenContainer.className =
|
|
23
25
|
'fixed -left-[9999px] top-0 z-[10000] flex flex-col items-center gap-2 pointer-events-none';
|
|
24
26
|
this.offScreenContainer.setAttribute('aria-hidden', 'true');
|
|
25
27
|
document.body.appendChild(this.offScreenContainer);
|
|
28
|
+
// 创建 React 根节点
|
|
26
29
|
this.root = createRoot(this.container);
|
|
27
30
|
this.offScreenRoot = createRoot(this.offScreenContainer);
|
|
28
31
|
this.render();
|
|
@@ -32,13 +35,17 @@ class MessageManagerClass {
|
|
|
32
35
|
return;
|
|
33
36
|
const messages = Array.from(this.messages.values());
|
|
34
37
|
const totalCount = messages.length;
|
|
38
|
+
// 可见消息:最后 maxCount 条
|
|
35
39
|
const displayMessages = totalCount > this.maxCount ? messages.slice(-this.maxCount) : messages;
|
|
40
|
+
// 屏幕外消息:除了最后 maxCount 条之外的所有消息
|
|
36
41
|
const offScreenMessages = totalCount > this.maxCount ? messages.slice(0, -this.maxCount) : [];
|
|
37
42
|
const now = Date.now();
|
|
43
|
+
// 渲染可见消息
|
|
38
44
|
this.root.render(_jsx(_Fragment, { children: displayMessages.map((message) => (_jsx(Message, { ...message, duration: message.expirationTime - now, content: message.content, onClose: () => {
|
|
39
45
|
message.onClose?.();
|
|
40
46
|
this.close(message.id);
|
|
41
47
|
} }, message.id))) }));
|
|
48
|
+
// 渲染屏幕外消息
|
|
42
49
|
this.offScreenRoot.render(_jsx(_Fragment, { children: offScreenMessages.map((message) => (_jsx(Message, { ...message, duration: message.expirationTime - now, content: message.content, onClose: () => {
|
|
43
50
|
message.onClose?.();
|
|
44
51
|
this.close(message.id);
|
|
@@ -70,6 +77,7 @@ class MessageManagerClass {
|
|
|
70
77
|
this.maxCount = count;
|
|
71
78
|
}
|
|
72
79
|
}
|
|
80
|
+
// 单例模式
|
|
73
81
|
export const messageManager = new MessageManagerClass();
|
|
74
82
|
export const message = {
|
|
75
83
|
success: (content, config) => messageManager.show({ content, ...config }, 'success'),
|
|
@@ -14,7 +14,13 @@ export type ModalProps = {
|
|
|
14
14
|
width?: number | string;
|
|
15
15
|
centered?: boolean;
|
|
16
16
|
zIndex?: number;
|
|
17
|
+
/**
|
|
18
|
+
* @default document.body
|
|
19
|
+
*/
|
|
17
20
|
renderNode?: HTMLElement | (() => HTMLElement);
|
|
21
|
+
/**
|
|
22
|
+
* 是否支持键盘关闭 默认开启
|
|
23
|
+
*/
|
|
18
24
|
keyboard?: boolean;
|
|
19
25
|
};
|
|
20
26
|
export declare function Modal({ open, onClose, title, children, footer, className, contentClassName, mask, maskClosable, lockScroll, closable, width, centered, renderNode, keyboard, zIndex, }: ModalProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,6 +6,7 @@ import { Button } from '../Button';
|
|
|
6
6
|
import { Overlay } from '../Overlay';
|
|
7
7
|
export function Modal({ open = false, onClose, title, children, footer, className, contentClassName, mask = true, maskClosable = true, lockScroll = true, closable = true, width = 520, centered = true, renderNode, keyboard = true, zIndex = 1000, }) {
|
|
8
8
|
const t = useI18n();
|
|
9
|
+
// 点击内容区域阻止冒泡
|
|
9
10
|
const handleContentClick = (e) => {
|
|
10
11
|
e.stopPropagation();
|
|
11
12
|
};
|
|
@@ -22,22 +22,34 @@ declare class ModalManagerClass {
|
|
|
22
22
|
}
|
|
23
23
|
type OpenModalConfig = Omit<ModalConfig, 'id'>;
|
|
24
24
|
export declare const openConfirmModal: (pConfig: Pick<OpenModalConfig, "content"> & {
|
|
25
|
+
/** 标题 */
|
|
25
26
|
title?: ReactNode;
|
|
27
|
+
/** 内容 */
|
|
26
28
|
content: ReactNode;
|
|
29
|
+
/** 确认按钮文本 */
|
|
27
30
|
okText?: string;
|
|
31
|
+
/** 取消按钮文本 */
|
|
28
32
|
cancelText?: string;
|
|
33
|
+
/** 确认回调 */
|
|
29
34
|
onOk?: SumbitButtonProps["onClick"];
|
|
35
|
+
/** 取消回调 */
|
|
30
36
|
onCancel?: () => void;
|
|
31
37
|
}) => string;
|
|
32
38
|
export declare const modalManager: ModalManagerClass;
|
|
33
39
|
export declare const modal: {
|
|
34
40
|
open: (config: OpenModalConfig) => string;
|
|
35
41
|
confirm: (pConfig: Pick<OpenModalConfig, "content"> & {
|
|
42
|
+
/** 标题 */
|
|
36
43
|
title?: ReactNode;
|
|
44
|
+
/** 内容 */
|
|
37
45
|
content: ReactNode;
|
|
46
|
+
/** 确认按钮文本 */
|
|
38
47
|
okText?: string;
|
|
48
|
+
/** 取消按钮文本 */
|
|
39
49
|
cancelText?: string;
|
|
50
|
+
/** 确认回调 */
|
|
40
51
|
onOk?: SumbitButtonProps["onClick"];
|
|
52
|
+
/** 取消回调 */
|
|
41
53
|
onCancel?: () => void;
|
|
42
54
|
}) => string;
|
|
43
55
|
close: (id: string) => void;
|
|
@@ -14,6 +14,7 @@ class ModalManagerClass {
|
|
|
14
14
|
this.container = document.createElement('div');
|
|
15
15
|
this.container.id = 'modal-container';
|
|
16
16
|
document.body.appendChild(this.container);
|
|
17
|
+
// 创建 React 根节点
|
|
17
18
|
this.root = createRoot(this.container);
|
|
18
19
|
this.render();
|
|
19
20
|
}
|
|
@@ -28,7 +29,7 @@ class ModalManagerClass {
|
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
open(config) {
|
|
31
|
-
this.init();
|
|
32
|
+
this.init(); // 确保已初始化
|
|
32
33
|
const id = `modal-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
33
34
|
const modalConfig = {
|
|
34
35
|
...config,
|
|
@@ -78,7 +79,9 @@ export const openConfirmModal = (pConfig) => {
|
|
|
78
79
|
const currentModalId = modalManager.open(config);
|
|
79
80
|
return currentModalId;
|
|
80
81
|
};
|
|
82
|
+
// 单例模式
|
|
81
83
|
export const modalManager = new ModalManagerClass();
|
|
84
|
+
// 函数式 API
|
|
82
85
|
export const modal = {
|
|
83
86
|
open: (config) => modalManager.open(config),
|
|
84
87
|
confirm: openConfirmModal,
|
|
@@ -14,6 +14,9 @@ export type OverlayProps = {
|
|
|
14
14
|
closable?: boolean;
|
|
15
15
|
onClose?: () => void;
|
|
16
16
|
onClick?: (e: MouseEvent<HTMLDivElement>) => void;
|
|
17
|
+
/**
|
|
18
|
+
* @default document.body
|
|
19
|
+
*/
|
|
17
20
|
renderNode?: HTMLElement | (() => HTMLElement);
|
|
18
21
|
};
|
|
19
22
|
export declare function Overlay({ open, visible, children, className, style, zIndex, mask, maskClosable, lockScroll, keyboard, closable, onClose, onClick, renderNode, }: OverlayProps): import("react").ReactPortal | null;
|