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
|
||||
|
||||
## Pending
|
||||
|
||||
### Feats
|
||||
|
||||
- `n-checkbox-group` add `min` and `max` prop.
|
||||
|
||||
## 2.15.5 (2021-07-16)
|
||||
|
||||
### Feats
|
||||
|
@ -1,5 +1,11 @@
|
||||
# CHANGELOG
|
||||
|
||||
## Pending
|
||||
|
||||
### Feats
|
||||
|
||||
- `n-checkbox-group` 新增 `min` 和 `max` 属性.
|
||||
|
||||
## 2.15.5 (2021-07-16)
|
||||
|
||||
### Feats
|
||||
@ -9,7 +15,6 @@
|
||||
- `n-carousel` 新增 `show-arrow` 属性
|
||||
- `n-slider` 新增 `format-tooltip` 属性
|
||||
- `n-upload` 在 `on-finish` 回调参数中新增 `event`
|
||||
- `n-slider` 新增 `format-tooltip` 属性
|
||||
- `n-rate` 新增 `readonly` 属性
|
||||
- `n-time-picker` 新增 `seconds`、`minutes`、`hours`属性
|
||||
- `n-notification` 导出 `NotificationApi`, `NotificationOptions` and `NotificationReactive` 类型
|
||||
|
@ -20,11 +20,11 @@ event
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 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. |
|
||||
| disabled | `boolean` | `false` | Whether to disable. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| on-update:value | `(value: string \| number)` | `undefined` | Callback when checkbox group's value changes. |
|
||||
|
||||
|
@ -20,10 +20,10 @@ event
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| checked | `boolean` | `false` | 受控状态下是否选中 |
|
||||
| indeterminate | `boolean` | `false` | 是否部分选中 |
|
||||
| default-checked | `boolean` | `false` | 非受控模式下默认是否选中 |
|
||||
| disabled | `boolean` | `false` | 是否禁用 |
|
||||
| focusable | `boolean` | `true` | 是否可被 focus |
|
||||
| indeterminate | `boolean` | `false` | 是否部分选中 |
|
||||
| label | `string \| (() => VNodeChild)` | `undefined` | Checkbox 的标签 |
|
||||
| value | `string \| number` | `undefined` | Checkbox 在 checkbox group 中使用的值 |
|
||||
| on-update:checked | `(checked: boolean) => void` | `undefined` | 当 checked 改变时触发的回调函数 |
|
||||
@ -34,6 +34,8 @@ event
|
||||
| --- | --- | --- | --- |
|
||||
| disabled | `boolean` | `false` | 选项组是否禁用 |
|
||||
| default-value | `Array<string \| number>` | `null` | 选项组非受控模式下的默认值 |
|
||||
| max | `number` | `undefined` | 可被勾选的 checkbox 的最大数量 |
|
||||
| min | `number` | `undefined` | 可被勾选的 checkbox 的最小数量 |
|
||||
| value | `Array<string \| number> \| null` | `undefined` | 选项组受控模式下的值 |
|
||||
| on-update:value | `(value: string \| number)` | `undefined` | 选项组的值改变时的回调 |
|
||||
|
||||
|
@ -94,7 +94,28 @@ export default defineComponent({
|
||||
}
|
||||
})
|
||||
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, {
|
||||
mergedSize (NFormItem) {
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
toRef,
|
||||
ref,
|
||||
InjectionKey,
|
||||
Ref
|
||||
Ref,
|
||||
ComputedRef
|
||||
} from 'vue'
|
||||
import { useMergedState } from 'vooks'
|
||||
import { useConfig, useFormItem } from '../../_mixins'
|
||||
@ -15,17 +16,21 @@ import { warn, call, MaybeArray } from '../../_utils'
|
||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
|
||||
export interface CheckboxGroupInjection {
|
||||
checkedCountRef: ComputedRef<number>
|
||||
maxRef: Ref<number | undefined>
|
||||
minRef: Ref<number | undefined>
|
||||
disabledRef: Ref<boolean>
|
||||
valueSetRef: Ref<Set<string | number>>
|
||||
mergedSizeRef: Ref<'small' | 'medium' | 'large'>
|
||||
toggleCheckbox: (checked: boolean, checkboxValue: string | number) => void
|
||||
}
|
||||
|
||||
export const checkboxGroupInjectionKey: InjectionKey<CheckboxGroupInjection> = Symbol(
|
||||
'checkboxGroup'
|
||||
)
|
||||
export const checkboxGroupInjectionKey: InjectionKey<CheckboxGroupInjection> =
|
||||
Symbol('checkboxGroup')
|
||||
|
||||
const checkboxGroupProps = {
|
||||
min: Number,
|
||||
max: Number,
|
||||
size: String as PropType<'small' | 'medium' | 'large'>,
|
||||
value: Array as PropType<Array<string | number> | null>,
|
||||
defaultValue: {
|
||||
@ -74,6 +79,10 @@ export default defineComponent({
|
||||
controlledValueRef,
|
||||
uncontrolledValueRef
|
||||
)
|
||||
const checkedCount = computed(() => {
|
||||
return mergedValueRef.value?.length || 0
|
||||
})
|
||||
|
||||
const valueSetRef = computed<Set<string | number>>(() => {
|
||||
if (Array.isArray(mergedValueRef.value)) {
|
||||
return new Set(mergedValueRef.value)
|
||||
@ -90,6 +99,7 @@ export default defineComponent({
|
||||
'onUpdate:value': _onUpdateValue,
|
||||
onUpdateValue
|
||||
} = props
|
||||
|
||||
if (Array.isArray(mergedValueRef.value)) {
|
||||
const groupValue = Array.from(mergedValueRef.value)
|
||||
const index = groupValue.findIndex((value) => value === checkboxValue)
|
||||
@ -134,6 +144,9 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
provide(checkboxGroupInjectionKey, {
|
||||
checkedCountRef: checkedCount,
|
||||
maxRef: toRef(props, 'max'),
|
||||
minRef: toRef(props, 'min'),
|
||||
valueSetRef: valueSetRef,
|
||||
disabledRef: toRef(props, 'disabled'),
|
||||
mergedSizeRef: formItem.mergedSizeRef,
|
||||
|
@ -152,4 +152,132 @@ describe('n-checkbox-group', () => {
|
||||
})
|
||||
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