Skip to content

Commit

Permalink
Merge branch 'master' into fix-20946
Browse files Browse the repository at this point in the history
  • Loading branch information
yuwu9145 committed Feb 6, 2025
2 parents 2235db5 + fac2f99 commit 848deab
Show file tree
Hide file tree
Showing 26 changed files with 248 additions and 155 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,7 @@ jobs:
publish-docs:
needs: [lint, test-unit, build-docs]
runs-on: ubuntu-24.04
environment: Production
if: github.event_name == 'push' && github.repository_owner == 'vuetifyjs' && github.ref == 'refs/heads/master'
environment: ${{ github.ref_name }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
Expand Down
4 changes: 2 additions & 2 deletions lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
}
},
"npmClient": "pnpm",
"version": "3.7.9"
}
"version": "3.7.11"
}
2 changes: 1 addition & 1 deletion packages/api-generator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vuetify/api-generator",
"version": "3.7.9",
"version": "3.7.11",
"private": true,
"description": "",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"events": {
"click:finish": "Event emitted when clicking the finish button",
"click:next": "Event emitted when clicking the next button",
"click:previous": "Event emitted when clicking the previous button"
"click:prev": "Event emitted when clicking the previous button"
}
}
4 changes: 2 additions & 2 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "A Vue.js project",
"private": true,
"author": "John Leider <[email protected]>",
"version": "3.7.9",
"version": "3.7.11",
"repository": {
"type": "git",
"url": "git+https://github.com/vuetifyjs/vuetify.git",
Expand Down Expand Up @@ -87,7 +87,7 @@
"vite-plugin-pages": "^0.32.1",
"vite-plugin-pwa": "^0.17.4",
"vite-plugin-vue-layouts": "^0.11.0",
"vite-plugin-vuetify": "^2.0.4",
"vite-plugin-vuetify": "^2.1.0",
"vue-tsc": "^2.0.29"
},
"publishConfig": {
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
rules: {
'no-console': 'error',
'no-debugger': 'error',
'no-labels': 'off',

// 'vue/html-self-closing': 'off',
// 'vue/html-closing-bracket-spacing': 'off',
Expand Down
4 changes: 2 additions & 2 deletions packages/vuetify/build/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export default [
(await this.resolve('src/components/index.ts')).id
)
await Promise.all(importedIds.map(async id => {
const importFrom = path.relative(srcDir, id).replace(/\.ts$/, '.mjs')
const importFrom = path.relative(srcDir, id).replace(/\/index\.ts$/, '')

if (await this.resolve(path.join(id, '../_variables.scss')) != null) {
variables.push(id)
Expand Down Expand Up @@ -247,7 +247,7 @@ export default [
(await this.resolve('src/labs/components.ts')).id
)
await Promise.all(importedIds.map(async id => {
const importFrom = path.relative(srcDir, id).replace(/\.ts$/, '.mjs')
const importFrom = path.relative(srcDir, id).replace(/\/index\.ts$/, '')

if (await this.resolve(path.join(id, '../_variables.scss')) != null) {
variables.push(id)
Expand Down
6 changes: 3 additions & 3 deletions packages/vuetify/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vuetify",
"description": "Vue Material Component Framework",
"version": "3.7.9",
"version": "3.7.11",
"author": {
"name": "John Leider",
"email": "[email protected]"
Expand Down Expand Up @@ -184,9 +184,9 @@
},
"peerDependencies": {
"typescript": ">=4.7",
"vite-plugin-vuetify": ">=1.0.0",
"vite-plugin-vuetify": ">=2.1.0",
"vue": "^3.3.0",
"webpack-plugin-vuetify": ">=2.0.0"
"webpack-plugin-vuetify": ">=3.1.0"
},
"peerDependenciesMeta": {
"typescript": {
Expand Down
13 changes: 3 additions & 10 deletions packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import { useForm } from '@/composables/form'
import { forwardRefs } from '@/composables/forwardRefs'
import { useItems } from '@/composables/list-items'
import { useLocale } from '@/composables/locale'
import { useIsMousedown } from '@/composables/mousedown'
import { useProxiedModel } from '@/composables/proxiedModel'
import { makeTransitionProps } from '@/composables/transition'

// Utilities
import { computed, mergeProps, nextTick, ref, shallowRef, watch } from 'vue'
import {
checkPrintable,
deepEqual,
ensureValidVNode,
genericComponent,
IN_BROWSER,
Expand Down Expand Up @@ -151,7 +151,6 @@ export const VAutocomplete = genericComponent<new <
const label = computed(() => menu.value ? props.closeText : props.openText)
const { items, transformIn, transformOut } = useItems(props)
const { textColorClasses, textColorStyles } = useTextColor(color)
const { isMousedown } = useIsMousedown()
const search = useProxiedModel(props, 'search', '')
const model = useProxiedModel(
props,
Expand Down Expand Up @@ -348,7 +347,7 @@ export const VAutocomplete = genericComponent<new <
if (!item || item.props.disabled) return

if (props.multiple) {
const index = model.value.findIndex(selection => props.valueComparator(selection.value, item.value))
const index = model.value.findIndex(selection => (props.valueComparator || deepEqual)(selection.value, item.value))
const add = set == null ? !~index : set

if (~index) {
Expand All @@ -375,12 +374,6 @@ export const VAutocomplete = genericComponent<new <
}
}

function onBlur (e: FocusEvent) {
if (!isMousedown.value) {
menu.value = false
}
}

watch(isFocused, (val, oldVal) => {
if (val === oldVal) return

Expand All @@ -392,6 +385,7 @@ export const VAutocomplete = genericComponent<new <
nextTick(() => isSelecting.value = false)
} else {
if (!props.multiple && search.value == null) model.value = []
menu.value = false
if (!model.value.some(({ title }) => title === search.value)) search.value = ''
selectionIndex.value = -1
}
Expand Down Expand Up @@ -460,7 +454,6 @@ export const VAutocomplete = genericComponent<new <
readonly={ form.isReadonly.value }
placeholder={ isDirty ? undefined : props.placeholder }
onClick:clear={ onClear }
onBlur={ onBlur }
onMousedown:control={ onMousedownControl }
onKeydown={ onKeydown }
>
Expand Down
16 changes: 4 additions & 12 deletions packages/vuetify/src/components/VCombobox/VCombobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ import { useForm } from '@/composables/form'
import { forwardRefs } from '@/composables/forwardRefs'
import { transformItem, useItems } from '@/composables/list-items'
import { useLocale } from '@/composables/locale'
import { useIsMousedown } from '@/composables/mousedown'
import { useProxiedModel } from '@/composables/proxiedModel'
import { makeTransitionProps } from '@/composables/transition'

// Utilities
import { computed, mergeProps, nextTick, ref, shallowRef, watch } from 'vue'
import {
checkPrintable,
deepEqual,
ensureValidVNode,
genericComponent,
IN_BROWSER,
Expand Down Expand Up @@ -167,7 +167,6 @@ export const VCombobox = genericComponent<new <
}
)
const form = useForm(props)
const { isMousedown } = useIsMousedown()

const hasChips = computed(() => !!(props.chips || slots.chip))
const hasSelectionSlot = computed(() => hasChips.value || !!slots.selection)
Expand Down Expand Up @@ -378,19 +377,12 @@ export const VCombobox = genericComponent<new <
vTextFieldRef.value?.focus()
}
}

function onBlur (e: FocusEvent) {
if (!isMousedown.value) {
menu.value = false
}
}

/** @param set - null means toggle */
function select (item: ListItem | undefined, set: boolean | null = true) {
if (!item || item.props.disabled) return

if (props.multiple) {
const index = model.value.findIndex(selection => props.valueComparator(selection.value, item.value))
const index = model.value.findIndex(selection => (props.valueComparator || deepEqual)(selection.value, item.value))
const add = set == null ? !~index : set

if (~index) {
Expand Down Expand Up @@ -434,6 +426,7 @@ export const VCombobox = genericComponent<new <
if (val || val === oldVal) return

selectionIndex.value = -1
menu.value = false

if (search.value) {
if (props.multiple) {
Expand All @@ -454,7 +447,7 @@ export const VCombobox = genericComponent<new <
watch(menu, () => {
if (!props.hideSelected && menu.value && model.value.length) {
const index = displayItems.value.findIndex(
item => model.value.some(s => props.valueComparator(s.value, item.value))
item => model.value.some(s => (props.valueComparator || deepEqual)(s.value, item.value))
)
IN_BROWSER && window.requestAnimationFrame(() => {
index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index)
Expand Down Expand Up @@ -505,7 +498,6 @@ export const VCombobox = genericComponent<new <
readonly={ form.isReadonly.value }
placeholder={ isDirty ? undefined : props.placeholder }
onClick:clear={ onClear }
onBlur={ onBlur }
onMousedown:control={ onMousedownControl }
onKeydown={ onKeydown }
>
Expand Down
3 changes: 2 additions & 1 deletion packages/vuetify/src/components/VDatePicker/VDatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,9 @@ export const VDatePicker = genericComponent<new <
} else {
let _date = adapter.date()

_date = adapter.setYear(_date, year.value)
_date = adapter.startOfMonth(_date)
_date = adapter.setMonth(_date, month.value)
_date = adapter.setYear(_date, year.value)

if (minDate.value) {
const date = adapter.addDays(adapter.startOfMonth(_date), -1)
Expand Down
15 changes: 10 additions & 5 deletions packages/vuetify/src/components/VList/VList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@ import { makeVariantProps } from '@/composables/variant'

// Utilities
import { computed, ref, shallowRef, toRef } from 'vue'
import { EventProp, focusChild, genericComponent, getPropertyFromItem, omit, propsFactory, useRender } from '@/util'
import {
EventProp,
focusChild,
genericComponent,
getPropertyFromItem,
isPrimitive,
omit,
propsFactory,
useRender,
} from '@/util'

// Types
import type { PropType } from 'vue'
Expand All @@ -35,10 +44,6 @@ export interface InternalListItem<T = any> extends ListItem<T> {
type?: 'item' | 'subheader' | 'divider'
}

function isPrimitive (value: unknown): value is string | number | boolean {
return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean'
}

function transformItem (props: ItemProps & { itemType?: string }, item: any): InternalListItem {
const type = getPropertyFromItem(item, props.itemType, 'item')
const title = isPrimitive(item) ? item : getPropertyFromItem(item, props.itemTitle)
Expand Down
11 changes: 5 additions & 6 deletions packages/vuetify/src/components/VSelect/VSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import { forwardRefs } from '@/composables/forwardRefs'
import { IconValue } from '@/composables/icons'
import { makeItemsProps, useItems } from '@/composables/list-items'
import { useLocale } from '@/composables/locale'
import { useIsMousedown } from '@/composables/mousedown'
import { useProxiedModel } from '@/composables/proxiedModel'
import { makeTransitionProps } from '@/composables/transition'

// Utilities
import { computed, mergeProps, nextTick, ref, shallowRef, watch } from 'vue'
import {
checkPrintable,
deepEqual,
ensureValidVNode,
genericComponent,
IN_BROWSER,
Expand Down Expand Up @@ -169,7 +169,6 @@ export const VSelect = genericComponent<new <
: model.value.length
})
const form = useForm(props)
const { isMousedown } = useIsMousedown()
const selectedValues = computed(() => model.value.map(selection => selection.value))
const isFocused = shallowRef(false)
const label = computed(() => menu.value ? props.closeText : props.openText)
Expand All @@ -179,7 +178,7 @@ export const VSelect = genericComponent<new <

const displayItems = computed(() => {
if (props.hideSelected) {
return items.value.filter(item => !model.value.some(s => props.valueComparator(s, item)))
return items.value.filter(item => !model.value.some(s => (props.valueComparator || deepEqual)(s, item)))
}
return items.value
})
Expand Down Expand Up @@ -264,7 +263,7 @@ export const VSelect = genericComponent<new <
if (item.props.disabled) return

if (props.multiple) {
const index = model.value.findIndex(selection => props.valueComparator(selection.value, item.value))
const index = model.value.findIndex(selection => (props.valueComparator || deepEqual)(selection.value, item.value))
const add = set == null ? !~index : set

if (~index) {
Expand All @@ -284,7 +283,7 @@ export const VSelect = genericComponent<new <
}
}
function onBlur (e: FocusEvent) {
if (!listRef.value?.$el.contains(e.relatedTarget as HTMLElement) && !isMousedown.value) {
if (!listRef.value?.$el.contains(e.relatedTarget as HTMLElement)) {
menu.value = false
}
}
Expand Down Expand Up @@ -316,7 +315,7 @@ export const VSelect = genericComponent<new <
watch(menu, () => {
if (!props.hideSelected && menu.value && model.value.length) {
const index = displayItems.value.findIndex(
item => model.value.some(s => props.valueComparator(s.value, item.value))
item => model.value.some(s => (props.valueComparator || deepEqual)(s.value, item.value))
)
IN_BROWSER && window.requestAnimationFrame(() => {
index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,47 @@ describe('VSelect', () => {
await expect.poll(() => screen.queryByRole('listbox')).toBeNull()
})

describe('reactivity', () => {
it('adds a new item', async () => {
const items = ref(['Foo'])
const { element } = render(() => (
<VSelect items={ items.value } />
))

await userEvent.click(element)
await expect.poll(() => screen.queryByRole('listbox')).toBeInTheDocument()

items.value.push('Bar')
await expect.poll(() => screen.getByText('Bar')).toBeInTheDocument()
})

it('removes an item', async () => {
const items = ref(['Foo', 'Bar'])
const { element } = render(() => (
<VSelect items={ items.value } />
))

await userEvent.click(element)
await expect.poll(() => screen.queryByRole('listbox')).toBeInTheDocument()

items.value.splice(1, 1)
await expect.element(screen.getByText('Bar')).not.toBeInTheDocument()
})

it('updates an item title', async () => {
const items = ref([{ title: 'Foo' }])
const { element } = render(() => (
<VSelect items={ items.value } />
))

await userEvent.click(element)
await expect.poll(() => screen.queryByRole('listbox')).toBeInTheDocument()

items.value[0].title = 'Bar'
await expect.poll(() => screen.getByText('Bar')).toBeInTheDocument()
})
})

describe('Showcase', () => {
generate({ stories })
})
Expand Down
Loading

0 comments on commit 848deab

Please sign in to comment.