Skip to content

Commit

Permalink
feat(select): add count-limit prop
Browse files Browse the repository at this point in the history
  • Loading branch information
qmhc committed Sep 7, 2023
1 parent e9e378e commit adbda63
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 4 deletions.
3 changes: 2 additions & 1 deletion common/config/src/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ export function useProps<T extends Record<string, any>>(
const getDefault = () =>
(!isFunc && isFunction(defaultValue) ? defaultValue() : defaultValue) as T[keyof T]

validator &&
import.meta.env.MODE !== 'test' &&
validator &&
watch(
() => sourceProps[key],
value => {
Expand Down
1 change: 1 addition & 0 deletions components/select/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const selectProps = buildProps({
fitPopper: booleanNumberProp,
name: String,
popperAlive: booleanProp,
countLimit: Number,
onFocus: eventProp<(event: FocusEvent) => void>(),
onBlur: eventProp<(event: FocusEvent) => void>(),
onToggle: eventProp<(visible: boolean) => void>(),
Expand Down
13 changes: 11 additions & 2 deletions components/select/select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
v-else
:label="option.label"
:value="option.value"
:disabled="option.disabled"
:disabled="option.disabled || (limited && !isSelected(option))"
:divided="option.divided"
:no-title="option.title"
:hitting="option.hitting"
Expand Down Expand Up @@ -436,7 +436,8 @@ export default defineComponent({
default: '',
static: true
},
popperAlive: null
popperAlive: null,
countLimit: 0
})
const locale = useLocale('select', toRef(props, 'locale'))
Expand Down Expand Up @@ -710,6 +711,11 @@ export default defineComponent({
const hittingLabel = computed(() => {
return !props.noPreview && currentVisible.value ? hittingOption.value?.label : undefined
})
const limited = computed(() => {
return (
props.multiple && props.countLimit > 0 && currentValues.value.length >= props.countLimit
)
})
function getOptionFromMap(value?: SelectBaseValue | null) {
if (isNull(value)) return null
Expand Down Expand Up @@ -981,6 +987,8 @@ export default defineComponent({
userOptions.value.length = 0
}
if (limited.value) return
if (dynamicOption.value && value === dynamicOption.value) {
const newOption = { ...dynamicOption }
Expand Down Expand Up @@ -1210,6 +1218,7 @@ export default defineComponent({
normalOptions,
optionParentMap,
hittingLabel,
limited,
wrapper,
reference,
Expand Down
29 changes: 28 additions & 1 deletion components/select/tests/select.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { DOMWrapper } from '@vue/test-utils'
const TEXT = 'Text'
const OPTIONS = ['Option 1', 'Option 2', 'Option 3', 'Option 4']
const LONG_OPTIONS = [
'longOption 1 longOption 1 longOption 1 longOption 1 longOption 1 longOption 1 longOption 1 longOption 1 longOption 1'
'Long Long Long Long Long Long Long Long Long Long Long Long Long Long Long Long Long Long Option 1'
]

function getValue(wrapper: DOMWrapper<Element>) {
Expand Down Expand Up @@ -410,6 +410,33 @@ describe('Select', () => {
expect(onChange).toHaveBeenLastCalledWith([OPTIONS[1], OPTIONS[0]], [OPTIONS[1], OPTIONS[0]])
})

it('count limit', async () => {
const onChange = vi.fn()
const onSelect = vi.fn()
const wrapper = mount(Select, {
props: {
visible: true,
multiple: true,
options: OPTIONS,
countLimit: 1,
onChange,
onSelect
}
})

const options = wrapper.findAll('.vxp-option')

await options[0].trigger('click')
expect(options[1].classes()).toContain('vxp-option--disabled')

onChange.mockClear()
onSelect.mockClear()

await options[1].trigger('click')
expect(onSelect).toHaveBeenCalledTimes(0)
expect(onChange).toHaveBeenCalledTimes(0)
})

it('clearable', async () => {
const onClear = vi.fn()
const wrapper = mount(Select, {
Expand Down
1 change: 1 addition & 0 deletions docs/demos/select/multiple/demo.en-US.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
multiple
clearable
option-check
:count-limit="3"
:options="options"
></Select>
<br />
Expand Down
1 change: 1 addition & 0 deletions docs/demos/select/multiple/demo.zh-CN.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
multiple
clearable
option-check
:count-limit="3"
:options="options"
></Select>
<br />
Expand Down
1 change: 1 addition & 0 deletions docs/en-US/component/select.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ type SelectFilter = (value: string, options: SelectOptionState) => boolean
| fit-popper | `boolean \| number` | Set whether the option list and the selector are forced to be of equal width, or you can pass in a value to specify the width of the option list | `false` | `2.1.23` |
| name | `string` | set `name` attribute of internal `<input>`, only effect when using filter | `''` | `2.2.2` |
| popper-alive | `boolean` | Set whether the Popper is persistent, by default it will be persistent when the `transfer` prop is not set | `null` | `2.2.3` |
| count-limit | `number` | Limit the maximum count of options for multiple selection, no limit when it is `0` | `0` | `2.2.3` |
### Select Events
Expand Down
1 change: 1 addition & 0 deletions docs/zh-CN/component/select.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ type SelectFilter = (value: string, options: SelectOptionState) => boolean
| fit-popper | `boolean \| number` | 设置选项列表与选择器是否强制等宽,也可以传入一个数值指定选项列表的宽度 | `false` | `2.1.23` |
| name | `string` | 设置内部 `<input>``name` 属性,仅使用过滤时有效 | `''` | `2.2.2` |
| popper-alive | `boolean` | 设置 Popper 元素是否持久化,默认会在未设置 `transfer` 属性时持久化 | `null` | `2.2.3` |
| count-limit | `number` | 多选时限制最大的可选数量,为 `0` 时不限制 | `0` | `2.2.3` |
### Select 事件
Expand Down

0 comments on commit adbda63

Please sign in to comment.