diff --git a/packages/varlet-ui/src/checkbox-group/CheckboxGroup.vue b/packages/varlet-ui/src/checkbox-group/CheckboxGroup.vue index 68a3391b2f2..14825c18abf 100644 --- a/packages/varlet-ui/src/checkbox-group/CheckboxGroup.vue +++ b/packages/varlet-ui/src/checkbox-group/CheckboxGroup.vue @@ -77,17 +77,10 @@ export default defineComponent({ return changedModelValue } - watch( - () => props.modelValue, - () => syncAllCheckbox(), - { deep: true } - ) + watch(() => props.modelValue, syncAllCheckbox, { deep: true }) // checkbox insert or remove - watch( - () => length.value, - () => syncAllCheckbox() - ) + watch(() => length.value, syncAllCheckbox) bindChildren({ checkedCount, diff --git a/packages/varlet-ui/src/checkbox/Checkbox.vue b/packages/varlet-ui/src/checkbox/Checkbox.vue index 62c27d44488..b27ef5b4758 100644 --- a/packages/varlet-ui/src/checkbox/Checkbox.vue +++ b/packages/varlet-ui/src/checkbox/Checkbox.vue @@ -89,8 +89,10 @@ export default defineComponent({ } // has parent check max - const forbidCheck = checkboxGroupProvider.checkedCount.value >= Number(checkboxGroupProvider.max.value) - if (checkboxGroupProvider && !checked.value && forbidCheck) { + const maximum = checkboxGroupProvider + ? checkboxGroupProvider.checkedCount.value >= Number(checkboxGroupProvider.max.value) + : false + if (!checked.value && maximum) { return } diff --git a/packages/varlet-ui/src/checkbox/example/index.vue b/packages/varlet-ui/src/checkbox/example/index.vue index 157760e6de4..72571d39d24 100644 --- a/packages/varlet-ui/src/checkbox/example/index.vue +++ b/packages/varlet-ui/src/checkbox/example/index.vue @@ -28,13 +28,15 @@ - checkbox 组 {{ v2 }} - - 1 - 2 - 3 - 4 - {{ l }} + checkbox 组 {{ v2 }} {{ v3 }} + + + 1 + 2 + 3 + 4 + {{ l }} + group 推4 @@ -67,6 +69,7 @@ export default defineComponent({ v: ref(false), v1: ref(0), v2: ref([1, 3]), + v3: ref([2, 3]), list: ref([]), g: ref(null), log(v: any) { diff --git a/packages/varlet-ui/src/chip/Chip.vue b/packages/varlet-ui/src/chip/Chip.vue index 6c83a82af88..f4803173366 100644 --- a/packages/varlet-ui/src/chip/Chip.vue +++ b/packages/varlet-ui/src/chip/Chip.vue @@ -1,16 +1,26 @@ diff --git a/packages/varlet-ui/src/menu/menu.less b/packages/varlet-ui/src/menu/menu.less index 688d36287b0..fb6a623d462 100644 --- a/packages/varlet-ui/src/menu/menu.less +++ b/packages/varlet-ui/src/menu/menu.less @@ -1,35 +1,31 @@ @menu-background: #fff; .var { - &-menu-enter-from, - &-menu-leave-to { - transform: scale(.3); - opacity: 0; - } - &-menu-enter-active, - &-menu-leave-active { - transition-property: opacity, transform; - transition-duration: .3s; - } + &-menu-enter-from, + &-menu-leave-to { + transform: scale(0.3); + opacity: 0; + } + &-menu-enter-active, + &-menu-leave-active { + transition-property: opacity, transform; + transition-duration: 0.3s; + } } .var-menu { - display: inline-block; - background: @menu-background; + display: inline-block; + background: @menu-background; - &__host { - display: inline-block; - } + &__menu { + position: absolute; + } - &__menu { - position: absolute; - } + &--origin-top { + transform-origin: 0 0; + } - &--origin-top { - transform-origin: 0 0; - } - - &--origin-bottom { - transform-origin: 0 100%; - } + &--origin-bottom { + transform-origin: 0 100%; + } } diff --git a/packages/varlet-ui/src/menu/props.ts b/packages/varlet-ui/src/menu/props.ts index 3863242a7ae..ee5245d7470 100644 --- a/packages/varlet-ui/src/menu/props.ts +++ b/packages/varlet-ui/src/menu/props.ts @@ -1,26 +1,29 @@ function alignmentValidator(alignment: string) { - return ['top', 'bottom'].includes(alignment) + return ['top', 'bottom'].includes(alignment) } export const props = { - show: { - type: Boolean, - default: false - }, - 'onUpdate:show': { - type: Function - }, - alignment: { - type: String, - default: 'top', - validator: alignmentValidator - }, - offsetX: { - type: String, - default: '0px' - }, - offsetY: { - type: String, - default: '0px' - } + show: { + type: Boolean, + default: false, + }, + 'onUpdate:show': { + type: Function, + }, + alignment: { + type: String, + default: 'top', + validator: alignmentValidator, + }, + offsetX: { + type: String, + default: '0px', + }, + offsetY: { + type: String, + default: '0px', + }, + onBlur: { + type: Function, + }, } diff --git a/packages/varlet-ui/src/option/Option.vue b/packages/varlet-ui/src/option/Option.vue new file mode 100644 index 00000000000..6a13add3472 --- /dev/null +++ b/packages/varlet-ui/src/option/Option.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/packages/varlet-ui/src/option/__tests__/index.spec.js b/packages/varlet-ui/src/option/__tests__/index.spec.js new file mode 100644 index 00000000000..60a613d7759 --- /dev/null +++ b/packages/varlet-ui/src/option/__tests__/index.spec.js @@ -0,0 +1,7 @@ +const Option = require('../../../cjs/option').default +const { render } = require('@testing-library/vue') + +test('test option', async () => { + const wrapper = render(Option) + console.log(wrapper) +}) diff --git a/packages/varlet-ui/src/option/docs/en_US.md b/packages/varlet-ui/src/option/docs/en_US.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/varlet-ui/src/option/docs/zh_CN.md b/packages/varlet-ui/src/option/docs/zh_CN.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/varlet-ui/src/option/example/index.vue b/packages/varlet-ui/src/option/example/index.vue new file mode 100644 index 00000000000..b8df4b19f39 --- /dev/null +++ b/packages/varlet-ui/src/option/example/index.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/packages/varlet-ui/src/option/index.ts b/packages/varlet-ui/src/option/index.ts new file mode 100644 index 00000000000..bd77ea352da --- /dev/null +++ b/packages/varlet-ui/src/option/index.ts @@ -0,0 +1,8 @@ +import { App } from 'vue' +import Option from './Option.vue' + +Option.install = function (app: App) { + app.component(Option.name, Option) +} + +export default Option diff --git a/packages/varlet-ui/src/option/option.less b/packages/varlet-ui/src/option/option.less new file mode 100644 index 00000000000..ba11464e919 --- /dev/null +++ b/packages/varlet-ui/src/option/option.less @@ -0,0 +1,31 @@ +@import '../select/select'; + +@option-height: 38px; +@option-padding: 0 12px; +@option-selected-background: @select-active-color; + +.var-option { + position: relative; + display: flex; + align-items: center; + height: @option-height; + padding: @option-padding; + + &__cover { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + opacity: 0.2; + background: transparent; + } + + &--selected-background { + background: @option-selected-background; + } + + &--selected-color { + color: @option-selected-background; + } +} diff --git a/packages/varlet-ui/src/option/props.ts b/packages/varlet-ui/src/option/props.ts new file mode 100644 index 00000000000..adf901ecc81 --- /dev/null +++ b/packages/varlet-ui/src/option/props.ts @@ -0,0 +1,10 @@ +export const props = { + value: { + type: [String, Number, Boolean], + default: undefined, + }, + label: { + type: [String], + required: true, + }, +} diff --git a/packages/varlet-ui/src/option/provide.ts b/packages/varlet-ui/src/option/provide.ts new file mode 100644 index 00000000000..32a4ba369bf --- /dev/null +++ b/packages/varlet-ui/src/option/provide.ts @@ -0,0 +1,8 @@ +import { ComputedRef } from 'vue' + +export interface OptionProvider { + label: ComputedRef + value: ComputedRef + selected: ComputedRef + sync(checked: boolean): void +} diff --git a/packages/varlet-ui/src/radio-group/RadioGroup.vue b/packages/varlet-ui/src/radio-group/RadioGroup.vue index b538fe4992e..bc5eef8c676 100644 --- a/packages/varlet-ui/src/radio-group/RadioGroup.vue +++ b/packages/varlet-ui/src/radio-group/RadioGroup.vue @@ -30,16 +30,10 @@ export default defineComponent({ props.onChange?.(changedValue) } - watch( - () => props.modelValue, - () => syncAllRadio() - ) + watch(() => props.modelValue, syncAllRadio) // radio insert or remove - watch( - () => length.value, - () => syncAllRadio() - ) + watch(() => length.value, syncAllRadio) bindChildren({ onToggle, diff --git a/packages/varlet-ui/src/radio/provide.ts b/packages/varlet-ui/src/radio/provide.ts index 5bf0801e283..4bd11dcd8d3 100644 --- a/packages/varlet-ui/src/radio/provide.ts +++ b/packages/varlet-ui/src/radio/provide.ts @@ -1,3 +1,3 @@ export interface RadioProvider { - sync(values: Array): void + sync(value: any): void } diff --git a/packages/varlet-ui/src/ripple/index.ts b/packages/varlet-ui/src/ripple/index.ts index ff8c6453728..678150258a9 100644 --- a/packages/varlet-ui/src/ripple/index.ts +++ b/packages/varlet-ui/src/ripple/index.ts @@ -2,7 +2,6 @@ import { Directive, Plugin, App } from 'vue' import { DirectiveBinding } from '@vue/runtime-core' import './ripple.less' import '../styles/common.less' -import { doc } from 'prettier' interface RippleStyles { x: number @@ -15,6 +14,7 @@ interface RippleStyles { interface RippleOptions { color?: string disabled?: boolean + tasker?: number | null } interface RippleHTMLElement extends HTMLElement { @@ -24,39 +24,30 @@ interface RippleHTMLElement extends HTMLElement { function recordStyles(element: RippleHTMLElement) { const { zIndex, position, overflow, overflowX, overflowY } = window.getComputedStyle(element) - if (zIndex === 'auto') { - element.style.zIndex = '1' - element.dataset.prevZIndex = zIndex - } + zIndex === 'auto' && (element.dataset.prevZIndex = zIndex) + position === 'static' && (element.dataset.prevPosition = position) + element.dataset.prevOverflow = overflow + element.dataset.prevOverflowX = overflowX + element.dataset.prevOverflowY = overflowY +} - if (position === 'static') { - element.style.position = 'relative' - element.dataset.prevPosition = position - } +function setStyles(element: RippleHTMLElement) { + const { zIndex, position } = window.getComputedStyle(element) element.style.overflow = 'hidden' element.style.overflowX = 'hidden' element.style.overflowY = 'hidden' - - element.dataset.prevOverflow = overflow - element.dataset.prevOverflowX = overflowX - element.dataset.prevOverflowY = overflowY + position === 'static' && (element.style.position = 'relative') + zIndex === 'auto' && (element.style.zIndex = '1') } function resetStyles(element: RippleHTMLElement) { - if (element.dataset.prevZIndex) { - element.style.zIndex = element.dataset.prevZIndex - delete element.dataset.prevZIndex - } - - if (element.dataset.prevPosition) { - element.style.position = element.dataset.prevPosition - delete element.dataset.prevPosition - } + element.dataset.prevZIndex && (element.style.zIndex = element.dataset.prevZIndex) + element.dataset.prevPosition && (element.style.position = element.dataset.prevPosition) - element.style.overflow = element.dataset.prevOverflow - element.style.overflowX = element.dataset.prevOverflowX - element.style.overflowY = element.dataset.prevOverflowY + element.style.overflow = element.dataset.prevOverflow as string + element.style.overflowX = element.dataset.prevOverflowX as string + element.style.overflowY = element.dataset.prevOverflowY as string } function computeRippleStyles(element: RippleHTMLElement, event: TouchEvent): RippleStyles { @@ -79,69 +70,96 @@ function computeRippleStyles(element: RippleHTMLElement, event: TouchEvent): Rip } function createRipple(this: RippleHTMLElement, event: TouchEvent) { - if (this._ripple?.disabled) { + const _ripple = this._ripple as RippleOptions + if (_ripple.disabled) { return } - const { x, y, centerX, centerY, size }: RippleStyles = computeRippleStyles(this, event) + const task = () => { + _ripple.tasker = null - const ripple: RippleHTMLElement = document.createElement('div') - ripple.classList.add('var-ripple') - ripple.style.opacity = `0` - ripple.style.transform = `translate(${x}px, ${y}px) scale3d(.3, .3, .3)` - ripple.style.width = `${size}px` - ripple.style.height = `${size}px` - ripple.style.backgroundColor = this._ripple?.color ?? 'currentColor' - ripple.dataset.createdAt = String(performance.now()) + const { x, y, centerX, centerY, size }: RippleStyles = computeRippleStyles(this, event) + const ripple: RippleHTMLElement = document.createElement('div') + ripple.classList.add('var-ripple') + ripple.style.opacity = `0` + ripple.style.transform = `translate(${x}px, ${y}px) scale3d(.3, .3, .3)` + ripple.style.width = `${size}px` + ripple.style.height = `${size}px` + ripple.style.backgroundColor = _ripple.color ?? 'currentColor' + ripple.dataset.createdAt = String(performance.now()) - recordStyles(this) + setStyles(this) - this.appendChild(ripple) + this.appendChild(ripple) - setTimeout(() => { - ripple.style.transform = `translate(${centerX}px, ${centerY}px) scale3d(1, 1, 1)` - ripple.style.opacity = `.25` - }) + window.setTimeout(() => { + ripple.style.transform = `translate(${centerX}px, ${centerY}px) scale3d(1, 1, 1)` + ripple.style.opacity = `.25` + }, 20) + } + + _ripple.tasker = window.setTimeout(task, 60) } function removeRipple(this: RippleHTMLElement) { - const ripples: NodeListOf = this.querySelectorAll('.var-ripple') - if (!ripples.length) { - return - } + const _ripple = this._ripple as RippleOptions - const lastRipple: RippleHTMLElement = ripples[ripples.length - 1] - const delay: number = 300 - performance.now() + Number(lastRipple.dataset.createdAt) + const task = () => { + const ripples: NodeListOf = this.querySelectorAll('.var-ripple') + if (!ripples.length) { + return + } - setTimeout(() => { - lastRipple.style.opacity = `0` + const lastRipple: RippleHTMLElement = ripples[ripples.length - 1] + const delay: number = 300 - performance.now() + Number(lastRipple.dataset.createdAt) setTimeout(() => { - const ripples: NodeListOf = this.querySelectorAll('.var-ripple') + lastRipple.style.opacity = `0` + + setTimeout(() => { + const ripples: NodeListOf = this.querySelectorAll('.var-ripple') + + ripples.length === 1 && resetStyles(this) - ripples.length === 1 && resetStyles(this) + lastRipple.parentNode?.removeChild(lastRipple) + }, 300) + }, delay) + } + + _ripple.tasker ? setTimeout(task, 60) : task() +} - lastRipple.parentNode?.removeChild(lastRipple) - }, 300) - }, delay) +function forbidRippleTask(this: RippleHTMLElement) { + const _ripple = this._ripple as RippleOptions + + _ripple.tasker && window.clearTimeout(_ripple.tasker) + _ripple.tasker = null } function mounted(el: RippleHTMLElement, binding: DirectiveBinding) { - el._ripple = binding.value + el._ripple = binding.value ?? {} + el._ripple.tasker = null + + recordStyles(el) el.addEventListener('touchstart', createRipple, { passive: true }) el.addEventListener('touchend', removeRipple, { passive: true }) el.addEventListener('touchcancel', removeRipple, { passive: true }) + el.addEventListener('touchmove', forbidRippleTask, { passive: true }) } function unmounted(el: RippleHTMLElement) { el.removeEventListener('touchstart', createRipple) el.removeEventListener('touchend', removeRipple) el.removeEventListener('touchcancel', removeRipple) + el.removeEventListener('touchmove', forbidRippleTask) } function updated(el: RippleHTMLElement, binding: DirectiveBinding) { - el._ripple = binding.value + el._ripple = binding.value ?? {} + el._ripple.tasker = null + + recordStyles(el) } const Ripple: Directive & Plugin = { diff --git a/packages/varlet-ui/src/select/Select.vue b/packages/varlet-ui/src/select/Select.vue new file mode 100644 index 00000000000..8e387f06c4b --- /dev/null +++ b/packages/varlet-ui/src/select/Select.vue @@ -0,0 +1,349 @@ + + + + + diff --git a/packages/varlet-ui/src/select/__tests__/index.spec.js b/packages/varlet-ui/src/select/__tests__/index.spec.js new file mode 100644 index 00000000000..df7ae4f44a8 --- /dev/null +++ b/packages/varlet-ui/src/select/__tests__/index.spec.js @@ -0,0 +1,7 @@ +const Select = require('../../../cjs/select').default +const { render } = require('@testing-library/vue') + +test('test select', async () => { + const wrapper = render(Select) + console.log(wrapper) +}) diff --git a/packages/varlet-ui/src/select/docs/en_US.md b/packages/varlet-ui/src/select/docs/en_US.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/varlet-ui/src/select/docs/zh_CN.md b/packages/varlet-ui/src/select/docs/zh_CN.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/varlet-ui/src/select/example/index.vue b/packages/varlet-ui/src/select/example/index.vue new file mode 100644 index 00000000000..96b67748b09 --- /dev/null +++ b/packages/varlet-ui/src/select/example/index.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/packages/varlet-ui/src/select/index.ts b/packages/varlet-ui/src/select/index.ts new file mode 100644 index 00000000000..47ba11924b7 --- /dev/null +++ b/packages/varlet-ui/src/select/index.ts @@ -0,0 +1,8 @@ +import { App } from 'vue' +import Select from './Select.vue' + +Select.install = function (app: App) { + app.component(Select.name, Select) +} + +export default Select diff --git a/packages/varlet-ui/src/select/props.ts b/packages/varlet-ui/src/select/props.ts new file mode 100644 index 00000000000..0b77d5113ee --- /dev/null +++ b/packages/varlet-ui/src/select/props.ts @@ -0,0 +1,103 @@ +import { PropType } from 'vue' + +export function textAlignValidator(textAlign: string) { + return ['left', 'right', 'center'].includes(textAlign) +} + +export type ValidateTriggers = 'onFocus' | 'onBlur' | 'onChange' | 'onClick' | 'onClear' + +export const props = { + modelValue: { + type: [String, Number, Boolean, Array] as PropType>, + default: undefined, + }, + textColor: { + type: String, + }, + activeColor: { + type: String, + }, + inactiveColor: { + type: String, + }, + multiple: { + type: Boolean, + default: false, + }, + chip: { + type: Boolean, + default: false, + }, + separator: { + type: String, + default: ',', + }, + disabled: { + type: Boolean, + default: false, + }, + readonly: { + type: Boolean, + default: false, + }, + clearable: { + type: Boolean, + default: false, + }, + textAlign: { + type: String, + default: 'left', + validator: textAlignValidator, + }, + placeholder: { + type: String, + }, + prependIcon: { + type: String, + }, + appendIcon: { + type: String, + }, + line: { + type: Boolean, + default: true, + }, + hint: { + type: Boolean, + default: true, + }, + validateTrigger: { + type: Array as PropType>, + default: ['onChange', 'onClear'], + }, + rules: { + type: Array as PropType | undefined) => any>>, + }, + onFocus: { + type: Function, + }, + onBlur: { + type: Function, + }, + onChange: { + type: Function, + }, + onClick: { + type: Function, + }, + onClear: { + type: Function, + }, + onClose: { + type: Function, + }, + onClickAppendIcon: { + type: Function, + }, + onClickPrependIcon: { + type: Function, + }, + 'onUpdate:modelValue': { + type: Function, + }, +} diff --git a/packages/varlet-ui/src/select/provide.ts b/packages/varlet-ui/src/select/provide.ts new file mode 100644 index 00000000000..cbd8e7e12b4 --- /dev/null +++ b/packages/varlet-ui/src/select/provide.ts @@ -0,0 +1,12 @@ +import { ComputedRef } from 'vue' +import { OptionProvider } from '../option/provide' + +export const SELECT_BIND_OPTION_KEY = Symbol('SELECT_BIND_OPTION_KEY') +export const SELECT_COUNT_OPTION_KEY = Symbol('SELECT_COUNT_OPTION_KEY') + +export interface SelectProvider { + wrapWidth: ComputedRef + multiple: ComputedRef + activeColor: ComputedRef + onSelect(optionProvider: OptionProvider): void +} diff --git a/packages/varlet-ui/src/select/select.less b/packages/varlet-ui/src/select/select.less new file mode 100644 index 00000000000..6d70cb0f119 --- /dev/null +++ b/packages/varlet-ui/src/select/select.less @@ -0,0 +1,170 @@ +@import '../styles/var'; + +@select-select-text-color: #555; +@select-error-color: @color-danger; +@select-inactive-color: #888; +@select-active-color: @color-primary; + +@select-scroller-background: #fff; +@select-scroller-padding: 6px 0; +@select-scroller-max-height: 278px; + +@select-footer-margin-top: 6px; +@select-footer-font-size: 12px; + +@select-placeholder-size: 14px; + +@select-textarea-height: auto; + +@select-icon-padding: 18px 2px 0 0; +@select-icon-size: 20px; + +@select-select-padding-y: 8px; +@select-select-text-color: #555; + +@select-line-size: 1px; +@select-line-spread-size: 2px; + +@select-disabled-color: #aaa; + +.var { + &-select-footer-margin-enter-from, + &-select-footer-margin-leave-to { + opacity: 0; + margin-top: 2px !important; + } + + &-select-footer-margin-enter-active, + &-select-footer-margin-leave-active { + transition: 0.2s all cubic-bezier(0.25, 0.8, 0.5, 1); + } +} + +.var-select { + width: 100%; + color: @select-select-text-color; + + &__controller { + width: 100%; + display: flex; + position: relative; + } + + &__menu { + flex-grow: 1; + } + + &__chip { + margin-right: 5px; + margin-top: 5px; + } + + &__scroller { + max-height: @select-scroller-max-height; + background: @select-scroller-background; + padding: @select-scroller-padding; + overflow-y: auto; + } + + &__wrap { + position: relative; + display: flex; + flex-direction: column; + padding-top: @select-placeholder-size; + } + + &__icon { + padding: @select-icon-padding; + font-size: 20px; + } + + &__placeholder { + position: absolute; + top: 0; + left: 0; + transform: translate(0, @select-placeholder-size + @select-select-padding-y / 2 + 1px); + transform-origin: left; + transition: transform 0.3s; + font-size: @select-placeholder-size / 0.875; + } + + &__select { + width: 100%; + min-height: 32px; + padding: @select-select-padding-y 0; + outline: none; + border: none; + font-size: inherit; + color: @select-select-text-color; + overflow-x: auto; + + &[disabled] { + background: transparent; + } + } + + &__line { + width: 100%; + height: @select-line-size; + background: @select-inactive-color; + } + + &__dot { + width: 100%; + height: @select-line-spread-size; + background: @select-active-color; + transform: scaleX(0); + transform-origin: center; + transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); + } + + &__footer { + display: flex; + justify-content: space-between; + font-size: @select-footer-font-size; + margin-top: @select-footer-margin-top; + } + + &__message { + flex-grow: 1; + color: @select-error-color; + margin-right: 4px; + } + + &--textarea { + height: @select-textarea-height; + } + + &--placeholder-hint { + top: 0; + transform: translate(0, 0) scale(0.72); + } + + &--placeholder-hidden { + visibility: hidden; + } + + &--focus { + color: @select-active-color; + } + + &--spread { + transform: scaleX(1); + } + + &--disabled { + color: @select-disabled-color; + } + + &--error { + color: @select-error-color; + } + + &--line-disabled { + background: @select-disabled-color; + } + + &--line-error { + background: @select-error-color; + } +} diff --git a/packages/varlet-ui/src/utils/components.ts b/packages/varlet-ui/src/utils/components.ts index b5d420b8f15..537b55cbefa 100644 --- a/packages/varlet-ui/src/utils/components.ts +++ b/packages/varlet-ui/src/utils/components.ts @@ -140,13 +140,12 @@ export function useAtChildrenCounter(key: symbol) { } export function useAtParentIndex(key: symbol) { - const childrenCounter: ChildrenCounter | undefined = inject(key) - if (!childrenCounter) { - return { - index: null, - } + if (!keyInProvides(key)) { + return { index: null } } + const childrenCounter: ChildrenCounter = inject(key) as ChildrenCounter + const { collect, clear, instances } = childrenCounter const instance: ComponentInternalInstance = getCurrentInstance() as ComponentInternalInstance @@ -191,15 +190,15 @@ export function useChildren(key: symbol) { } export function useParent(key: symbol) { - const rawParentProvider = inject

>(key) as P & BaseParentProvider - - if (!rawParentProvider) { + if (!keyInProvides(key)) { return { parentProvider: null, bindParent: null, } } + const rawParentProvider = inject

>(key) as P & BaseParentProvider + const { collect, clear, ...parentProvider } = rawParentProvider const bindParent = (childProvider: C) => { @@ -212,3 +211,9 @@ export function useParent(key: symbol) { bindParent, } } + +export function keyInProvides(key: symbol) { + const instance = getCurrentInstance() as any + + return Object.prototype.hasOwnProperty.call(instance.provides, key) +} diff --git a/packages/varlet-ui/src/utils/shared.ts b/packages/varlet-ui/src/utils/shared.ts index 50c08b306dc..efceec5e047 100644 --- a/packages/varlet-ui/src/utils/shared.ts +++ b/packages/varlet-ui/src/utils/shared.ts @@ -19,7 +19,8 @@ export const isArray = (val: unknown): val is Array => Array.isArray(val) export const isURL = (val: string) => /^(http)|(\.*\/)/.test(val) -export const isEmpty = (val: unknown) => val === undefined || val === null || val === '' +export const isEmpty = (val: unknown) => + val === undefined || val === null || val === '' || (Array.isArray(val) && !val.length) export const removeItem = (arr: Array, item: unknown) => { if (arr.length) { diff --git a/packages/varlet-ui/varlet.config.js b/packages/varlet-ui/varlet.config.js index 20a46208fad..7c4292de1f3 100644 --- a/packages/varlet-ui/varlet.config.js +++ b/packages/varlet-ui/varlet.config.js @@ -19,6 +19,12 @@ module.exports = { }, }, menu: [ + { + text: { + zh_CN: '快速开始', + }, + isTitle: true, + }, { text: { zh_CN: 'Ripple 水波指令',