@wzyjs/antd 0.2.41
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/package.json +25 -0
- package/src/form/CheckboxButton/index.module.scss +24 -0
- package/src/form/CheckboxButton/index.tsx +31 -0
- package/src/form/RadioButton/index.tsx +26 -0
- package/src/form/Upload/index.tsx +65 -0
- package/src/form/index.ts +3 -0
- package/src/index.ts +34 -0
- package/src/pro/Alert/index.tsx +24 -0
- package/src/pro/Button/components/Confirm.tsx +24 -0
- package/src/pro/Button/components/Copy.tsx +46 -0
- package/src/pro/Button/components/Drawer.tsx +37 -0
- package/src/pro/Button/components/Group.tsx +26 -0
- package/src/pro/Button/index.tsx +11 -0
- package/src/pro/Card/index.tsx +92 -0
- package/src/pro/Collapse/components/Item.tsx +30 -0
- package/src/pro/Collapse/index.tsx +27 -0
- package/src/pro/Image/index.tsx +17 -0
- package/src/pro/Input/components/Range.tsx +46 -0
- package/src/pro/Input/index.tsx +61 -0
- package/src/pro/Popconfirm/index.tsx +16 -0
- package/src/pro/Radio/components/Cancel.tsx +30 -0
- package/src/pro/Radio/index.tsx +7 -0
- package/src/pro/Space/index.tsx +15 -0
- package/src/pro/Typography/components/String.tsx +72 -0
- package/src/pro/Typography/index.tsx +9 -0
- package/src/pro/index.ts +10 -0
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wzyjs/antd",
|
|
3
|
+
"version": "0.2.41",
|
|
4
|
+
"description": "description",
|
|
5
|
+
"author": "wzy",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@ant-design/icons": "^5.6.1",
|
|
12
|
+
"@ant-design/nextjs-registry": "^1.0.2",
|
|
13
|
+
"@ant-design/pro-components": "^2.8.6",
|
|
14
|
+
"@ant-design/v5-patch-for-react-19": "^1.0.3"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@wzyjs/hooks": "^0.2.37",
|
|
18
|
+
"@wzyjs/utils": "^0.2.37",
|
|
19
|
+
"antd": "^5.24.3"
|
|
20
|
+
},
|
|
21
|
+
"gitHead": "22795bdb9c670d3e37e9a6e83b544f916bab3c16",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.checkcard {
|
|
2
|
+
:global(.ant-pro-checkcard-content) {
|
|
3
|
+
padding: 0 !important;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
:global(.ant-pro-checkcard) {
|
|
7
|
+
margin-bottom: 0 !important;
|
|
8
|
+
text-align: center !important;
|
|
9
|
+
display: flex;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
border-radius: 0 !important;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:global(.ant-pro-checkcard-title) {
|
|
15
|
+
height: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:global(.ant-pro-checkcard div) {
|
|
19
|
+
width: 100%;
|
|
20
|
+
font-weight: 400 !important;
|
|
21
|
+
height: 30px !important;
|
|
22
|
+
line-height: 28px !important;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Col, Row } from 'antd'
|
|
4
|
+
import { CheckCard } from '@ant-design/pro-components'
|
|
5
|
+
import { CheckCardValueType } from '@ant-design/pro-card/es/components/CheckCard/Group'
|
|
6
|
+
|
|
7
|
+
import styles from './index.module.scss'
|
|
8
|
+
|
|
9
|
+
interface CheckboxButtonProps {
|
|
10
|
+
options: { label: string; value: CheckCardValueType }[]
|
|
11
|
+
value?: CheckCardValueType
|
|
12
|
+
onChange?: (value?: CheckCardValueType) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const CheckboxButton = (props: CheckboxButtonProps) => {
|
|
16
|
+
const { options, value, onChange } = props
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className={styles.checkcard}>
|
|
20
|
+
<CheckCard.Group style={{ width: '100%' }} size='small' multiple value={value} onChange={onChange}>
|
|
21
|
+
<Row>
|
|
22
|
+
{options.map((item, index) => (
|
|
23
|
+
<Col key={index}>
|
|
24
|
+
<CheckCard title={item.label} value={item.value} style={{ width: 60, height: 30 }} />
|
|
25
|
+
</Col>
|
|
26
|
+
))}
|
|
27
|
+
</Row>
|
|
28
|
+
</CheckCard.Group>
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Radio } from 'antd'
|
|
4
|
+
|
|
5
|
+
interface FilterButtonProps<V> {
|
|
6
|
+
options: { label: string; value: V }[]
|
|
7
|
+
value: V
|
|
8
|
+
onChange: (value: V) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const RadioButton = <V = string | number | boolean | null>(props: FilterButtonProps<V>) => {
|
|
12
|
+
const { value, options, onChange } = props
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Radio.Group
|
|
16
|
+
optionType='button'
|
|
17
|
+
buttonStyle='solid'
|
|
18
|
+
value={value}
|
|
19
|
+
onChange={e => onChange(e.target.value as V)}
|
|
20
|
+
>
|
|
21
|
+
{options.filter(item => item.label).map(item => (
|
|
22
|
+
<Radio key={String(item.value)} value={item.value}>{item.label}</Radio>
|
|
23
|
+
))}
|
|
24
|
+
</Radio.Group>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Upload } from 'antd'
|
|
4
|
+
import { InboxOutlined } from '@ant-design/icons'
|
|
5
|
+
import { generateUniqueFileName } from '@wzyjs/utils'
|
|
6
|
+
|
|
7
|
+
interface item {
|
|
8
|
+
name: string
|
|
9
|
+
url: string
|
|
10
|
+
status: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface UploadFormItemProps {
|
|
14
|
+
oss: any
|
|
15
|
+
multiple?: boolean,
|
|
16
|
+
mode?: 'image' | 'video'
|
|
17
|
+
value?: item[]
|
|
18
|
+
onChange?: (value: item[]) => void
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const UploadFormItem = (props: UploadFormItemProps) => {
|
|
22
|
+
const { oss, mode = 'image', multiple = true, onChange } = props
|
|
23
|
+
|
|
24
|
+
const accept = mode === 'image' ? '.jpg,.png,.jpeg' : '.mp4,.mov'
|
|
25
|
+
|
|
26
|
+
const onUpload = async (info: any) => {
|
|
27
|
+
onChange?.(info.fileList.map((item: any) => ({
|
|
28
|
+
name: item?.response.name,
|
|
29
|
+
url: item?.response.url,
|
|
30
|
+
})))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const customRequest = async ({ file, onSuccess }: any) => {
|
|
34
|
+
const newName = generateUniqueFileName(file.name)
|
|
35
|
+
const result = await oss.put(newName, file, {
|
|
36
|
+
headers: {
|
|
37
|
+
'Cache-Control': 'public, max-age=31536000, immutable', // 设置缓存时间为365天
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
onSuccess(result)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Upload.Dragger
|
|
45
|
+
multiple={multiple}
|
|
46
|
+
accept={accept}
|
|
47
|
+
listType='picture-card'
|
|
48
|
+
onChange={onUpload}
|
|
49
|
+
customRequest={customRequest}
|
|
50
|
+
>
|
|
51
|
+
<p className='ant-upload-drag-icon'>
|
|
52
|
+
<InboxOutlined />
|
|
53
|
+
</p>
|
|
54
|
+
<p className='ant-upload-text'>
|
|
55
|
+
<span>点击或拖拽文件到这里以上传</span>
|
|
56
|
+
</p>
|
|
57
|
+
{mode === 'image' && (
|
|
58
|
+
<p className='ant-upload-hint'>支持上传多张 JPG 或者 PNG 格式的照片</p>
|
|
59
|
+
)}
|
|
60
|
+
{mode === 'video' && (
|
|
61
|
+
<p className='ant-upload-hint'>支持上传多个 MP4 或者 MOV 格式的视频</p>
|
|
62
|
+
)}
|
|
63
|
+
</Upload.Dragger>
|
|
64
|
+
)
|
|
65
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import '@ant-design/v5-patch-for-react-19'
|
|
2
|
+
|
|
3
|
+
export * from 'antd'
|
|
4
|
+
|
|
5
|
+
export * from '@ant-design/icons'
|
|
6
|
+
|
|
7
|
+
export { default as zh_CN } from 'antd/locale/zh_CN'
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
AntdRegistry,
|
|
11
|
+
} from '@ant-design/nextjs-registry'
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
PageLoading,
|
|
15
|
+
PageHeader,
|
|
16
|
+
|
|
17
|
+
ProCard,
|
|
18
|
+
ProList,
|
|
19
|
+
|
|
20
|
+
ProFormText,
|
|
21
|
+
ProFormCaptcha,
|
|
22
|
+
ProFormCheckbox,
|
|
23
|
+
ProFormUploadButton,
|
|
24
|
+
LoginForm,
|
|
25
|
+
BetaSchemaForm,
|
|
26
|
+
|
|
27
|
+
CheckCard,
|
|
28
|
+
EditableProTable,
|
|
29
|
+
} from '@ant-design/pro-components'
|
|
30
|
+
|
|
31
|
+
export type { ProLayoutProps, ProFormInstance } from '@ant-design/pro-components'
|
|
32
|
+
|
|
33
|
+
export * from './pro'
|
|
34
|
+
export * from './form'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { ReactNode } from 'react'
|
|
4
|
+
import { Alert, AlertProps, Space } from 'antd'
|
|
5
|
+
|
|
6
|
+
export interface AlertProProps extends AlertProps {
|
|
7
|
+
children?: ReactNode,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// 1. 支持 children 作为 description 显示
|
|
11
|
+
export const AlertPro = (props: AlertProProps) => {
|
|
12
|
+
const { children, description = children } = props
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Alert
|
|
16
|
+
{...props}
|
|
17
|
+
description={(
|
|
18
|
+
<Space style={{ width: '100%' }} direction='vertical'>
|
|
19
|
+
{description}
|
|
20
|
+
</Space>
|
|
21
|
+
)}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { _ } from '@wzyjs/utils'
|
|
5
|
+
import { Button, Popconfirm, PopconfirmProps, ButtonProps } from 'antd'
|
|
6
|
+
|
|
7
|
+
export interface ConfirmProps extends PopconfirmProps {
|
|
8
|
+
btnProps?: ButtonProps
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 1. 给按钮增加了确认功能
|
|
12
|
+
export const Confirm = (props: ConfirmProps) => {
|
|
13
|
+
const { children, btnProps } = props
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Popconfirm
|
|
17
|
+
okText='是'
|
|
18
|
+
cancelText='否'
|
|
19
|
+
{..._.omit(props, ['children', 'btnProps'])}
|
|
20
|
+
>
|
|
21
|
+
<Button type='link' {...btnProps}>{children}</Button>
|
|
22
|
+
</Popconfirm>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useState, ReactNode } from 'react'
|
|
4
|
+
|
|
5
|
+
import { Button, ButtonProps, message } from 'antd'
|
|
6
|
+
import { CheckOutlined } from '@ant-design/icons'
|
|
7
|
+
|
|
8
|
+
import { copy, readClipboard } from '@wzyjs/utils'
|
|
9
|
+
import { useControllableValue } from '@wzyjs/hooks'
|
|
10
|
+
|
|
11
|
+
export interface CopyProps extends ButtonProps {
|
|
12
|
+
value?: string,
|
|
13
|
+
canPaste?: boolean,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const Copy = (props: CopyProps) => {
|
|
17
|
+
const [icon, setIcon] = useState<ReactNode>(null)
|
|
18
|
+
|
|
19
|
+
const [value, setValue] = useControllableValue<string>(props, {
|
|
20
|
+
defaultValue: props.value,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const onContextMenu = async () => {
|
|
24
|
+
setValue(await readClipboard())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Button
|
|
29
|
+
{...props}
|
|
30
|
+
icon={icon}
|
|
31
|
+
onContextMenu={props.canPaste ? onContextMenu : undefined}
|
|
32
|
+
children={props.children || value || '记录'}
|
|
33
|
+
onClick={(ev: any) => {
|
|
34
|
+
props.onClick?.(ev)
|
|
35
|
+
|
|
36
|
+
copy(value)
|
|
37
|
+
message.success('复制成功')
|
|
38
|
+
|
|
39
|
+
setIcon(<CheckOutlined />)
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
setIcon(null)
|
|
42
|
+
}, 1000)
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react'
|
|
4
|
+
import { _ } from '@wzyjs/utils'
|
|
5
|
+
import { Button, Drawer as AntdDrawer, DrawerProps as AntdDrawerProps, ButtonProps } from 'antd'
|
|
6
|
+
|
|
7
|
+
export interface DrawerProps extends AntdDrawerProps {
|
|
8
|
+
btnProps?: ButtonProps
|
|
9
|
+
defaultOpen?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const Drawer = (props: DrawerProps) => {
|
|
13
|
+
const { children, defaultOpen, btnProps } = props
|
|
14
|
+
const [open, setOpen] = useState<boolean>(defaultOpen ?? false)
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
<Button
|
|
19
|
+
type='link'
|
|
20
|
+
{...btnProps}
|
|
21
|
+
onClick={ev => {
|
|
22
|
+
btnProps?.onClick?.(ev)
|
|
23
|
+
setOpen(true)
|
|
24
|
+
}}
|
|
25
|
+
/>
|
|
26
|
+
<AntdDrawer
|
|
27
|
+
title={btnProps?.children}
|
|
28
|
+
open={open}
|
|
29
|
+
onClose={() => setOpen(false)}
|
|
30
|
+
destroyOnClose
|
|
31
|
+
{..._.omit(props, ['children', 'btnProps'])}
|
|
32
|
+
>
|
|
33
|
+
{children}
|
|
34
|
+
</AntdDrawer>
|
|
35
|
+
</>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Button } from 'antd'
|
|
5
|
+
import { Confirm, ConfirmProps } from './Confirm'
|
|
6
|
+
|
|
7
|
+
export interface GroupProps {
|
|
8
|
+
list?: (ConfirmProps & { visible?: boolean, title?: string })[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 1. 按钮组
|
|
12
|
+
export const Group = (props: GroupProps) => {
|
|
13
|
+
const { list = [] } = props
|
|
14
|
+
|
|
15
|
+
if (!list?.length) {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Button.Group>
|
|
21
|
+
{list.filter(item => item.visible).map((item, index) => (
|
|
22
|
+
<Confirm key={index} {...item}>{item.title}</Confirm>
|
|
23
|
+
))}
|
|
24
|
+
</Button.Group>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useState, useRef, useEffect, forwardRef } from 'react'
|
|
4
|
+
import { Card, Button, CardProps } from 'antd'
|
|
5
|
+
import { DownOutlined, UpOutlined } from '@ant-design/icons'
|
|
6
|
+
|
|
7
|
+
interface CardProProps extends CardProps {
|
|
8
|
+
collapsedHeight?: number; // 默认折叠高度,可根据需要调整
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const CardPro = forwardRef((props: CardProProps, ref: any) => {
|
|
12
|
+
const { collapsedHeight = 300, children, ...rest } = props
|
|
13
|
+
|
|
14
|
+
const [collapsed, setCollapsed] = useState(true)
|
|
15
|
+
const [hovered, setHovered] = useState(false)
|
|
16
|
+
const [isOverflow, setIsOverflow] = useState(false)
|
|
17
|
+
const contentRef = useRef<HTMLSpanElement>(null)
|
|
18
|
+
|
|
19
|
+
const toggleCollapse = (ev: any) => {
|
|
20
|
+
ev.stopPropagation()
|
|
21
|
+
setCollapsed(!collapsed)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const contentEl = contentRef.current
|
|
26
|
+
if (contentEl) {
|
|
27
|
+
// 获取内容的实际高度
|
|
28
|
+
const actualHeight = contentEl.scrollHeight
|
|
29
|
+
if (actualHeight > collapsedHeight) {
|
|
30
|
+
setIsOverflow(true)
|
|
31
|
+
} else {
|
|
32
|
+
setIsOverflow(false)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}, [children, collapsedHeight])
|
|
36
|
+
|
|
37
|
+
const cardStyle: React.CSSProperties = {
|
|
38
|
+
position: 'relative',
|
|
39
|
+
overflow: 'hidden',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const contentStyle: React.CSSProperties = {
|
|
43
|
+
maxHeight: collapsed ? `${collapsedHeight}px` : 'none',
|
|
44
|
+
overflowY: collapsed ? 'auto' : 'visible',
|
|
45
|
+
transition: 'max-height 0.3s ease',
|
|
46
|
+
display: 'block',
|
|
47
|
+
textOverflow: 'ellipsis',
|
|
48
|
+
overflow: 'hidden',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const buttonContainerStyle: React.CSSProperties = {
|
|
52
|
+
position: 'absolute',
|
|
53
|
+
bottom: hovered ? '10px' : '-40px', // 增加隐藏时的负值,确保按钮完全隐藏
|
|
54
|
+
left: '50%',
|
|
55
|
+
transform: 'translateX(-50%)',
|
|
56
|
+
transition: 'bottom 0.3s ease, opacity 0.3s ease',
|
|
57
|
+
display: 'flex',
|
|
58
|
+
justifyContent: 'center',
|
|
59
|
+
width: '100%',
|
|
60
|
+
pointerEvents: 'none', // 默认情况下,禁止点击
|
|
61
|
+
opacity: hovered && isOverflow ? 1 : 0, // 控制按钮的透明度
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const buttonStyle: React.CSSProperties = {
|
|
65
|
+
pointerEvents: 'auto', // 允许按钮在悬停时可点击
|
|
66
|
+
border: 'none',
|
|
67
|
+
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Card
|
|
72
|
+
ref={ref}
|
|
73
|
+
style={cardStyle}
|
|
74
|
+
onMouseEnter={() => setHovered(true)}
|
|
75
|
+
onMouseLeave={() => setHovered(false)}
|
|
76
|
+
{...rest}
|
|
77
|
+
>
|
|
78
|
+
<span style={contentStyle} ref={contentRef}>
|
|
79
|
+
{children}
|
|
80
|
+
</span>
|
|
81
|
+
{isOverflow && (
|
|
82
|
+
<div style={buttonContainerStyle}>
|
|
83
|
+
<Button
|
|
84
|
+
icon={collapsed ? <DownOutlined /> : <UpOutlined />}
|
|
85
|
+
onClick={toggleCollapse}
|
|
86
|
+
style={buttonStyle}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
</Card>
|
|
91
|
+
)
|
|
92
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Collapse, CollapsePanelProps, Space } from 'antd'
|
|
5
|
+
|
|
6
|
+
export interface CollapseItemProps extends Omit<CollapsePanelProps, 'key'> {
|
|
7
|
+
step?: boolean; // 为true自动给标题添加 `第{index}步:`
|
|
8
|
+
index?: number; // step为true时才需要
|
|
9
|
+
space?: boolean; // 子元素是否有间距
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const Item = (props: CollapseItemProps) => {
|
|
13
|
+
const { step = true, header, index, space } = props
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Collapse.Panel
|
|
17
|
+
key={String(header)}
|
|
18
|
+
{...props}
|
|
19
|
+
header={step ? `第${index}步: ${header}` : header}
|
|
20
|
+
>
|
|
21
|
+
{space ? (
|
|
22
|
+
<Space direction='vertical' size='small' style={{ width: '100%' }}>
|
|
23
|
+
{props.children}
|
|
24
|
+
</Space>
|
|
25
|
+
) : (
|
|
26
|
+
props.children
|
|
27
|
+
)}
|
|
28
|
+
</Collapse.Panel>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Collapse, CollapseProps } from 'antd'
|
|
5
|
+
import { Item, CollapseItemProps } from './components/Item'
|
|
6
|
+
|
|
7
|
+
export interface CollapseProProps extends CollapseProps {
|
|
8
|
+
list?: CollapseItemProps[],
|
|
9
|
+
step?: boolean; // 为true自动给标题添加 `第{index}步:`
|
|
10
|
+
space?: boolean; // 子元素是否有间距
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const CollapsePro = (props: CollapseProProps) => {
|
|
14
|
+
const { list = [], step = false, space = true, accordion = true } = props
|
|
15
|
+
|
|
16
|
+
if (!props.children && list.length) {
|
|
17
|
+
props.children = list.map((item, index) => (
|
|
18
|
+
<Item key={index} step={step} space={space} index={index + 1} {...item} />
|
|
19
|
+
))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Collapse accordion={accordion} {...props} />
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
CollapsePro.Pane = Item
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Image, ImageProps } from 'antd'
|
|
5
|
+
|
|
6
|
+
export type ImageProProps = ImageProps
|
|
7
|
+
|
|
8
|
+
export const ImagePro = (props: ImageProProps) => {
|
|
9
|
+
const { preview = false } = props
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Image
|
|
13
|
+
{...props}
|
|
14
|
+
preview={preview}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { InputNumber, InputNumberProps, Space } from 'antd'
|
|
5
|
+
import { _ } from '@wzyjs/utils'
|
|
6
|
+
|
|
7
|
+
export interface RangeProps extends Omit<InputNumberProps, 'value' | 'onChange'> {
|
|
8
|
+
value?: number[];
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
onChange?: (numbers: number[]) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 最小值 最大值 的输入框
|
|
15
|
+
export const Range = (props: RangeProps) => {
|
|
16
|
+
const { value = [], min, max, onChange } = props
|
|
17
|
+
|
|
18
|
+
const onNumberChange = (index: 0 | 1, v: number | null) => {
|
|
19
|
+
if (Number.isNaN(v) || v === null) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const numbers = _.cloneDeep(value) || []
|
|
24
|
+
numbers[index] = v
|
|
25
|
+
|
|
26
|
+
onChange?.(numbers)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Space>
|
|
31
|
+
<InputNumber
|
|
32
|
+
min={min}
|
|
33
|
+
max={max}
|
|
34
|
+
value={value[0]}
|
|
35
|
+
onChange={(v: number | null) => onNumberChange(0, v)}
|
|
36
|
+
/>
|
|
37
|
+
<span style={{ margin: '0 3px' }}> - </span>
|
|
38
|
+
<InputNumber
|
|
39
|
+
min={min}
|
|
40
|
+
max={max}
|
|
41
|
+
value={value[1]}
|
|
42
|
+
onChange={(v: number | null) => onNumberChange(1, v)}
|
|
43
|
+
/>
|
|
44
|
+
</Space>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useState, useEffect, useMemo } from 'react'
|
|
4
|
+
import { Input, InputProps } from 'antd'
|
|
5
|
+
import { getStrLength } from '@wzyjs/utils'
|
|
6
|
+
import { Range } from './components/Range'
|
|
7
|
+
|
|
8
|
+
export interface InputProProps extends Omit<InputProps, 'onChange'> {
|
|
9
|
+
maxLengthChinese?: boolean; // 限制长度:中文算2个字符
|
|
10
|
+
onChange?: (value: string) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// 1. 增加对中文字符串的长度限制 (Input的maxLength会认为汉字为1个长度)
|
|
14
|
+
export const InputPro = (props: InputProProps) => {
|
|
15
|
+
const {
|
|
16
|
+
value: _value,
|
|
17
|
+
onChange: _onChange,
|
|
18
|
+
addonAfter: _addonAfter,
|
|
19
|
+
maxLength,
|
|
20
|
+
maxLengthChinese,
|
|
21
|
+
...rest
|
|
22
|
+
} = props
|
|
23
|
+
|
|
24
|
+
const [value, setValue] = useState<string>('')
|
|
25
|
+
|
|
26
|
+
const addonAfter = useMemo(() => {
|
|
27
|
+
if (!maxLengthChinese) {
|
|
28
|
+
return _addonAfter
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
{_addonAfter}
|
|
34
|
+
{maxLength ? `${getStrLength(value)} / ${maxLength}` : null}
|
|
35
|
+
</>
|
|
36
|
+
)
|
|
37
|
+
}, [_addonAfter, value, maxLength])
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
_onChange?.(value)
|
|
41
|
+
}, [value])
|
|
42
|
+
|
|
43
|
+
const onChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
|
44
|
+
if (maxLengthChinese && maxLength && getStrLength(ev.target.value) > maxLength) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
setValue(ev.target.value)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Input
|
|
52
|
+
value={value}
|
|
53
|
+
onChange={onChange}
|
|
54
|
+
addonAfter={addonAfter}
|
|
55
|
+
maxLength={maxLength}
|
|
56
|
+
{...rest}
|
|
57
|
+
/>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
InputPro.Range = Range
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Popconfirm, PopconfirmProps } from 'antd'
|
|
5
|
+
|
|
6
|
+
export type PopconfirmProProps = PopconfirmProps
|
|
7
|
+
|
|
8
|
+
export const PopconfirmPro = (props: PopconfirmProProps) => {
|
|
9
|
+
return (
|
|
10
|
+
<Popconfirm
|
|
11
|
+
okText="确定"
|
|
12
|
+
cancelText="取消"
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Checkbox, CheckboxProps, CheckboxOptionType } from 'antd'
|
|
5
|
+
|
|
6
|
+
export interface CancelProps {
|
|
7
|
+
value: CheckboxProps['value'];
|
|
8
|
+
options: CheckboxOptionType[];
|
|
9
|
+
onChange?: CheckboxProps['onChange'];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 给Radio组件增加取消选择的功能,是用Checkbox组件实现的
|
|
13
|
+
export const Cancel = (props: CancelProps) => {
|
|
14
|
+
const { value, options, onChange } = props
|
|
15
|
+
|
|
16
|
+
const evs = {
|
|
17
|
+
onChange: (checkedValue: CheckboxProps['value'][]) => {
|
|
18
|
+
onChange?.(checkedValue.find(i => i !== value) || '')
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Checkbox.Group
|
|
24
|
+
value={[value]}
|
|
25
|
+
prefixCls='ant-radio'
|
|
26
|
+
options={options}
|
|
27
|
+
onChange={evs.onChange}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Space, SpaceProps } from 'antd'
|
|
5
|
+
|
|
6
|
+
export type SpaceProProps = SpaceProps
|
|
7
|
+
|
|
8
|
+
export const SpacePro = (props: SpaceProProps) => {
|
|
9
|
+
return (
|
|
10
|
+
<Space
|
|
11
|
+
style={{ width: '100%' }}
|
|
12
|
+
{...props}
|
|
13
|
+
/>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useMemo } from 'react'
|
|
4
|
+
|
|
5
|
+
import { Typography } from 'antd'
|
|
6
|
+
import { TextProps } from 'antd/lib/typography/Text'
|
|
7
|
+
|
|
8
|
+
import { replaceByRules } from '@wzyjs/utils'
|
|
9
|
+
|
|
10
|
+
export interface StringProps extends TextProps {
|
|
11
|
+
isCopy?: boolean;
|
|
12
|
+
isEllipsis?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const String = (props: StringProps) => {
|
|
16
|
+
const { isEllipsis, isCopy, children } = props
|
|
17
|
+
|
|
18
|
+
const { source = '', __html = '' } = useMemo<{ source?: string, __html?: string }>(() => {
|
|
19
|
+
if (typeof children !== 'string') {
|
|
20
|
+
return {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!children.includes('’')) {
|
|
24
|
+
return {
|
|
25
|
+
source: children.trim(),
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
source: children.trim(),
|
|
31
|
+
__html: replaceByRules(children.trim(), [
|
|
32
|
+
[
|
|
33
|
+
'‘',
|
|
34
|
+
'<xmp style="display: inline-block; color: #d56161; margin: 0 3px; font-family: Consolas, Monaco, monospace;">',
|
|
35
|
+
],
|
|
36
|
+
['’', '</xmp>'],
|
|
37
|
+
]),
|
|
38
|
+
}
|
|
39
|
+
}, [])
|
|
40
|
+
|
|
41
|
+
const ellipsis = useMemo(() => {
|
|
42
|
+
if (!isEllipsis) {
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
45
|
+
return { rows: 100, expandable: true }
|
|
46
|
+
}, [isEllipsis])
|
|
47
|
+
|
|
48
|
+
const copyable = useMemo(() => {
|
|
49
|
+
if (!isCopy) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
text: replaceByRules(source, [
|
|
54
|
+
['‘', ''],
|
|
55
|
+
['’', ''],
|
|
56
|
+
]),
|
|
57
|
+
}
|
|
58
|
+
}, [isCopy, source])
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Typography.Paragraph
|
|
62
|
+
{...props}
|
|
63
|
+
ellipsis={ellipsis}
|
|
64
|
+
copyable={copyable}
|
|
65
|
+
>
|
|
66
|
+
<span
|
|
67
|
+
style={{ whiteSpace: 'pre' }}
|
|
68
|
+
dangerouslySetInnerHTML={{ __html: __html || source }}
|
|
69
|
+
/>
|
|
70
|
+
</Typography.Paragraph>
|
|
71
|
+
)
|
|
72
|
+
}
|
package/src/pro/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './Alert'
|
|
2
|
+
export * from './Button'
|
|
3
|
+
export * from './Card'
|
|
4
|
+
export * from './Collapse'
|
|
5
|
+
export * from './Image'
|
|
6
|
+
export * from './Input'
|
|
7
|
+
export * from './Radio'
|
|
8
|
+
export * from './Space'
|
|
9
|
+
export * from './Typography'
|
|
10
|
+
export * from './Popconfirm'
|