@huibo-ui/react-antd 1.0.10 → 1.0.12
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/LICENSE +21 -0
- package/lib/components/Affix.js +1 -1
- package/lib/components/Alert.js +1 -1
- package/lib/components/Avatar.js +4 -1
- package/lib/components/BackTop.js +1 -1
- package/lib/components/Badge.js +1 -1
- package/lib/components/Breadcrumb.js +4 -2
- package/lib/components/Button.js +3 -2
- package/lib/components/Card.d.ts +14 -1
- package/lib/components/Card.js +30 -3
- package/lib/components/Checkbox.d.ts +2 -0
- package/lib/components/Checkbox.js +14 -2
- package/lib/components/Collapse.d.ts +34 -4
- package/lib/components/Collapse.js +122 -4
- package/lib/components/Descriptions.js +3 -5
- package/lib/components/Divider.d.ts +8 -0
- package/lib/components/Divider.js +38 -3
- package/lib/components/Drawer.d.ts +7 -1
- package/lib/components/Drawer.js +167 -4
- package/lib/components/Dropdown.js +1 -1
- package/lib/components/FloatButton.js +1 -1
- package/lib/components/Form.d.ts +25 -14
- package/lib/components/Form.js +315 -92
- package/lib/components/Image.js +1 -1
- package/lib/components/Input.js +25 -4
- package/lib/components/InputNumber.d.ts +1 -1
- package/lib/components/InputNumber.js +15 -1
- package/lib/components/Layout.d.ts +1 -1
- package/lib/components/Layout.js +41 -16
- package/lib/components/Menu.js +55 -11
- package/lib/components/Modal.d.ts +4 -1
- package/lib/components/Modal.js +137 -20
- package/lib/components/PageHeader.js +1 -1
- package/lib/components/Pagination.js +1 -1
- package/lib/components/Popconfirm.js +1 -1
- package/lib/components/Popover.js +1 -1
- package/lib/components/Progress.js +1 -1
- package/lib/components/Radio.d.ts +5 -3
- package/lib/components/Radio.js +24 -13
- package/lib/components/Rate.js +1 -1
- package/lib/components/Result.js +1 -1
- package/lib/components/Segmented.d.ts +5 -3
- package/lib/components/Segmented.js +4 -1
- package/lib/components/Select.js +1 -1
- package/lib/components/Slider.d.ts +9 -2
- package/lib/components/Slider.js +8 -1
- package/lib/components/Space.d.ts +2 -1
- package/lib/components/Space.js +47 -4
- package/lib/components/Spin.js +1 -1
- package/lib/components/Statistic.d.ts +1 -0
- package/lib/components/Statistic.js +5 -1
- package/lib/components/Steps.js +4 -2
- package/lib/components/Switch.d.ts +6 -0
- package/lib/components/Switch.js +15 -1
- package/lib/components/Table.js +68 -12
- package/lib/components/Tabs.js +52 -27
- package/lib/components/Tag.d.ts +1 -0
- package/lib/components/Tag.js +16 -2
- package/lib/components/TimePicker.js +1 -1
- package/lib/components/Timeline.js +9 -1
- package/lib/components/Tooltip.js +1 -1
- package/lib/components/Tree.js +2 -4
- package/lib/components/TreeSelect.d.ts +2 -0
- package/lib/components/TreeSelect.js +19 -1
- package/lib/components/Typography.js +7 -3
- package/lib/components/Upload.js +1 -1
- package/lib/components/Watermark.js +21 -1
- package/lib/components/message.js +4 -3
- package/lib/components/notification.js +3 -1
- package/package.json +5 -6
package/lib/components/Drawer.js
CHANGED
|
@@ -1,6 +1,169 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* antd Drawer 兼容层(纯 div 实现)。
|
|
5
|
+
*
|
|
6
|
+
* 不再走 <HbDrawer>(Shadow DOM slot):抽屉内容进 slot 后,<Form>/<Descriptions> 等
|
|
7
|
+
* 嵌套布局受 ::slotted 干扰。纯 div 自渲染 mask + 四方向滑入容器,children 作为真实 DOM,
|
|
8
|
+
* 嵌套复杂内容布局稳定。动画复刻 hb-drawer 的四方向 slide(@keyframes 内联,不依赖 hb-*)。
|
|
9
|
+
*/
|
|
10
|
+
// @keyframes 只需注入一次(与 Modal 共享 head,独立命名避免与 Modal 冲突)。
|
|
11
|
+
let drawerMotionInjected = false;
|
|
12
|
+
function injectDrawerMotion() {
|
|
13
|
+
if (drawerMotionInjected || typeof document === 'undefined')
|
|
14
|
+
return;
|
|
15
|
+
drawerMotionInjected = true;
|
|
16
|
+
const style = document.createElement('style');
|
|
17
|
+
style.setAttribute('data-hb-drawer-motion', '');
|
|
18
|
+
style.textContent = `
|
|
19
|
+
@keyframes hb-drawer2-overlay-in { from { opacity: 0; } to { opacity: 1; } }
|
|
20
|
+
@keyframes hb-drawer2-overlay-out { from { opacity: 1; } to { opacity: 0; } }
|
|
21
|
+
@keyframes hb-drawer2-in-ltr { from { transform: translateX(-100%); } to { transform: translateX(0); } }
|
|
22
|
+
@keyframes hb-drawer2-out-ltr { from { transform: translateX(0); } to { transform: translateX(-100%); } }
|
|
23
|
+
@keyframes hb-drawer2-in-rtl { from { transform: translateX(100%); } to { transform: translateX(0); } }
|
|
24
|
+
@keyframes hb-drawer2-out-rtl { from { transform: translateX(0); } to { transform: translateX(100%); } }
|
|
25
|
+
@keyframes hb-drawer2-in-ttb { from { transform: translateY(-100%); } to { transform: translateY(0); } }
|
|
26
|
+
@keyframes hb-drawer2-out-ttb { from { transform: translateY(0); } to { transform: translateY(-100%); } }
|
|
27
|
+
@keyframes hb-drawer2-in-btt { from { transform: translateY(100%); } to { transform: translateY(0); } }
|
|
28
|
+
@keyframes hb-drawer2-out-btt { from { transform: translateY(0); } to { transform: translateY(100%); } }
|
|
29
|
+
`;
|
|
30
|
+
document.head.appendChild(style);
|
|
31
|
+
}
|
|
32
|
+
const CloseIcon = () => (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 1024 1024", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { d: "M563.8 512l262.5-312.9c14.4-17.2.5-43.1-21.3-43.1H704.5c-7.9 0-15.4 3.5-20.5 9.5L512 417.8 339.9 165.5c-5.1-6-12.6-9.5-20.5-9.5H198.7c-21.8 0-35.7 25.9-21.3 43.1L439.9 512 177.4 824.9c-14.4 17.2-.5 43.1 21.3 43.1h120.5c7.9 0 15.4-3.5 20.5-9.5L512 606.2l172.1 252.3c5.1 6 12.6 9.5 20.5 9.5h120.5c21.8 0 35.7-25.9 21.3-43.1L563.8 512z" }) }));
|
|
33
|
+
const placementToDir = { left: 'ltr', right: 'rtl', top: 'ttb', bottom: 'btt' };
|
|
3
34
|
export function Drawer(props) {
|
|
4
|
-
const
|
|
5
|
-
|
|
35
|
+
const { open, title, placement = 'right', width, height, onClose, maskClosable = true, keyboard = true, destroyOnClose, children, footer, style, className, closable = true, } = props;
|
|
36
|
+
injectDrawerMotion();
|
|
37
|
+
const dir = placementToDir[placement];
|
|
38
|
+
const isHorizontal = placement === 'left' || placement === 'right';
|
|
39
|
+
const resolvedSize = isHorizontal
|
|
40
|
+
? width != null
|
|
41
|
+
? typeof width === 'number'
|
|
42
|
+
? `${width}px`
|
|
43
|
+
: String(width)
|
|
44
|
+
: '378px'
|
|
45
|
+
: height != null
|
|
46
|
+
? typeof height === 'number'
|
|
47
|
+
? `${height}px`
|
|
48
|
+
: String(height)
|
|
49
|
+
: '378px';
|
|
50
|
+
// 离场动画:open 由 true→false 时播放 0.3s 出场再卸载。
|
|
51
|
+
// 关键:显示条件 = open || leaving;两者都为 false 时返回 null(完全卸载),
|
|
52
|
+
// 否则 open=false 后 drawer 仍 fixed 显示,导致遮罩挡住下层、X/Esc「看似」关不掉。
|
|
53
|
+
const [leaving, setLeaving] = React.useState(false);
|
|
54
|
+
const prevOpen = React.useRef(!!open);
|
|
55
|
+
React.useEffect(() => {
|
|
56
|
+
if (open && !prevOpen.current) {
|
|
57
|
+
setLeaving(false);
|
|
58
|
+
}
|
|
59
|
+
else if (!open && prevOpen.current) {
|
|
60
|
+
setLeaving(true);
|
|
61
|
+
const t = setTimeout(() => setLeaving(false), 300);
|
|
62
|
+
return () => clearTimeout(t);
|
|
63
|
+
}
|
|
64
|
+
prevOpen.current = !!open;
|
|
65
|
+
}, [open]);
|
|
66
|
+
// Esc 关闭(必须在所有 hooks 内,不能被下面的 return null 跳过 → 否则违反 Rules of Hooks)
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
if (!open || !keyboard)
|
|
69
|
+
return;
|
|
70
|
+
const onKey = (e) => {
|
|
71
|
+
if (e.key === 'Escape')
|
|
72
|
+
onClose?.();
|
|
73
|
+
};
|
|
74
|
+
window.addEventListener('keydown', onKey);
|
|
75
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
76
|
+
}, [open, keyboard, onClose]);
|
|
77
|
+
// body 滚动锁定:弹层显示时锁住 body 滚动,避免关闭时页面因滚动条显隐而 reflow 闪烁。
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
if (!open)
|
|
80
|
+
return;
|
|
81
|
+
const body = document.body;
|
|
82
|
+
const prevOverflow = body.style.overflow;
|
|
83
|
+
const prevPaddingRight = body.style.paddingRight;
|
|
84
|
+
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
85
|
+
if (scrollbarWidth > 0)
|
|
86
|
+
body.style.paddingRight = `${scrollbarWidth}px`;
|
|
87
|
+
body.style.overflow = 'hidden';
|
|
88
|
+
return () => {
|
|
89
|
+
body.style.overflow = prevOverflow;
|
|
90
|
+
body.style.paddingRight = prevPaddingRight;
|
|
91
|
+
};
|
|
92
|
+
}, [open]);
|
|
93
|
+
// 不显示(关闭且离场动画结束)→ 完全不渲染(必须在所有 hooks 之后)
|
|
94
|
+
if (!open && !leaving)
|
|
95
|
+
return null;
|
|
96
|
+
// 容器定位(四方向)
|
|
97
|
+
const posStyle = { position: 'fixed' };
|
|
98
|
+
if (dir === 'ltr') {
|
|
99
|
+
posStyle.top = 0;
|
|
100
|
+
posStyle.left = 0;
|
|
101
|
+
posStyle.bottom = 0;
|
|
102
|
+
posStyle.width = resolvedSize;
|
|
103
|
+
posStyle.maxWidth = '100vw';
|
|
104
|
+
}
|
|
105
|
+
if (dir === 'rtl') {
|
|
106
|
+
posStyle.top = 0;
|
|
107
|
+
posStyle.right = 0;
|
|
108
|
+
posStyle.bottom = 0;
|
|
109
|
+
posStyle.width = resolvedSize;
|
|
110
|
+
posStyle.maxWidth = '100vw';
|
|
111
|
+
}
|
|
112
|
+
if (dir === 'ttb') {
|
|
113
|
+
posStyle.left = 0;
|
|
114
|
+
posStyle.right = 0;
|
|
115
|
+
posStyle.top = 0;
|
|
116
|
+
posStyle.height = resolvedSize;
|
|
117
|
+
posStyle.maxHeight = '100vh';
|
|
118
|
+
}
|
|
119
|
+
if (dir === 'btt') {
|
|
120
|
+
posStyle.left = 0;
|
|
121
|
+
posStyle.right = 0;
|
|
122
|
+
posStyle.bottom = 0;
|
|
123
|
+
posStyle.height = resolvedSize;
|
|
124
|
+
posStyle.maxHeight = '100vh';
|
|
125
|
+
}
|
|
126
|
+
return (_jsxs("div", { style: { position: 'fixed', inset: 0, zIndex: 1000, pointerEvents: 'none' }, children: [_jsx("div", { onClick: () => maskClosable && onClose?.(), style: {
|
|
127
|
+
position: 'fixed',
|
|
128
|
+
inset: 0,
|
|
129
|
+
background: 'var(--hb-color-bg-mask, rgba(0,0,0,0.45))',
|
|
130
|
+
pointerEvents: 'auto',
|
|
131
|
+
animation: `${leaving ? 'hb-drawer2-overlay-out' : 'hb-drawer2-overlay-in'} 0.3s ease both`,
|
|
132
|
+
} }), _jsxs("div", { style: {
|
|
133
|
+
...posStyle,
|
|
134
|
+
background: 'var(--hb-color-bg-elevated, #fff)',
|
|
135
|
+
boxShadow: '-6px 0 16px 0 rgba(0,0,0,0.08), -3px 0 6px -4px rgba(0,0,0,0.12), -9px 0 28px 8px rgba(0,0,0,0.05)',
|
|
136
|
+
pointerEvents: 'auto',
|
|
137
|
+
display: 'flex',
|
|
138
|
+
flexDirection: 'column',
|
|
139
|
+
zIndex: 1050,
|
|
140
|
+
animation: `${leaving ? `hb-drawer2-out-${dir}` : `hb-drawer2-in-${dir}`} 0.3s cubic-bezier(0.16, 1, 0.3, 1) both`,
|
|
141
|
+
...style,
|
|
142
|
+
}, className: className, children: [title !== undefined && (_jsxs("div", { style: {
|
|
143
|
+
display: 'flex',
|
|
144
|
+
alignItems: 'center',
|
|
145
|
+
justifyContent: 'space-between',
|
|
146
|
+
padding: '16px 24px',
|
|
147
|
+
borderBottom: '1px solid var(--hb-color-border-secondary, #f0f0f0)',
|
|
148
|
+
}, children: [_jsx("div", { style: { fontSize: 16, fontWeight: 600, color: 'var(--hb-color-text, rgba(0,0,0,0.88))' }, children: title }), closable && (_jsx("button", { type: "button", onClick: () => onClose?.(), "aria-label": "close", style: {
|
|
149
|
+
display: 'flex',
|
|
150
|
+
alignItems: 'center',
|
|
151
|
+
justifyContent: 'center',
|
|
152
|
+
width: 28,
|
|
153
|
+
height: 28,
|
|
154
|
+
border: 'none',
|
|
155
|
+
background: 'none',
|
|
156
|
+
color: 'var(--hb-color-text-secondary, rgba(0,0,0,0.45))',
|
|
157
|
+
cursor: 'pointer',
|
|
158
|
+
borderRadius: 6,
|
|
159
|
+
padding: 0,
|
|
160
|
+
transition: 'all 0.2s',
|
|
161
|
+
}, onMouseEnter: e => (e.currentTarget.style.background = 'var(--hb-color-fill-tertiary, #fafafa)'), onMouseLeave: e => (e.currentTarget.style.background = 'none'), children: _jsx(CloseIcon, {}) }))] })), _jsx("div", { style: { flex: 1, padding: 24, overflowY: 'auto' }, children: children }), footer !== null && footer !== undefined && (_jsx("div", { style: {
|
|
162
|
+
display: 'flex',
|
|
163
|
+
alignItems: 'center',
|
|
164
|
+
justifyContent: 'flex-end',
|
|
165
|
+
gap: 8,
|
|
166
|
+
padding: '8px 24px',
|
|
167
|
+
borderTop: '1px solid var(--hb-color-border-secondary, #f0f0f0)',
|
|
168
|
+
}, children: footer }))] })] }));
|
|
6
169
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { HbDropdown } from '@huibo-ui/react';
|
|
3
3
|
export function Dropdown(props) {
|
|
4
|
-
return _jsx(HbDropdown, { items: props.menu?.items || [], trigger: (props.trigger?.[0] || 'hover'), placement: props.placement, children: props.children });
|
|
4
|
+
return (_jsx(HbDropdown, { items: props.menu?.items || [], trigger: (props.trigger?.[0] || 'hover'), placement: props.placement, children: props.children }));
|
|
5
5
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { HbFloatButton } from '@huibo-ui/react';
|
|
3
3
|
export function FloatButton(props) {
|
|
4
|
-
return _jsx(HbFloatButton, { type: props.type, icon: props.icon, shape: props.shape, onHbClick: () => props.onClick?.(), children: props.children });
|
|
4
|
+
return (_jsx(HbFloatButton, { type: props.type, icon: props.icon, shape: props.shape, onHbClick: () => props.onClick?.(), children: props.children }));
|
|
5
5
|
}
|
package/lib/components/Form.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
/**
|
|
3
|
-
* antd Form
|
|
3
|
+
* antd Form 兼容层(纯 div + React 受控实现)。
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* 不再走 <HbForm>/<HbFormItem>(Shadow DOM slot):
|
|
6
|
+
* 1) hb-form-item 的 labelCol/wrapperCol 栅格、labelAlign、必填星号等布局受 Shadow DOM
|
|
7
|
+
* 限制,弹窗/卡片内嵌表单极易错位;
|
|
8
|
+
* 2) hb-form 内部靠 querySelector('hb-input,...') 取子控件 modelValue,在纯 React 子树
|
|
9
|
+
* (兼容层组件已是标准 antd 签名 value/onChange)下完全多余且脆弱。
|
|
8
10
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - validateFields / validate 保持异步(antd 本身也返回 Promise)
|
|
11
|
+
* 新方案对齐 antd 的 rc-field-form 思路:Form 持有 values/errors 的 React state,
|
|
12
|
+
* FormItem 通过 cloneElement 给唯一子控件注入 value/onChange/onChange(标准 antd 签名),
|
|
13
|
+
* 子控件作为真实 DOM 参与 flex 文档流。校验在 React 层跑,validateFields 返回 values。
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
* useForm 与 ref 共享同一份 createFormInstance 逻辑。
|
|
15
|
+
* FormInstance 保持 antd 语义:getFieldsValue/setFieldsValue/validateFields/resetFields。
|
|
16
16
|
*/
|
|
17
17
|
export interface FormInstance {
|
|
18
18
|
getFieldValue: (name: string) => any;
|
|
@@ -24,11 +24,22 @@ export interface FormInstance {
|
|
|
24
24
|
resetFields: (nameList?: string[]) => void;
|
|
25
25
|
submit: () => void;
|
|
26
26
|
scrollToField: (name: string) => void;
|
|
27
|
-
getFieldsError: () =>
|
|
27
|
+
getFieldsError: () => Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
errors: string[];
|
|
30
|
+
}>;
|
|
28
31
|
getFieldError: (name: string) => string[];
|
|
29
|
-
/**
|
|
32
|
+
/** 内部:注册字段(FormItem 挂载时调用) */
|
|
33
|
+
__registerField?: (name: string, field: FieldControl) => () => void;
|
|
34
|
+
/** scrm 兼容 */
|
|
30
35
|
handleReset?: () => void;
|
|
31
36
|
}
|
|
37
|
+
interface FieldControl {
|
|
38
|
+
setValue: (value: any) => void;
|
|
39
|
+
validate: () => Promise<string[]>;
|
|
40
|
+
setErrors: (errors: string[]) => void;
|
|
41
|
+
props: FormItemProps;
|
|
42
|
+
}
|
|
32
43
|
export interface FormProps {
|
|
33
44
|
form?: FormInstance;
|
|
34
45
|
initialValues?: Record<string, any>;
|
|
@@ -49,10 +60,11 @@ export interface FormProps {
|
|
|
49
60
|
children?: React.ReactNode;
|
|
50
61
|
style?: React.CSSProperties;
|
|
51
62
|
className?: string;
|
|
63
|
+
name?: string;
|
|
52
64
|
[key: string]: any;
|
|
53
65
|
}
|
|
54
66
|
type FormType = React.ForwardRefExoticComponent<FormProps & React.RefAttributes<FormInstance>> & {
|
|
55
|
-
Item:
|
|
67
|
+
Item: React.ComponentType<FormItemProps>;
|
|
56
68
|
useForm: () => [FormInstance];
|
|
57
69
|
useWatch: (namePath: string | string[], form?: FormInstance) => any;
|
|
58
70
|
List: any;
|
|
@@ -75,7 +87,6 @@ export interface FormItemProps {
|
|
|
75
87
|
};
|
|
76
88
|
colon?: boolean;
|
|
77
89
|
tooltip?: React.ReactNode;
|
|
78
|
-
/** antd noStyle:不额外包裹。hb-form-item 无对应概念,这里仅消费该 prop 不报错 */
|
|
79
90
|
noStyle?: boolean;
|
|
80
91
|
style?: React.CSSProperties;
|
|
81
92
|
className?: string;
|