diff --git a/packages/varlet-ui/src/checkbox-group/__tests__/index.spec.js b/packages/varlet-ui/src/checkbox-group/__tests__/index.spec.js
index a8983a7e57f..9e124aadd7f 100644
--- a/packages/varlet-ui/src/checkbox-group/__tests__/index.spec.js
+++ b/packages/varlet-ui/src/checkbox-group/__tests__/index.spec.js
@@ -72,7 +72,7 @@ test('test checkbox onClick & onChange', async () => {
await wrapper.find('.var-checkbox').trigger('click')
expect(onClick).toHaveBeenCalledTimes(1)
- expect(onChange).lastCalledWith(true)
+ expect(onChange).lastCalledWith(true, false)
wrapper.unmount()
})
@@ -146,16 +146,20 @@ test('test checkbox readonly', async () => {
wrapper.unmount()
})
-test('test checkbox indeterminate', () => {
+test('test checkbox indeterminate', async () => {
+ const onChange = vi.fn()
const wrapper = mount(VarCheckbox, {
props: {
modelValue: false,
indeterminate: true,
+ onChange,
},
})
expect(wrapper.html()).toMatchSnapshot()
+ await wrapper.find('.var-checkbox').trigger('click')
+ expect(onChange).lastCalledWith(false, false)
wrapper.unmount()
})
diff --git a/packages/varlet-ui/src/checkbox/Checkbox.vue b/packages/varlet-ui/src/checkbox/Checkbox.vue
index eb5cde1ce57..c058c231de2 100644
--- a/packages/varlet-ui/src/checkbox/Checkbox.vue
+++ b/packages/varlet-ui/src/checkbox/Checkbox.vue
@@ -19,28 +19,13 @@
@blur="isFocusing = false"
>
-
+
-
+
-
+
value.value === props.checkedValue)
const checkedValue = computed(() => props.checkedValue)
- const withAnimation = ref(false)
const { checkboxGroup, bindCheckboxGroup } = useCheckboxGroup()
const { hovering, handleHovering } = useHoverOverlay()
const { form, bindForm } = useForm()
@@ -118,7 +102,6 @@ export default defineComponent({
validate,
resetValidation,
reset,
- resetWithAnimation,
}
call(bindCheckboxGroup, checkboxProvider)
@@ -138,9 +121,7 @@ export default defineComponent({
const { checkedValue, onChange } = props
value.value = changedValue
- isIndeterminate.value = false
-
- call(onChange, value.value)
+ call(onChange, value.value, isIndeterminate.value)
validateWithTrigger('onChange')
changedValue === checkedValue ? checkboxGroup?.onChecked(checkedValue) : checkboxGroup?.onUnchecked(checkedValue)
}
@@ -158,7 +139,13 @@ export default defineComponent({
return
}
- withAnimation.value = true
+ if (isIndeterminate.value === true) {
+ isIndeterminate.value = false
+ call(props.onChange, value.value, isIndeterminate.value)
+ validateWithTrigger('onChange')
+ return
+ }
+
const maximum = checkboxGroup ? checkboxGroup.checkedCount.value >= Number(checkboxGroup.max.value) : false
if (!checked.value && maximum) {
@@ -177,10 +164,6 @@ export default defineComponent({
value.value = values.includes(checkedValue) ? checkedValue : uncheckedValue
}
- function resetWithAnimation() {
- withAnimation.value = false
- }
-
// expose
function reset() {
value.value = props.uncheckedValue
@@ -235,7 +218,6 @@ export default defineComponent({
action,
isFocusing,
isIndeterminate,
- withAnimation,
checked,
errorMessage,
checkboxGroupErrorMessage: checkboxGroup?.errorMessage,
diff --git a/packages/varlet-ui/src/checkbox/checkbox.less b/packages/varlet-ui/src/checkbox/checkbox.less
index acde2bd47b2..5c0e547bc96 100644
--- a/packages/varlet-ui/src/checkbox/checkbox.less
+++ b/packages/varlet-ui/src/checkbox/checkbox.less
@@ -8,23 +8,6 @@
--checkbox-icon-size: 24px;
}
-@keyframes var-vibrate-animation {
- 0% {
- opacity: 1;
- transform: scale(1);
- }
-
- 50% {
- opacity: 0.8;
- transform: scale(0.8);
- }
-
- 100% {
- opacity: 1;
- transform: scale(1);
- }
-}
-
.var-checkbox {
display: flex;
align-items: center;
@@ -58,10 +41,6 @@
color: var(--checkbox-text-color);
}
- &--with-animation {
- animation: var-vibrate-animation 0.25s;
- }
-
&--checked {
color: var(--checkbox-checked-color);
}
diff --git a/packages/varlet-ui/src/checkbox/docs/en-US.md b/packages/varlet-ui/src/checkbox/docs/en-US.md
index 650c7c961a1..8738f6a6d4b 100644
--- a/packages/varlet-ui/src/checkbox/docs/en-US.md
+++ b/packages/varlet-ui/src/checkbox/docs/en-US.md
@@ -21,7 +21,7 @@
| Event | Description | Arguments |
| --- | --- | --- |
| `click` | Triggered on Click | `e: Event` |
-| `change` | Triggered on change | `value: any` |
+| `change` | Triggered on change | `value: any, indeterminate: boolean` |
### Slots
diff --git a/packages/varlet-ui/src/checkbox/docs/zh-CN.md b/packages/varlet-ui/src/checkbox/docs/zh-CN.md
index d701e1bf0a2..327a9639754 100644
--- a/packages/varlet-ui/src/checkbox/docs/zh-CN.md
+++ b/packages/varlet-ui/src/checkbox/docs/zh-CN.md
@@ -21,7 +21,7 @@
| 事件名 | 说明 | 参数 |
| --- | --- | --- |
| `click` | 点击时触发 | `e: Event` |
-| `change` | 状态变更时触发 | `value: any` |
+| `change` | 状态变更时触发 | `value: any, indeterminate: boolean` |
### 插槽
diff --git a/packages/varlet-ui/src/checkbox/props.ts b/packages/varlet-ui/src/checkbox/props.ts
index ec67612e018..a439ce95323 100644
--- a/packages/varlet-ui/src/checkbox/props.ts
+++ b/packages/varlet-ui/src/checkbox/props.ts
@@ -32,7 +32,7 @@ export const props = {
},
rules: [Array, Function, Object] as PropType,
onClick: defineListenerProp<(e: Event) => void>(),
- onChange: defineListenerProp<(value: any) => void>(),
+ onChange: defineListenerProp<(value: any, indeterminate: boolean) => void>(),
'onUpdate:modelValue': defineListenerProp<(value: any) => void>(),
'onUpdate:indeterminate': defineListenerProp<(value: boolean) => void>(),
}
diff --git a/packages/varlet-ui/src/checkbox/provide.ts b/packages/varlet-ui/src/checkbox/provide.ts
index 978e8c49e28..e9aed0a8c18 100644
--- a/packages/varlet-ui/src/checkbox/provide.ts
+++ b/packages/varlet-ui/src/checkbox/provide.ts
@@ -7,7 +7,6 @@ export interface CheckboxProvider extends Validation {
checkedValue: ComputedRef
checked: ComputedRef
sync(values: Array): void
- resetWithAnimation(): void
}
export function useCheckboxGroup() {
diff --git a/packages/varlet-ui/src/menu-option/MenuOption.vue b/packages/varlet-ui/src/menu-option/MenuOption.vue
index 1eadfa6559e..a02e6eac37a 100644
--- a/packages/varlet-ui/src/menu-option/MenuOption.vue
+++ b/packages/varlet-ui/src/menu-option/MenuOption.vue
@@ -2,7 +2,14 @@
diff --git a/packages/varlet-ui/src/menu-select/MenuSelect.vue b/packages/varlet-ui/src/menu-select/MenuSelect.vue
index 76ca18af85c..862203119d0 100644
--- a/packages/varlet-ui/src/menu-select/MenuSelect.vue
+++ b/packages/varlet-ui/src/menu-select/MenuSelect.vue
@@ -31,17 +31,29 @@
ref="menuOptionsRef"
:class="classes(n('menu'), formatElevation(elevation, 3), [scrollable, n('--scrollable')])"
>
-
+
+
+
@@ -51,8 +63,9 @@
+
+
+
+ Please Select
+
+
+
+
+
+
+
+
+```
+
### Size
```html
@@ -246,6 +270,110 @@ const options = ref([
```
+### Cascade
+
+An array of options may be passed to the `children` attribute of options to achieve a cascading effect.
+
+```html
+
+
+
+
+ {{ value ? value : 'Please Select' }}
+
+
+```
+
+### Multiple Cascade
+
+Cascading multiple selections can be achieved by setting the `multiple` attribute on the basis of cascading single selections.
+
+```html
+
+
+
+
+ {{ value ? value : 'Please Select' }}
+
+
+```
+
### Options API With Customized Key
You can pass the options as an array of objects to the `options` property. Use the `label-key` and `value-key` properties to specify the fields for the label and value within the options array.
@@ -308,6 +436,7 @@ const options = ref([
| `options` ***3.3.7*** | Specifies options | _MenuSelectOption[]_ | `[]` |
| `label-key` ***3.3.7*** | As the key that uniquely identifies label | _string_ | `label` |
| `value-key` ***3.3.7*** | As the key that uniquely identifies value | _string_ | `value` |
+| `children-key` ***3.8.0*** | As the key that uniquely identifies children | _string_ | `children` |
#### MenuSelectOption
@@ -315,6 +444,7 @@ const options = ref([
| ------- | --- |----------------|-----------|
| `label` | The text of option | _string \| VNode \| (option: MenuSelectOption, selected: boolean) => VNodeChild_ | `-` |
| `value` | The value of option | _any_ | `-` |
+| `children` ***3.8.0*** | The children options of option | _MenuSelectOption[]_ | `-` |
| `disabled` | Whether to disable option | _boolean_ | `-` |
| `ripple` | Whether to enable ripple | _boolean_ | `true` |
@@ -374,6 +504,7 @@ const options = ref([
| `close` | Triggered when the menu is closed | `-` |
| `closed` | Triggered when the closing menu animation ends | `-` |
| `click-outside` | Triggered when clicking outside the menu | `event: Event` |
+| `select` ***3.8.0*** | Triggered when selecting a option | `value: any, option: MenuSelectOption` |
### Slots
diff --git a/packages/varlet-ui/src/menu-select/docs/zh-CN.md b/packages/varlet-ui/src/menu-select/docs/zh-CN.md
index d1530b51381..fdf72abbb50 100644
--- a/packages/varlet-ui/src/menu-select/docs/zh-CN.md
+++ b/packages/varlet-ui/src/menu-select/docs/zh-CN.md
@@ -26,6 +26,30 @@ const value = ref()
```
+### 选中事件
+
+```html
+
+
+
+
+ 请选择
+
+
+
+
+
+
+
+
+```
+
### 尺寸
```html
@@ -246,6 +270,110 @@ const options = ref([
```
+### 级联单选
+
+可以将选项数组传递给选项的 `children` 属性以实现级联效果。
+
+```html
+
+
+
+
+ {{ value ? value : '请选择' }}
+
+
+```
+
+### 级联多选
+
+在级联单选的基础上设置 `multiple` 属性即可实现级联多选。
+
+```html
+
+
+
+
+ {{ value ? value : '请选择' }}
+
+
+```
+
### 选项式 API(自定义字段)
可以将选项以数组形式传给 `options` 属性,同时通过 `label-key` 和 `value-key` 属性指定选项数组内文本和值的字段。
@@ -308,6 +436,7 @@ const options = ref([
| `options` ***3.3.7*** | 指定可选项 | _MenuSelectOption[]_ | `[]` |
| `label-key` ***3.3.7*** | 作为 label 唯一标识的键名 | _string_ | `label` |
| `value-key` ***3.3.7*** | 作为 value 唯一标识的键名 | _string_ | `value` |
+| `children-key` ***3.8.0*** | 作为 children 唯一标识的键名 | _string_ | `children` |
#### MenuSelectOption
@@ -315,6 +444,7 @@ const options = ref([
| ------- | --- |----------------|-----------|
| `label` | 选项的标签 | _string \| VNode \| (option: MenuSelectOption, selected: boolean) => VNodeChild_ | `-` |
| `value` | 选项的值 | _any_ | `-` |
+| `children` ***3.8.0*** | 选项的子选项 | _MenuSelectOption[]_ | `-` |
| `disabled` | 是否禁用 | _boolean_ | `-` |
| `ripple` | 是否启用水波效果 | _boolean_ | `true` |
@@ -374,6 +504,7 @@ const options = ref([
| `close` | 关闭菜单时触发 | `-` |
| `closed` | 关闭菜单动画结束时触发 | `-` |
| `click-outside` | 点击菜单外部时触发 | `event: Event` |
+| `select` ***3.8.0*** | 选择某个选项时触发 | `value: any, option: MenuSelectOption` |
### 插槽
diff --git a/packages/varlet-ui/src/menu-select/example/index.vue b/packages/varlet-ui/src/menu-select/example/index.vue
index bc6f34f4cfc..73464071f11 100644
--- a/packages/varlet-ui/src/menu-select/example/index.vue
+++ b/packages/varlet-ui/src/menu-select/example/index.vue
@@ -2,6 +2,7 @@
import { computed, ref } from 'vue'
import { watchLang, onThemeChange, AppType } from '@varlet/cli/client'
import { use, t } from './locale'
+import { Snackbar } from '@varlet/ui'
const value = ref()
const valueNormal = ref()
@@ -47,6 +48,43 @@ const keyedSelectOptions = computed(() => [
},
])
+const cascadeValue = ref()
+const cascadeMultipleValue = ref([])
+const cascadeOptions = ref([
+ {
+ label: '1',
+ value: 1,
+ },
+ {
+ label: '2',
+ value: 2,
+ children: [
+ {
+ label: '2-1',
+ value: 21,
+ children: [
+ {
+ label: '2-1-1',
+ value: 211,
+ },
+ {
+ label: '2-1-2',
+ value: 212,
+ },
+ ],
+ },
+ {
+ label: '2-2',
+ value: 22,
+ },
+ ],
+ },
+ {
+ label: '3',
+ value: 3,
+ },
+])
+
watchLang((lang) => {
use(lang)
value.value = undefined
@@ -59,8 +97,15 @@ watchLang((lang) => {
valueScrollable.value = undefined
valueCloseOnSelect.value = undefined
valueMultiple.value = []
+ cascadeValue.value = undefined
+ cascadeMultipleValue.value = []
})
+
onThemeChange()
+
+function handleSelect(value) {
+ Snackbar(`Select: ${value}`)
+}
@@ -75,6 +120,17 @@ onThemeChange()
+
{{ t('onSelect') }}
+
+ {{ t('please') }}
+
+
+
+
+
+
+
+
{{ t('size') }}
@@ -178,6 +234,16 @@ onThemeChange()
{{ valueSelectOptions ? valueSelectOptions : t('please') }}
+ {{ t('cascade') }}
+
+ {{ cascadeValue ? cascadeValue : t('please') }}
+
+
+ {{ t('multipleCascade') }}
+
+ {{ cascadeMultipleValue.length ? cascadeMultipleValue : t('please') }}
+
+
{{ t('selectOptionsWithCustomizedKey') }}
{{ valueKeyedSelectOptions ? valueKeyedSelectOptions : t('please') }}
diff --git a/packages/varlet-ui/src/menu-select/example/locale/en-US.ts b/packages/varlet-ui/src/menu-select/example/locale/en-US.ts
index 4a6dd0d51df..94a79a9eb52 100644
--- a/packages/varlet-ui/src/menu-select/example/locale/en-US.ts
+++ b/packages/varlet-ui/src/menu-select/example/locale/en-US.ts
@@ -18,4 +18,7 @@ export default {
closeOnSelect: 'Disable Close On Select',
selectOptions: 'Options API',
selectOptionsWithCustomizedKey: 'Options API (With Customized Key)',
+ onSelect: 'Selected Event',
+ cascade: 'Cascade',
+ multipleCascade: 'Multiple Cascade',
}
diff --git a/packages/varlet-ui/src/menu-select/example/locale/zh-CN.ts b/packages/varlet-ui/src/menu-select/example/locale/zh-CN.ts
index 42baecff0e2..b9d8ed53a8f 100644
--- a/packages/varlet-ui/src/menu-select/example/locale/zh-CN.ts
+++ b/packages/varlet-ui/src/menu-select/example/locale/zh-CN.ts
@@ -18,4 +18,7 @@ export default {
closeOnSelect: '选择选项时禁止关闭菜单',
selectOptions: '选项式 API',
selectOptionsWithCustomizedKey: '选项式 API(自定义字段)',
+ onSelect: '选中事件',
+ cascade: '级联单选',
+ multipleCascade: '级联多选',
}
diff --git a/packages/varlet-ui/src/menu-select/menuSelect.less b/packages/varlet-ui/src/menu-select/menuSelect.less
index 8cc5fa557e3..d5fc065c22e 100644
--- a/packages/varlet-ui/src/menu-select/menuSelect.less
+++ b/packages/varlet-ui/src/menu-select/menuSelect.less
@@ -17,3 +17,8 @@
max-height: var(--menu-select-menu-max-height);
}
}
+
+.var-menu-children[var-menu-children-cover] {
+ width: 100%;
+ display: block;
+}
diff --git a/packages/varlet-ui/src/menu-select/props.ts b/packages/varlet-ui/src/menu-select/props.ts
index a27aef163bc..a820decde26 100644
--- a/packages/varlet-ui/src/menu-select/props.ts
+++ b/packages/varlet-ui/src/menu-select/props.ts
@@ -11,9 +11,14 @@ export type MenuSelectOptionLabel = string | VNode | MenuSelectOptionLabelRender
export interface MenuSelectOption {
label?: MenuSelectOptionLabel
value?: any
+ children?: MenuSelectOption[]
disabled?: boolean
ripple?: boolean
[key: PropertyKey]: any
+
+ _parent?: MenuSelectOption
+ _children?: MenuSelectOption[]
+ _rawOption?: MenuSelectOption
}
export const props = {
@@ -33,6 +38,10 @@ export const props = {
type: String,
default: 'value',
},
+ childrenKey: {
+ type: String,
+ default: 'children',
+ },
size: {
type: String as PropType,
default: 'normal',
@@ -44,6 +53,7 @@ export const props = {
default: true,
},
'onUpdate:modelValue': defineListenerProp<(value: any) => void>(),
+ onSelect: defineListenerProp<(value: any, option: MenuSelectOption) => void>(),
...pickProps(menuProps, [
'show',
'disabled',
diff --git a/packages/varlet-ui/src/menu/Menu.vue b/packages/varlet-ui/src/menu/Menu.vue
index 5bbff9daf04..675535e0d73 100644
--- a/packages/varlet-ui/src/menu/Menu.vue
+++ b/packages/varlet-ui/src/menu/Menu.vue
@@ -55,6 +55,7 @@ export default defineComponent({
handlePopoverMouseleave,
handlePopoverClose,
handleClosed,
+ setAllowClose,
// expose
open,
// expose
@@ -65,6 +66,10 @@ export default defineComponent({
setReference,
} = usePopover(props)
+ function allowClose() {
+ setAllowClose(true)
+ }
+
return {
popover,
host,
@@ -72,6 +77,7 @@ export default defineComponent({
show,
zIndex,
teleportDisabled,
+ allowClose,
formatElevation,
toSizeUnit,
n,
diff --git a/packages/varlet-ui/src/menu/menu.less b/packages/varlet-ui/src/menu/menu.less
index bd91df39bff..459965ece1f 100644
--- a/packages/varlet-ui/src/menu/menu.less
+++ b/packages/varlet-ui/src/menu/menu.less
@@ -4,7 +4,7 @@
}
.var-menu {
- display: inline-block;
+ display: inline-flex;
outline: none;
&__menu {
diff --git a/packages/varlet-ui/src/menu/props.ts b/packages/varlet-ui/src/menu/props.ts
index 507f3272911..bc6ce0c9c0c 100644
--- a/packages/varlet-ui/src/menu/props.ts
+++ b/packages/varlet-ui/src/menu/props.ts
@@ -52,4 +52,8 @@ export const props = {
onClosed: defineListenerProp<() => void>(),
onClickOutside: defineListenerProp<(event: Event) => void>(),
'onUpdate:show': defineListenerProp<(show: boolean) => void>(),
+
+ // internal start
+ cascadeOptimization: Boolean,
+ // internal end
}
diff --git a/packages/varlet-ui/src/menu/usePopover.ts b/packages/varlet-ui/src/menu/usePopover.ts
index f13830c60f9..faf6d000fb6 100644
--- a/packages/varlet-ui/src/menu/usePopover.ts
+++ b/packages/varlet-ui/src/menu/usePopover.ts
@@ -55,6 +55,7 @@ export interface UsePopoverOptions {
onClose?: ListenerProp<() => void>
onClosed?: ListenerProp<() => void>
onClickOutside?: ListenerProp<(event: Event) => void>
+ cascadeOptimization?: boolean
'onUpdate:show'?: ListenerProp<(show: boolean) => void>
}
@@ -81,6 +82,7 @@ export function usePopover(options: UsePopoverOptions) {
let reference: Reference | undefined = undefined
let enterPopover = false
let enterReference = false
+ let allowClose = true
useEventListener(() => window, 'keydown', handleKeydown)
watch(() => [options.offsetX, options.offsetY, options.placement, options.strategy], resize)
@@ -207,6 +209,10 @@ export function usePopover(options: UsePopoverOptions) {
}
enterPopover = true
+
+ if (options.cascadeOptimization) {
+ allowClose = false
+ }
}
async function handlePopoverMouseleave() {
@@ -413,6 +419,10 @@ export function usePopover(options: UsePopoverOptions) {
return targetReference
}
+ function setAllowClose(value: boolean) {
+ allowClose = value
+ }
+
function setReference(newReference: Reference) {
destroyPopperInstance()
reference = newReference
@@ -444,6 +454,10 @@ export function usePopover(options: UsePopoverOptions) {
// expose
function close() {
+ if (!allowClose) {
+ return
+ }
+
show.value = false
call(options['onUpdate:show'], false)
}
@@ -459,6 +473,7 @@ export function usePopover(options: UsePopoverOptions) {
handlePopoverMouseleave,
handleClosed,
setReference,
+ setAllowClose,
resize,
open,
close,
diff --git a/packages/varlet-ui/src/option/Option.vue b/packages/varlet-ui/src/option/Option.vue
index 3aa861736eb..ac773feee01 100644
--- a/packages/varlet-ui/src/option/Option.vue
+++ b/packages/varlet-ui/src/option/Option.vue
@@ -6,7 +6,7 @@
color: optionSelected ? focusColor : undefined,
}"
:tabindex="disabled ? undefined : '-1'"
- v-ripple="{ disabled }"
+ v-ripple="{ disabled: disabled || !ripple }"
v-hover:desktop="handleHovering"
@focus="isFocusing = true"
@blur="isFocusing = false"
@@ -67,6 +67,13 @@ export default defineComponent({
const isFocusing = ref(false)
const optionSelected = ref(false)
const selected = computed(() => optionSelected.value)
+ const value = computed(() => props.value)
+ const disabled = computed(() => props.disabled)
+ const ripple = computed(() => props.ripple)
+ const { select, bindSelect } = useSelect()
+ const { multiple, focusColor, onSelect, computeLabel } = select
+ const { hovering, handleHovering } = useHoverOverlay()
+
const labelVNode = computed(() =>
isFunction(props.label)
? props.label(
@@ -79,14 +86,12 @@ export default defineComponent({
)
: props.label
)
- const value = computed(() => props.value)
- const { select, bindSelect } = useSelect()
- const { multiple, focusColor, onSelect, computeLabel } = select
- const { hovering, handleHovering } = useHoverOverlay()
const optionProvider: OptionProvider = {
label: labelVNode,
value,
+ disabled,
+ ripple,
selected,
sync,
}
diff --git a/packages/varlet-ui/src/option/docs/en-US.md b/packages/varlet-ui/src/option/docs/en-US.md
index e71d74c5879..4ea433874cf 100644
--- a/packages/varlet-ui/src/option/docs/en-US.md
+++ b/packages/varlet-ui/src/option/docs/en-US.md
@@ -7,6 +7,7 @@
| `label` | The text that the option displays | _any_ | `-` |
| `value` | The value of the option binding | _any_ | `-` |
| `disabled` | Whether to disable | _boolean_ | `false` |
+| `ripple` ***3.8.0*** | Whether to enable ripple | _boolean_ | `true` |
### Slots
diff --git a/packages/varlet-ui/src/option/docs/zh-CN.md b/packages/varlet-ui/src/option/docs/zh-CN.md
index 94db5c269b7..95b5a02933e 100644
--- a/packages/varlet-ui/src/option/docs/zh-CN.md
+++ b/packages/varlet-ui/src/option/docs/zh-CN.md
@@ -7,6 +7,7 @@
| `label` | 选项显示的文本 | _any_ | `-` |
| `value` | 选项绑定的值 | _any_ | `-` |
| `disabled` | 是否禁用 | _boolean_ | `false` |
+| `ripple` ***3.8.0*** | 是否启用水波效果 | _boolean_ | `true` |
### 插槽
diff --git a/packages/varlet-ui/src/option/props.ts b/packages/varlet-ui/src/option/props.ts
index ba1d366ae5a..cf117fe3242 100644
--- a/packages/varlet-ui/src/option/props.ts
+++ b/packages/varlet-ui/src/option/props.ts
@@ -5,6 +5,10 @@ export const props = {
label: {},
value: {},
disabled: Boolean,
+ ripple: {
+ type: Boolean,
+ default: true,
+ },
// internal
option: Object as PropType,
}
diff --git a/packages/varlet-ui/src/option/provide.ts b/packages/varlet-ui/src/option/provide.ts
index 3ff9b2dcb41..547294a37dd 100644
--- a/packages/varlet-ui/src/option/provide.ts
+++ b/packages/varlet-ui/src/option/provide.ts
@@ -6,8 +6,11 @@ import { SELECT_BIND_OPTION_KEY, type SelectProvider } from '../select/provide'
export interface OptionProvider {
label: ComputedRef
value: ComputedRef
+ disabled: ComputedRef
+ ripple: ComputedRef
selected: ComputedRef
- sync(checked: boolean): void
+ indeterminate?: ComputedRef
+ sync(checked: boolean, indeterminate?: boolean): void
}
export function useSelect() {
diff --git a/packages/varlet-ui/src/radio-group/__tests__/__snapshots__/index.spec.js.snap b/packages/varlet-ui/src/radio-group/__tests__/__snapshots__/index.spec.js.snap
index e093a319f79..500f311ef93 100644
--- a/packages/varlet-ui/src/radio-group/__tests__/__snapshots__/index.spec.js.snap
+++ b/packages/varlet-ui/src/radio-group/__tests__/__snapshots__/index.spec.js.snap
@@ -97,7 +97,7 @@ exports[`test radio group label is function 2`] = `
-
+
0-false
@@ -108,7 +108,7 @@ exports[`test radio group label is function 2`] = `
-
+
1-true
@@ -140,7 +140,7 @@ exports[`test radio group label is function 3`] = `
-
+
0-false
@@ -151,7 +151,7 @@ exports[`test radio group label is function 3`] = `
-
+
1-true
@@ -347,7 +347,7 @@ exports[`test radio group validation 2`] = `
-
+
@@ -445,7 +445,7 @@ exports[`test radio validation 1`] = `
exports[`test radio validation 2`] = `
"
-
+
@@ -484,7 +484,7 @@ exports[`test validation with zod > radio 1`] = `
exports[`test validation with zod > radio 2`] = `
"
-
+
@@ -545,7 +545,7 @@ exports[`test validation with zod > radio group 2`] = `
-
+
diff --git a/packages/varlet-ui/src/radio/Radio.vue b/packages/varlet-ui/src/radio/Radio.vue
index 4b9b5821c64..921c29dca52 100644
--- a/packages/varlet-ui/src/radio/Radio.vue
+++ b/packages/varlet-ui/src/radio/Radio.vue
@@ -19,20 +19,10 @@
@blur="isFocusing = false"
>
-
+
-
+
value.value === props.checkedValue)
- const withAnimation = ref(false)
const { radioGroup, bindRadioGroup } = useRadioGroup()
const { hovering, handleHovering } = useHoverOverlay()
const { form, bindForm } = useForm()
@@ -183,7 +172,6 @@ export default defineComponent({
return
}
- withAnimation.value = true
change(checked.value ? uncheckedValue : checkedValue)
}
@@ -222,7 +210,6 @@ export default defineComponent({
return {
action,
isFocusing,
- withAnimation,
checked,
errorMessage,
radioGroupErrorMessage: radioGroup?.errorMessage,
diff --git a/packages/varlet-ui/src/radio/radio.less b/packages/varlet-ui/src/radio/radio.less
index 28c57dc6c31..08f39e1b76c 100644
--- a/packages/varlet-ui/src/radio/radio.less
+++ b/packages/varlet-ui/src/radio/radio.less
@@ -8,23 +8,6 @@
--radio-text-color: #555;
}
-@keyframes var-vibrate-animation {
- 0% {
- opacity: 1;
- transform: scale(1);
- }
-
- 50% {
- opacity: 0.8;
- transform: scale(0.8);
- }
-
- 100% {
- opacity: 1;
- transform: scale(1);
- }
-}
-
.var-radio {
display: flex;
align-items: center;
@@ -58,10 +41,6 @@
color: var(--radio-text-color);
}
- &--with-animation[var-radio-cover] {
- animation: var-vibrate-animation 0.25s;
- }
-
&--checked {
color: var(--radio-checked-color);
}
diff --git a/packages/varlet-ui/src/select/Select.vue b/packages/varlet-ui/src/select/Select.vue
index a92c3423081..8d0ffc2c128 100644
--- a/packages/varlet-ui/src/select/Select.vue
+++ b/packages/varlet-ui/src/select/Select.vue
@@ -120,6 +120,7 @@
:value="option[valueKey]"
:option="option"
:disabled="option.disabled"
+ :ripple="option.ripple"
/>
diff --git a/packages/varlet-ui/src/select/docs/en-US.md b/packages/varlet-ui/src/select/docs/en-US.md
index 956752d954d..92d9feb1abd 100644
--- a/packages/varlet-ui/src/select/docs/en-US.md
+++ b/packages/varlet-ui/src/select/docs/en-US.md
@@ -488,6 +488,7 @@ const keyOptions = ref([
| `label` | The text of option | _string \| VNode \| (option: SelectOption, selected: boolean) => VNodeChild_ | `-` |
| `value` | The value of option | _any_ | `-` |
| `disabled` | Whether to disable option | _boolean_ | `-` |
+| `ripple` ***3.3.0*** | Whether to enable ripple | _boolean_ | `true` |
#### Option Props
diff --git a/packages/varlet-ui/src/select/docs/zh-CN.md b/packages/varlet-ui/src/select/docs/zh-CN.md
index 990d96386f1..bc38009d474 100644
--- a/packages/varlet-ui/src/select/docs/zh-CN.md
+++ b/packages/varlet-ui/src/select/docs/zh-CN.md
@@ -497,6 +497,7 @@ const keyOptions = ref([
| `label` | 选项显示的文本 | _any_ | `-` |
| `value` | 选项绑定的值 | _any_ | `-` |
| `disabled` | 是否禁用 | _boolean_ | `false` |
+| `ripple` ***3.8.0*** | 是否启用水波效果 | _boolean_ | `true` |
### 方法
diff --git a/packages/varlet-ui/src/select/useSelectController.ts b/packages/varlet-ui/src/select/useSelectController.ts
index efc966d0cb7..00a16cff361 100644
--- a/packages/varlet-ui/src/select/useSelectController.ts
+++ b/packages/varlet-ui/src/select/useSelectController.ts
@@ -7,6 +7,7 @@ export interface UseSelectControllerOptions {
multiple: () => boolean
optionProviders: () => OptionProvider[]
optionProvidersLength: () => number
+ optionIsIndeterminate?: (option: OptionProvider) => boolean
}
export function useSelectController(options: UseSelectControllerOptions) {
@@ -15,6 +16,7 @@ export function useSelectController(options: UseSelectControllerOptions) {
modelValue: modelValueGetter,
optionProviders: optionProvidersGetter,
optionProvidersLength: optionProvidersLengthGetter,
+ optionIsIndeterminate,
} = options
const label = ref('')
const labels = ref([])
@@ -51,7 +53,7 @@ export function useSelectController(options: UseSelectControllerOptions) {
return option?.label.value ?? ''
}
- function findValueOrLabel({ value, label }: OptionProvider) {
+ function getOptionProviderKey({ value, label }: OptionProvider) {
return value.value ?? label.value
}
@@ -59,7 +61,9 @@ export function useSelectController(options: UseSelectControllerOptions) {
const multiple = multipleGetter()
const options = optionProvidersGetter()
- return multiple ? options.filter(({ selected }) => selected.value).map(findValueOrLabel) : findValueOrLabel(option)
+ return multiple
+ ? options.filter(({ selected }) => selected.value).map(getOptionProviderKey)
+ : getOptionProviderKey(option)
}
function syncOptions() {
@@ -68,9 +72,14 @@ export function useSelectController(options: UseSelectControllerOptions) {
const options = optionProvidersGetter()
if (multiple) {
- options.forEach((option) => option.sync(modelValue.includes(findValueOrLabel(option))))
+ options.forEach((option) =>
+ option.sync(
+ modelValue.includes(getOptionProviderKey(option)),
+ optionIsIndeterminate ? optionIsIndeterminate(option) : undefined
+ )
+ )
} else {
- options.forEach((option) => option.sync(modelValue === findValueOrLabel(option)))
+ options.forEach((option) => option.sync(modelValue === getOptionProviderKey(option)))
}
computeLabel()
@@ -79,6 +88,7 @@ export function useSelectController(options: UseSelectControllerOptions) {
return {
label,
labels,
+ getOptionProviderKey,
computeLabel,
getSelectedValue,
}
diff --git a/packages/varlet-ui/src/utils/elements.ts b/packages/varlet-ui/src/utils/elements.ts
index 671b6f5aa82..3e0edbf130f 100644
--- a/packages/varlet-ui/src/utils/elements.ts
+++ b/packages/varlet-ui/src/utils/elements.ts
@@ -247,6 +247,20 @@ export function padStartFlex(style: string | undefined) {
return style === 'start' || style === 'end' ? `flex-${style}` : style
}
+export function isDisplayNoneElement(element: HTMLElement) {
+ let parent: HTMLElement | null = element
+
+ while (parent && parent !== document.documentElement) {
+ if (getStyle(parent).display === 'none') {
+ return true
+ }
+
+ parent = parent.parentNode as HTMLElement | null
+ }
+
+ return false
+}
+
const focusableSelector = ['button', 'input', 'select', 'textarea', '[tabindex]', '[href]']
.map((s) => `${s}:not([disabled])`)
.join(', ')
@@ -256,7 +270,10 @@ export function focusChildElementByKey(
parentElement: HTMLElement,
key: 'ArrowDown' | 'ArrowUp'
) {
- const focusableElements = parentElement.querySelectorAll(focusableSelector)
+ const focusableElements = Array.from(parentElement.querySelectorAll(focusableSelector)).filter(
+ (element) => !isDisplayNoneElement(element)
+ )
+
if (!focusableElements.length) {
return
}
diff --git a/packages/varlet-ui/tsconfig.json b/packages/varlet-ui/tsconfig.json
index f90fbd3fdc7..d7912ac9f36 100644
--- a/packages/varlet-ui/tsconfig.json
+++ b/packages/varlet-ui/tsconfig.json
@@ -8,5 +8,5 @@
"allowJs": true,
"types": ["vitest/globals"]
},
- "include": ["src/**/*.{ts,tsx,vue}"]
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
}
diff --git a/packages/varlet-ui/types/checkbox.d.ts b/packages/varlet-ui/types/checkbox.d.ts
index dc87dfb7ba6..3842ee6be2a 100644
--- a/packages/varlet-ui/types/checkbox.d.ts
+++ b/packages/varlet-ui/types/checkbox.d.ts
@@ -19,7 +19,7 @@ export interface CheckboxProps extends BasicAttributes {
validateTrigger?: Array
rules?: CheckboxRules
onClick?: ListenerProp<(e: Event) => void>
- onChange?: ListenerProp<(value: any) => void>
+ onChange?: ListenerProp<(value: any, indeterminate: boolean) => void>
'onUpdate:modelValue'?: ListenerProp<(value: any) => void>
'onUpdate:indeterminate'?: ListenerProp<(value: boolean) => void>
}
diff --git a/packages/varlet-ui/types/checkboxGroup.d.ts b/packages/varlet-ui/types/checkboxGroup.d.ts
index 684e091c811..d70bf260596 100644
--- a/packages/varlet-ui/types/checkboxGroup.d.ts
+++ b/packages/varlet-ui/types/checkboxGroup.d.ts
@@ -29,9 +29,9 @@ export interface CheckboxGroupProps extends BasicAttributes {
max?: string | number
labelKey?: string
valueKey?: string
- options?: Array
+ options?: CheckboxGroupOption[]
direction?: CheckboxGroupDirection
- validateTrigger?: Array
+ validateTrigger?: CheckboxGroupValidateTrigger[]
rules?: CheckboxGroupRules
onChange?: ListenerProp<(value: Array) => void>
'onUpdate:modelValue'?: ListenerProp<(value: Array) => void>
diff --git a/packages/varlet-ui/types/menuSelect.d.ts b/packages/varlet-ui/types/menuSelect.d.ts
index f756d57f767..7908e7ec5c6 100644
--- a/packages/varlet-ui/types/menuSelect.d.ts
+++ b/packages/varlet-ui/types/menuSelect.d.ts
@@ -30,13 +30,17 @@ export type MenuSelectOptionLabelRender = (option: MenuSelectOption, checked: bo
export interface MenuSelectOption {
label?: string | VNode | MenuSelectOptionLabelRender
- disabled?: boolean
value?: any
+ disabled?: boolean
ripple?: boolean
+ children?: MenuSelectOption[]
+
+ [key: PropertyKey]: any
}
export interface MenuSelectProps extends BasicAttributes {
modelValue?: any
+ options?: MenuSelectOption[]
size?: MenuSelectSize
multiple?: boolean
scrollable?: boolean
@@ -47,6 +51,9 @@ export interface MenuSelectProps extends BasicAttributes {
reference?: MenuSelectReference
placement?: MenuSelectPlacement
strategy?: MenuSelectStrategy
+ labelKey?: string
+ valueKey?: string
+ childrenKey?: string
offsetX?: string | number
offsetY?: string | number
teleport?: TeleportProps['to'] | false
@@ -58,6 +65,7 @@ export interface MenuSelectProps extends BasicAttributes {
onOpened?: ListenerProp<() => void>
onClose?: ListenerProp<() => void>
onClosed?: ListenerProp<() => void>
+ onSelect?: ListenerProp<(value: any) => void>
'onUpdate:modelValue'?: ListenerProp<(value: any) => void>
'onUpdate:show'?: ListenerProp<(show: boolean) => void>
}
diff --git a/packages/varlet-ui/types/radioGroup.d.ts b/packages/varlet-ui/types/radioGroup.d.ts
index 8fc5b381f19..f3ab544c358 100644
--- a/packages/varlet-ui/types/radioGroup.d.ts
+++ b/packages/varlet-ui/types/radioGroup.d.ts
@@ -27,10 +27,10 @@ export { RadioGroupDirection }
export interface RadioGroupProps extends BasicAttributes {
modelValue?: any
direction?: RadioGroupDirection
- options?: Array
+ options?: RadioGroupOption[]
labelKey?: string
valueKey?: string
- validateTrigger?: Array
+ validateTrigger?: RadioGroupValidateTrigger[]
rules?: RadioGroupRules
onChange?: ListenerProp<(value: any) => void>
'onUpdate:modelValue'?: ListenerProp<(value: any) => void>
diff --git a/packages/varlet-ui/types/select.d.ts b/packages/varlet-ui/types/select.d.ts
index 7863b536237..ae9e3dc0632 100644
--- a/packages/varlet-ui/types/select.d.ts
+++ b/packages/varlet-ui/types/select.d.ts
@@ -30,7 +30,7 @@ export interface SelectOption {
export interface SelectProps extends BasicAttributes {
modelValue?: any
- options?: Array
+ options?: SelectOption[]
labelKey?: string
valueKey?: string
variant?: SelectVariant