@huibo-ui/react-antd 1.0.0
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/Affix.d.ts +6 -0
- package/lib/components/Affix.js +5 -0
- package/lib/components/Alert.d.ts +10 -0
- package/lib/components/Alert.js +5 -0
- package/lib/components/Anchor.d.ts +7 -0
- package/lib/components/Anchor.js +5 -0
- package/lib/components/App.d.ts +4 -0
- package/lib/components/App.js +6 -0
- package/lib/components/Avatar.d.ts +8 -0
- package/lib/components/Avatar.js +6 -0
- package/lib/components/BackTop.d.ts +6 -0
- package/lib/components/BackTop.js +5 -0
- package/lib/components/Badge.d.ts +9 -0
- package/lib/components/Badge.js +5 -0
- package/lib/components/Breadcrumb.d.ts +12 -0
- package/lib/components/Breadcrumb.js +10 -0
- package/lib/components/Button.d.ts +14 -0
- package/lib/components/Button.js +7 -0
- package/lib/components/Card.d.ts +11 -0
- package/lib/components/Card.js +5 -0
- package/lib/components/Cascader.d.ts +12 -0
- package/lib/components/Cascader.js +5 -0
- package/lib/components/Checkbox.d.ts +18 -0
- package/lib/components/Checkbox.js +10 -0
- package/lib/components/Collapse.d.ts +11 -0
- package/lib/components/Collapse.js +7 -0
- package/lib/components/ConfigProvider.d.ts +27 -0
- package/lib/components/ConfigProvider.js +80 -0
- package/lib/components/DatePicker.d.ts +35 -0
- package/lib/components/DatePicker.js +15 -0
- package/lib/components/Descriptions.d.ts +12 -0
- package/lib/components/Descriptions.js +13 -0
- package/lib/components/Divider.d.ts +8 -0
- package/lib/components/Divider.js +5 -0
- package/lib/components/Drawer.d.ts +11 -0
- package/lib/components/Drawer.js +6 -0
- package/lib/components/Dropdown.d.ts +10 -0
- package/lib/components/Dropdown.js +5 -0
- package/lib/components/Empty.d.ts +10 -0
- package/lib/components/Empty.js +14 -0
- package/lib/components/FloatButton.d.ts +8 -0
- package/lib/components/FloatButton.js +5 -0
- package/lib/components/Form.d.ts +79 -0
- package/lib/components/Form.js +97 -0
- package/lib/components/Image.d.ts +9 -0
- package/lib/components/Image.js +5 -0
- package/lib/components/Input.d.ts +39 -0
- package/lib/components/Input.js +37 -0
- package/lib/components/InputNumber.d.ts +13 -0
- package/lib/components/InputNumber.js +5 -0
- package/lib/components/Layout.d.ts +46 -0
- package/lib/components/Layout.js +85 -0
- package/lib/components/Menu.d.ts +39 -0
- package/lib/components/Menu.js +32 -0
- package/lib/components/Modal.d.ts +26 -0
- package/lib/components/Modal.js +76 -0
- package/lib/components/PageHeader.d.ts +8 -0
- package/lib/components/PageHeader.js +5 -0
- package/lib/components/Pagination.d.ts +11 -0
- package/lib/components/Pagination.js +5 -0
- package/lib/components/Popconfirm.d.ts +10 -0
- package/lib/components/Popconfirm.js +5 -0
- package/lib/components/Popover.d.ts +8 -0
- package/lib/components/Popover.js +5 -0
- package/lib/components/Progress.d.ts +10 -0
- package/lib/components/Progress.js +5 -0
- package/lib/components/QRCode.d.ts +14 -0
- package/lib/components/QRCode.js +10 -0
- package/lib/components/Radio.d.ts +24 -0
- package/lib/components/Radio.js +23 -0
- package/lib/components/Rate.d.ts +9 -0
- package/lib/components/Rate.js +5 -0
- package/lib/components/Result.d.ts +8 -0
- package/lib/components/Result.js +5 -0
- package/lib/components/Segmented.d.ts +11 -0
- package/lib/components/Segmented.js +5 -0
- package/lib/components/Select.d.ts +30 -0
- package/lib/components/Select.js +43 -0
- package/lib/components/Skeleton.d.ts +19 -0
- package/lib/components/Skeleton.js +20 -0
- package/lib/components/Slider.d.ts +11 -0
- package/lib/components/Slider.js +5 -0
- package/lib/components/Space.d.ts +12 -0
- package/lib/components/Space.js +12 -0
- package/lib/components/Spin.d.ts +8 -0
- package/lib/components/Spin.js +8 -0
- package/lib/components/Statistic.d.ts +9 -0
- package/lib/components/Statistic.js +5 -0
- package/lib/components/Steps.d.ts +13 -0
- package/lib/components/Steps.js +7 -0
- package/lib/components/Switch.d.ts +10 -0
- package/lib/components/Switch.js +5 -0
- package/lib/components/Table.d.ts +55 -0
- package/lib/components/Table.js +187 -0
- package/lib/components/Tabs.d.ts +21 -0
- package/lib/components/Tabs.js +7 -0
- package/lib/components/Tag.d.ts +8 -0
- package/lib/components/Tag.js +6 -0
- package/lib/components/TimePicker.d.ts +11 -0
- package/lib/components/TimePicker.js +5 -0
- package/lib/components/Timeline.d.ts +7 -0
- package/lib/components/Timeline.js +5 -0
- package/lib/components/Tooltip.d.ts +7 -0
- package/lib/components/Tooltip.js +5 -0
- package/lib/components/Tour.d.ts +6 -0
- package/lib/components/Tour.js +5 -0
- package/lib/components/Tree.d.ts +22 -0
- package/lib/components/Tree.js +45 -0
- package/lib/components/TreeSelect.d.ts +11 -0
- package/lib/components/TreeSelect.js +5 -0
- package/lib/components/Typography.d.ts +10 -0
- package/lib/components/Typography.js +19 -0
- package/lib/components/Upload.d.ts +18 -0
- package/lib/components/Upload.js +12 -0
- package/lib/components/Watermark.d.ts +13 -0
- package/lib/components/Watermark.js +5 -0
- package/lib/components/message.d.ts +19 -0
- package/lib/components/message.js +32 -0
- package/lib/components/notification.d.ts +19 -0
- package/lib/components/notification.js +28 -0
- package/lib/index.d.ts +219 -0
- package/lib/index.js +123 -0
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { HbForm, HbFormItem } from '@huibo-ui/react';
|
|
4
|
+
export function Form(props) {
|
|
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() {
|
|
33
|
+
let ceEl = null;
|
|
34
|
+
const pending = [];
|
|
35
|
+
const bind = (el) => {
|
|
36
|
+
ceEl = el;
|
|
37
|
+
if (el) {
|
|
38
|
+
pending.splice(0).forEach(fn => fn());
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/** CE 挂载前排队,挂载后立即执行;返回 promise 以兼容 await */
|
|
42
|
+
const run = (fn) => {
|
|
43
|
+
if (ceEl)
|
|
44
|
+
return fn(ceEl);
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
pending.push(() => fn(ceEl).then(resolve, reject));
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const instance = {
|
|
50
|
+
__setRef: bind,
|
|
51
|
+
getFieldValue: (name) => run(el => el.getFieldValue(name)),
|
|
52
|
+
getFieldsValue: (nameList) => run(el => el.getFieldsValue(nameList)),
|
|
53
|
+
setFieldValue: (name, value) => run(el => el.setFieldValueMethod(name, value)),
|
|
54
|
+
setFieldsValue: (values) => run(el => el.setFieldsValue(values)),
|
|
55
|
+
validateFields: (nameList) => run(el => el.validateFields(nameList)),
|
|
56
|
+
validate: (nameList) => run(el => (nameList ? el.validate(nameList) : el.validate())),
|
|
57
|
+
resetFields: (nameList) => run(el => el.resetFields(nameList)),
|
|
58
|
+
submit: () => {
|
|
59
|
+
// 提交由表单内 type=submit 按钮触发;此处做兜底校验
|
|
60
|
+
run(async (el) => {
|
|
61
|
+
try {
|
|
62
|
+
await el.validateFields();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* 校验失败错误已由 FormItem 展示 */
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
scrollToField: () => { },
|
|
70
|
+
getFieldsError: () => [],
|
|
71
|
+
getFieldError: () => [],
|
|
72
|
+
};
|
|
73
|
+
return [instance];
|
|
74
|
+
};
|
|
75
|
+
Form.List = (({ children }) => children || null);
|
|
76
|
+
Form.Provider = (({ children }) => children);
|
|
77
|
+
/**
|
|
78
|
+
* Form.useWatch —— 监听某字段值(简易实现:挂载时从 CE 取一次值)。
|
|
79
|
+
* 用于「读初始/回填值」场景;实时联动需要外层 <Form onValuesChange> 驱动,当前项目未用到联动。
|
|
80
|
+
*/
|
|
81
|
+
Form.useWatch = function useWatch(namePath, form) {
|
|
82
|
+
const name = Array.isArray(namePath) ? namePath.join('.') : namePath;
|
|
83
|
+
const [val, setVal] = React.useState(undefined);
|
|
84
|
+
React.useEffect(() => {
|
|
85
|
+
if (!form)
|
|
86
|
+
return;
|
|
87
|
+
let active = true;
|
|
88
|
+
form.getFieldsValue().then((all) => {
|
|
89
|
+
if (active && all && name in all)
|
|
90
|
+
setVal(all[name]);
|
|
91
|
+
});
|
|
92
|
+
return () => {
|
|
93
|
+
active = false;
|
|
94
|
+
};
|
|
95
|
+
}, [form, name]);
|
|
96
|
+
return val;
|
|
97
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HbImage } from '@huibo-ui/react';
|
|
3
|
+
export function Image(props) {
|
|
4
|
+
return _jsx(HbImage, { src: props.src || '', width: props.width ? String(props.width) : undefined, height: props.height ? String(props.height) : undefined, preview: props.preview, alt: props.alt, style: props.style });
|
|
5
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface InputProps {
|
|
3
|
+
value?: string;
|
|
4
|
+
defaultValue?: string;
|
|
5
|
+
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
6
|
+
onInput?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
7
|
+
onPressEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
size?: 'small' | 'middle' | 'large';
|
|
12
|
+
allowClear?: boolean;
|
|
13
|
+
showCount?: boolean;
|
|
14
|
+
maxLength?: number;
|
|
15
|
+
prefix?: React.ReactNode;
|
|
16
|
+
suffix?: React.ReactNode;
|
|
17
|
+
addonBefore?: React.ReactNode;
|
|
18
|
+
addonAfter?: React.ReactNode;
|
|
19
|
+
type?: string;
|
|
20
|
+
style?: React.CSSProperties;
|
|
21
|
+
className?: string;
|
|
22
|
+
id?: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
autoFocus?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function Input(props: InputProps): React.JSX.Element;
|
|
27
|
+
export declare namespace Input {
|
|
28
|
+
var TextArea: any;
|
|
29
|
+
var Password: any;
|
|
30
|
+
var Search: any;
|
|
31
|
+
}
|
|
32
|
+
export interface TextAreaProps extends InputProps {
|
|
33
|
+
rows?: number;
|
|
34
|
+
autoSize?: boolean | {
|
|
35
|
+
minRows?: number;
|
|
36
|
+
maxRows?: number;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export { Input as TextArea };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { HbInput } from '@huibo-ui/react';
|
|
3
|
+
export function Input(props) {
|
|
4
|
+
const { value, onChange, onInput, placeholder, disabled, readOnly, size, allowClear, showCount, maxLength, prefix, suffix, addonBefore, addonAfter, type, style, className, id, name, } = props;
|
|
5
|
+
return (_jsx(HbInput, { modelValue: value ?? '', placeholder: placeholder, disabled: disabled, readonly: readOnly, size: size === 'middle' ? 'default' : size, clearable: allowClear, showWordLimit: showCount, maxlength: maxLength, type: type === 'password' ? 'password' : 'text', inputId: id, name: name, style: style,
|
|
6
|
+
// antd onChange 接收 React.ChangeEvent,huibo hbChange 接收 CustomEvent<string>
|
|
7
|
+
onHbChange: (e) => {
|
|
8
|
+
if (onChange)
|
|
9
|
+
onChange({ target: { value: e.detail } });
|
|
10
|
+
}, onHbInput: (e) => {
|
|
11
|
+
if (onInput)
|
|
12
|
+
onInput({ target: { value: e.detail } });
|
|
13
|
+
} }));
|
|
14
|
+
}
|
|
15
|
+
Input.TextArea = function TextArea(props) {
|
|
16
|
+
return _jsx(Input, { ...props, type: "textarea" });
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Input.Password —— 复用 Input,通过 type="password"(hb-input 的 showPassword 视觉由其内部决定)。
|
|
20
|
+
*/
|
|
21
|
+
Input.Password = function Password(props) {
|
|
22
|
+
return _jsx(Input, { ...props, type: "password" });
|
|
23
|
+
};
|
|
24
|
+
Input.Search = function Search(props) {
|
|
25
|
+
const { onSearch, enterButton, ...rest } = props;
|
|
26
|
+
const handleSearch = (e) => {
|
|
27
|
+
const v = (e?.target?.value ?? rest.value ?? '');
|
|
28
|
+
onSearch?.(v, e);
|
|
29
|
+
};
|
|
30
|
+
const triggerFromInput = (e) => {
|
|
31
|
+
// 维持受控值
|
|
32
|
+
rest.onChange?.(e);
|
|
33
|
+
};
|
|
34
|
+
return (_jsxs("span", { style: { display: 'inline-flex', alignItems: 'center', width: rest.style?.width || '100%' }, children: [_jsx(Input, { ...rest, onChange: triggerFromInput, onPressEnter: (e) => handleSearch(e) }), enterButton ? (_jsx("span", { style: { marginLeft: 8, cursor: 'pointer', color: '#1677ff' }, onClick: () => handleSearch({ target: { value: rest.value } }), children: typeof enterButton === 'boolean' ? '搜索' : enterButton })) : (_jsx("span", { style: { marginLeft: 4, cursor: 'pointer', color: '#1677ff' }, onClick: () => handleSearch({ target: { value: rest.value } }), children: "\u641C\u7D22" }))] }));
|
|
35
|
+
};
|
|
36
|
+
// 具名导出 TextArea(兼容 import { TextArea } from '@huibo-ui/react-antd')
|
|
37
|
+
export { Input as TextArea };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function InputNumber(props: {
|
|
3
|
+
value?: number;
|
|
4
|
+
onChange?: (value: number) => void;
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
step?: number;
|
|
8
|
+
precision?: number;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
size?: 'small' | 'middle' | 'large';
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
style?: React.CSSProperties;
|
|
13
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HbInputNumber } from '@huibo-ui/react';
|
|
3
|
+
export function InputNumber(props) {
|
|
4
|
+
return _jsx(HbInputNumber, { modelValue: props.value ?? 0, min: props.min, max: props.max, step: props.step, precision: props.precision, disabled: props.disabled, size: props.size === 'middle' ? 'default' : props.size, placeholder: props.placeholder, style: props.style, onHbChange: (e) => props.onChange?.(e.detail) });
|
|
5
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Layout 兼容层。
|
|
4
|
+
*
|
|
5
|
+
* antd Layout 基于 React Context 自动判断方向(嵌套的 Layout 变成 vertical)。
|
|
6
|
+
* 这里改用普通 div + flex 实现:外层 Layout 默认水平(sider | 右侧),
|
|
7
|
+
* 内层 Layout 通过 className(flex flex-col)或显式 hasSider=false 转垂直。
|
|
8
|
+
*
|
|
9
|
+
* 不用 hb-container:它的 ::slotted 机制在 antd 嵌套 Layout 场景下不可靠
|
|
10
|
+
* (slotted 样式、flex 方向、宽度计算都会出问题)。纯 div + flex 最可控,
|
|
11
|
+
* 且消费方的 Tailwind className(full / flex flex-col / h-full)能直接生效。
|
|
12
|
+
*/
|
|
13
|
+
export interface LayoutProps {
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
style?: React.CSSProperties;
|
|
16
|
+
className?: string;
|
|
17
|
+
/** antd hasSider:true=水平排列(sider 在左);false/默认=由 className 决定 */
|
|
18
|
+
hasSider?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function Layout(props: LayoutProps): React.JSX.Element;
|
|
21
|
+
export declare namespace Layout {
|
|
22
|
+
var Header: ({ children, style, className }: any) => React.JSX.Element;
|
|
23
|
+
var Sider: ({ children, style, className, collapsed, theme, width, collapsedWidth }: any) => React.JSX.Element;
|
|
24
|
+
var Content: ({ children, style, className }: any) => React.JSX.Element;
|
|
25
|
+
var Footer: ({ children, style, className }: any) => React.JSX.Element;
|
|
26
|
+
}
|
|
27
|
+
export declare function Row(props: {
|
|
28
|
+
gutter?: number | number[];
|
|
29
|
+
justify?: string;
|
|
30
|
+
align?: string;
|
|
31
|
+
children?: React.ReactNode;
|
|
32
|
+
style?: React.CSSProperties;
|
|
33
|
+
className?: string;
|
|
34
|
+
}): React.JSX.Element;
|
|
35
|
+
export declare function Col(props: {
|
|
36
|
+
span?: number;
|
|
37
|
+
offset?: number;
|
|
38
|
+
xs?: number;
|
|
39
|
+
sm?: number;
|
|
40
|
+
md?: number;
|
|
41
|
+
lg?: number;
|
|
42
|
+
xl?: number;
|
|
43
|
+
children?: React.ReactNode;
|
|
44
|
+
style?: React.CSSProperties;
|
|
45
|
+
className?: string;
|
|
46
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function Layout(props) {
|
|
3
|
+
const { children, style, className, hasSider } = props;
|
|
4
|
+
// 默认 flex 行布局(sider + 右侧);若 className 含 flex-col 则尊重它(垂直)
|
|
5
|
+
const isVertical = className && /flex-col|flex-direction:\s*column/.test(className);
|
|
6
|
+
const flexStyle = {
|
|
7
|
+
display: 'flex',
|
|
8
|
+
flexDirection: isVertical ? 'column' : 'row',
|
|
9
|
+
flex: 1,
|
|
10
|
+
minHeight: 0,
|
|
11
|
+
width: '100%',
|
|
12
|
+
...style,
|
|
13
|
+
};
|
|
14
|
+
return (_jsx("div", { style: flexStyle, className: className, children: children }));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Header —— 顶栏。固定高度、block,让消费方 className(flex/h-64/bg-white)生效。
|
|
18
|
+
*/
|
|
19
|
+
Layout.Header = function Header({ children, style, className }) {
|
|
20
|
+
return (_jsx("div", { style: { flexShrink: 0, ...style }, className: className, children: children }));
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Sider —— 侧边栏。固定宽度(或 collapsed 宽度),block。
|
|
24
|
+
*/
|
|
25
|
+
Layout.Sider = function Sider({ children, style, className, collapsed, theme, width, collapsedWidth }) {
|
|
26
|
+
const w = width || (collapsed ? collapsedWidth || 60 : 200);
|
|
27
|
+
return (_jsx("div", { style: { width: typeof w === 'number' ? `${w}px` : w, flexShrink: 0, ...style }, className: className, "data-collapsed": collapsed, "data-theme": theme, children: children }));
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Content —— 主内容区。flex:1 撑满剩余空间。
|
|
31
|
+
*/
|
|
32
|
+
Layout.Content = function Content({ children, style, className }) {
|
|
33
|
+
return (_jsx("div", { style: { flex: 1, minWidth: 0, minHeight: 0, ...style }, className: className, children: children }));
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Footer —— 页脚。固定高度。
|
|
37
|
+
*/
|
|
38
|
+
Layout.Footer = function Footer({ children, style, className }) {
|
|
39
|
+
return (_jsx("div", { style: { flexShrink: 0, ...style }, className: className, children: children }));
|
|
40
|
+
};
|
|
41
|
+
export function Row(props) {
|
|
42
|
+
const gutter = Array.isArray(props.gutter) ? props.gutter[0] : props.gutter;
|
|
43
|
+
const gap = gutter ? `${gutter}px` : undefined;
|
|
44
|
+
const justifyMap = {
|
|
45
|
+
start: 'flex-start',
|
|
46
|
+
end: 'flex-end',
|
|
47
|
+
center: 'center',
|
|
48
|
+
'space-between': 'space-between',
|
|
49
|
+
'space-around': 'space-around',
|
|
50
|
+
};
|
|
51
|
+
return (_jsx("div", { style: {
|
|
52
|
+
display: 'flex',
|
|
53
|
+
flexWrap: 'wrap',
|
|
54
|
+
gap,
|
|
55
|
+
justifyContent: props.justify ? justifyMap[props.justify] || props.justify : undefined,
|
|
56
|
+
alignItems: props.align,
|
|
57
|
+
...props.style,
|
|
58
|
+
}, className: props.className, children: props.children }));
|
|
59
|
+
}
|
|
60
|
+
// Col:用 CSS 百分比宽度实现栅格,支持响应式 xl/lg/md/sm/xs
|
|
61
|
+
export function Col(props) {
|
|
62
|
+
// 响应式:取当前视口匹配的最大断点(xl>lg>md>sm>xs),都没有则用 span(默认 24)
|
|
63
|
+
const resolveSpan = () => {
|
|
64
|
+
if (typeof window !== 'undefined') {
|
|
65
|
+
const w = window.innerWidth;
|
|
66
|
+
// antd 断点:xl≥1200, lg≥992, md≥768, sm≥576, xs<576
|
|
67
|
+
if (w >= 1200 && props.xl != null)
|
|
68
|
+
return props.xl;
|
|
69
|
+
if (w >= 992 && props.lg != null)
|
|
70
|
+
return props.lg;
|
|
71
|
+
if (w >= 768 && props.md != null)
|
|
72
|
+
return props.md;
|
|
73
|
+
if (w >= 576 && props.sm != null)
|
|
74
|
+
return props.sm;
|
|
75
|
+
if (w < 576 && props.xs != null)
|
|
76
|
+
return props.xs;
|
|
77
|
+
}
|
|
78
|
+
// 兜底:取最大配置过的断点(桌面端常用 xl/lg)
|
|
79
|
+
return props.xl ?? props.lg ?? props.md ?? props.sm ?? props.xs ?? props.span ?? 24;
|
|
80
|
+
};
|
|
81
|
+
const span = resolveSpan();
|
|
82
|
+
const pct = (span / 24) * 100;
|
|
83
|
+
const offsetPct = props.offset ? (props.offset / 24) * 100 : 0;
|
|
84
|
+
return (_jsx("div", { style: { width: `${pct}%`, marginLeft: offsetPct ? `${offsetPct}%` : undefined, boxSizing: 'border-box', ...props.style }, className: props.className, children: props.children }));
|
|
85
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface MenuItemType {
|
|
3
|
+
key: string;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
icon?: React.ReactNode;
|
|
6
|
+
children?: MenuItemType[];
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface MenuProps {
|
|
10
|
+
items?: MenuItemType[];
|
|
11
|
+
mode?: 'horizontal' | 'vertical' | 'inline';
|
|
12
|
+
selectedKeys?: string[];
|
|
13
|
+
openKeys?: string[];
|
|
14
|
+
theme?: 'light' | 'dark';
|
|
15
|
+
inlineCollapsed?: boolean;
|
|
16
|
+
onClick?: (info: {
|
|
17
|
+
key: string;
|
|
18
|
+
keyPath: string[];
|
|
19
|
+
}) => void;
|
|
20
|
+
onOpenChange?: (openKeys: string[]) => void;
|
|
21
|
+
onSelect?: (info: {
|
|
22
|
+
key: string;
|
|
23
|
+
keyPath: string[];
|
|
24
|
+
}) => void;
|
|
25
|
+
style?: React.CSSProperties;
|
|
26
|
+
className?: string;
|
|
27
|
+
children?: React.ReactNode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* antd Menu 兼容层。
|
|
31
|
+
*
|
|
32
|
+
* 关键:hb-menu 的 `items` 是数组,React 包装层(createReactComponent)只在
|
|
33
|
+
* componentDidUpdate 时把数组同步为 DOM 属性,首渲染(componentDidLoad)时 items 为
|
|
34
|
+
* undefined → hb-menu 走 <slot/> 分支渲染空。因此这里用 ref 在挂载时立即同步 items。
|
|
35
|
+
*/
|
|
36
|
+
export declare function Menu(props: MenuProps): React.JSX.Element;
|
|
37
|
+
export declare namespace Menu {
|
|
38
|
+
var Item: any;
|
|
39
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { HbMenu, HbMenuItem } from '@huibo-ui/react';
|
|
4
|
+
/**
|
|
5
|
+
* antd Menu 兼容层。
|
|
6
|
+
*
|
|
7
|
+
* 关键:hb-menu 的 `items` 是数组,React 包装层(createReactComponent)只在
|
|
8
|
+
* componentDidUpdate 时把数组同步为 DOM 属性,首渲染(componentDidLoad)时 items 为
|
|
9
|
+
* undefined → hb-menu 走 <slot/> 分支渲染空。因此这里用 ref 在挂载时立即同步 items。
|
|
10
|
+
*/
|
|
11
|
+
export function Menu(props) {
|
|
12
|
+
const { items, mode, selectedKeys, openKeys, theme, inlineCollapsed, onClick, onOpenChange, style, className, children } = props;
|
|
13
|
+
const refCallback = (el) => {
|
|
14
|
+
// 立即把 items 数组同步到 CE(绕过 Stencil 只把 string/bool/number 设为 attribute 的限制)
|
|
15
|
+
if (el && items) {
|
|
16
|
+
el.items = items;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
return (_jsx(HbMenu, { ref: refCallback, items: items, mode: (mode === 'inline' ? 'vertical' : mode), selectedKeys: selectedKeys, openKeys: openKeys, theme: theme, collapsed: inlineCollapsed, style: style, className: className, onHbSelect: (e) => {
|
|
20
|
+
const key = e?.detail;
|
|
21
|
+
if (onClick)
|
|
22
|
+
onClick({ key, keyPath: [key] });
|
|
23
|
+
if (props.onSelect)
|
|
24
|
+
props.onSelect({ key, keyPath: [key] });
|
|
25
|
+
}, onHbOpenChange: (e) => {
|
|
26
|
+
if (onOpenChange)
|
|
27
|
+
onOpenChange(e?.detail || []);
|
|
28
|
+
}, children: children }));
|
|
29
|
+
}
|
|
30
|
+
Menu.Item = function MenuItem({ children, key: itemKey, disabled, onClick }) {
|
|
31
|
+
return React.createElement(HbMenuItem, { itemKey, disabled, onClick }, children);
|
|
32
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ModalProps {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
title?: React.ReactNode;
|
|
5
|
+
width?: string | number;
|
|
6
|
+
onCancel?: (e: React.MouseEvent) => void;
|
|
7
|
+
onOk?: (e: React.MouseEvent) => void;
|
|
8
|
+
confirmLoading?: boolean;
|
|
9
|
+
okText?: string;
|
|
10
|
+
cancelText?: string;
|
|
11
|
+
maskClosable?: boolean;
|
|
12
|
+
keyboard?: boolean;
|
|
13
|
+
destroyOnClose?: boolean;
|
|
14
|
+
footer?: React.ReactNode | null;
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
export declare function Modal(props: ModalProps): React.JSX.Element;
|
|
19
|
+
export declare namespace Modal {
|
|
20
|
+
var confirm: any;
|
|
21
|
+
var info: any;
|
|
22
|
+
var warning: any;
|
|
23
|
+
var success: any;
|
|
24
|
+
var error: any;
|
|
25
|
+
var useModal: any;
|
|
26
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { HbDialog } from '@huibo-ui/react';
|
|
4
|
+
export function Modal(props) {
|
|
5
|
+
const { open, title, width, onCancel, maskClosable = true, keyboard = true, children } = props;
|
|
6
|
+
return (_jsxs(HbDialog, { modelValue: open || false, title: typeof title === 'string' ? title : '', width: width ? String(width) : undefined, closeOnClickModal: maskClosable, closeOnPressEscape: keyboard, showClose: true, onHbClose: () => { if (onCancel)
|
|
7
|
+
onCancel({}); }, children: [children, props.footer !== null && props.footer !== undefined ? props.footer : null] }));
|
|
8
|
+
}
|
|
9
|
+
function imperative(opts) {
|
|
10
|
+
const div = document.createElement('div');
|
|
11
|
+
document.body.appendChild(div);
|
|
12
|
+
let destroyed = false;
|
|
13
|
+
const destroy = () => {
|
|
14
|
+
if (destroyed)
|
|
15
|
+
return;
|
|
16
|
+
destroyed = true;
|
|
17
|
+
if (!root) {
|
|
18
|
+
// createRoot 尚未就绪(import 未完成),直接移除容器
|
|
19
|
+
div.remove();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
root.render(React.createElement(Modal, { open: false, title: opts.title }, opts.content));
|
|
23
|
+
setTimeout(() => {
|
|
24
|
+
root.unmount();
|
|
25
|
+
div.remove();
|
|
26
|
+
}, 200);
|
|
27
|
+
};
|
|
28
|
+
let root;
|
|
29
|
+
// 动态拿到 createRoot
|
|
30
|
+
import('react-dom/client').then(({ createRoot }) => {
|
|
31
|
+
root = createRoot(div);
|
|
32
|
+
const showCancel = opts.okCancel !== false; // 默认 confirm 两按钮,其余单按钮
|
|
33
|
+
root.render(React.createElement(Modal, {
|
|
34
|
+
open: true,
|
|
35
|
+
title: opts.title,
|
|
36
|
+
okText: opts.okText || (showCancel ? '确定' : '知道了'),
|
|
37
|
+
cancelText: opts.cancelText || '取消',
|
|
38
|
+
onCancel: () => {
|
|
39
|
+
opts.onCancel?.();
|
|
40
|
+
destroy();
|
|
41
|
+
},
|
|
42
|
+
onOk: async () => {
|
|
43
|
+
try {
|
|
44
|
+
await opts.onOk?.();
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
destroy();
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
footer: null, // hb-dialog footer 受限,交由 content 自行渲染按钮或使用默认
|
|
51
|
+
}, opts.content));
|
|
52
|
+
});
|
|
53
|
+
return { destroy };
|
|
54
|
+
}
|
|
55
|
+
Modal.confirm = ((p) => imperative({ ...p, type: 'confirm', okCancel: true }));
|
|
56
|
+
Modal.info = ((p) => imperative({ ...p, type: 'info', okCancel: false }));
|
|
57
|
+
Modal.warning = ((p) => imperative({ ...p, type: 'warning', okCancel: false }));
|
|
58
|
+
Modal.success = ((p) => imperative({ ...p, type: 'success', okCancel: false }));
|
|
59
|
+
Modal.error = ((p) => imperative({ ...p, type: 'error', okCancel: false }));
|
|
60
|
+
/**
|
|
61
|
+
* useModal —— 返回 [modal, contextHolder]。
|
|
62
|
+
* contextHolder 需渲染在组件树里(占位用,当前实现命令式调用走 body 挂载,holder 可不渲染内容)。
|
|
63
|
+
* modal 实例提供 confirm/info/warning/success/error,与静态方法同义。
|
|
64
|
+
*/
|
|
65
|
+
Modal.useModal = function useModal() {
|
|
66
|
+
const api = React.useMemo(() => ({
|
|
67
|
+
confirm: (p) => imperative({ ...p, type: 'confirm', okCancel: true }),
|
|
68
|
+
info: (p) => imperative({ ...p, type: 'info', okCancel: false }),
|
|
69
|
+
warning: (p) => imperative({ ...p, type: 'warning', okCancel: false }),
|
|
70
|
+
success: (p) => imperative({ ...p, type: 'success', okCancel: false }),
|
|
71
|
+
error: (p) => imperative({ ...p, type: 'error', okCancel: false }),
|
|
72
|
+
}), []);
|
|
73
|
+
// holder:命令式调用自己挂 body,这里返回空占位以满足 antd 的解构用法
|
|
74
|
+
const holder = React.createElement(React.Fragment, null);
|
|
75
|
+
return [api, holder];
|
|
76
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HbPageHeader } from '@huibo-ui/react';
|
|
3
|
+
export function PageHeader(props) {
|
|
4
|
+
return _jsx(HbPageHeader, { title: typeof props.title === 'string' ? props.title : '', subtitle: typeof props.subTitle === 'string' ? props.subTitle : '', extra: props.extra, showBack: !!props.onBack });
|
|
5
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function Pagination(props: {
|
|
3
|
+
current?: number;
|
|
4
|
+
pageSize?: number;
|
|
5
|
+
total?: number;
|
|
6
|
+
showSizeChanger?: boolean;
|
|
7
|
+
pageSizeOptions?: string[];
|
|
8
|
+
onChange?: (page: number, pageSize: number) => void;
|
|
9
|
+
showTotal?: (total: number) => React.ReactNode;
|
|
10
|
+
style?: React.CSSProperties;
|
|
11
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HbPagination } from '@huibo-ui/react';
|
|
3
|
+
export function Pagination(props) {
|
|
4
|
+
return _jsx(HbPagination, { "current-page": props.current ?? 1, "page-size": props.pageSize ?? 10, total: props.total ?? 0, "show-page-size": props.showSizeChanger, "page-sizes": props.pageSizeOptions?.map(Number), onHbCurrentChange: (e) => props.onChange?.(e.detail, props.pageSize ?? 10), style: props.style });
|
|
5
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function Popconfirm(props: {
|
|
3
|
+
title?: React.ReactNode;
|
|
4
|
+
onConfirm?: () => void;
|
|
5
|
+
onCancel?: () => void;
|
|
6
|
+
okText?: string;
|
|
7
|
+
cancelText?: string;
|
|
8
|
+
placement?: string;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HbPopconfirm } from '@huibo-ui/react';
|
|
3
|
+
export function Popconfirm(props) {
|
|
4
|
+
return _jsx(HbPopconfirm, { title: typeof props.title === 'string' ? props.title : '', confirmText: props.okText, cancelText: props.cancelText, position: (props.placement || 'top'), onHbConfirm: () => props.onConfirm?.(), onHbCancel: () => props.onCancel?.(), children: props.children });
|
|
5
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HbPopover } from '@huibo-ui/react';
|
|
3
|
+
export function Popover(props) {
|
|
4
|
+
return _jsx(HbPopover, { content: props.content, title: typeof props.title === 'string' ? props.title : '', position: (props.placement || 'top'), trigger: (props.trigger || 'hover'), children: props.children });
|
|
5
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function Progress(props: {
|
|
3
|
+
percent?: number;
|
|
4
|
+
type?: 'line' | 'circle';
|
|
5
|
+
status?: 'success' | 'exception' | 'active';
|
|
6
|
+
showInfo?: boolean;
|
|
7
|
+
strokeColor?: string;
|
|
8
|
+
strokeWidth?: number;
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HbProgress } from '@huibo-ui/react';
|
|
3
|
+
export function Progress(props) {
|
|
4
|
+
return _jsx(HbProgress, { percentage: props.percent ?? 0, type: props.type, status: props.status, showText: props.showInfo ?? true, strokeColor: props.strokeColor, strokeWidth: props.strokeWidth, style: props.style });
|
|
5
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function QRCode(props: {
|
|
3
|
+
value?: string;
|
|
4
|
+
size?: number;
|
|
5
|
+
icon?: string;
|
|
6
|
+
color?: string;
|
|
7
|
+
style?: React.CSSProperties;
|
|
8
|
+
}): React.DetailedReactHTMLElement<{
|
|
9
|
+
src: string;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
style: React.CSSProperties | undefined;
|
|
13
|
+
alt: string;
|
|
14
|
+
}, HTMLElement>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
// QRCode:antd 有此组件,huibo-ui 暂无。
|
|
3
|
+
// 提供占位实现(使用第三方 qrcode 库或 canvas 绘制)。
|
|
4
|
+
// 如果项目依赖此功能,请安装 qrcode 包或接入在线生成 API。
|
|
5
|
+
export function QRCode(props) {
|
|
6
|
+
const { value = '', size = 160 } = props;
|
|
7
|
+
// 使用在线 QR 生成 API 作为临时方案
|
|
8
|
+
const src = `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(value)}`;
|
|
9
|
+
return React.createElement('img', { src, width: size, height: size, style: props.style, alt: 'QR Code' });
|
|
10
|
+
}
|