...
 
Commits (7)
    https://gitcode.net/jd/nutui-react/-/commit/7967fe9e6e30f2b0ce172e6f37f43aa4d83b8e3f chore: 增加对 props 的受控和非受控的封装 2023-04-04T09:56:53+08:00 oasis-cloud suanbanren@foxmail.com https://gitcode.net/jd/nutui-react/-/commit/56f96c29f011c6ebacb524c59fe622eb59d162f2 Merge remote-tracking branch 'origin/next' into next 2023-04-04T09:57:17+08:00 oasis-cloud suanbanren@foxmail.com https://gitcode.net/jd/nutui-react/-/commit/21605c97069fd68a6305fb02a4d7cb6d4f471075 chore: 增加对 props 的受控和非受控的封装 2023-04-04T10:00:57+08:00 oasis-cloud suanbanren@foxmail.com https://gitcode.net/jd/nutui-react/-/commit/74fd7ae9d80d1de73377d051e5b398c3f4c1b3fd chore: 更新文档 2023-04-04T14:45:41+08:00 oasis-cloud suanbanren@foxmail.com https://gitcode.net/jd/nutui-react/-/commit/0fdcd4773722f1a6ed0c639e8253b7bc31c86394 chore: button (#877) 2023-04-06T11:33:22+08:00 oasis-cloud suanbanren@foxmail.com * chore: button * chore: button https://gitcode.net/jd/nutui-react/-/commit/dec79e3d0dcd77d0e06fb0ea1f12824ee6b8e216 chore: icon包更新 2023-04-06T11:52:24+08:00 oasis-cloud suanbanren@foxmail.com https://gitcode.net/jd/nutui-react/-/commit/af73a7fc10d67a2c65186a404ef1086e13c01fc1 Merge remote-tracking branch 'origin/next' into next 2023-04-06T11:52:43+08:00 oasis-cloud suanbanren@foxmail.com
# 从 v1 升级到 v4 # 从 v1 升级到 v2
## 介绍 ## 介绍
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
### 基础组件 ### 基础组件
#### Button #### Button
- 删除 plain,通过 fill="outline" 实现
- 增加 ref,对外暴露组件内 button 元素
- `xxx` 重命名为 `yyy` - `xxx` 重命名为 `yyy`
- 删除 `x`, 通过 `z` 实现 - 删除 `x`, 通过 `z` 实现
- 优化 `x` 类型为 ReactNode - 优化 `x` 类型为 ReactNode
......
...@@ -18,8 +18,8 @@ specifiers: ...@@ -18,8 +18,8 @@ specifiers:
'@commitlint/cli': ^12.1.4 '@commitlint/cli': ^12.1.4
'@commitlint/config-conventional': ^12.1.4 '@commitlint/config-conventional': ^12.1.4
'@loadable/component': ^5.15.0 '@loadable/component': ^5.15.0
'@nutui/icons-react': 0.0.1-beta.3 '@nutui/icons-react': 0.0.1-beta.5
'@nutui/icons-react-taro': 0.0.1-beta.3 '@nutui/icons-react-taro': 0.0.1-beta.5
'@pmmmwh/react-refresh-webpack-plugin': ^0.5.10 '@pmmmwh/react-refresh-webpack-plugin': ^0.5.10
'@react-spring/web': ~9.6.1 '@react-spring/web': ~9.6.1
'@rollup/plugin-babel': ^6.0.3 '@rollup/plugin-babel': ^6.0.3
...@@ -113,8 +113,8 @@ specifiers: ...@@ -113,8 +113,8 @@ specifiers:
dependencies: dependencies:
'@babel/runtime': 7.21.0 '@babel/runtime': 7.21.0
'@bem-react/classname': 1.5.12 '@bem-react/classname': 1.5.12
'@nutui/icons-react': 0.0.1-beta.3 '@nutui/icons-react': 0.0.1-beta.5
'@nutui/icons-react-taro': 0.0.1-beta.3 '@nutui/icons-react-taro': 0.0.1-beta.5
'@react-spring/web': 9.6.1_biqbaboplfbrettd7655fr4n2y '@react-spring/web': 9.6.1_biqbaboplfbrettd7655fr4n2y
'@use-gesture/react': 10.2.20_react@18.2.0 '@use-gesture/react': 10.2.20_react@18.2.0
async-validator: 4.2.5 async-validator: 4.2.5
...@@ -2323,14 +2323,14 @@ packages: ...@@ -2323,14 +2323,14 @@ packages:
fastq: 1.15.0 fastq: 1.15.0
dev: true dev: true
/@nutui/icons-react-taro/0.0.1-beta.3: /@nutui/icons-react-taro/0.0.1-beta.5:
resolution: {integrity: sha512-tK6ObmMlDjHiy2qgqylYUnvVa0Tspg0PtlYNQsDDjAEngCg2nZQXyBrOf6yFi/0nAd8cr4cTCGlvEcpKyji72A==} resolution: {integrity: sha512-QDyNLcYzQ7S7yk7qXX0qCJjJjHSanDWItGvrreHYRSL2WhRRwbsh3xDdg9OEzIqncrEDkUHcLXoI6EnpGtUDAg==}
dependencies: dependencies:
classnames: 2.3.2 classnames: 2.3.2
dev: false dev: false
/@nutui/icons-react/0.0.1-beta.3: /@nutui/icons-react/0.0.1-beta.5:
resolution: {integrity: sha512-+0PdMZZuBCN6xVJ6dDmoK5nAqxMTu5qqfIWUcFjHxIrBUaR/Z+DoqdByHAmPt/msSS3cVSxNqO6wHrkZErfNUA==} resolution: {integrity: sha512-Mzc5MlthJ1d19xI7NdrYSXooznEixaoItarNzcqqhTX9GShZZvi0QXKr1jkEhxrWO1snTq1/E9jD2KoIiNJ9jQ==}
dependencies: dependencies:
classnames: 2.3.2 classnames: 2.3.2
dev: false dev: false
......
@import '../icon/icon.scss';
.nut-theme-dark {
.nut-button {
&--default {
color: $dark1;
background: $dark6;
}
&--primary {
color: $dark6;
}
&--info {
color: $dark6;
}
&--success {
color: $dark6;
}
&--danger {
color: $dark6;
}
&--warning {
color: $dark6;
}
&--plain {
background: $dark6;
&.nut-button--primary {
color: $button-primary-border-color;
border-color: $button-primary-border-color;
}
&.nut-button--info {
color: $button-info-border-color;
border-color: $button-info-border-color;
}
&.nut-button--success {
color: $button-success-border-color;
border-color: $button-success-border-color;
}
&.nut-button--danger {
color: $button-danger-border-color;
border-color: $button-danger-border-color;
}
&.nut-button--warning {
color: $button-warning-border-color;
border-color: $button-warning-border-color;
}
}
}
}
.nut-button { .nut-button {
position: relative; position: relative;
display: inline-block; display: inline-block;
...@@ -75,7 +15,11 @@ ...@@ -75,7 +15,11 @@
user-select: none; user-select: none;
touch-action: manipulation; touch-action: manipulation;
.text { color: $button-default-color;
background: $button-default-bg-color;
border: $button-border-width solid $button-default-border-color;
.nut-button-text {
margin-left: $button-text-icon-width; margin-left: $button-text-icon-width;
} }
...@@ -118,69 +62,111 @@ ...@@ -118,69 +62,111 @@
} }
} }
&--default { &--solid {
color: $button-default-color; color: $button-primary-color;
background: $button-default-bg-color; background: $button-primary-background-color;
border: $button-border-width solid $button-default-border-color; border: $button-border-width solid transparent;
}
&.nut-button--outline {
color: $button-primary-border-color;
border-color: $button-primary-border-color;
background: transparent;
}
&.nut-button--none {
color: $button-primary-border-color;
background: transparent;
border-color: transparent;
} }
&--primary { &--primary {
color: $button-primary-color; color: $button-primary-color;
background: $button-primary-background-color; background: $button-primary-background-color;
border: $button-border-width solid transparent; border: $button-border-width solid transparent;
&.nut-button--outline {
color: $button-primary-border-color;
border-color: $button-primary-border-color;
background: transparent;
}
&.nut-button--none {
color: $button-primary-border-color;
background: transparent;
border-color: transparent;
}
} }
&--info { &--info {
color: $button-info-color; color: $button-info-color;
background: $button-info-background-color; background: $button-info-background-color;
border: $button-border-width solid transparent; border: $button-border-width solid transparent;
&.nut-button--outline {
color: $button-info-border-color;
border-color: $button-info-border-color;
background: transparent;
}
&.nut-button--none {
color: $button-info-border-color;
background: transparent;
border-color: transparent;
}
} }
&--success { &--success {
color: $button-success-color; color: $button-success-color;
background: $button-success-background-color; background: $button-success-background-color;
border: $button-border-width solid transparent; border: $button-border-width solid transparent;
&.nut-button--outline {
color: $button-success-border-color;
border-color: $button-success-border-color;
background: transparent;
}
&.nut-button--none {
color: $button-success-border-color;
background: transparent;
border-color: transparent;
}
} }
&--danger { &--danger {
color: $button-danger-color; color: $button-danger-color;
background: $button-danger-background-color; background: $button-danger-background-color;
border: $button-border-width solid transparent; border: $button-border-width solid transparent;
&.nut-button--outline {
color: $button-danger-border-color;
border-color: $button-danger-border-color;
background: transparent;
}
&.nut-button--none {
color: $button-danger-border-color;
background: transparent;
border-color: transparent;
}
} }
&--warning { &--warning {
color: $button-warning-color; color: $button-warning-color;
background: $button-warning-background-color; background: $button-warning-background-color;
border: $button-border-width solid transparent; border: $button-border-width solid transparent;
}
&--plain { &.nut-button--outline {
color: $button-plain-color; color: $button-warning-border-color;
background: $button-plain-background-color; border-color: $button-warning-border-color;
background: transparent;
&.nut-button--primary {
color: $button-primary-border-color;
border-color: $button-primary-border-color;
}
&.nut-button--info {
color: $button-info-border-color;
border-color: $button-info-border-color;
}
&.nut-button--success {
color: $button-success-border-color;
border-color: $button-success-border-color;
}
&.nut-button--danger {
color: $button-danger-border-color;
border-color: $button-danger-border-color;
} }
&.nut-button--warning { &.nut-button--none {
color: $button-warning-border-color; color: $button-warning-border-color;
border-color: $button-warning-border-color; background: transparent;
border-color: transparent;
} }
} }
......
import React, { import React, { CSSProperties, useCallback } from 'react'
CSSProperties, import classNames from 'classnames'
FunctionComponent,
useCallback,
useEffect,
useState,
} from 'react'
import { ButtonProps as MiniProgramButtonProps } from '@tarojs/components' import { ButtonProps as MiniProgramButtonProps } from '@tarojs/components'
import { Loading } from '@nutui/icons-react-taro' import { Loading } from '@nutui/icons-react-taro'
import { BasicComponent, ComponentDefaults } from '@/utils/typings' import { BasicComponent, ComponentDefaults } from '@/utils/typings'
type OmitMiniProgramButtonProps = Omit< type OmitMiniProgramButtonProps = Omit<
MiniProgramButtonProps, MiniProgramButtonProps,
'size' | 'type' | 'onClick' 'size' | 'type' | 'onClick' | 'style'
> >
export type ButtonType =
| 'default'
| 'primary'
| 'info'
| 'success'
| 'warning'
| 'danger'
export type ButtonSize = 'large' | 'normal' | 'small'
export type ButtonShape = 'square' | 'round'
export type ButtonFill = 'solid' | 'outline' | 'none'
export interface ButtonProps export interface ButtonProps
extends BasicComponent, extends BasicComponent,
OmitMiniProgramButtonProps { OmitMiniProgramButtonProps {
className: string
color: string color: string
shape: ButtonShape shape: ButtonShape
plain: boolean
loading: boolean
disabled: boolean
style: React.CSSProperties
type: ButtonType type: ButtonType
size: ButtonSize size: ButtonSize
fill: ButtonFill
block: boolean block: boolean
loading: boolean
disabled: boolean
icon: React.ReactNode icon: React.ReactNode
children: any
onClick: (e: MouseEvent) => void onClick: (e: MouseEvent) => void
} }
export type ButtonType = const prefixCls = 'nut-button'
| 'default'
| 'primary'
| 'info'
| 'success'
| 'warning'
| 'danger'
export type ButtonSize = 'large' | 'normal' | 'small'
export type ButtonShape = 'square' | 'round'
const defaultProps = { const defaultProps = {
...ComponentDefaults, ...ComponentDefaults,
className: '',
color: '', color: '',
type: 'default',
size: 'normal',
shape: 'round', shape: 'round',
plain: false, fill: 'solid',
loading: false, loading: false,
disabled: false, disabled: false,
type: 'default',
size: 'normal',
block: false, block: false,
icon: '', icon: null,
style: {},
children: undefined,
onClick: (e: MouseEvent) => {}, onClick: (e: MouseEvent) => {},
} as ButtonProps } as ButtonProps
export const Button: FunctionComponent<Partial<ButtonProps>> = (props) => { export const Button = React.forwardRef<HTMLButtonElement, Partial<ButtonProps>>(
const { (props, ref) => {
color, const {
shape, color,
plain, shape,
loading, fill,
disabled, loading,
type, disabled,
size, type,
block, size,
icon, block,
children, icon,
onClick, children,
className, onClick,
style, className,
...rest style,
} = { ...rest
...defaultProps, } = {
...props, ...defaultProps,
} ...props,
const getStyle = useCallback(() => { }
const style: CSSProperties = {} const getStyle = useCallback(() => {
if (color) { const style: CSSProperties = {}
if (plain) { if (props.color) {
style.color = color if (fill && fill === 'outline') {
style.background = '#fff' style.color = color
if (!color?.includes('gradient')) { style.background = '#fff'
style.borderColor = color if (!color?.includes('gradient')) {
style.borderColor = color
}
} else {
style.color = '#fff'
style.background = color
} }
} else {
style.color = '#fff'
style.background = color
} }
} return style
return style }, [color])
}, [color, plain])
const classes = useCallback(() => {
const prefixCls = 'nut-button'
return [
prefixCls,
`${type ? `${prefixCls}--${type}` : ''}`,
`${size ? `${prefixCls}--${size}` : ''}`,
`${shape ? `${prefixCls}--${shape}` : ''}`,
`${plain ? `${prefixCls}--plain` : ''}`,
`${block ? `${prefixCls}--block` : ''}`,
`${disabled ? `${prefixCls}--disabled` : ''}`,
`${loading ? `${prefixCls}--loading` : ''}`,
]
.filter(Boolean)
.join(' ')
}, [block, disabled, loading, plain, shape, size, type])
const [btnName, setBtnName] = useState(classes())
const [btnStyle, setBtnStyle] = useState(getStyle())
useEffect(() => {
setBtnName(classes())
setBtnStyle(getStyle())
}, [
className,
color,
shape,
plain,
loading,
disabled,
style,
type,
size,
block,
icon,
children,
onClick,
classes,
getStyle,
])
const handleClick = (e: any) => { const handleClick = (e: any) => {
if (!loading && !disabled && onClick) { if (!loading && !disabled && onClick) {
onClick(e) onClick(e)
}
} }
}
return ( return (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
// eslint-disable-next-line react/button-has-type // eslint-disable-next-line react/button-has-type
<button <button
className={`${btnName} ${className}`} {...rest}
style={{ ...btnStyle, ...style }} ref={ref}
{...rest} className={classNames(
onClick={(e) => handleClick(e)} prefixCls,
> className,
<div className="nut-button__warp"> props.type ? `${prefixCls}--${type}` : null,
{loading && <Loading className="nut-icon-loading" />} props.fill ? `${prefixCls}--${fill}` : null,
{!loading && icon ? icon : null} {
{children && ( [`${prefixCls}--${size}`]: size,
<div className={icon || loading ? 'text' : ''}>{children}</div> [`${prefixCls}--${shape}`]: shape,
[`${prefixCls}--block`]: block,
[`${prefixCls}--disabled`]: disabled,
[`${prefixCls}--loading`]: loading,
}
)} )}
</div> style={{ ...getStyle(), ...style }}
</button> onClick={(e) => handleClick(e)}
) >
} <div className="nut-button__warp">
{loading && <Loading className="nut-icon-loading" />}
{!loading && icon ? icon : null}
{children && (
<div className={icon || loading ? 'nut-button-text' : ''}>
{children}
</div>
)}
</div>
</button>
)
}
)
Button.defaultProps = defaultProps
Button.displayName = 'NutButton' Button.displayName = 'NutButton'
import React, { import React, { CSSProperties, useCallback } from 'react'
CSSProperties, import classNames from 'classnames'
FunctionComponent,
useCallback,
useEffect,
useState,
} from 'react'
import { Loading } from '@nutui/icons-react' import { Loading } from '@nutui/icons-react'
import { BasicComponent, ComponentDefaults } from '@/utils/typings' import { BasicComponent, ComponentDefaults } from '@/utils/typings'
export type ButtonType =
| 'default'
| 'primary'
| 'info'
| 'success'
| 'warning'
| 'danger'
export type ButtonSize = 'large' | 'normal' | 'small'
export type ButtonShape = 'square' | 'round'
export type ButtonFill = 'solid' | 'outline' | 'none'
export interface ButtonProps extends BasicComponent { export interface ButtonProps extends BasicComponent {
className: string
color: string color: string
shape: ButtonShape shape: ButtonShape
plain: boolean
loading: boolean
disabled: boolean
style: React.CSSProperties
type: ButtonType type: ButtonType
size: ButtonSize size: ButtonSize
fill: ButtonFill
block: boolean block: boolean
loading: boolean
disabled: boolean
icon: React.ReactNode icon: React.ReactNode
children: any
onClick: (e: MouseEvent) => void onClick: (e: MouseEvent) => void
} }
export type ButtonType = const prefixCls = 'nut-button'
| 'default'
| 'primary'
| 'info'
| 'success'
| 'warning'
| 'danger'
export type ButtonSize = 'large' | 'normal' | 'small'
export type ButtonShape = 'square' | 'round'
const defaultProps = { const defaultProps = {
...ComponentDefaults, ...ComponentDefaults,
className: '',
color: '', color: '',
type: 'default',
size: 'normal',
shape: 'round', shape: 'round',
plain: false, fill: 'solid',
loading: false, loading: false,
disabled: false, disabled: false,
type: 'default',
size: 'normal',
block: false, block: false,
icon: '', icon: null,
style: {},
children: undefined,
onClick: (e: MouseEvent) => {}, onClick: (e: MouseEvent) => {},
} as ButtonProps } as ButtonProps
export const Button: FunctionComponent<Partial<ButtonProps>> = (props) => { export const Button = React.forwardRef<HTMLButtonElement, Partial<ButtonProps>>(
const { (props, ref) => {
color, const {
shape, color,
plain, shape,
loading, fill,
disabled, loading,
type, disabled,
size, type,
block, size,
icon, block,
children, icon,
onClick, children,
className, onClick,
style, className,
...rest style,
} = { ...rest
...defaultProps, } = {
...props, ...defaultProps,
} ...props,
const getStyle = useCallback(() => { }
const style: CSSProperties = {} const getStyle = useCallback(() => {
if (color) { const style: CSSProperties = {}
if (plain) { if (props.color) {
style.color = color if (fill && fill === 'outline') {
style.background = '#fff' style.color = color
if (!color?.includes('gradient')) { style.background = '#fff'
style.borderColor = color if (!color?.includes('gradient')) {
style.borderColor = color
}
} else {
style.color = '#fff'
style.background = color
} }
} else {
style.color = '#fff'
style.background = color
} }
} return style
return style }, [color])
}, [color, plain])
const classes = useCallback(() => {
const prefixCls = 'nut-button'
return [
prefixCls,
`${type ? `${prefixCls}--${type}` : ''}`,
`${size ? `${prefixCls}--${size}` : ''}`,
`${shape ? `${prefixCls}--${shape}` : ''}`,
`${plain ? `${prefixCls}--plain` : ''}`,
`${block ? `${prefixCls}--block` : ''}`,
`${disabled ? `${prefixCls}--disabled` : ''}`,
`${loading ? `${prefixCls}--loading` : ''}`,
]
.filter(Boolean)
.join(' ')
}, [block, disabled, loading, plain, shape, size, type])
const [btnName, setBtnName] = useState(classes())
const [btnStyle, setBtnStyle] = useState(getStyle())
useEffect(() => {
setBtnName(classes())
setBtnStyle(getStyle())
}, [
className,
color,
shape,
plain,
loading,
disabled,
style,
type,
size,
block,
icon,
children,
onClick,
classes,
getStyle,
])
const handleClick = (e: any) => { const handleClick = (e: any) => {
if (!loading && !disabled && onClick) { if (!loading && !disabled && onClick) {
onClick(e) onClick(e)
}
} }
}
return ( return (
// eslint-disable-next-line react/button-has-type // eslint-disable-next-line react/button-has-type
<button <button
className={`${btnName} ${className}`} {...rest}
style={{ ...btnStyle, ...style }} ref={ref}
{...rest} className={classNames(
onClick={(e) => handleClick(e)} prefixCls,
> className,
<div className="nut-button__warp"> props.type ? `${prefixCls}--${type}` : null,
{loading ? <Loading className="nut-icon-loading" /> : null} props.fill ? `${prefixCls}--${fill}` : null,
{!loading && icon ? icon : null} {
{children && ( [`${prefixCls}--${size}`]: size,
<div className={icon || loading ? 'text' : ''}>{children}</div> [`${prefixCls}--${shape}`]: shape,
[`${prefixCls}--block`]: block,
[`${prefixCls}--disabled`]: disabled,
[`${prefixCls}--loading`]: loading,
}
)} )}
</div> style={{ ...getStyle(), ...style }}
</button> onClick={(e) => handleClick(e)}
) >
} <div className="nut-button__warp">
{loading ? <Loading className="nut-icon-loading" /> : null}
{!loading && icon ? icon : null}
{children && (
<div className={icon || loading ? 'nut-button-text' : ''}>
{children}
</div>
)}
</div>
</button>
)
}
)
Button.defaultProps = defaultProps
Button.displayName = 'NutButton' Button.displayName = 'NutButton'
...@@ -40,7 +40,7 @@ const ButtonDemo = () => { ...@@ -40,7 +40,7 @@ const ButtonDemo = () => {
'8dab2f66': '危险按钮', '8dab2f66': '危险按钮',
cfbdc781: '警告按钮', cfbdc781: '警告按钮',
c3a3a1d2: '成功按钮', c3a3a1d2: '成功按钮',
e51e4582: '朴素按钮', e51e4582: '填充模式',
'7db1a8b2': '禁用状态', '7db1a8b2': '禁用状态',
a52bef0c: '加载状态', a52bef0c: '加载状态',
d04fcbda: '加载中', d04fcbda: '加载中',
...@@ -63,7 +63,7 @@ const ButtonDemo = () => { ...@@ -63,7 +63,7 @@ const ButtonDemo = () => {
'8dab2f66': '危險按鈕', '8dab2f66': '危險按鈕',
cfbdc781: '警告按鈕', cfbdc781: '警告按鈕',
c3a3a1d2: '成功按鈕', c3a3a1d2: '成功按鈕',
e51e4582: '樸素按鈕', e51e4582: '填充模式',
'7db1a8b2': '禁用狀態', '7db1a8b2': '禁用狀態',
a52bef0c: '載入狀態', a52bef0c: '載入狀態',
d04fcbda: '載入中', d04fcbda: '載入中',
...@@ -86,7 +86,7 @@ const ButtonDemo = () => { ...@@ -86,7 +86,7 @@ const ButtonDemo = () => {
'8dab2f66': 'Danger Button', '8dab2f66': 'Danger Button',
cfbdc781: 'Warning button', cfbdc781: 'Warning button',
c3a3a1d2: 'Success Button', c3a3a1d2: 'Success Button',
e51e4582: 'Naive button', e51e4582: 'Fill',
'7db1a8b2': 'Disabled State', '7db1a8b2': 'Disabled State',
a52bef0c: 'Load State', a52bef0c: 'Load State',
d04fcbda: 'Loading', d04fcbda: 'Loading',
...@@ -146,11 +146,14 @@ const ButtonDemo = () => { ...@@ -146,11 +146,14 @@ const ButtonDemo = () => {
<h2>{translated.e51e4582}</h2> <h2>{translated.e51e4582}</h2>
<Cell className="button-cell"> <Cell className="button-cell">
<Button plain style={{ margin: 8 }}> <Button fill="solid" style={{ margin: 8 }}>
{translated.e51e4582} Solid
</Button> </Button>
<Button plain color="red" style={{ margin: 8 }}> <Button fill="outline" style={{ margin: 8 }}>
{translated.e51e4582} Outline
</Button>
<Button fill="none" style={{ margin: 8 }}>
None
</Button> </Button>
</Cell> </Cell>
<h2>{translated['7db1a8b2']}</h2> <h2>{translated['7db1a8b2']}</h2>
...@@ -158,10 +161,10 @@ const ButtonDemo = () => { ...@@ -158,10 +161,10 @@ const ButtonDemo = () => {
<Button disabled style={{ margin: 8 }} type="primary"> <Button disabled style={{ margin: 8 }} type="primary">
{translated['7db1a8b2']} {translated['7db1a8b2']}
</Button> </Button>
<Button plain disabled style={{ margin: 8 }} type="info"> <Button disabled style={{ margin: 8 }} type="info">
{translated['7db1a8b2']} {translated['7db1a8b2']}
</Button> </Button>
<Button plain disabled style={{ margin: 8 }} type="primary"> <Button disabled style={{ margin: 8 }} type="primary">
{translated['7db1a8b2']} {translated['7db1a8b2']}
</Button> </Button>
</Cell> </Cell>
...@@ -192,7 +195,7 @@ const ButtonDemo = () => { ...@@ -192,7 +195,7 @@ const ButtonDemo = () => {
<Cell className="button-cell"> <Cell className="button-cell">
<Button <Button
shape="square" shape="square"
plain fill="outline"
type="primary" type="primary"
icon={<StarFill />} icon={<StarFill />}
style={{ margin: 8 }} style={{ margin: 8 }}
...@@ -240,7 +243,7 @@ const ButtonDemo = () => { ...@@ -240,7 +243,7 @@ const ButtonDemo = () => {
<Button color="#7232dd" style={{ margin: 8 }}> <Button color="#7232dd" style={{ margin: 8 }}>
{translated['1076d771']} {translated['1076d771']}
</Button> </Button>
<Button color="#7232dd" plain style={{ margin: 8 }}> <Button color="#7232dd" style={{ margin: 8 }}>
{translated['1076d771']} {translated['1076d771']}
</Button> </Button>
<Button color="rgba(10,101,208,0.75)" style={{ margin: 8 }}> <Button color="rgba(10,101,208,0.75)" style={{ margin: 8 }}>
......
...@@ -39,7 +39,7 @@ const ButtonDemo = () => { ...@@ -39,7 +39,7 @@ const ButtonDemo = () => {
'8dab2f66': '危险按钮', '8dab2f66': '危险按钮',
cfbdc781: '警告按钮', cfbdc781: '警告按钮',
c3a3a1d2: '成功按钮', c3a3a1d2: '成功按钮',
e51e4582: '朴素按钮', e51e4582: '填充模式',
'7db1a8b2': '禁用状态', '7db1a8b2': '禁用状态',
a52bef0c: '加载状态', a52bef0c: '加载状态',
d04fcbda: '加载中', d04fcbda: '加载中',
...@@ -62,7 +62,7 @@ const ButtonDemo = () => { ...@@ -62,7 +62,7 @@ const ButtonDemo = () => {
'8dab2f66': '危險按鈕', '8dab2f66': '危險按鈕',
cfbdc781: '警告按鈕', cfbdc781: '警告按鈕',
c3a3a1d2: '成功按鈕', c3a3a1d2: '成功按鈕',
e51e4582: '樸素按鈕', e51e4582: '填充模式',
'7db1a8b2': '禁用狀態', '7db1a8b2': '禁用狀態',
a52bef0c: '載入狀態', a52bef0c: '載入狀態',
d04fcbda: '載入中', d04fcbda: '載入中',
...@@ -85,7 +85,7 @@ const ButtonDemo = () => { ...@@ -85,7 +85,7 @@ const ButtonDemo = () => {
'8dab2f66': 'Danger Button', '8dab2f66': 'Danger Button',
cfbdc781: 'Warning button', cfbdc781: 'Warning button',
c3a3a1d2: 'Success Button', c3a3a1d2: 'Success Button',
e51e4582: 'Naive button', e51e4582: 'Fill',
'7db1a8b2': 'Disabled State', '7db1a8b2': 'Disabled State',
a52bef0c: 'Load State', a52bef0c: 'Load State',
d04fcbda: 'Loading', d04fcbda: 'Loading',
...@@ -135,11 +135,14 @@ const ButtonDemo = () => { ...@@ -135,11 +135,14 @@ const ButtonDemo = () => {
<h2>{translated.e51e4582}</h2> <h2>{translated.e51e4582}</h2>
<Cell className="button-cell"> <Cell className="button-cell">
<Button plain style={{ margin: 8 }}> <Button fill="solid" style={{ margin: 8 }}>
{translated.e51e4582} Solid
</Button> </Button>
<Button plain color="red" style={{ margin: 8 }}> <Button fill="outline" style={{ margin: 8 }}>
{translated.e51e4582} Outline
</Button>
<Button fill="none" style={{ margin: 8 }}>
None
</Button> </Button>
</Cell> </Cell>
<h2>{translated['7db1a8b2']}</h2> <h2>{translated['7db1a8b2']}</h2>
...@@ -147,10 +150,10 @@ const ButtonDemo = () => { ...@@ -147,10 +150,10 @@ const ButtonDemo = () => {
<Button disabled style={{ margin: 8 }} type="primary"> <Button disabled style={{ margin: 8 }} type="primary">
{translated['7db1a8b2']} {translated['7db1a8b2']}
</Button> </Button>
<Button plain disabled style={{ margin: 8 }} type="info"> <Button disabled style={{ margin: 8 }} type="info">
{translated['7db1a8b2']} {translated['7db1a8b2']}
</Button> </Button>
<Button plain disabled style={{ margin: 8 }} type="primary"> <Button disabled style={{ margin: 8 }} type="primary">
{translated['7db1a8b2']} {translated['7db1a8b2']}
</Button> </Button>
</Cell> </Cell>
...@@ -181,7 +184,7 @@ const ButtonDemo = () => { ...@@ -181,7 +184,7 @@ const ButtonDemo = () => {
<Cell className="button-cell"> <Cell className="button-cell">
<Button <Button
shape="square" shape="square"
plain fill="outline"
type="primary" type="primary"
icon={<StarFill />} icon={<StarFill />}
style={{ margin: 8 }} style={{ margin: 8 }}
...@@ -229,7 +232,7 @@ const ButtonDemo = () => { ...@@ -229,7 +232,7 @@ const ButtonDemo = () => {
<Button color="#7232dd" style={{ margin: 8 }}> <Button color="#7232dd" style={{ margin: 8 }}>
{translated['1076d771']} {translated['1076d771']}
</Button> </Button>
<Button color="#7232dd" plain style={{ margin: 8 }}> <Button color="#7232dd" style={{ margin: 8 }}>
{translated['1076d771']} {translated['1076d771']}
</Button> </Button>
<Button color="rgba(10,101,208,0.75)" style={{ margin: 8 }}> <Button color="rgba(10,101,208,0.75)" style={{ margin: 8 }}>
......
...@@ -41,9 +41,7 @@ export default App; ...@@ -41,9 +41,7 @@ export default App;
::: :::
### Plain button ### Fill button
Set the button to naïve with the text of the naïve button and the background white with the 'plain' attribute.
:::demo :::demo
...@@ -54,8 +52,9 @@ import { Button } from '@nutui/nutui-react'; ...@@ -54,8 +52,9 @@ import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
return ( return (
<> <>
<Button plain type="primary">primary</Button> <Button fill="solid">Solid</Button>
<Button plain type="info">info</Button> <Button fill="outline">Outline</Button>
<Button fill="none">None</Button>
</> </>
); );
}; };
...@@ -254,18 +253,17 @@ export default App; ...@@ -254,18 +253,17 @@ export default App;
### Props ### Props
| Props | Description | Type | Default | | Property | Description | Type | Default |
|----------|----------------------------------|--------|------------------| |----------|-------------------------------|-------------|----------|
| type | Type, optionally `primary` `info` `warning` `danger` `success` | string |`default` | | type | button style | `'default' \| 'primary' \| 'info' \| 'warning' \| 'danger' \| 'success'` | `'default'` |
| size | Dimensions, optionally `large` `small` | string | `normal` | | size | button size | `'normal' \| 'large' \| 'small'` | `'normal'` |
| shape | Shape, optionally `square` | string | `round` | | shape | button shape | `'square' \| 'round'` | `'round'` |
| color | Button color, which supports incoming linear-gradient gradients | string | - | | color | button color | `string` | - |
| plain | Whether it is a naïve button or not | boolean | `false` | | fill | fill pattern | `'solid' \| 'ouline' \| 'none'` | `'solid'` |
| disabled | Whether to disable the button | boolean | `false` | | disabled | disable the button | `boolean` | `false` |
| block | Whether it is a block-level element | boolean | `false` | | block | block element | `boolean` | `false` |
| icon | Button icon, with the Icon component name property | string | - | | icon | icon | `ReactNode` | - |
| iconSize`v1.4.7` | Button icon size, with the Icon's size property | string \| number | `16` | | loading | loading status | `boolean` | `false` |
| loading | loading status | boolean | `false` |
### Events ### Events
......
...@@ -18,53 +18,58 @@ import { Button } from '@nutui/nutui-react'; ...@@ -18,53 +18,58 @@ import { Button } from '@nutui/nutui-react';
按钮支持 `default``primary``info``warning``danger``success` 六种类型,默认为 `default` 按钮支持 `default``primary``info``warning``danger``success` 六种类型,默认为 `default`
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
return ( return (
<> <>
<Button type="primary">主要按钮</Button> <Button type="primary">主要按钮</Button>
<Button type="info">信息按钮</Button> <Button type="info">信息按钮</Button>
<Button type="default">默认按钮</Button> <Button type="default">默认按钮</Button>
<Button type="danger">危险按钮</Button> <Button type="danger">危险按钮</Button>
<Button type="warning">警告按钮</Button> <Button type="warning">警告按钮</Button>
<Button type="success">成功按钮</Button> <Button type="success">成功按钮</Button>
</> </>
); );
}; };
export default App; export default App;
``` ```
:::
### 朴素按钮 :::
通过 `plain` 属性将按钮设置为朴素按钮,朴素按钮的文字为按钮颜色,背景为白色。 ### 填充模式
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
return ( return (
<> <>
<Button plain type="primary">朴素按钮</Button> <Button fill="solid">Solid</Button>
<Button plain type="info">朴素按钮</Button> <Button fill="outline">Outline</Button>
<Button fill="none">None</Button>
</> </>
); );
}; };
export default App; export default App;
``` ```
::: :::
### 禁用状态 ### 禁用状态
通过 `disabled` 属性来禁用按钮,禁用状态下按钮不可点击。 通过 `disabled` 属性来禁用按钮,禁用状态下按钮不可点击。
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
...@@ -78,6 +83,7 @@ const App = () => { ...@@ -78,6 +83,7 @@ const App = () => {
}; };
export default App; export default App;
``` ```
::: :::
### 按钮形状 ### 按钮形状
...@@ -85,8 +91,9 @@ export default App; ...@@ -85,8 +91,9 @@ export default App;
通过 `shape` 属性设置按钮形状,支持圆形、方形按钮,默认为圆形。 通过 `shape` 属性设置按钮形状,支持圆形、方形按钮,默认为圆形。
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
...@@ -99,45 +106,50 @@ const App = () => { ...@@ -99,45 +106,50 @@ const App = () => {
}; };
export default App; export default App;
``` ```
::: :::
### 加载状态 ### 加载状态
:::demo :::demo
```tsx ```tsx
import React ,{useState} from "react"; import React, { useState } from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
const [loading,setLoading] = useState(false) const [loading, setLoading] = useState(false)
return ( return (
<> <>
<Button loading type="info" /> <Button loading type="info" />
<Button loading type="warning">加载中...</Button> <Button loading type="warning">加载中...</Button>
<Button <Button
loading={loading} loading={loading}
type="success" type="success"
onClick={() => { onClick={() => {
setTimeout(() => { setTimeout(() => {
setLoading(false) setLoading(false)
}, 1500); }, 1500);
setLoading(!loading) setLoading(!loading)
}} }}
style={{ margin: 8 }} style={{ margin: 8 }}
> >
Click me! Click me!
</Button> </Button>
</> </>
); );
}; };
export default App; export default App;
``` ```
::: :::
### 图标按钮 ### 图标按钮
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
...@@ -159,17 +171,20 @@ const App = () => { ...@@ -159,17 +171,20 @@ const App = () => {
}; };
export default App; export default App;
``` ```
::: :::
### 按钮尺寸 ### 按钮尺寸
支持 `large``normal``small` 三种尺寸,默认为 `normal` 支持 `large``normal``small` 三种尺寸,默认为 `normal`
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
return ( return (
<> <>
<Button size="large" type="primary">大号按钮</Button> <Button size="large" type="primary">大号按钮</Button>
...@@ -180,6 +195,7 @@ const App = () => { ...@@ -180,6 +195,7 @@ const App = () => {
}; };
export default App; export default App;
``` ```
::: :::
### 块级元素 ### 块级元素
...@@ -187,11 +203,12 @@ export default App; ...@@ -187,11 +203,12 @@ export default App;
按钮在默认情况下为行内块级元素,通过 `block` 属性可以将按钮的元素类型设置为块级元素,常用来实现通栏按钮。 按钮在默认情况下为行内块级元素,通过 `block` 属性可以将按钮的元素类型设置为块级元素,常用来实现通栏按钮。
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
return ( return (
<> <>
<Button block type="primary">块级元素</Button> <Button block type="primary">块级元素</Button>
...@@ -200,17 +217,20 @@ const App = () => { ...@@ -200,17 +217,20 @@ const App = () => {
}; };
export default App; export default App;
``` ```
::: :::
### 自定义颜色 ### 自定义颜色
通过 color 属性可以自定义按钮的颜色。 通过 color 属性可以自定义按钮的颜色。
:::demo :::demo
```tsx ```tsx
import React from "react"; import React from "react";
import { Button } from '@nutui/nutui-react'; import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
return ( return (
<> <>
<Button color="#7232dd">单色按钮</Button> <Button color="#7232dd">单色按钮</Button>
...@@ -224,23 +244,24 @@ const App = () => { ...@@ -224,23 +244,24 @@ const App = () => {
}; };
export default App; export default App;
``` ```
::: :::
## API ## API
### Props ### Props
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
|--------------------|----------------------------------|----------|------------------| |----------|-------------------------------|-------------|----------|
| type | 类型,可选值为 `primary` `info` `warning` `danger` `success` | string |`default` | | type | 按钮的样式 | `'default' \| 'primary' \| 'info' \| 'warning' \| 'danger' \| 'success'` | `'default'` |
| size | 尺寸,可选值为 `large` `small` | string | `normal` | | size | 按钮的尺寸 | `'normal' \| 'large' \| 'small'` | `'normal'` |
| shape | 形状,可选值为 `square` | string | `round` | | shape | 按钮的形状 | `'square' \| 'round'` | `'round'` |
| color | 按钮颜色,支持传入 linear-gradient 渐变色 | string | - | | color | 按钮颜色,支持传入 linear-gradient 渐变色 | `string` | - |
| plain | 是否为朴素按钮 | boolean | `false` | | fill | 填充模式 | `'solid' \| 'ouline' \| 'none'` | `'solid'` |
| disabled | 是否禁用按钮 | boolean | `false` | | disabled | 是否禁用按钮 | `boolean` | `false` |
| block | 是否为块级元素 | boolean | `false` | | block | 是否为块级元素 | `boolean` | `false` |
| icon | 按钮图标 | `ReactNode` | - | | icon | 按钮图标 | `ReactNode` | - |
| iconSize`v2.0.0废弃` | 按钮图标大小,同Icon组件的size属性 | string \ | number | `16` | | loading | 按钮loading状态 | `boolean` | `false` |
| loading | 按钮loading状态 | boolean | `false` |
### Events ### Events
...@@ -249,13 +270,16 @@ export default App; ...@@ -249,13 +270,16 @@ export default App;
| onClick | 点击按钮时触发 | `event: MouseEvent` | | onClick | 点击按钮时触发 | `event: MouseEvent` |
### 支持小程序API能力 ### 支持小程序API能力
目前1.3.11版本以前不支持原生小程序API, 如果你是需要使用原生小程序button组件能力的用户,请尽快升级至1.3.11版本,关于原生小程序button组件的详细API请前往[查阅更多文档](https://taro-docs.jd.com/docs/components/forms/button)
目前1.3.11版本以前不支持原生小程序API,
如果你是需要使用原生小程序button组件能力的用户,请尽快升级至1.3.11版本,关于原生小程序button组件的详细API请前往[查阅更多文档](https://taro-docs.jd.com/docs/components/forms/button)
## 主题定制 ## 主题定制
### 样式变量 ### 样式变量
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/component/configprovider) 组件提供了下列 CSS
变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/component/configprovider)
| 名称 | 默认值 | | 名称 | 默认值 |
| --- | --- | | --- | --- |
......
...@@ -55,9 +55,7 @@ export default App; ...@@ -55,9 +55,7 @@ export default App;
``` ```
::: :::
### 朴素按钮 ### 填充模式
通过 `plain` 属性将按钮设置为朴素按钮,朴素按钮的文字为按钮颜色,背景为白色。
:::demo :::demo
```tsx ```tsx
...@@ -67,8 +65,9 @@ import { Button } from '@nutui/nutui-react-taro'; ...@@ -67,8 +65,9 @@ import { Button } from '@nutui/nutui-react-taro';
const App = () => { const App = () => {
return ( return (
<> <>
<Button plain type="primary">朴素按钮</Button> <Button fill="solid">Solid</Button>
<Button plain type="info">朴素按钮</Button> <Button fill="outline">Outline</Button>
<Button fill="none">None</Button>
</> </>
); );
}; };
...@@ -247,17 +246,16 @@ export default App; ...@@ -247,17 +246,16 @@ export default App;
### Props ### Props
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
|--------------------|-----------------------------|----------|------------------| |----------|-------------------------------|-------------|----------|
| type | 类型,可选值为 `primary` `info` `warning` `danger` `success` | string |`default` | | type | 按钮的样式 | `'default' \| 'primary' \| 'info' \| 'warning' \| 'danger' \| 'success'` | `'default'` |
| size | 尺寸,可选值为 `large` `small` | string | `normal` | | size | 按钮的尺寸 | `'normal' \| 'large' \| 'small'` | `'normal'` |
| shape | 形状,可选值为 `square` | string | `round` | | shape | 按钮的形状 | `'square' \| 'round'` | `'round'` |
| color | 按钮颜色,支持传入 linear-gradient 渐变色 | string | - | | color | 按钮颜色,支持传入 linear-gradient 渐变色 | `string` | - |
| plain | 是否为朴素按钮 | boolean | `false` | | fill | 填充模式 | `'solid' \| 'ouline' \| 'none'` | `'solid'` |
| disabled | 是否禁用按钮 | boolean | `false` | | disabled | 是否禁用按钮 | `boolean` | `false` |
| block | 是否为块级元素 | boolean | `false` | | block | 是否为块级元素 | `boolean` | `false` |
| icon | 按钮图标 | `ReactNode` | - | | icon | 按钮图标 | `ReactNode` | - |
| iconSize`v2.0.0废弃` | 按钮图标大小,同Icon组件的size属性 | string \ | number | `16` | | loading | 按钮loading状态 | `boolean` | `false` |
| loading | 按钮loading状态 | boolean | `false` |
### Events ### Events
......
...@@ -39,9 +39,7 @@ export default App; ...@@ -39,9 +39,7 @@ export default App;
::: :::
### 樸素按鈕 ### 填充模式
通過 『plain』 屬性將按鈕設置為樸素按鈕,樸素按鈕的文字為按鈕顏色,背景為白色。
:::demo :::demo
...@@ -52,8 +50,9 @@ import { Button } from '@nutui/nutui-react'; ...@@ -52,8 +50,9 @@ import { Button } from '@nutui/nutui-react';
const App = () => { const App = () => {
return ( return (
<> <>
<Button plain type="primary">樸素按鈕</Button> <Button fill="solid">Solid</Button>
<Button plain type="info">樸素按鈕</Button> <Button fill="outline">Outline</Button>
<Button fill="none">None</Button>
</> </>
); );
}; };
...@@ -251,19 +250,17 @@ export default App; ...@@ -251,19 +250,17 @@ export default App;
### Props ### Props
| 屬性 | 說明 | 類型 | 預設值 | | 參數 | 說明 | 類型 | 默認值 |
|--------------------|----------------------------------|----------|------------------| |----------|-------------------------------|-------------|----------|
| type | 類型,可選值為 `primary` `info` `warning` `danger` `success` | string |`default` | | type | 按鈕的樣式 | `'default' \| 'primary' \| 'info' \| 'warning' \| 'danger' \| 'success'` | `'default'` |
| size | 尺寸,可選值為 `large` `small` | string | `normal` | | size | 按鈕的尺寸 | `'normal' \| 'large' \| 'small'` | `'normal'` |
| shape | 形狀,可選值為 `square` | string | `round` | | shape | 按鈕的形狀 | `'square' \| 'round'` | `'round'` |
| color | 按鈕顏色,支持傳入linear-gradient漸變色 | string | - | | color | 按鈕顏色,支持傳入 linear-gradient 漸變色 | `string` | - |
| plain | 是否為樸素按鈕 | boolean | `false` | | fill | 填充模式 | `'solid' \| 'ouline' \| 'none'` | `'solid'` |
| disabled | 是否禁用按鈕 | boolean | `false` | | disabled | 是否禁用按鈕 | `boolean` | `false` |
| block | 是否為塊級元素 | boolean | `false` | | block | 是否為塊級元素 | `boolean` | `false` |
| icon | 按鈕圖示 | `ReactNode` | - | | icon | 按鈕圖標 | `ReactNode` | - |
| iconSize`v2.0.0废弃` | 按鈕圖示大小,同 Icon 的size属性 | string \ | number | `16` | | loading | 按鈕loading狀態 | `boolean` | `false` |
| loading | 按鈕loading狀態 | boolean | `false` |
### Events ### Events
| 事件名稱 | 說明 | 回調參數 | | 事件名稱 | 說明 | 回調參數 |
......
...@@ -44,7 +44,7 @@ test('should fireEvent correctly', () => { ...@@ -44,7 +44,7 @@ test('should fireEvent correctly', () => {
<CheckboxGroup <CheckboxGroup
data-testid="group" data-testid="group"
className="test" className="test"
checkedValue={['1']} defaultValue={['1']}
onChange={handleChange} onChange={handleChange}
> >
<Checkbox checked={false} label="1"> <Checkbox checked={false} label="1">
...@@ -72,7 +72,7 @@ test('should fireEvent correctly', () => { ...@@ -72,7 +72,7 @@ test('should fireEvent correctly', () => {
test('Render checkboxs by configuring options', () => { test('Render checkboxs by configuring options', () => {
const CheckboxGroupOptions = () => { const CheckboxGroupOptions = () => {
const [checkedValue] = useState(['1']) const [defaultValue] = useState(['1'])
const [optionsDemo1, setOptionsDemo1] = useState([ const [optionsDemo1, setOptionsDemo1] = useState([
{ {
label: '选项一', label: '选项一',
...@@ -91,7 +91,7 @@ test('Render checkboxs by configuring options', () => { ...@@ -91,7 +91,7 @@ test('Render checkboxs by configuring options', () => {
return ( return (
<> <>
<CheckboxGroup <CheckboxGroup
checkedValue={checkedValue} defaultValue={defaultValue}
options={optionsDemo1} options={optionsDemo1}
></CheckboxGroup> ></CheckboxGroup>
</> </>
......
...@@ -9,10 +9,12 @@ import CheckboxGroup from '@/packages/checkboxgroup' ...@@ -9,10 +9,12 @@ import CheckboxGroup from '@/packages/checkboxgroup'
import bem from '@/utils/bem' import bem from '@/utils/bem'
import { BasicComponent, ComponentDefaults } from '@/utils/typings' import { BasicComponent, ComponentDefaults } from '@/utils/typings'
import Context from '../checkboxgroup/context' import Context from '../checkboxgroup/context'
import { usePropsValue } from '@/utils/use-props-value'
export interface CheckboxProps extends BasicComponent { export interface CheckboxProps extends BasicComponent {
checked: boolean checked: boolean
disabled: boolean disabled: boolean
defaultChecked: boolean
textPosition: 'left' | 'right' textPosition: 'left' | 'right'
iconSize: string | number iconSize: string | number
icon: React.ReactNode icon: React.ReactNode
...@@ -22,12 +24,11 @@ export interface CheckboxProps extends BasicComponent { ...@@ -22,12 +24,11 @@ export interface CheckboxProps extends BasicComponent {
iconFontClassName: string iconFontClassName: string
indeterminate: boolean indeterminate: boolean
label: string | number label: string | number
onChange: (state: boolean, label: string) => void onChange: (state: boolean) => void
} }
const defaultProps = { const defaultProps = {
...ComponentDefaults, ...ComponentDefaults,
checked: false,
disabled: false, disabled: false,
textPosition: 'right', textPosition: 'right',
iconSize: 18, iconSize: 18,
...@@ -36,7 +37,7 @@ const defaultProps = { ...@@ -36,7 +37,7 @@ const defaultProps = {
iconClassPrefix: 'nut-icon', iconClassPrefix: 'nut-icon',
iconFontClassName: 'nutui-iconfont', iconFontClassName: 'nutui-iconfont',
indeterminateIcon: 'check-disabled', indeterminateIcon: 'check-disabled',
onChange: (state, label) => {}, onChange: (state) => {},
} as CheckboxProps } as CheckboxProps
export const Checkbox: FunctionComponent< export const Checkbox: FunctionComponent<
Partial<CheckboxProps> & Partial<CheckboxProps> &
...@@ -54,6 +55,7 @@ export const Checkbox: FunctionComponent< ...@@ -54,6 +55,7 @@ export const Checkbox: FunctionComponent<
className, className,
checkedIcon, checkedIcon,
checked, checked,
defaultChecked,
disabled, disabled,
onChange, onChange,
indeterminate, indeterminate,
...@@ -66,24 +68,29 @@ export const Checkbox: FunctionComponent< ...@@ -66,24 +68,29 @@ export const Checkbox: FunctionComponent<
let { textPosition, ...rest } = others let { textPosition, ...rest } = others
const ctx = useContext(Context) const ctx = useContext(Context)
let [innerChecked, setInnerChecked] = useState(checked) let [_checked, setChecked] = usePropsValue<boolean>({
value: props.checked,
defaultValue: props.defaultChecked,
finalValue: defaultChecked,
onChange,
})
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let [innerDisabled, setDisabled] = useState(disabled) let [innerDisabled, setDisabled] = useState(disabled)
const [_indeterminate, setIndeterminate] = useState(indeterminate) const [_indeterminate, setIndeterminate] = useState(indeterminate)
useEffect(() => { useEffect(() => {
!ctx && setInnerChecked(checked) !ctx && setChecked(checked)
setDisabled(disabled) setDisabled(disabled)
setIndeterminate(indeterminate) setIndeterminate(indeterminate)
}, [disabled, checked, indeterminate]) }, [disabled, indeterminate])
if (ctx) { if (ctx) {
if (ctx.textPosition !== undefined) { if (ctx.textPosition !== undefined) {
textPosition = ctx.textPosition textPosition = ctx.textPosition
} }
innerDisabled = ctx.disabled innerDisabled = ctx.disabled
innerChecked = ctx.checkedValue.includes(label) _checked = ctx.checkedValue.includes(label)
setInnerChecked = (checked: boolean) => { setChecked = (checked: boolean) => {
if (ctx.disabled) return if (ctx.disabled) return
if (checked) ctx.check(label) if (checked) ctx.check(label)
if (!checked) ctx.uncheck(label) if (!checked) ctx.uncheck(label)
...@@ -91,7 +98,7 @@ export const Checkbox: FunctionComponent< ...@@ -91,7 +98,7 @@ export const Checkbox: FunctionComponent<
} }
const renderIcon = () => { const renderIcon = () => {
if (!innerChecked) { if (!_checked) {
return React.isValidElement(icon) ? ( return React.isValidElement(icon) ? (
icon icon
) : ( ) : (
...@@ -115,7 +122,7 @@ export const Checkbox: FunctionComponent< ...@@ -115,7 +122,7 @@ export const Checkbox: FunctionComponent<
if (innerDisabled) { if (innerDisabled) {
return 'nut-checkbox__icon--disable' return 'nut-checkbox__icon--disable'
} }
if (innerChecked) { if (_checked) {
if (_indeterminate) { if (_indeterminate) {
return 'nut-checkbox__icon--indeterminate' return 'nut-checkbox__icon--indeterminate'
} }
...@@ -135,13 +142,14 @@ export const Checkbox: FunctionComponent< ...@@ -135,13 +142,14 @@ export const Checkbox: FunctionComponent<
// 禁用的时候直接返回 // 禁用的时候直接返回
if (disabled) return if (disabled) return
// 先转换状态 // 先转换状态
const latestChecked = !innerChecked const latestChecked = !_checked
// 判断是不是有 context 和 max,有的话需要判断是不是超过最大限制 // 判断是不是有 context 和 max,有的话需要判断是不是超过最大限制
if (ctx && ctx.max !== undefined) { if (ctx && ctx.max !== undefined) {
if (latestChecked && ctx.checkedValue.length >= ctx.max) return if (latestChecked && ctx.checkedValue.length >= ctx.max) return
} }
onChange && onChange(latestChecked, label || (children as string)) onChange && onChange(latestChecked, label || (children as string))
setInnerChecked(latestChecked) // setInnerChecked(latestChecked)
setChecked(latestChecked)
} }
return ( return (
......
...@@ -7,6 +7,8 @@ import { Checkbox } from './checkbox' ...@@ -7,6 +7,8 @@ import { Checkbox } from './checkbox'
import Button from '@/packages/button' import Button from '@/packages/button'
interface T { interface T {
uncontrolled: string
controlled: string
basic: string basic: string
checkbox: string checkbox: string
disbaled: string disbaled: string
...@@ -34,6 +36,8 @@ interface T { ...@@ -34,6 +36,8 @@ interface T {
const CheckboxDemo = () => { const CheckboxDemo = () => {
const [translated] = useTranslate<T>({ const [translated] = useTranslate<T>({
'zh-CN': { 'zh-CN': {
uncontrolled: '非受控',
controlled: '受控',
basic: '基本用法', basic: '基本用法',
checkbox: '复选框', checkbox: '复选框',
disbaled: '禁用状态', disbaled: '禁用状态',
...@@ -58,6 +62,8 @@ const CheckboxDemo = () => { ...@@ -58,6 +62,8 @@ const CheckboxDemo = () => {
threeState: '全选/半选/取消', threeState: '全选/半选/取消',
}, },
'zh-TW': { 'zh-TW': {
uncontrolled: '非受控',
controlled: '受控',
basic: '基本用法', basic: '基本用法',
checkbox: '複選框', checkbox: '複選框',
disbaled: '禁用狀態', disbaled: '禁用狀態',
...@@ -82,6 +88,8 @@ const CheckboxDemo = () => { ...@@ -82,6 +88,8 @@ const CheckboxDemo = () => {
threeState: '全选/半选/取消', threeState: '全选/半选/取消',
}, },
'en-US': { 'en-US': {
uncontrolled: 'uncontrolled',
controlled: 'controlled',
basic: 'Basic Usage', basic: 'Basic Usage',
checkbox: 'Checkbox', checkbox: 'Checkbox',
disbaled: 'Disabled State', disbaled: 'Disabled State',
...@@ -107,7 +115,7 @@ const CheckboxDemo = () => { ...@@ -107,7 +115,7 @@ const CheckboxDemo = () => {
}, },
}) })
const [checked] = useState(true) const [checked, setChecked] = useState(false)
const [checkbox1, setCheckbox1] = useState(false) const [checkbox1, setCheckbox1] = useState(false)
const [indeterminate, setIndeterminate] = useState(false) const [indeterminate, setIndeterminate] = useState(false)
const [checkboxgroup1, setCheckboxgroup1] = useState(['1']) const [checkboxgroup1, setCheckboxgroup1] = useState(['1'])
...@@ -133,9 +141,37 @@ const CheckboxDemo = () => { ...@@ -133,9 +141,37 @@ const CheckboxDemo = () => {
}, },
]) ])
const [controlled, setControlled] = useState(false)
return ( return (
<> <>
<div className="demo"> <div className="demo">
<h2>{translated.uncontrolled}</h2>
<Cell className="nut-cell">
<Checkbox
className="test"
label={translated.checkbox}
defaultChecked={checked}
/>
</Cell>
<h2>{translated.controlled}</h2>
<Cell className="nut-cell">
<Checkbox
className="test"
label={translated.checkbox}
checked={controlled}
onChange={(val) => setControlled(val)}
/>
</Cell>
<Cell className="nut-cell">
<Checkbox.Group textPosition="left" defaultValue={['选项 2']}>
<span>
<Checkbox label={optionsDemo1[0].label} />
</span>
<Checkbox label={optionsDemo1[1].label} />
<Checkbox label={optionsDemo1[2].label} />
</Checkbox.Group>
</Cell>
<h2>{translated.basic}</h2> <h2>{translated.basic}</h2>
<Cell className="nut-cell"> <Cell className="nut-cell">
<Checkbox <Checkbox
...@@ -146,7 +182,7 @@ const CheckboxDemo = () => { ...@@ -146,7 +182,7 @@ const CheckboxDemo = () => {
/> />
</Cell> </Cell>
<Cell className="nut-cell"> <Cell className="nut-cell">
<Checkbox.Group textPosition="left" checkedValue={['选项 1']}> <Checkbox.Group textPosition="left" defaultValue={['选项 1']}>
<span> <span>
<Checkbox label={optionsDemo1[0].label} checked={false} /> <Checkbox label={optionsDemo1[0].label} checked={false} />
</span> </span>
...@@ -156,7 +192,7 @@ const CheckboxDemo = () => { ...@@ -156,7 +192,7 @@ const CheckboxDemo = () => {
</Cell> </Cell>
<h2>{translated.selective}</h2> <h2>{translated.selective}</h2>
<Cell> <Cell>
<Checkbox.Group checkedValue={checkboxgroup1}> <Checkbox.Group defaultValue={checkboxgroup1}>
<Checkbox label={`${translated.checkbox}1`} checked indeterminate /> <Checkbox label={`${translated.checkbox}1`} checked indeterminate />
</Checkbox.Group> </Checkbox.Group>
</Cell> </Cell>
...@@ -201,11 +237,11 @@ const CheckboxDemo = () => { ...@@ -201,11 +237,11 @@ const CheckboxDemo = () => {
<Cell className="nut-cell"> <Cell className="nut-cell">
<Checkbox <Checkbox
checked={false} checked={false}
onChange={(state, label) => { onChange={(state) => {
if (state) { if (state) {
Toast.text(translated.selected.replace('x', label)) Toast.text(translated.selected.replace('x', state.toString()))
} else { } else {
Toast.text(translated.uncheckedx.replace('x', label)) Toast.text(translated.uncheckedx.replace('x', state.toString()))
} }
}} }}
> >
...@@ -215,7 +251,7 @@ const CheckboxDemo = () => { ...@@ -215,7 +251,7 @@ const CheckboxDemo = () => {
<h2>Checkbox.Group</h2> <h2>Checkbox.Group</h2>
<Cell> <Cell>
<Checkbox.Group <Checkbox.Group
checkedValue={checkboxgroup1} defaultValue={checkboxgroup1}
direction="horizontal" direction="horizontal"
onChange={(value) => { onChange={(value) => {
Toast.text(value) Toast.text(value)
...@@ -245,7 +281,7 @@ const CheckboxDemo = () => { ...@@ -245,7 +281,7 @@ const CheckboxDemo = () => {
<h2>{translated.Disabled}</h2> <h2>{translated.Disabled}</h2>
<Cell> <Cell>
<Checkbox.Group <Checkbox.Group
checkedValue={checkboxgroup1} defaultValue={checkboxgroup1}
disabled disabled
direction="horizontal" direction="horizontal"
> >
...@@ -261,7 +297,7 @@ const CheckboxDemo = () => { ...@@ -261,7 +297,7 @@ const CheckboxDemo = () => {
textPosition="left" textPosition="left"
direction="horizontal" direction="horizontal"
ref={checkboxgroup2Ref} ref={checkboxgroup2Ref}
checkedValue={checkboxgroup2} defaultValue={checkboxgroup2}
onChange={(value) => { onChange={(value) => {
Toast.text( Toast.text(
`${ `${
...@@ -317,7 +353,7 @@ const CheckboxDemo = () => { ...@@ -317,7 +353,7 @@ const CheckboxDemo = () => {
<h2>{translated.max}</h2> <h2>{translated.max}</h2>
<Cell> <Cell>
<Checkbox.Group <Checkbox.Group
checkedValue={checkboxgroup3} defaultValue={checkboxgroup3}
max={2} max={2}
onChange={(value) => { onChange={(value) => {
Toast.text(value) Toast.text(value)
...@@ -343,7 +379,7 @@ const CheckboxDemo = () => { ...@@ -343,7 +379,7 @@ const CheckboxDemo = () => {
<Checkbox <Checkbox
checked={checkbox1} checked={checkbox1}
indeterminate={indeterminate} indeterminate={indeterminate}
onChange={(state, label) => { onChange={(state) => {
if (state) { if (state) {
setIndeterminate(false) setIndeterminate(false)
} }
...@@ -358,7 +394,7 @@ const CheckboxDemo = () => { ...@@ -358,7 +394,7 @@ const CheckboxDemo = () => {
<Checkbox.Group <Checkbox.Group
ref={checkboxgroup3Ref} ref={checkboxgroup3Ref}
direction="horizontal" direction="horizontal"
checkedValue={checkboxgroup4} defaultValue={checkboxgroup4}
onChange={(value) => { onChange={(value) => {
if (value.length === 4) { if (value.length === 4) {
setIndeterminate(false) setIndeterminate(false)
...@@ -389,7 +425,7 @@ const CheckboxDemo = () => { ...@@ -389,7 +425,7 @@ const CheckboxDemo = () => {
<Cell> <Cell>
<Checkbox.Group <Checkbox.Group
options={optionsDemo1} options={optionsDemo1}
checkedValue={checkboxgroup5} defaultValue={checkboxgroup5}
onChange={(val) => { onChange={(val) => {
console.log(val) console.log(val)
setCheckboxgroup5(val) setCheckboxgroup5(val)
......
import React, { import React, { useCallback, useImperativeHandle } from 'react'
useCallback,
useEffect,
useImperativeHandle,
useState,
} from 'react'
import bem from '@/utils/bem' import bem from '@/utils/bem'
import { RadioGroupOptionType } from '@/packages/radiogroup/type' import { RadioGroupOptionType } from '@/packages/radiogroup/type'
import { Checkbox } from '../checkbox/checkbox' import { Checkbox } from '../checkbox/checkbox'
import Context from './context' import Context from './context'
import { usePropsValue } from '@/utils/use-props-value'
export type CheckboxTextPosition = 'left' | 'right' export type CheckboxTextPosition = 'left' | 'right'
export type CheckboxDirection = 'horizontal' | 'vertical' export type CheckboxDirection = 'horizontal' | 'vertical'
export interface CheckboxGroupProps { export interface CheckboxGroupProps {
disabled: boolean disabled: boolean
checkedValue: string[] value?: string[]
defaultValue?: string[]
max: number | undefined max: number | undefined
textPosition: CheckboxTextPosition textPosition: CheckboxTextPosition
direction: CheckboxDirection direction: CheckboxDirection
...@@ -23,7 +21,6 @@ export interface CheckboxGroupProps { ...@@ -23,7 +21,6 @@ export interface CheckboxGroupProps {
const defaultProps = { const defaultProps = {
disabled: false, disabled: false,
checkedValue: [],
max: undefined, max: undefined,
textPosition: 'right', textPosition: 'right',
direction: 'vertical', direction: 'vertical',
...@@ -43,7 +40,8 @@ export const CheckboxGroup = React.forwardRef( ...@@ -43,7 +40,8 @@ export const CheckboxGroup = React.forwardRef(
className, className,
disabled, disabled,
onChange, onChange,
checkedValue, value,
defaultValue,
max, max,
textPosition, textPosition,
direction, direction,
...@@ -54,14 +52,14 @@ export const CheckboxGroup = React.forwardRef( ...@@ -54,14 +52,14 @@ export const CheckboxGroup = React.forwardRef(
useImperativeHandle<any, any>(ref, () => ({ useImperativeHandle<any, any>(ref, () => ({
toggleAll(state: boolean) { toggleAll(state: boolean) {
if (state === false) { if (state === false) {
setInnerValue([]) setValue([])
} else { } else {
const childrenLabel: string[] = [] const childrenLabel: string[] = []
React.Children.map(children, (child) => { React.Children.map(children, (child) => {
const childProps = (child as any).props const childProps = (child as any).props
childrenLabel.push(childProps.label || (child as any).children) childrenLabel.push(childProps.label || (child as any).children)
}) })
setInnerValue(childrenLabel) setValue(childrenLabel)
} }
}, },
toggleReverse() { toggleReverse() {
...@@ -71,16 +69,18 @@ export const CheckboxGroup = React.forwardRef( ...@@ -71,16 +69,18 @@ export const CheckboxGroup = React.forwardRef(
childrenLabel.push(childProps.label || (child as any).children) childrenLabel.push(childProps.label || (child as any).children)
}) })
const reverse: string[] = childrenLabel.filter( const reverse: string[] = childrenLabel.filter(
(c) => innerValue?.findIndex((v) => v === c) === -1 (c) => _value?.findIndex((v) => v === c) === -1
) )
setInnerValue(reverse) setValue(reverse)
}, },
})) }))
const [innerValue, setInnerValue] = useState(checkedValue || []) const [_value, setValue] = usePropsValue<string[]>({
useEffect(() => { value: props.value,
setInnerValue(checkedValue || []) defaultValue: props.defaultValue,
}, [checkedValue]) finalValue: [] as string[],
onChange,
})
const renderOptions = useCallback(() => { const renderOptions = useCallback(() => {
return options?.map(({ label, value, disabled, onChange, ...rest }) => { return options?.map(({ label, value, disabled, onChange, ...rest }) => {
...@@ -101,15 +101,15 @@ export const CheckboxGroup = React.forwardRef( ...@@ -101,15 +101,15 @@ export const CheckboxGroup = React.forwardRef(
textPosition: textPosition || 'left', textPosition: textPosition || 'left',
disabled, disabled,
max, max,
checkedValue: innerValue || [], checkedValue: _value,
check: (value: string) => { check: (value: string) => {
const combined = [...innerValue, value] const combined: string[] = [..._value, value]
setInnerValue(combined) setValue(combined)
onChange && onChange(combined) onChange && onChange(combined)
}, },
uncheck: (value: string) => { uncheck: (value: string) => {
const reduced = innerValue.filter((item) => item !== value) const reduced = _value.filter((item) => item !== value)
setInnerValue(reduced) setValue(reduced)
onChange && onChange(reduced) onChange && onChange(reduced)
}, },
}} }}
......
...@@ -79,7 +79,7 @@ const BaseDialog: ForwardRefRenderFunction< ...@@ -79,7 +79,7 @@ const BaseDialog: ForwardRefRenderFunction<
{!noCancelBtn && ( {!noCancelBtn && (
<Button <Button
size="small" size="small"
plain fill="outline"
type="primary" type="primary"
className="nut-dialog__footer-cancel" className="nut-dialog__footer-cancel"
onClick={handleCancel} onClick={handleCancel}
......
//@import '../../../styles/font/iconfont.css'; @import '../../../styles/font/iconfont.css';
.h5-span { .h5-span {
display: inline; display: inline;
} }
......
import React from 'react' import React from 'react'
import * as ReactDOM from 'react-dom/client' import * as ReactDOM from 'react-dom/client'
import App from './App' import App from './App'
import '@/utils/touchEmulator' // 适配 h5 示例桌面端预览 import '../assets/util/touch-emulator' // 适配 h5 示例桌面端预览
import '@/sites/assets/styles/reset.scss' import '@/sites/assets/styles/reset.scss'
// import '@/styles/font/iconfont.css' // import '@/styles/font/iconfont.css'
......
...@@ -3,15 +3,10 @@ import type { CSSProperties, ReactNode } from 'react' ...@@ -3,15 +3,10 @@ import type { CSSProperties, ReactNode } from 'react'
export interface BasicComponent { export interface BasicComponent {
className?: string className?: string
style?: CSSProperties style?: CSSProperties
iconFontClassName?: string
iconClassPrefix?: string
children?: ReactNode children?: ReactNode
} }
export const ComponentDefaults = { export const ComponentDefaults = {
// className: '', className: '',
// style: {}, style: {},
// children: undefined,
iconClassPrefix: 'nut-icon',
iconFontClassName: 'nutui-iconfont',
} }
import { useState } from 'react'
interface UsePropsValue<T> {
value?: T
defaultValue?: T
finalValue?: T
onChange?: (value: T) => void
}
export function usePropsValue<T>({
value,
defaultValue,
finalValue,
onChange = (value: T) => {},
}: UsePropsValue<T>): [value: T, onChange: (value: T) => void] {
const [uncontrolled, setUncontrolled] = useState(
defaultValue !== undefined ? defaultValue : finalValue
)
const handleUncontrolledChange = (val: T) => {
setUncontrolled(val)
onChange?.(val)
}
if (value !== undefined) {
return [value as T, onChange]
}
return [uncontrolled as T, handleUncontrolledChange]
}