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