@huibo-ui/react-antd 1.0.1 → 1.0.3
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/lib/components/Button.d.ts +4 -1
- package/lib/components/Button.js +2 -2
- package/lib/components/ConfigProvider.d.ts +1 -0
- package/lib/components/DatePicker.d.ts +2 -0
- package/lib/components/Form.d.ts +26 -27
- package/lib/components/Form.js +78 -66
- package/lib/components/Input.d.ts +1 -0
- package/lib/components/Layout.d.ts +1 -0
- package/lib/components/Layout.js +6 -3
- package/lib/components/Menu.d.ts +1 -0
- package/lib/components/Modal.d.ts +1 -0
- package/lib/components/Modal.js +7 -4
- package/lib/components/Select.d.ts +1 -0
- package/lib/components/Tree.d.ts +1 -0
- package/package.json +2 -2
|
@@ -8,7 +8,10 @@ export interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonE
|
|
|
8
8
|
loading?: boolean;
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
icon?: React.ReactNode;
|
|
11
|
+
/** antd htmlType:submit/reset/button。转发到 hb-button 内部 <button type>,触发表单提交。 */
|
|
12
|
+
htmlType?: 'button' | 'submit' | 'reset';
|
|
11
13
|
children?: React.ReactNode;
|
|
12
14
|
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
15
|
+
[key: string]: any;
|
|
13
16
|
}
|
|
14
|
-
export declare function Button({ type, size, danger, block, loading, disabled, icon, children, onClick, ...rest }: ButtonProps): React.JSX.Element;
|
|
17
|
+
export declare function Button({ type, size, danger, block, loading, disabled, icon, htmlType, children, onClick, ...rest }: ButtonProps): React.JSX.Element;
|
package/lib/components/Button.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { HbButton } from '@huibo-ui/react';
|
|
3
|
-
export function Button({ type, size, danger, block, loading, disabled, icon, children, onClick, ...rest }) {
|
|
3
|
+
export function Button({ type, size, danger, block, loading, disabled, icon, htmlType, children, onClick, ...rest }) {
|
|
4
4
|
const huiboType = danger ? 'danger' : type || 'default';
|
|
5
5
|
const huiboSize = size === 'middle' ? 'default' : size || 'default';
|
|
6
|
-
return (_jsxs(HbButton, { type: huiboType, size: huiboSize, disabled: disabled, loading: loading, onClick: onClick, children: [icon, children] }));
|
|
6
|
+
return (_jsxs(HbButton, { type: huiboType, htmlType: htmlType || 'button', size: huiboSize, disabled: disabled, loading: loading, block: block, onClick: onClick, children: [icon, children] }));
|
|
7
7
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export interface DatePickerProps {
|
|
3
|
+
[key: string]: any;
|
|
3
4
|
value?: any;
|
|
4
5
|
onChange?: (value: any, dateString: string) => void;
|
|
5
6
|
picker?: 'date' | 'month' | 'year' | 'week' | 'quarter';
|
|
@@ -20,6 +21,7 @@ export declare namespace DatePicker {
|
|
|
20
21
|
var RangePicker: any;
|
|
21
22
|
}
|
|
22
23
|
export interface RangePickerProps {
|
|
24
|
+
[key: string]: any;
|
|
23
25
|
value?: any[];
|
|
24
26
|
onChange?: (dates: any[], dateStrings: [string, string]) => void;
|
|
25
27
|
format?: string;
|
package/lib/components/Form.d.ts
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
/**
|
|
3
|
-
* antd Form
|
|
3
|
+
* antd Form 兼容层(同步化版)。
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* 核心改造:hb-form 的 @Method 是异步(Promise),但 antd FormInstance 的
|
|
6
|
+
* getFieldsValue / resetFields / setFieldsValue 是同步。scrm 等业务大量
|
|
7
|
+
* `formRef.current.getFieldsValue()` 同步取值,异步会拿到 Promise 而崩。
|
|
8
|
+
*
|
|
9
|
+
* 解法:instance 内部维护同步 `values` 缓存,hbChange(onValuesChange) 实时更新;
|
|
10
|
+
* - 读方法同步返回缓存
|
|
11
|
+
* - 写方法同步更新缓存 + 异步调 hb-form @Method 落到子控件
|
|
12
|
+
* - validateFields / validate 保持异步(antd 本身也返回 Promise)
|
|
13
|
+
*
|
|
14
|
+
* Form 用 forwardRef:`<Form ref={formRef}>` 拿到同步 FormInstance。
|
|
15
|
+
* useForm 与 ref 共享同一份 createFormInstance 逻辑。
|
|
11
16
|
*/
|
|
12
17
|
export interface FormInstance {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
setFieldValue: (name: string, value: any) => Promise<void>;
|
|
18
|
-
setFieldsValue: (values: Record<string, any>) => Promise<void>;
|
|
19
|
-
/** 对齐 antd:通过 resolve(values)/reject(errorFields) */
|
|
18
|
+
getFieldValue: (name: string) => any;
|
|
19
|
+
getFieldsValue: (nameList?: string[]) => Record<string, any>;
|
|
20
|
+
setFieldValue: (name: string, value: any) => void;
|
|
21
|
+
setFieldsValue: (values: Record<string, any>) => void;
|
|
20
22
|
validateFields: (nameList?: string[]) => Promise<Record<string, any>>;
|
|
21
|
-
/** 返回布尔,对齐早期用法 */
|
|
22
23
|
validate: (nameList?: string[]) => Promise<boolean>;
|
|
23
|
-
resetFields: (nameList?: string[]) =>
|
|
24
|
-
/** 兼容 antd 上的其它常用方法(简易实现,保持不崩溃) */
|
|
24
|
+
resetFields: (nameList?: string[]) => void;
|
|
25
25
|
submit: () => void;
|
|
26
|
-
scrollToField: (
|
|
26
|
+
scrollToField: (name: string) => void;
|
|
27
27
|
getFieldsError: () => any[];
|
|
28
|
-
getFieldError: (
|
|
28
|
+
getFieldError: (name: string) => string[];
|
|
29
|
+
/** scrm 兼容:handleReset = resetFields */
|
|
30
|
+
handleReset?: () => void;
|
|
29
31
|
}
|
|
30
32
|
export interface FormProps {
|
|
31
33
|
form?: FormInstance;
|
|
@@ -47,15 +49,9 @@ export interface FormProps {
|
|
|
47
49
|
children?: React.ReactNode;
|
|
48
50
|
style?: React.CSSProperties;
|
|
49
51
|
className?: string;
|
|
52
|
+
[key: string]: any;
|
|
50
53
|
}
|
|
51
|
-
export declare
|
|
52
|
-
export declare namespace Form {
|
|
53
|
-
var Item: typeof FormItem;
|
|
54
|
-
var useForm: any;
|
|
55
|
-
var List: any;
|
|
56
|
-
var Provider: any;
|
|
57
|
-
var useWatch: any;
|
|
58
|
-
}
|
|
54
|
+
export declare const Form: React.ForwardRefExoticComponent<Omit<FormProps, "ref"> & React.RefAttributes<FormInstance>>;
|
|
59
55
|
export interface FormItemProps {
|
|
60
56
|
name?: string | string[];
|
|
61
57
|
label?: React.ReactNode;
|
|
@@ -72,8 +68,11 @@ export interface FormItemProps {
|
|
|
72
68
|
};
|
|
73
69
|
colon?: boolean;
|
|
74
70
|
tooltip?: React.ReactNode;
|
|
71
|
+
/** antd noStyle:不额外包裹。hb-form-item 无对应概念,这里仅消费该 prop 不报错 */
|
|
72
|
+
noStyle?: boolean;
|
|
75
73
|
style?: React.CSSProperties;
|
|
76
74
|
className?: string;
|
|
77
75
|
children?: React.ReactNode;
|
|
76
|
+
[key: string]: any;
|
|
78
77
|
}
|
|
79
78
|
export declare function FormItem(props: FormItemProps): React.JSX.Element;
|
package/lib/components/Form.js
CHANGED
|
@@ -1,44 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { HbForm, HbFormItem } from '@huibo-ui/react';
|
|
4
|
-
|
|
5
|
-
const { form, initialValues, onFinish, onFinishFailed, onValuesChange, layout, labelCol, children, style, className, } = props;
|
|
6
|
-
const labelPosition = layout === 'vertical' ? 'top' : layout === 'inline' ? 'left' : 'right';
|
|
7
|
-
// 延迟绑定:ref 回调把 CE 元素交给 form 实例
|
|
8
|
-
const refCallback = (el) => {
|
|
9
|
-
if (form)
|
|
10
|
-
form.__setRef(el);
|
|
11
|
-
};
|
|
12
|
-
return (_jsx(HbForm, { ref: refCallback, initialValues: initialValues, onFinish: onFinish, onFinishFailed: onFinishFailed ? (errors) => onFinishFailed({ errorFields: errors, values: {} }) : undefined, onValuesChange: onValuesChange
|
|
13
|
-
? (info) => {
|
|
14
|
-
const prop = info?.prop;
|
|
15
|
-
if (!prop)
|
|
16
|
-
return;
|
|
17
|
-
onValuesChange({ [prop]: info.value }, {});
|
|
18
|
-
}
|
|
19
|
-
: undefined, labelPosition: labelPosition, labelWidth: labelCol?.span ? `${(labelCol.span / 24) * 100}%` : '80px', style: style, className: className, children: children }));
|
|
20
|
-
}
|
|
21
|
-
export function FormItem(props) {
|
|
22
|
-
const { name, label, rules, required, labelCol, children, style, className } = props;
|
|
23
|
-
// name 可能是路径数组 ['a','b'],hb-form-item 的 prop 取路径字符串
|
|
24
|
-
const propName = Array.isArray(name) ? name.join('.') : name;
|
|
25
|
-
return (_jsx(HbFormItem, { prop: propName || '', label: typeof label === 'string' ? label : '', rules: rules || [], required: required, labelCol: labelCol?.span, style: style, className: className, children: children }));
|
|
26
|
-
}
|
|
27
|
-
Form.Item = FormItem;
|
|
28
|
-
/**
|
|
29
|
-
* useForm —— 返回 antd 风格的 form 实例。
|
|
30
|
-
* 实例方法转发到 <hb-form> CE 的 @Method。CE 尚未挂载时,方法调用会被队列等待。
|
|
31
|
-
*/
|
|
32
|
-
Form.useForm = function useForm() {
|
|
4
|
+
function createFormInstance() {
|
|
33
5
|
let ceEl = null;
|
|
34
6
|
const pending = [];
|
|
7
|
+
const values = {};
|
|
35
8
|
const bind = (el) => {
|
|
36
9
|
ceEl = el;
|
|
37
|
-
if (el)
|
|
10
|
+
if (el)
|
|
38
11
|
pending.splice(0).forEach(fn => fn());
|
|
39
|
-
}
|
|
40
12
|
};
|
|
41
|
-
/** CE 挂载前排队,挂载后立即执行;返回 promise 以兼容 await */
|
|
42
13
|
const run = (fn) => {
|
|
43
14
|
if (ceEl)
|
|
44
15
|
return fn(ceEl);
|
|
@@ -46,52 +17,93 @@ Form.useForm = function useForm() {
|
|
|
46
17
|
pending.push(() => fn(ceEl).then(resolve, reject));
|
|
47
18
|
});
|
|
48
19
|
};
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// 提交由表单内 type=submit 按钮触发;此处做兜底校验
|
|
60
|
-
run(async (el) => {
|
|
61
|
-
try {
|
|
62
|
-
await el.validateFields();
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
/* 校验失败错误已由 FormItem 展示 */
|
|
66
|
-
}
|
|
67
|
-
});
|
|
20
|
+
const inst = {
|
|
21
|
+
getFieldValue: (name) => values[name],
|
|
22
|
+
getFieldsValue: (nameList) => {
|
|
23
|
+
if (nameList && nameList.length > 0) {
|
|
24
|
+
const picked = {};
|
|
25
|
+
nameList.forEach(n => { if (n in values)
|
|
26
|
+
picked[n] = values[n]; });
|
|
27
|
+
return picked;
|
|
28
|
+
}
|
|
29
|
+
return { ...values };
|
|
68
30
|
},
|
|
31
|
+
setFieldValue: (name, value) => {
|
|
32
|
+
values[name] = value;
|
|
33
|
+
void run(el => el.setFieldValueMethod(name, value));
|
|
34
|
+
},
|
|
35
|
+
setFieldsValue: (vals) => {
|
|
36
|
+
if (vals)
|
|
37
|
+
Object.assign(values, vals);
|
|
38
|
+
void run(el => el.setFieldsValue(vals));
|
|
39
|
+
},
|
|
40
|
+
resetFields: (nameList) => {
|
|
41
|
+
if (nameList && nameList.length > 0) {
|
|
42
|
+
nameList.forEach(n => { delete values[n]; });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
Object.keys(values).forEach(k => { delete values[k]; });
|
|
46
|
+
}
|
|
47
|
+
void run(el => el.resetFields(nameList));
|
|
48
|
+
},
|
|
49
|
+
validateFields: (nameList) => run(el => el.validateFields(nameList)).then(() => ({ ...values })),
|
|
50
|
+
validate: (nameList) => run(el => (nameList ? el.validate(nameList) : el.validate())),
|
|
51
|
+
submit: () => { void run(async (el) => { try {
|
|
52
|
+
await el.validateFields();
|
|
53
|
+
}
|
|
54
|
+
catch { /* 校验失败由 FormItem 展示 */ } }); },
|
|
69
55
|
scrollToField: () => { },
|
|
70
56
|
getFieldsError: () => [],
|
|
71
57
|
getFieldError: () => [],
|
|
58
|
+
handleReset: () => inst.resetFields(),
|
|
72
59
|
};
|
|
73
|
-
|
|
60
|
+
// 内部钩子:Form 组件挂
|
|
61
|
+
inst.__setRef = bind;
|
|
62
|
+
inst.__syncValue = (prop, value) => { if (prop)
|
|
63
|
+
values[prop] = value; };
|
|
64
|
+
return inst;
|
|
65
|
+
}
|
|
66
|
+
export const Form = React.forwardRef(function Form(props, ref) {
|
|
67
|
+
const { form: formProp, initialValues, onFinish, onFinishFailed, onValuesChange, layout, labelCol, children, style, className, } = props;
|
|
68
|
+
const [innerForm] = React.useState(() => formProp || createFormInstance());
|
|
69
|
+
const form = formProp || innerForm;
|
|
70
|
+
React.useImperativeHandle(ref, () => form, [form]);
|
|
71
|
+
// initialValues 落到同步缓存 + hb-form(子控件)
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
if (initialValues) {
|
|
74
|
+
void form.setFieldsValue(initialValues);
|
|
75
|
+
}
|
|
76
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
77
|
+
}, []);
|
|
78
|
+
const labelPosition = layout === 'vertical' ? 'top' : layout === 'inline' ? 'left' : 'right';
|
|
79
|
+
const refCallback = (el) => { form.__setRef?.(el); };
|
|
80
|
+
return (_jsx(HbForm, { ref: refCallback, initialValues: initialValues, onFinish: onFinish, onFinishFailed: onFinishFailed ? (errors) => onFinishFailed({ errorFields: errors, values: {} }) : undefined, onValuesChange: (info) => {
|
|
81
|
+
const prop = info?.prop;
|
|
82
|
+
if (prop)
|
|
83
|
+
form.__syncValue?.(prop, info.value);
|
|
84
|
+
if (onValuesChange)
|
|
85
|
+
onValuesChange({ [prop]: info?.value }, {});
|
|
86
|
+
}, labelPosition: labelPosition, labelWidth: labelCol?.span ? `${(labelCol.span / 24) * 100}%` : '80px', style: style, className: className, children: children }));
|
|
87
|
+
});
|
|
88
|
+
Form.useForm = function useForm() {
|
|
89
|
+
const [f] = React.useState(createFormInstance);
|
|
90
|
+
return [f];
|
|
74
91
|
};
|
|
75
|
-
Form.List = (({ children }) => children || null);
|
|
76
|
-
Form.Provider = (({ children }) => children);
|
|
77
|
-
/**
|
|
78
|
-
* Form.useWatch —— 监听某字段值(简易实现:挂载时从 CE 取一次值)。
|
|
79
|
-
* 用于「读初始/回填值」场景;实时联动需要外层 <Form onValuesChange> 驱动,当前项目未用到联动。
|
|
80
|
-
*/
|
|
81
92
|
Form.useWatch = function useWatch(namePath, form) {
|
|
82
93
|
const name = Array.isArray(namePath) ? namePath.join('.') : namePath;
|
|
83
94
|
const [val, setVal] = React.useState(undefined);
|
|
84
95
|
React.useEffect(() => {
|
|
85
96
|
if (!form)
|
|
86
97
|
return;
|
|
87
|
-
|
|
88
|
-
form.getFieldsValue().then((all) => {
|
|
89
|
-
if (active && all && name in all)
|
|
90
|
-
setVal(all[name]);
|
|
91
|
-
});
|
|
92
|
-
return () => {
|
|
93
|
-
active = false;
|
|
94
|
-
};
|
|
98
|
+
setVal(form.getFieldValue?.(name));
|
|
95
99
|
}, [form, name]);
|
|
96
100
|
return val;
|
|
97
101
|
};
|
|
102
|
+
Form.List = (({ children }) => children || null);
|
|
103
|
+
Form.Provider = (({ children }) => children || null);
|
|
104
|
+
export function FormItem(props) {
|
|
105
|
+
const { name, label, rules, required, labelCol, noStyle, children, style, className } = props;
|
|
106
|
+
const propName = Array.isArray(name) ? name.join('.') : name;
|
|
107
|
+
return (_jsx(HbFormItem, { prop: propName || '', label: typeof label === 'string' ? label : '', rules: rules || [], required: required, labelCol: labelCol?.span, style: style, className: className, children: children }));
|
|
108
|
+
}
|
|
109
|
+
Form.Item = FormItem;
|
package/lib/components/Layout.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
2
3
|
export function Layout(props) {
|
|
3
4
|
const { children, style, className, hasSider } = props;
|
|
4
|
-
//
|
|
5
|
-
|
|
5
|
+
// antd 语义:含 Sider 直接子→水平(row);否则→垂直(column, Header 顶部)。
|
|
6
|
+
// 之前硬编码 row 导致 scrm 外层 Layout(Header+下层)横排,Header 跑到左侧。
|
|
7
|
+
const childrenArr = React.Children.toArray(children);
|
|
8
|
+
const siderDetected = hasSider || childrenArr.some(c => c?.type === Layout.Sider);
|
|
6
9
|
const flexStyle = {
|
|
7
10
|
display: 'flex',
|
|
8
|
-
flexDirection:
|
|
11
|
+
flexDirection: siderDetected ? 'row' : 'column',
|
|
9
12
|
flex: 1,
|
|
10
13
|
minHeight: 0,
|
|
11
14
|
width: '100%',
|
package/lib/components/Menu.d.ts
CHANGED
package/lib/components/Modal.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { HbDialog } from '@huibo-ui/react';
|
|
4
4
|
export function Modal(props) {
|
|
5
|
-
const { open, title, width, onCancel, maskClosable = true, keyboard = true, children } = props;
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const { open, title, width, onCancel, onOk, confirmLoading, okText, cancelText, maskClosable = true, keyboard = true, destroyOnClose, footer, children } = props;
|
|
6
|
+
// 默认 footer:OK/Cancel 按钮(对齐 antd 默认行为)。footer=null 时无底部。
|
|
7
|
+
const defaultFooter = (_jsxs("div", { style: { textAlign: 'right', marginTop: 16, display: 'flex', justifyContent: 'flex-end', gap: 8 }, children: [_jsx("button", { type: "button", onClick: (e) => onCancel?.(e), style: { padding: '4px 15px', height: 32, borderRadius: 6, border: '1px solid #d9d9d9', background: '#fff', cursor: 'pointer' }, children: cancelText || '取消' }), _jsx("button", { type: "button", disabled: confirmLoading, onClick: (e) => onOk?.(e), style: { padding: '4px 15px', height: 32, borderRadius: 6, border: 'none', background: 'var(--hb-color-primary, #ff6700)', color: '#fff', cursor: 'pointer' }, children: confirmLoading ? '加载中...' : (okText || '确定') })] }));
|
|
8
|
+
const resolvedFooter = footer === undefined ? defaultFooter : footer;
|
|
9
|
+
return (_jsxs(HbDialog, { modelValue: open || false, title: typeof title === 'string' ? title : '', width: width ? String(width) : undefined, closeOnClickModal: maskClosable, closeOnPressEscape: keyboard, destroyOnClose: destroyOnClose, showClose: true, onHbClose: () => { if (onCancel)
|
|
10
|
+
onCancel({}); }, children: [children, resolvedFooter !== null && resolvedFooter !== undefined ? resolvedFooter : null] }));
|
|
8
11
|
}
|
|
9
12
|
function imperative(opts) {
|
|
10
13
|
const div = document.createElement('div');
|
package/lib/components/Tree.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huibo-ui/react-antd",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "antd 兼容层 — 接收 antd 原生 props,内部转换为 huibo-ui,实现丝滑平替",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -30,4 +30,4 @@
|
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
32
32
|
}
|
|
33
|
-
}
|
|
33
|
+
}
|