Skip to content

Commit

Permalink
fix(std/component-options): correctly filter component props. Remove …
Browse files Browse the repository at this point in the history
…unpassed props
  • Loading branch information
m0ksem committed Feb 10, 2025
1 parent 1ef482a commit 593d862
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/docs/components/layout/header/ThemeSwitch.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div>
<VaMenu>
<VaMenu stick-to-edges>
<template #anchor>
<VaButton
:icon="currentTheme?.icon"
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/src/components/va-menu/VaMenu.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<VaDropdown v-bind="dropdownProps" ref="dropdown">
<VaDropdown v-bind="dropdownProps" ref="dropdown" v-model="vModel">
<template #anchor>
<slot name="anchor" />
</template>
Expand All @@ -22,6 +22,7 @@ import { extractComponentProps, extractComponentEmits, filterComponentProps } fr
import { useComponentPresetProp, useChildComponents, defineChildProps } from '../../composables'
import { focusElement, focusFirstFocusableChild } from '../../utils/focus'
import { unwrapEl } from '../../utils/unwrapEl'
import { useStatefulControl } from '../../composables/fabrics/useStatefulControl'
const VaMenuListProps = extractComponentProps(VaMenuList)
const VaMenuListEmits = extractComponentEmits(VaMenuList)
Expand Down Expand Up @@ -54,6 +55,8 @@ const emit = defineEmits([
const menuList = ref<HTMLElement>()
const dropdown = ref<typeof VaDropdown>()
const vModel = useStatefulControl(props, emit)
watchEffect(() => {
if (menuList.value) {
nextTick(() => {
Expand Down
27 changes: 26 additions & 1 deletion packages/ui/src/composables/std/internal/useUserProvidedProp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { computed, getCurrentInstance } from 'vue'

const simplifyPropName = (propName: string) => propName.replace(/ |-|_/, '').toLowerCase()
/** Removes camelCase, kebabCase, etc. */
const simplifyPropName = (propName: string) => propName.replace(/ |-|_/g, '').toLowerCase()

const isPropInObject = (props: Record<string, any>, propName: string) => {
return Object.keys(props).find((passedPropName) => simplifyPropName(passedPropName) === simplifyPropName(propName)) !== undefined
Expand All @@ -17,3 +18,27 @@ export const useIsUserProvidedProp = (propName: string) => {
return isPropInObject(vm.vnode.props, propName)
})
}

/** Returns props object without default values. If prop is not preset in the object it means it wasn't passed to this instance */
export const useUserProvidedProps = () => {
const instance = getCurrentInstance()!

return computed(() => {
const userProvidedProps = Object.keys(instance.vnode.props ?? {}).map(simplifyPropName)

return Object
.keys(instance.props)
.reduce((acc, propName: string) => {
// Trigger reactive effect. Notice: instance.vnode.props is not reactive.
const prop = instance.props[propName] as unknown
// Check if prop is user provided (v-bind, v-model, etc.)
const isUserProvided = userProvidedProps.includes(simplifyPropName(propName))

// If prop is not user provided, it means it's default value and we should not pass it to child component
if (isUserProvided) {
;(acc as any)[propName] = prop
}
return acc
}, {} as Record<string, any>)
})
}

0 comments on commit 593d862

Please sign in to comment.