@wzyjs/uis 0.3.29 → 0.3.30
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/dist/advanced/Com2Canvas/index.d.ts +8 -0
- package/dist/advanced/Com2Canvas/index.js +39 -0
- package/dist/advanced/Crud/components/CardList/index.d.ts +2 -0
- package/dist/advanced/Crud/components/CardList/index.js +90 -0
- package/dist/advanced/Crud/components/CreateUpdate/index.d.ts +2 -0
- package/dist/advanced/Crud/components/CreateUpdate/index.js +78 -0
- package/dist/advanced/Crud/components/ListTabs/index.d.ts +8 -0
- package/dist/advanced/Crud/components/ListTabs/index.js +7 -0
- package/dist/advanced/Crud/components/Provider/index.d.ts +7 -0
- package/dist/advanced/Crud/components/Provider/index.js +42 -0
- package/dist/advanced/Crud/components/QuickFilters/index.d.ts +8 -0
- package/dist/advanced/Crud/components/QuickFilters/index.js +20 -0
- package/dist/advanced/Crud/components/Remove/index.d.ts +2 -0
- package/dist/advanced/Crud/components/Remove/index.js +18 -0
- package/dist/advanced/Crud/components/index.d.ts +6 -0
- package/dist/advanced/Crud/components/index.js +6 -0
- package/dist/advanced/Crud/hooks/index.d.ts +5 -0
- package/dist/advanced/Crud/hooks/index.js +5 -0
- package/dist/advanced/Crud/hooks/useColumns.d.ts +11 -0
- package/dist/advanced/Crud/hooks/useColumns.js +111 -0
- package/dist/advanced/Crud/hooks/useList.d.ts +12 -0
- package/dist/advanced/Crud/hooks/useList.js +53 -0
- package/dist/advanced/Crud/hooks/useListFilters.d.ts +11 -0
- package/dist/advanced/Crud/hooks/useListFilters.js +159 -0
- package/dist/advanced/Crud/hooks/useOrderable.d.ts +15 -0
- package/dist/advanced/Crud/hooks/useOrderable.js +75 -0
- package/dist/advanced/Crud/hooks/useRequest.d.ts +13 -0
- package/dist/advanced/Crud/hooks/useRequest.js +27 -0
- package/dist/advanced/Crud/index.d.ts +3 -0
- package/dist/advanced/Crud/index.js +46 -0
- package/dist/advanced/Crud/types/index.d.ts +176 -0
- package/dist/advanced/Crud/types/index.js +1 -0
- package/dist/advanced/Crud/utils/index.d.ts +7 -0
- package/dist/advanced/Crud/utils/index.js +80 -0
- package/dist/advanced/Crud/utils/query.d.ts +3 -0
- package/dist/advanced/Crud/utils/query.js +34 -0
- package/dist/advanced/MindMap/context.d.ts +12 -0
- package/dist/advanced/MindMap/context.js +12 -0
- package/dist/advanced/MindMap/hooks/useAlignmentSnap.d.ts +15 -0
- package/dist/advanced/MindMap/hooks/useAlignmentSnap.js +164 -0
- package/dist/advanced/MindMap/hooks/useCopyPaste.d.ts +11 -0
- package/dist/advanced/MindMap/hooks/useCopyPaste.js +209 -0
- package/dist/advanced/MindMap/hooks/useDropToReparent.d.ts +21 -0
- package/dist/advanced/MindMap/hooks/useDropToReparent.js +216 -0
- package/dist/advanced/MindMap/hooks/useExpandCollapse.d.ts +18 -0
- package/dist/advanced/MindMap/hooks/useExpandCollapse.js +108 -0
- package/dist/advanced/MindMap/hooks/useMoveDescendants.d.ts +12 -0
- package/dist/advanced/MindMap/hooks/useMoveDescendants.js +98 -0
- package/dist/advanced/MindMap/hooks/useUndoRedo.d.ts +14 -0
- package/dist/advanced/MindMap/hooks/useUndoRedo.js +181 -0
- package/dist/advanced/MindMap/index.d.ts +29 -0
- package/dist/advanced/MindMap/index.js +52 -0
- package/dist/advanced/index.d.ts +5 -0
- package/dist/advanced/index.js +5 -0
- package/dist/antd/index.d.ts +6 -0
- package/dist/antd/index.js +5 -0
- package/dist/buttons/ButtonGroup/index.d.ts +8 -0
- package/dist/buttons/ButtonGroup/index.js +13 -0
- package/dist/buttons/ConfirmButton/index.d.ts +5 -0
- package/dist/buttons/ConfirmButton/index.js +9 -0
- package/dist/buttons/CopyButton/index.d.ts +6 -0
- package/dist/buttons/CopyButton/index.js +26 -0
- package/dist/buttons/DrawerButton/index.d.ts +6 -0
- package/dist/buttons/DrawerButton/index.js +13 -0
- package/dist/buttons/ProgressButton/index.css +63 -0
- package/dist/buttons/ProgressButton/index.d.ts +17 -0
- package/dist/buttons/ProgressButton/index.js +31 -0
- package/dist/buttons/SectorButton/index.d.ts +20 -0
- package/dist/buttons/SectorButton/index.js +130 -0
- package/dist/buttons/index.d.ts +6 -0
- package/dist/buttons/index.js +6 -0
- package/dist/display/CodeView/index.d.ts +26 -0
- package/dist/display/CodeView/index.js +60 -0
- package/dist/display/EnumTag/index.d.ts +12 -0
- package/dist/display/EnumTag/index.js +10 -0
- package/dist/display/HtmlDataRenderer/index.d.ts +6 -0
- package/dist/display/HtmlDataRenderer/index.js +15 -0
- package/dist/display/HtmlView/index.d.ts +6 -0
- package/dist/display/HtmlView/index.js +6 -0
- package/dist/display/IframePro/index.d.ts +8 -0
- package/dist/display/IframePro/index.js +24 -0
- package/dist/display/JsonSchemaRenderer/index.d.ts +11 -0
- package/dist/display/JsonSchemaRenderer/index.js +62 -0
- package/dist/display/JsonView/index.d.ts +3 -0
- package/dist/display/JsonView/index.js +7 -0
- package/dist/display/MarkdownView/index.d.ts +7 -0
- package/dist/display/MarkdownView/index.js +80 -0
- package/dist/display/MarkdownView/style.d.ts +1 -0
- package/{src/components/Markdown/style.ts → dist/display/MarkdownView/style.js} +1 -1
- package/dist/display/VideoPro/index.d.ts +9 -0
- package/dist/display/VideoPro/index.js +15 -0
- package/dist/display/index.d.ts +9 -0
- package/dist/display/index.js +9 -0
- package/dist/inputs/CheckboxButton/index.css +22 -0
- package/dist/inputs/CheckboxButton/index.d.ts +12 -0
- package/dist/inputs/CheckboxButton/index.js +9 -0
- package/dist/inputs/DateSwitcher/index.css +10 -0
- package/dist/inputs/DateSwitcher/index.d.ts +8 -0
- package/dist/inputs/DateSwitcher/index.js +29 -0
- package/dist/inputs/FetchSelect/index.d.ts +3 -0
- package/dist/inputs/FetchSelect/index.js +121 -0
- package/dist/inputs/FetchSelect/types.d.ts +33 -0
- package/dist/inputs/FetchSelect/types.js +1 -0
- package/dist/inputs/FetchSelect/utils.d.ts +21 -0
- package/dist/inputs/FetchSelect/utils.js +67 -0
- package/dist/inputs/FileUploader/index.d.ts +22 -0
- package/dist/inputs/FileUploader/index.js +79 -0
- package/dist/inputs/IconSelect/index.d.ts +89 -0
- package/dist/inputs/IconSelect/index.js +54 -0
- package/dist/inputs/ImageUploader/index.d.ts +12 -0
- package/dist/inputs/ImageUploader/index.js +192 -0
- package/dist/inputs/RadioButton/index.d.ts +15 -0
- package/dist/inputs/RadioButton/index.js +11 -0
- package/dist/inputs/RangeInput/index.d.ts +8 -0
- package/dist/inputs/RangeInput/index.js +17 -0
- package/dist/inputs/TextInput/index.d.ts +6 -0
- package/dist/inputs/TextInput/index.js +30 -0
- package/dist/inputs/index.d.ts +9 -0
- package/dist/inputs/index.js +9 -0
- package/dist/layout/DragSort/index.d.ts +16 -0
- package/dist/layout/DragSort/index.js +12 -0
- package/dist/layout/FoldCard/index.d.ts +9 -0
- package/dist/layout/FoldCard/index.js +69 -0
- package/dist/layout/PageBase/index.d.ts +6 -0
- package/dist/layout/PageBase/index.js +6 -0
- package/dist/layout/ResizableGridLayout/index.d.ts +11 -0
- package/dist/layout/ResizableGridLayout/index.js +13 -0
- package/dist/layout/SideMenu/index.d.ts +27 -0
- package/dist/layout/SideMenu/index.js +40 -0
- package/dist/layout/TabsPro/index.d.ts +9 -0
- package/dist/layout/TabsPro/index.js +87 -0
- package/dist/layout/index.d.ts +6 -0
- package/dist/layout/index.js +6 -0
- package/dist/web.d.ts +6 -0
- package/dist/web.js +6 -0
- package/package.json +28 -11
- package/src/antd/form/CheckboxButton/index.module.scss +0 -24
- package/src/antd/form/CheckboxButton/index.tsx +0 -31
- package/src/antd/form/FileUploader/index.tsx +0 -163
- package/src/antd/form/RadioButton/index.tsx +0 -32
- package/src/antd/form/Upload/index.tsx +0 -65
- package/src/antd/form/UploadImage/index.tsx +0 -338
- package/src/antd/form/index.ts +0 -6
- package/src/antd/index.ts +0 -46
- package/src/antd/pro/FoldCard/index.tsx +0 -131
- package/src/antd/pro/RangeInput/index.tsx +0 -46
- package/src/antd/pro/Tabs/index.tsx +0 -135
- package/src/antd/pro/Typography/components/String.tsx +0 -72
- package/src/antd/pro/Typography/index.tsx +0 -9
- package/src/antd/pro/buttons/ButtonGroup.tsx +0 -26
- package/src/antd/pro/buttons/ConfirmButton.tsx +0 -24
- package/src/antd/pro/buttons/CopyButton.tsx +0 -47
- package/src/antd/pro/buttons/DrawerButton.tsx +0 -37
- package/src/antd/pro/buttons/index.tsx +0 -4
- package/src/antd/pro/index.ts +0 -5
- package/src/components/BottomBar/index.tsx +0 -28
- package/src/components/CodeView/index.tsx +0 -85
- package/src/components/Collapse/index.tsx +0 -26
- package/src/components/Com2Canvas/index.tsx +0 -60
- package/src/components/CompileHtml/index.tsx +0 -26
- package/src/components/Crud/components/CardList/index.tsx +0 -174
- package/src/components/Crud/components/CreateUpdate/index.tsx +0 -179
- package/src/components/Crud/components/Provider/index.tsx +0 -83
- package/src/components/Crud/components/Remove/index.tsx +0 -56
- package/src/components/Crud/components/index.ts +0 -4
- package/src/components/Crud/hooks/index.ts +0 -4
- package/src/components/Crud/hooks/useColumns.tsx +0 -169
- package/src/components/Crud/hooks/useList.ts +0 -65
- package/src/components/Crud/hooks/useOrderable.tsx +0 -107
- package/src/components/Crud/hooks/useRequest.ts +0 -41
- package/src/components/Crud/index.tsx +0 -91
- package/src/components/Crud/types/index.ts +0 -188
- package/src/components/Crud/utils/index.ts +0 -87
- package/src/components/DateSwitcher/index.module.scss +0 -10
- package/src/components/DateSwitcher/index.tsx +0 -75
- package/src/components/DownloadLink/index.tsx +0 -36
- package/src/components/DragSort/index.tsx +0 -77
- package/src/components/DynamicSelect/index.tsx +0 -76
- package/src/components/DynamicSelect/types.ts +0 -8
- package/src/components/DynamicSelect/utils.ts +0 -47
- package/src/components/EnumTag/index.tsx +0 -24
- package/src/components/FetchSelect/index.tsx +0 -57
- package/src/components/FormPro/index.tsx +0 -28
- package/src/components/GroupLayout/index.tsx +0 -45
- package/src/components/HtmlPro/index.tsx +0 -18
- package/src/components/IframePro/index.tsx +0 -52
- package/src/components/JsonRenderer/index.tsx +0 -114
- package/src/components/JsonView/index.tsx +0 -21
- package/src/components/Markdown/index.tsx +0 -152
- package/src/components/MindMap/context.tsx +0 -29
- package/src/components/MindMap/hooks/useAlignmentSnap.ts +0 -220
- package/src/components/MindMap/hooks/useCopyPaste.ts +0 -272
- package/src/components/MindMap/hooks/useDropToReparent.ts +0 -288
- package/src/components/MindMap/hooks/useExpandCollapse.ts +0 -146
- package/src/components/MindMap/hooks/useMoveDescendants.ts +0 -136
- package/src/components/MindMap/hooks/useUndoRedo.ts +0 -232
- package/src/components/MindMap/index.tsx +0 -117
- package/src/components/MultiImageDisplay/index.tsx +0 -63
- package/src/components/ProgressButton/index.module.scss +0 -65
- package/src/components/ProgressButton/index.tsx +0 -96
- package/src/components/SectorButton/index.tsx +0 -247
- package/src/components/TextInput/index.tsx +0 -61
- package/src/components/TimelineBar/components/CurrentWeekHighlight/index.tsx +0 -64
- package/src/components/TimelineBar/components/Guides/index.tsx +0 -61
- package/src/components/TimelineBar/components/Ticks/index.tsx +0 -56
- package/src/components/TimelineBar/components/TodayIndicator/index.tsx +0 -54
- package/src/components/TimelineBar/components/index.ts +0 -4
- package/src/components/TimelineBar/const.ts +0 -3
- package/src/components/TimelineBar/hooks/index.ts +0 -5
- package/src/components/TimelineBar/hooks/useHighlightRange.ts +0 -21
- package/src/components/TimelineBar/hooks/useMonthGuides.ts +0 -40
- package/src/components/TimelineBar/hooks/useTickValues.ts +0 -18
- package/src/components/TimelineBar/hooks/useVisibleRange.ts +0 -43
- package/src/components/TimelineBar/hooks/useWeekGuides.ts +0 -39
- package/src/components/TimelineBar/index.tsx +0 -63
- package/src/components/TimelineBar/utils.ts +0 -27
- package/src/components/Video/index.tsx +0 -37
- package/src/components/index.ts +0 -26
- package/src/rn.ts +0 -1
- package/src/rns/index.ts +0 -0
- package/src/web.ts +0 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { FileTextOutlined, ApartmentOutlined, AppstoreOutlined, BookOutlined, BulbOutlined, CalendarOutlined, DatabaseOutlined, DeleteOutlined, DownOutlined, EditOutlined, EyeOutlined, FolderAddOutlined, HomeOutlined, MinusOutlined, PlusOutlined, QuestionOutlined, SendOutlined, ShoppingOutlined, StarOutlined, UserOutlined, } from '@ant-design/icons';
|
|
4
|
+
import { Select, Space } from 'antd';
|
|
5
|
+
export const iconSelectOptions = [
|
|
6
|
+
{ value: 'home', label: 'Home', icon: _jsx(HomeOutlined, {}) },
|
|
7
|
+
{ value: 'calendar', label: 'Calendar', icon: _jsx(CalendarOutlined, {}) },
|
|
8
|
+
{ value: 'appstore', label: 'Appstore', icon: _jsx(AppstoreOutlined, {}) },
|
|
9
|
+
{ value: 'fileText', label: 'FileText', icon: _jsx(FileTextOutlined, {}) },
|
|
10
|
+
{ value: 'bulb', label: 'Bulb', icon: _jsx(BulbOutlined, {}) },
|
|
11
|
+
{ value: 'user', label: 'User', icon: _jsx(UserOutlined, {}) },
|
|
12
|
+
{ value: 'shopping', label: 'Shopping', icon: _jsx(ShoppingOutlined, {}) },
|
|
13
|
+
{ value: 'book', label: 'Book', icon: _jsx(BookOutlined, {}) },
|
|
14
|
+
{ value: 'database', label: 'Database', icon: _jsx(DatabaseOutlined, {}) },
|
|
15
|
+
{ value: 'apartment', label: 'Apartment', icon: _jsx(ApartmentOutlined, {}) },
|
|
16
|
+
{ value: 'folderAdd', label: 'FolderAdd', icon: _jsx(FolderAddOutlined, {}) },
|
|
17
|
+
{ value: 'send', label: 'Send', icon: _jsx(SendOutlined, {}) },
|
|
18
|
+
{ value: 'plus', label: 'Plus', icon: _jsx(PlusOutlined, {}) },
|
|
19
|
+
{ value: 'minus', label: 'Minus', icon: _jsx(MinusOutlined, {}) },
|
|
20
|
+
{ value: 'eye', label: 'Eye', icon: _jsx(EyeOutlined, {}) },
|
|
21
|
+
{ value: 'edit', label: 'Edit', icon: _jsx(EditOutlined, {}) },
|
|
22
|
+
{ value: 'delete', label: 'Delete', icon: _jsx(DeleteOutlined, {}) },
|
|
23
|
+
{ value: 'star', label: 'Star', icon: _jsx(StarOutlined, {}) },
|
|
24
|
+
{ value: 'down', label: 'Down', icon: _jsx(DownOutlined, {}) },
|
|
25
|
+
{ value: 'question', label: 'Question', icon: _jsx(QuestionOutlined, {}) },
|
|
26
|
+
];
|
|
27
|
+
const iconNodeByValue = iconSelectOptions.reduce((acc, item) => {
|
|
28
|
+
acc[item.value] = item.icon;
|
|
29
|
+
return acc;
|
|
30
|
+
}, {});
|
|
31
|
+
export const getIconNode = (value) => {
|
|
32
|
+
if (!value) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const key = value;
|
|
36
|
+
return iconNodeByValue[key] ?? null;
|
|
37
|
+
};
|
|
38
|
+
export const IconSelect = (props) => {
|
|
39
|
+
const { value, onChange } = props;
|
|
40
|
+
const options = iconSelectOptions.map(item => ({
|
|
41
|
+
value: item.value,
|
|
42
|
+
rawLabel: item.label,
|
|
43
|
+
label: (_jsxs(Space, { size: 8, children: [_jsx("span", { className: 'text-base leading-none', children: getIconNode(item.value) }), _jsx("span", { children: item.label })] })),
|
|
44
|
+
}));
|
|
45
|
+
return (_jsx(Select, { allowClear: true, placeholder: '\u8BF7\u9009\u62E9\u56FE\u6807', value: typeof value === 'string' ? value : undefined, onChange: (nextValue) => {
|
|
46
|
+
onChange?.(typeof nextValue === 'string' ? nextValue : undefined);
|
|
47
|
+
}, options: options, showSearch: true, filterOption: (input, option) => {
|
|
48
|
+
const opt = option;
|
|
49
|
+
const raw = (opt?.rawLabel ?? '').toLowerCase();
|
|
50
|
+
const val = String(opt?.value ?? '').toLowerCase();
|
|
51
|
+
const keyword = input.toLowerCase();
|
|
52
|
+
return raw.includes(keyword) || val.includes(keyword);
|
|
53
|
+
} }));
|
|
54
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface ImageUploaderProps {
|
|
2
|
+
value?: string[];
|
|
3
|
+
onChange?: (value: string[]) => void;
|
|
4
|
+
maxImages?: number;
|
|
5
|
+
enablePreview?: boolean;
|
|
6
|
+
enableDragDrop?: boolean;
|
|
7
|
+
enableFileSelect?: boolean;
|
|
8
|
+
enablePaste?: boolean;
|
|
9
|
+
enablePasteTip?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const ImageUploader: (props: ImageUploaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { Alert, Button, Modal, Popover, Space, Typography } from 'antd';
|
|
5
|
+
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
|
6
|
+
export const ImageUploader = (props) => {
|
|
7
|
+
const { value = [], onChange, maxImages = 10, enablePreview = false, enableDragDrop = false, enableFileSelect = false, enablePaste = true, enablePasteTip = false, } = props;
|
|
8
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
9
|
+
const fileInputRef = useRef(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!enablePaste)
|
|
12
|
+
return;
|
|
13
|
+
const handlePaste = (event) => {
|
|
14
|
+
if (event.clipboardData && event.clipboardData.items) {
|
|
15
|
+
const items = event.clipboardData.items;
|
|
16
|
+
for (let i = 0; i < items.length; i++) {
|
|
17
|
+
const item = items[i];
|
|
18
|
+
if (item && item.type.indexOf('image') !== -1) {
|
|
19
|
+
const file = item.getAsFile();
|
|
20
|
+
if (file) {
|
|
21
|
+
convertToBase64(file);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
document.addEventListener('paste', handlePaste);
|
|
28
|
+
return () => {
|
|
29
|
+
document.removeEventListener('paste', handlePaste);
|
|
30
|
+
};
|
|
31
|
+
}, [value, enablePaste]);
|
|
32
|
+
const handleDragOver = (e) => {
|
|
33
|
+
if (!enableDragDrop)
|
|
34
|
+
return;
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
e.stopPropagation();
|
|
37
|
+
setIsDragging(true);
|
|
38
|
+
};
|
|
39
|
+
const handleDragLeave = (e) => {
|
|
40
|
+
if (!enableDragDrop)
|
|
41
|
+
return;
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
e.stopPropagation();
|
|
44
|
+
setIsDragging(false);
|
|
45
|
+
};
|
|
46
|
+
const handleDrop = (e) => {
|
|
47
|
+
if (!enableDragDrop)
|
|
48
|
+
return;
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
e.stopPropagation();
|
|
51
|
+
setIsDragging(false);
|
|
52
|
+
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
53
|
+
const fileList = Array.from(e.dataTransfer.files);
|
|
54
|
+
fileList.forEach((file) => {
|
|
55
|
+
if (file.type.match('image.*')) {
|
|
56
|
+
convertToBase64(file);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const handleClick = () => {
|
|
62
|
+
if (!enableFileSelect)
|
|
63
|
+
return;
|
|
64
|
+
fileInputRef.current?.click();
|
|
65
|
+
};
|
|
66
|
+
const handleFileChange = (e) => {
|
|
67
|
+
if (!enableFileSelect)
|
|
68
|
+
return;
|
|
69
|
+
if (e.target.files && e.target.files.length > 0) {
|
|
70
|
+
const fileList = Array.from(e.target.files);
|
|
71
|
+
fileList.forEach((file) => {
|
|
72
|
+
if (file.type.match('image.*')) {
|
|
73
|
+
convertToBase64(file);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const handlePasteButton = () => {
|
|
79
|
+
if (!enablePaste)
|
|
80
|
+
return;
|
|
81
|
+
navigator.clipboard.read().then((clipboardItems) => {
|
|
82
|
+
for (const clipboardItem of clipboardItems) {
|
|
83
|
+
for (const type of clipboardItem.types) {
|
|
84
|
+
if (type.startsWith('image/')) {
|
|
85
|
+
clipboardItem.getType(type).then((blob) => {
|
|
86
|
+
convertToBase64(blob);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}).catch(error => {
|
|
92
|
+
console.error('读取剪贴板失败:', error);
|
|
93
|
+
alert('读取剪贴板失败。请尝试使用 Ctrl+V 粘贴或手动上传图片。');
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
const convertToBase64 = (file) => {
|
|
97
|
+
if (value.length >= maxImages) {
|
|
98
|
+
alert(`最多允许上传 ${maxImages} 张图片。`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
compressImage(file).then(compressedFile => {
|
|
102
|
+
const reader = new FileReader();
|
|
103
|
+
reader.onloadend = () => {
|
|
104
|
+
const base64String = reader.result;
|
|
105
|
+
if (!value.includes(base64String)) {
|
|
106
|
+
onChange?.([...value, base64String]);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
reader.readAsDataURL(compressedFile);
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
const compressImage = (file) => {
|
|
113
|
+
return new Promise((resolve) => {
|
|
114
|
+
const originalSize = file.size / 1024;
|
|
115
|
+
const img = new Image();
|
|
116
|
+
img.src = URL.createObjectURL(file);
|
|
117
|
+
img.onload = () => {
|
|
118
|
+
URL.revokeObjectURL(img.src);
|
|
119
|
+
const canvas = document.createElement('canvas');
|
|
120
|
+
let width = img.width;
|
|
121
|
+
let height = img.height;
|
|
122
|
+
// 计算压缩比例,保持宽高比
|
|
123
|
+
const maxWidth = 1200;
|
|
124
|
+
const maxHeight = 1200;
|
|
125
|
+
if (width > maxWidth || height > maxHeight) {
|
|
126
|
+
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
127
|
+
width = width * ratio;
|
|
128
|
+
height = height * ratio;
|
|
129
|
+
}
|
|
130
|
+
canvas.width = width;
|
|
131
|
+
canvas.height = height;
|
|
132
|
+
const ctx = canvas.getContext('2d');
|
|
133
|
+
if (!ctx) {
|
|
134
|
+
resolve(file);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
138
|
+
// 转换为blob,压缩质量为0.8
|
|
139
|
+
canvas.toBlob((blob) => {
|
|
140
|
+
if (!blob) {
|
|
141
|
+
resolve(file);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// 获取压缩后的图片大小
|
|
145
|
+
const compressedSize = blob.size / 1024;
|
|
146
|
+
console.log(`原始图片: ${originalSize.toFixed(2)} KB => ${compressedSize.toFixed(2)} KB`);
|
|
147
|
+
console.log(`压缩到了: ${((compressedSize / originalSize) * 100).toFixed(2)}%`);
|
|
148
|
+
resolve(blob);
|
|
149
|
+
}, 'image/jpeg', 0.8);
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
const handleRemoveImage = (index) => {
|
|
154
|
+
Modal.confirm({
|
|
155
|
+
title: '确认删除',
|
|
156
|
+
content: '您确定要删除这张图片吗?',
|
|
157
|
+
okText: '确定',
|
|
158
|
+
cancelText: '取消',
|
|
159
|
+
onOk: () => {
|
|
160
|
+
const newImages = [...value];
|
|
161
|
+
newImages.splice(index, 1);
|
|
162
|
+
onChange?.(newImages);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
return (_jsxs("div", { className: 'w-full space-y-4', children: [_jsxs("div", { className: 'flex flex-wrap gap-3', children: [value.map((image, index) => {
|
|
167
|
+
const imageNode = (_jsxs("div", { className: 'rounded border overflow-hidden relative group bg-white', style: { maxWidth: 200 }, children: [_jsx("img", { src: image, alt: `图片 ${index + 1}`, className: 'object-contain', style: { maxWidth: '100%', height: 'auto', display: 'block' } }), _jsx(Button, { type: 'text', icon: _jsx(DeleteOutlined, {}), onClick: (e) => {
|
|
168
|
+
e.stopPropagation();
|
|
169
|
+
handleRemoveImage(index);
|
|
170
|
+
}, style: { position: 'absolute', top: 0, right: 0 }, className: 'absolute top-0 right-0 bg-black/40 text-white border-none hover:bg-black/60', size: 'small' })] }));
|
|
171
|
+
if (!enablePreview) {
|
|
172
|
+
return (_jsx("div", { className: 'relative', children: imageNode }, index));
|
|
173
|
+
}
|
|
174
|
+
return (_jsx("div", { className: 'relative', children: _jsx(Popover, { trigger: 'hover', placement: 'top', content: (_jsx("img", { src: image, alt: `预览图片 ${index + 1}`, style: {
|
|
175
|
+
maxWidth: '400px',
|
|
176
|
+
height: 'auto',
|
|
177
|
+
objectFit: 'contain',
|
|
178
|
+
} })), children: imageNode }) }, index));
|
|
179
|
+
}), value.length < maxImages && (_jsxs(Space, { style: { width: '100%' }, children: [enableFileSelect && (_jsxs("div", { className: `border-2 border-dashed rounded flex flex-col items-center justify-center cursor-pointer transition-colors ${isDragging && enableDragDrop ? 'border-blue-500 bg-blue-50' : 'border-gray-300 hover:border-blue-500'}`, onDragOver: enableDragDrop ? handleDragOver : undefined, onDragLeave: enableDragDrop ? handleDragLeave : undefined, onDrop: enableDragDrop ? handleDrop : undefined, onClick: handleClick, style: { width: '50px', height: '50px' }, children: [_jsx(PlusOutlined, { style: { fontSize: '24px', color: '#8c8c8c' } }), _jsx(Typography.Text, { type: 'secondary', className: 'm-2', children: "\u4E0A\u4F20" })] })), enablePaste && (_jsxs("div", { style: { width: '50px', height: '50px' }, className: `border-2 border-dashed rounded flex flex-col items-center justify-center cursor-pointer transition-colors ${isDragging ? 'border-blue-500 bg-blue-50' : 'border-gray-300 hover:border-blue-500'}`, onClick: handlePasteButton, children: [_jsx(PlusOutlined, { style: { fontSize: '24px', color: '#8c8c8c' } }), _jsx(Typography.Text, { type: 'secondary', className: 'm-2', children: "\u7C98\u8D34" })] }))] }))] }), enableFileSelect && (_jsx("input", { type: 'file', ref: fileInputRef, onChange: handleFileChange, accept: 'image/*', multiple: true, style: { display: 'none' } })), (enablePasteTip && enablePaste) && (_jsx(Alert, { type: 'info', showIcon: true, title: _jsxs(Typography.Text, { type: 'secondary', children: ["\u63D0\u793A\uFF1A\u60A8\u4E5F\u53EF\u4EE5\u5728\u4EFB\u610F\u4F4D\u7F6E\u6309\u4E0B ", _jsx("kbd", { style: {
|
|
180
|
+
padding: '0.1rem 0.4rem',
|
|
181
|
+
background: '#f5f5f5',
|
|
182
|
+
border: '1px solid #d9d9d9',
|
|
183
|
+
borderRadius: '3px',
|
|
184
|
+
fontSize: '12px',
|
|
185
|
+
}, children: "Ctrl" }), " + ", _jsx("kbd", { style: {
|
|
186
|
+
padding: '0.1rem 0.4rem',
|
|
187
|
+
background: '#f5f5f5',
|
|
188
|
+
border: '1px solid #d9d9d9',
|
|
189
|
+
borderRadius: '3px',
|
|
190
|
+
fontSize: '12px',
|
|
191
|
+
}, children: "V" }), " \u4ECE\u526A\u8D34\u677F\u7C98\u8D34\u56FE\u7247"] }) }))] }));
|
|
192
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
interface FilterButtonProps<V> {
|
|
3
|
+
options: {
|
|
4
|
+
label: string;
|
|
5
|
+
value: V;
|
|
6
|
+
}[];
|
|
7
|
+
value?: V;
|
|
8
|
+
buttonStyle?: 'outline' | 'solid';
|
|
9
|
+
onChange?: (value: V) => void;
|
|
10
|
+
style?: CSSProperties;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
allowClear?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare const RadioButton: <V = string | number | boolean | null>(props: FilterButtonProps<V>) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Radio } from 'antd';
|
|
4
|
+
export const RadioButton = (props) => {
|
|
5
|
+
const { value, options, buttonStyle = 'outline', disabled, style, allowClear, onChange } = props;
|
|
6
|
+
return (_jsx(Radio.Group, { optionType: 'button', buttonStyle: buttonStyle, value: value, style: style, disabled: disabled, onChange: e => onChange?.(e.target.value), children: options.filter(item => item.label).map(item => (_jsx(Radio, { value: item.value, onClick: () => {
|
|
7
|
+
if (allowClear && value === item.value) {
|
|
8
|
+
onChange?.(undefined);
|
|
9
|
+
}
|
|
10
|
+
}, children: item.label }, String(item.value)))) }));
|
|
11
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { InputNumberProps } from 'antd';
|
|
2
|
+
export interface RangeInputProps extends Omit<InputNumberProps, 'value' | 'onChange'> {
|
|
3
|
+
value?: number[];
|
|
4
|
+
min?: number;
|
|
5
|
+
max?: number;
|
|
6
|
+
onChange?: (numbers: number[]) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const RangeInput: (props: RangeInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { InputNumber, Space } from 'antd';
|
|
4
|
+
import { _ } from '@wzyjs/utils/web';
|
|
5
|
+
// 最小值 最大值 的输入框
|
|
6
|
+
export const RangeInput = (props) => {
|
|
7
|
+
const { value = [], min, max, onChange } = props;
|
|
8
|
+
const onNumberChange = (index, v) => {
|
|
9
|
+
if (Number.isNaN(v) || v === null) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const numbers = _.cloneDeep(value) || [];
|
|
13
|
+
numbers[index] = v;
|
|
14
|
+
onChange?.(numbers);
|
|
15
|
+
};
|
|
16
|
+
return (_jsxs(Space, { children: [_jsx(InputNumber, { min: min, max: max, value: value[0], onChange: (v) => onNumberChange(0, v) }), _jsx("span", { style: { margin: '0 3px' }, children: " - " }), _jsx(InputNumber, { min: min, max: max, value: value[1], onChange: (v) => onNumberChange(1, v) })] }));
|
|
17
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Input } from 'antd';
|
|
5
|
+
import { useBoolean } from '@wzyjs/hooks/web';
|
|
6
|
+
export const TextInput = (props) => {
|
|
7
|
+
const { value, onChange } = props;
|
|
8
|
+
const [text, setText] = useState(value);
|
|
9
|
+
const [isEditing, { setTrue, setFalse }] = useBoolean(false);
|
|
10
|
+
const onSubmit = () => {
|
|
11
|
+
if (!text.trim()) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (text === value) {
|
|
15
|
+
setFalse();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
onChange?.(text.trim());
|
|
19
|
+
setFalse();
|
|
20
|
+
};
|
|
21
|
+
const onBlur = () => {
|
|
22
|
+
onSubmit();
|
|
23
|
+
};
|
|
24
|
+
const onKeyDown = (e) => {
|
|
25
|
+
if (e.key === 'Enter') {
|
|
26
|
+
onSubmit();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return (_jsx("div", { onDoubleClick: setTrue, children: !isEditing ? (_jsx("span", { children: text })) : (_jsx(Input, { value: text, onChange: ev => setText(ev.target.value), onBlur: onBlur, onKeyDown: onKeyDown, autoFocus: true, size: 'small', style: { width: 200 } })) }));
|
|
30
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './TextInput';
|
|
2
|
+
export * from './RangeInput';
|
|
3
|
+
export * from './DateSwitcher';
|
|
4
|
+
export * from './ImageUploader';
|
|
5
|
+
export * from './FileUploader';
|
|
6
|
+
export * from './CheckboxButton';
|
|
7
|
+
export * from './RadioButton';
|
|
8
|
+
export * from './FetchSelect';
|
|
9
|
+
export * from './IconSelect';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './TextInput';
|
|
2
|
+
export * from './RangeInput';
|
|
3
|
+
export * from './DateSwitcher';
|
|
4
|
+
export * from './ImageUploader';
|
|
5
|
+
export * from './FileUploader';
|
|
6
|
+
export * from './CheckboxButton';
|
|
7
|
+
export * from './RadioButton';
|
|
8
|
+
export * from './FetchSelect';
|
|
9
|
+
export * from './IconSelect';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type OnDragEndResponder, type DraggableProvided } from '@hello-pangea/dnd';
|
|
3
|
+
interface DragSortProps<T> {
|
|
4
|
+
direction?: 'vertical' | 'horizontal';
|
|
5
|
+
droppableId?: string;
|
|
6
|
+
list?: T[];
|
|
7
|
+
children: (item: T, provided: DraggableProvided) => React.ReactNode;
|
|
8
|
+
lastChildren?: React.ReactNode;
|
|
9
|
+
onDragEnd?: OnDragEndResponder;
|
|
10
|
+
hasContext?: boolean;
|
|
11
|
+
dropType?: string;
|
|
12
|
+
}
|
|
13
|
+
export { type DropResult, type DraggableProvided } from '@hello-pangea/dnd';
|
|
14
|
+
export declare const DragSort: <T extends {
|
|
15
|
+
id: string;
|
|
16
|
+
}>(props: DragSortProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Space } from 'antd';
|
|
4
|
+
import { DragDropContext, Draggable, Droppable, } from '@hello-pangea/dnd';
|
|
5
|
+
export const DragSort = (props) => {
|
|
6
|
+
const { dropType, direction = 'vertical', droppableId = 'list', list, children, hasContext = true, lastChildren, onDragEnd = () => undefined, } = props;
|
|
7
|
+
const content = (_jsx(Droppable, { type: dropType, droppableId: droppableId, direction: direction, isDropDisabled: false, isCombineEnabled: false, ignoreContainerClipping: true, children: provided => (_jsx("div", { ref: provided.innerRef, ...provided.droppableProps, children: _jsxs(Space, { orientation: direction, wrap: true, style: { width: '100%' }, children: [list?.map((item, index) => (_jsx(Draggable, { disableInteractiveElementBlocking: true, draggableId: item.id.toString(), index: index, children: provided => (_jsx("div", { ref: provided.innerRef, ...provided.draggableProps, children: children(item, provided) })) }, item.id))), provided.placeholder, lastChildren] }) })) }));
|
|
8
|
+
if (!hasContext) {
|
|
9
|
+
return content;
|
|
10
|
+
}
|
|
11
|
+
return (_jsx(DragDropContext, { onDragEnd: onDragEnd, children: content }));
|
|
12
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
import { CardProps } from 'antd';
|
|
3
|
+
export interface FoldCardProps extends CardProps {
|
|
4
|
+
max?: number;
|
|
5
|
+
buttonStyle?: CSSProperties;
|
|
6
|
+
defaultCollapsed?: boolean;
|
|
7
|
+
showButtonOnHover?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const FoldCard: React.ForwardRefExoticComponent<FoldCardProps & React.RefAttributes<unknown>>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef, useEffect, forwardRef } from 'react';
|
|
4
|
+
import { Card, Button } from 'antd';
|
|
5
|
+
import { DownOutlined, UpOutlined } from '@ant-design/icons';
|
|
6
|
+
export const FoldCard = forwardRef((props, ref) => {
|
|
7
|
+
const { max, buttonStyle, defaultCollapsed = true, showButtonOnHover = true, children, style, onMouseEnter, onMouseLeave, ...rest } = props;
|
|
8
|
+
const maxHeight = max ?? 300;
|
|
9
|
+
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
|
10
|
+
const [hovered, setHovered] = useState(false);
|
|
11
|
+
const [isOverflow, setIsOverflow] = useState(false);
|
|
12
|
+
const contentRef = useRef(null);
|
|
13
|
+
const measureOverflow = () => {
|
|
14
|
+
const contentEl = contentRef.current;
|
|
15
|
+
if (!contentEl) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
setIsOverflow(contentEl.scrollHeight > maxHeight);
|
|
19
|
+
};
|
|
20
|
+
const toggleCollapse = (ev) => {
|
|
21
|
+
ev.stopPropagation();
|
|
22
|
+
setCollapsed(value => !value);
|
|
23
|
+
};
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
measureOverflow();
|
|
26
|
+
const contentEl = contentRef.current;
|
|
27
|
+
if (!contentEl || typeof ResizeObserver === 'undefined') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const observer = new ResizeObserver(measureOverflow);
|
|
31
|
+
observer.observe(contentEl);
|
|
32
|
+
return () => observer.disconnect();
|
|
33
|
+
}, [children, maxHeight]);
|
|
34
|
+
const contentStyle = {
|
|
35
|
+
maxHeight: collapsed ? maxHeight : undefined,
|
|
36
|
+
transition: 'max-height 0.3s ease',
|
|
37
|
+
overflow: collapsed ? 'hidden' : 'visible',
|
|
38
|
+
};
|
|
39
|
+
const hoverButtonContainerStyle = {
|
|
40
|
+
position: 'absolute',
|
|
41
|
+
bottom: hovered ? 10 : -40,
|
|
42
|
+
left: '50%',
|
|
43
|
+
transform: 'translateX(-50%)',
|
|
44
|
+
transition: 'bottom 0.3s ease, opacity 0.3s ease',
|
|
45
|
+
display: 'flex',
|
|
46
|
+
justifyContent: 'center',
|
|
47
|
+
width: '100%',
|
|
48
|
+
pointerEvents: 'none',
|
|
49
|
+
opacity: hovered && isOverflow ? 1 : 0,
|
|
50
|
+
};
|
|
51
|
+
const inlineButtonContainerStyle = {
|
|
52
|
+
textAlign: 'center',
|
|
53
|
+
marginTop: 8,
|
|
54
|
+
};
|
|
55
|
+
const finalButtonStyle = {
|
|
56
|
+
pointerEvents: 'auto',
|
|
57
|
+
border: 'none',
|
|
58
|
+
boxShadow: showButtonOnHover ? '0 2px 8px rgba(0, 0, 0, 0.15)' : undefined,
|
|
59
|
+
...buttonStyle,
|
|
60
|
+
};
|
|
61
|
+
const button = (_jsx(Button, { size: 'small', icon: collapsed ? _jsx(DownOutlined, {}) : _jsx(UpOutlined, {}), onClick: toggleCollapse, style: finalButtonStyle }));
|
|
62
|
+
return (_jsxs(Card, { ref: ref, style: { position: 'relative', overflow: 'hidden', ...style }, onMouseEnter: (ev) => {
|
|
63
|
+
setHovered(true);
|
|
64
|
+
onMouseEnter?.(ev);
|
|
65
|
+
}, onMouseLeave: (ev) => {
|
|
66
|
+
setHovered(false);
|
|
67
|
+
onMouseLeave?.(ev);
|
|
68
|
+
}, ...rest, children: [_jsx("div", { style: contentStyle, ref: contentRef, children: children }), isOverflow && (showButtonOnHover ? (_jsx("div", { style: hoverButtonContainerStyle, children: button })) : (_jsx("div", { style: inlineButtonContainerStyle, children: button })))] }));
|
|
69
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
export const PageBase = (props) => {
|
|
4
|
+
const { title, children } = props;
|
|
5
|
+
return (_jsx("div", { className: 'max-w-7xl mx-auto', children: _jsxs("div", { className: 'p-6', children: [_jsx("h1", { className: 'text-2xl font-medium text-gray-900 mb-6', children: title }), children] }) }));
|
|
6
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { Layout } from 'react-grid-layout';
|
|
3
|
+
import 'react-grid-layout/css/styles.css';
|
|
4
|
+
export type { Layout as GridLayoutItem } from 'react-grid-layout';
|
|
5
|
+
interface ResizableGridLayoutProps<I> {
|
|
6
|
+
layout: I[];
|
|
7
|
+
style?: CSSProperties;
|
|
8
|
+
onChange?: (layout: I[]) => void;
|
|
9
|
+
renderItem?: (item: I) => ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export declare const ResizableGridLayout: <I extends Layout>(props: ResizableGridLayoutProps<I>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import GridLayout from 'react-grid-layout';
|
|
3
|
+
import 'react-grid-layout/css/styles.css';
|
|
4
|
+
export const ResizableGridLayout = (props) => {
|
|
5
|
+
const { style, layout, onChange, renderItem = item => item.i } = props;
|
|
6
|
+
const onLayoutChange = (items) => {
|
|
7
|
+
onChange?.(items.map(item => ({
|
|
8
|
+
...layout.find(i => i.i === item.i),
|
|
9
|
+
...item,
|
|
10
|
+
})));
|
|
11
|
+
};
|
|
12
|
+
return (_jsx(GridLayout, { layout: layout, cols: 24, rowHeight: 50, width: 1200, useCSSTransforms: false, containerPadding: [0, 0], style: { width: '100%', height: '100%', userSelect: 'none', ...style }, draggableHandle: '.drag-handle', resizeHandles: ['se'], onLayoutChange: onLayoutChange, children: layout.map(item => (_jsx("div", { children: renderItem(item) }, item.i))) }));
|
|
13
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface SideMenuItem {
|
|
3
|
+
key: string;
|
|
4
|
+
title: string;
|
|
5
|
+
path: string;
|
|
6
|
+
icon?: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface SideMenuGroup {
|
|
9
|
+
group: string;
|
|
10
|
+
items: SideMenuItem[];
|
|
11
|
+
}
|
|
12
|
+
export interface SideMenuLinkRenderProps {
|
|
13
|
+
item: SideMenuItem;
|
|
14
|
+
className: string;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
export interface SideMenuProps {
|
|
18
|
+
items?: SideMenuGroup[];
|
|
19
|
+
currentPath?: string;
|
|
20
|
+
title?: ReactNode;
|
|
21
|
+
footer?: ReactNode;
|
|
22
|
+
defaultCollapsed?: boolean;
|
|
23
|
+
className?: string;
|
|
24
|
+
isActive?: (item: SideMenuItem, currentPath: string) => boolean;
|
|
25
|
+
renderLink?: (props: SideMenuLinkRenderProps) => ReactNode;
|
|
26
|
+
}
|
|
27
|
+
export declare const SideMenu: (props: SideMenuProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { AppstoreOutlined, MenuFoldOutlined, MenuUnfoldOutlined, } from '@ant-design/icons';
|
|
5
|
+
import { Button } from 'antd';
|
|
6
|
+
import { getIconNode } from '../../inputs/IconSelect';
|
|
7
|
+
const defaultIsActive = (item, currentPath) => {
|
|
8
|
+
const prefix = item.path.split('/').slice(0, 2).join('/');
|
|
9
|
+
return currentPath.startsWith(prefix);
|
|
10
|
+
};
|
|
11
|
+
export const SideMenu = (props) => {
|
|
12
|
+
const { items, currentPath = '', title, footer, defaultCollapsed = false, className = '', isActive = defaultIsActive, renderLink, } = props;
|
|
13
|
+
const menuRef = useRef(null);
|
|
14
|
+
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
|
15
|
+
const [menuWidth, setMenuWidth] = useState(0);
|
|
16
|
+
const shouldShowTitle = menuWidth > 180;
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!menuRef.current)
|
|
19
|
+
return;
|
|
20
|
+
const resizeObserver = new ResizeObserver(entries => {
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
setMenuWidth(entry.contentRect.width);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
resizeObserver.observe(menuRef.current);
|
|
26
|
+
return () => {
|
|
27
|
+
resizeObserver.disconnect();
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
return (_jsxs("div", { ref: menuRef, className: `bg-gray-100 h-screen flex flex-col transition-all ${collapsed ? 'w-16' : 'w-48'} ${className}`.trim(), children: [_jsxs("div", { className: 'p-4 flex items-center justify-between', children: [shouldShowTitle && title ? _jsx("div", { className: 'text-xl font-bold', children: title }) : null, _jsx(Button, { type: 'text', icon: collapsed ? _jsx(MenuUnfoldOutlined, {}) : _jsx(MenuFoldOutlined, {}), onClick: () => setCollapsed(!collapsed), className: 'flex items-center justify-center' })] }), _jsx("ul", { className: 'flex-1 overflow-y-auto', children: items?.map(group => (_jsxs("div", { children: [shouldShowTitle && !collapsed ? (_jsx("div", { className: 'text-xs text-gray-500 py-2 px-4 font-medium', children: group.group })) : null, group.items.map(item => {
|
|
31
|
+
const active = isActive(item, currentPath);
|
|
32
|
+
const linkClassName = `flex items-center py-2 text-gray-900 transition-colors justify-center no-underline hover:no-underline ${collapsed ? '' : 'pr-4'} ${active
|
|
33
|
+
? '!bg-blue-500 !text-white'
|
|
34
|
+
: 'hover:!bg-gray-200 hover:!text-gray-900'}`;
|
|
35
|
+
const content = (_jsxs(_Fragment, { children: [_jsx("span", { className: 'text-lg', children: getIconNode(item.icon) ?? _jsx(AppstoreOutlined, {}) }), shouldShowTitle ? _jsx("span", { className: 'ml-2', children: item.title }) : null] }));
|
|
36
|
+
return (_jsx("li", { children: renderLink
|
|
37
|
+
? renderLink({ item, className: linkClassName, children: content })
|
|
38
|
+
: (_jsx("a", { href: item.path, className: linkClassName, children: content })) }, item.key));
|
|
39
|
+
})] }, group.group))) }), _jsx("div", { className: 'border-t border-gray-200 mt-auto', children: !collapsed ? footer : null })] }));
|
|
40
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type TabsProps } from 'antd';
|
|
2
|
+
type SyncMode = 'replace' | 'push';
|
|
3
|
+
export interface TabsProProps extends TabsProps {
|
|
4
|
+
syncToUrl?: boolean;
|
|
5
|
+
queryKey?: string;
|
|
6
|
+
historyMode?: SyncMode;
|
|
7
|
+
}
|
|
8
|
+
export declare const TabsPro: (props: TabsProProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|