mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2024-12-21 04:50:14 +08:00
feat(checkbox-group): add min max prop (#491)
* feat:n-input Support hidden password * feat(form): support require-mark-placement(#171) * Revert "feat(form): support require-mark-placement(#171)" This reverts commit0627777693
. * Revert "feat:n-input Support hidden password" This reverts commitea6491783d
. * feat(checkboxGroup): add min max prop WIP * feat(checkboxGroup): add min max prop WIP * feat(checkboxGroup): add min max prop * Update CHANGELOG.zh-CN.md * Update CheckboxGroup.tsx * feat(checkboxGroup): fix code * Update Checkbox.spec.ts * feat(checkboxGroup): fix code
This commit is contained in:
parent
fb2b30eec0
commit
cb929ff479
@ -1,5 +1,11 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## Pending
|
||||||
|
|
||||||
|
### Feats
|
||||||
|
|
||||||
|
- `n-checkbox-group` add `min` and `max` prop.
|
||||||
|
|
||||||
## 2.15.5 (2021-07-16)
|
## 2.15.5 (2021-07-16)
|
||||||
|
|
||||||
### Feats
|
### Feats
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## Pending
|
||||||
|
|
||||||
|
### Feats
|
||||||
|
|
||||||
|
- `n-checkbox-group` 新增 `min` 和 `max` 属性.
|
||||||
|
|
||||||
## 2.15.5 (2021-07-16)
|
## 2.15.5 (2021-07-16)
|
||||||
|
|
||||||
### Feats
|
### Feats
|
||||||
@ -9,7 +15,6 @@
|
|||||||
- `n-carousel` 新增 `show-arrow` 属性
|
- `n-carousel` 新增 `show-arrow` 属性
|
||||||
- `n-slider` 新增 `format-tooltip` 属性
|
- `n-slider` 新增 `format-tooltip` 属性
|
||||||
- `n-upload` 在 `on-finish` 回调参数中新增 `event`
|
- `n-upload` 在 `on-finish` 回调参数中新增 `event`
|
||||||
- `n-slider` 新增 `format-tooltip` 属性
|
|
||||||
- `n-rate` 新增 `readonly` 属性
|
- `n-rate` 新增 `readonly` 属性
|
||||||
- `n-time-picker` 新增 `seconds`、`minutes`、`hours`属性
|
- `n-time-picker` 新增 `seconds`、`minutes`、`hours`属性
|
||||||
- `n-notification` 导出 `NotificationApi`, `NotificationOptions` and `NotificationReactive` 类型
|
- `n-notification` 导出 `NotificationApi`, `NotificationOptions` and `NotificationReactive` 类型
|
||||||
|
@ -20,11 +20,11 @@ event
|
|||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| checked | `boolean` | `false` | Whether it is selected in the controlled mode. |
|
| checked | `boolean` | `false` | Whether it is selected in the controlled mode. |
|
||||||
| indeterminate | `boolean` | `false` | Whether partly selected. |
|
|
||||||
| default-checked | `boolean` | `false` | Whether selected by default in uncontrolled mode. |
|
| default-checked | `boolean` | `false` | Whether selected by default in uncontrolled mode. |
|
||||||
| disabled | `boolean` | `false` | Whether to disable. |
|
| disabled | `boolean` | `false` | Whether to disable. |
|
||||||
| focusable | `boolean` | `true` | Whether to focus on selection. |
|
| focusable | `boolean` | `true` | Whether to focus on selection. |
|
||||||
| label | `string \| (() => VNodeChild)` | `undefined` | Checkbox label |
|
| indeterminate | `boolean` | `false` | Whether partly selected. |
|
||||||
|
| label | `string \| (() => VNodeChild)` | `undefined` | Checkbox label. |
|
||||||
| value | `string \| number` | `undefined` | The value of the checkbox to be used in checkbox group. |
|
| value | `string \| number` | `undefined` | The value of the checkbox to be used in checkbox group. |
|
||||||
| on-update:checked | `(checked: boolean) => void` | `undefined` | Callback function triggered on checked status changes. |
|
| on-update:checked | `(checked: boolean) => void` | `undefined` | Callback function triggered on checked status changes. |
|
||||||
|
|
||||||
@ -34,6 +34,8 @@ event
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| disabled | `boolean` | `false` | Whether the checkbox group is disabled. |
|
| disabled | `boolean` | `false` | Whether the checkbox group is disabled. |
|
||||||
| default-value | `Array<string \| number>` | `null` | Checkbox group's default selected value. |
|
| default-value | `Array<string \| number>` | `null` | Checkbox group's default selected value. |
|
||||||
|
| max | `number` | `undefined` | The maximum number of checkboxes that can be checked. |
|
||||||
|
| min | `number` | `undefined` | The minimum number of checkboxes that can be checked. |
|
||||||
| value | `Array<string \| number> \| null` | `undefined` | Controlled value of checkbox group. |
|
| value | `Array<string \| number> \| null` | `undefined` | Controlled value of checkbox group. |
|
||||||
| on-update:value | `(value: string \| number)` | `undefined` | Callback when checkbox group's value changes. |
|
| on-update:value | `(value: string \| number)` | `undefined` | Callback when checkbox group's value changes. |
|
||||||
|
|
||||||
|
@ -20,10 +20,10 @@ event
|
|||||||
| 名称 | 类型 | 默认值 | 说明 |
|
| 名称 | 类型 | 默认值 | 说明 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| checked | `boolean` | `false` | 受控状态下是否选中 |
|
| checked | `boolean` | `false` | 受控状态下是否选中 |
|
||||||
| indeterminate | `boolean` | `false` | 是否部分选中 |
|
|
||||||
| default-checked | `boolean` | `false` | 非受控模式下默认是否选中 |
|
| default-checked | `boolean` | `false` | 非受控模式下默认是否选中 |
|
||||||
| disabled | `boolean` | `false` | 是否禁用 |
|
| disabled | `boolean` | `false` | 是否禁用 |
|
||||||
| focusable | `boolean` | `true` | 是否可被 focus |
|
| focusable | `boolean` | `true` | 是否可被 focus |
|
||||||
|
| indeterminate | `boolean` | `false` | 是否部分选中 |
|
||||||
| label | `string \| (() => VNodeChild)` | `undefined` | Checkbox 的标签 |
|
| label | `string \| (() => VNodeChild)` | `undefined` | Checkbox 的标签 |
|
||||||
| value | `string \| number` | `undefined` | Checkbox 在 checkbox group 中使用的值 |
|
| value | `string \| number` | `undefined` | Checkbox 在 checkbox group 中使用的值 |
|
||||||
| on-update:checked | `(checked: boolean) => void` | `undefined` | 当 checked 改变时触发的回调函数 |
|
| on-update:checked | `(checked: boolean) => void` | `undefined` | 当 checked 改变时触发的回调函数 |
|
||||||
@ -34,6 +34,8 @@ event
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| disabled | `boolean` | `false` | 选项组是否禁用 |
|
| disabled | `boolean` | `false` | 选项组是否禁用 |
|
||||||
| default-value | `Array<string \| number>` | `null` | 选项组非受控模式下的默认值 |
|
| default-value | `Array<string \| number>` | `null` | 选项组非受控模式下的默认值 |
|
||||||
|
| max | `number` | `undefined` | 可被勾选的 checkbox 的最大数量 |
|
||||||
|
| min | `number` | `undefined` | 可被勾选的 checkbox 的最小数量 |
|
||||||
| value | `Array<string \| number> \| null` | `undefined` | 选项组受控模式下的值 |
|
| value | `Array<string \| number> \| null` | `undefined` | 选项组受控模式下的值 |
|
||||||
| on-update:value | `(value: string \| number)` | `undefined` | 选项组的值改变时的回调 |
|
| on-update:value | `(value: string \| number)` | `undefined` | 选项组的值改变时的回调 |
|
||||||
|
|
||||||
|
@ -94,7 +94,28 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const mergedDisabledRef = computed(() => {
|
const mergedDisabledRef = computed(() => {
|
||||||
return props.disabled || NCheckboxGroup?.disabledRef.value
|
if (props.disabled) return true
|
||||||
|
if (NCheckboxGroup) {
|
||||||
|
if (NCheckboxGroup.disabledRef.value) return true
|
||||||
|
const {
|
||||||
|
maxRef: { value: max },
|
||||||
|
minRef: { value: min },
|
||||||
|
checkedCountRef: { value: checkedCount }
|
||||||
|
} = NCheckboxGroup
|
||||||
|
if (max !== undefined && min === undefined) {
|
||||||
|
return checkedCount >= max && !renderedCheckedRef.value
|
||||||
|
}
|
||||||
|
if (max === undefined && min !== undefined) {
|
||||||
|
return checkedCount <= min && renderedCheckedRef.value
|
||||||
|
}
|
||||||
|
if (max !== undefined && min !== undefined) {
|
||||||
|
return (
|
||||||
|
(checkedCount <= min && renderedCheckedRef.value) ||
|
||||||
|
(checkedCount >= max && !renderedCheckedRef.value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
})
|
})
|
||||||
const formItem = useFormItem(props, {
|
const formItem = useFormItem(props, {
|
||||||
mergedSize (NFormItem) {
|
mergedSize (NFormItem) {
|
||||||
|
@ -7,7 +7,8 @@ import {
|
|||||||
toRef,
|
toRef,
|
||||||
ref,
|
ref,
|
||||||
InjectionKey,
|
InjectionKey,
|
||||||
Ref
|
Ref,
|
||||||
|
ComputedRef
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { useMergedState } from 'vooks'
|
import { useMergedState } from 'vooks'
|
||||||
import { useConfig, useFormItem } from '../../_mixins'
|
import { useConfig, useFormItem } from '../../_mixins'
|
||||||
@ -15,17 +16,21 @@ import { warn, call, MaybeArray } from '../../_utils'
|
|||||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||||
|
|
||||||
export interface CheckboxGroupInjection {
|
export interface CheckboxGroupInjection {
|
||||||
|
checkedCountRef: ComputedRef<number>
|
||||||
|
maxRef: Ref<number | undefined>
|
||||||
|
minRef: Ref<number | undefined>
|
||||||
disabledRef: Ref<boolean>
|
disabledRef: Ref<boolean>
|
||||||
valueSetRef: Ref<Set<string | number>>
|
valueSetRef: Ref<Set<string | number>>
|
||||||
mergedSizeRef: Ref<'small' | 'medium' | 'large'>
|
mergedSizeRef: Ref<'small' | 'medium' | 'large'>
|
||||||
toggleCheckbox: (checked: boolean, checkboxValue: string | number) => void
|
toggleCheckbox: (checked: boolean, checkboxValue: string | number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const checkboxGroupInjectionKey: InjectionKey<CheckboxGroupInjection> = Symbol(
|
export const checkboxGroupInjectionKey: InjectionKey<CheckboxGroupInjection> =
|
||||||
'checkboxGroup'
|
Symbol('checkboxGroup')
|
||||||
)
|
|
||||||
|
|
||||||
const checkboxGroupProps = {
|
const checkboxGroupProps = {
|
||||||
|
min: Number,
|
||||||
|
max: Number,
|
||||||
size: String as PropType<'small' | 'medium' | 'large'>,
|
size: String as PropType<'small' | 'medium' | 'large'>,
|
||||||
value: Array as PropType<Array<string | number> | null>,
|
value: Array as PropType<Array<string | number> | null>,
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
@ -74,6 +79,10 @@ export default defineComponent({
|
|||||||
controlledValueRef,
|
controlledValueRef,
|
||||||
uncontrolledValueRef
|
uncontrolledValueRef
|
||||||
)
|
)
|
||||||
|
const checkedCount = computed(() => {
|
||||||
|
return mergedValueRef.value?.length || 0
|
||||||
|
})
|
||||||
|
|
||||||
const valueSetRef = computed<Set<string | number>>(() => {
|
const valueSetRef = computed<Set<string | number>>(() => {
|
||||||
if (Array.isArray(mergedValueRef.value)) {
|
if (Array.isArray(mergedValueRef.value)) {
|
||||||
return new Set(mergedValueRef.value)
|
return new Set(mergedValueRef.value)
|
||||||
@ -90,6 +99,7 @@ export default defineComponent({
|
|||||||
'onUpdate:value': _onUpdateValue,
|
'onUpdate:value': _onUpdateValue,
|
||||||
onUpdateValue
|
onUpdateValue
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
if (Array.isArray(mergedValueRef.value)) {
|
if (Array.isArray(mergedValueRef.value)) {
|
||||||
const groupValue = Array.from(mergedValueRef.value)
|
const groupValue = Array.from(mergedValueRef.value)
|
||||||
const index = groupValue.findIndex((value) => value === checkboxValue)
|
const index = groupValue.findIndex((value) => value === checkboxValue)
|
||||||
@ -134,6 +144,9 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
provide(checkboxGroupInjectionKey, {
|
provide(checkboxGroupInjectionKey, {
|
||||||
|
checkedCountRef: checkedCount,
|
||||||
|
maxRef: toRef(props, 'max'),
|
||||||
|
minRef: toRef(props, 'min'),
|
||||||
valueSetRef: valueSetRef,
|
valueSetRef: valueSetRef,
|
||||||
disabledRef: toRef(props, 'disabled'),
|
disabledRef: toRef(props, 'disabled'),
|
||||||
mergedSizeRef: formItem.mergedSizeRef,
|
mergedSizeRef: formItem.mergedSizeRef,
|
||||||
|
@ -152,4 +152,132 @@ describe('n-checkbox-group', () => {
|
|||||||
})
|
})
|
||||||
expect(wrapper.find('.n-checkbox__label').text()).toContain('test')
|
expect(wrapper.find('.n-checkbox__label').text()).toContain('test')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should work with `min` prop', async () => {
|
||||||
|
const wrapper = mount(NCheckboxGroup, {
|
||||||
|
props: {
|
||||||
|
min: 1,
|
||||||
|
value: ['Shanghai']
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
default: () => [
|
||||||
|
h(NCheckbox, { value: 'Shanghai' }, { default: () => 'Shanghai' }),
|
||||||
|
h(NCheckbox, { value: 'Beijing' }, { default: () => 'Beijing' }),
|
||||||
|
h(NCheckbox, { value: 'Shenzhen' }, { default: () => 'Shenzhen' })
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(wrapper.findAll('.n-checkbox').length).toBe(3)
|
||||||
|
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).not.toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).not.toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should work with `max` prop', async () => {
|
||||||
|
const wrapper = mount(NCheckboxGroup, {
|
||||||
|
props: {
|
||||||
|
max: 2,
|
||||||
|
value: ['Shanghai', 'Beijing']
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
default: () => [
|
||||||
|
h(NCheckbox, { value: 'Shanghai' }, { default: () => 'Shanghai' }),
|
||||||
|
h(NCheckbox, { value: 'Beijing' }, { default: () => 'Beijing' }),
|
||||||
|
h(NCheckbox, { value: 'Shenzhen' }, { default: () => 'Shenzhen' })
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(wrapper.findAll('.n-checkbox').length).toBe(3)
|
||||||
|
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).not.toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).not.toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[2].classes()).not.toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[2].classes()).toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should work with `max` and `min` prop', async () => {
|
||||||
|
const wrapper = mount(NCheckboxGroup, {
|
||||||
|
props: {
|
||||||
|
max: 2,
|
||||||
|
min: 1
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
default: () => [
|
||||||
|
h(NCheckbox, { value: 'Shanghai' }, { default: () => 'Shanghai' }),
|
||||||
|
h(NCheckbox, { value: 'Beijing' }, { default: () => 'Beijing' }),
|
||||||
|
h(NCheckbox, { value: 'Shenzhen' }, { default: () => 'Shenzhen' })
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.setProps({
|
||||||
|
value: ['Shanghai']
|
||||||
|
})
|
||||||
|
expect(wrapper.findAll('.n-checkbox').length).toBe(3)
|
||||||
|
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).not.toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).not.toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[2].classes()).not.toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[2].classes()).not.toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
await wrapper.setProps({
|
||||||
|
value: ['Shanghai', 'Beijing']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).not.toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[0].classes()).toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[1].classes()).not.toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[2].classes()).not.toContain(
|
||||||
|
'n-checkbox--checked'
|
||||||
|
)
|
||||||
|
expect(wrapper.findAll('.n-checkbox')[2].classes()).toContain(
|
||||||
|
'n-checkbox--disabled'
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user