From 9dbc30ac9264f0626c0b7a204857598b25c2fae1 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 5 May 2024 21:14:31 -0500 Subject: [PATCH 001/190] feat(VAvatar): add border prop support --- .../vuetify/src/components/VAvatar/VAvatar.sass | 1 + packages/vuetify/src/components/VAvatar/VAvatar.tsx | 4 ++++ .../vuetify/src/components/VAvatar/_variables.scss | 13 +++++++++++++ 3 files changed, 18 insertions(+) diff --git a/packages/vuetify/src/components/VAvatar/VAvatar.sass b/packages/vuetify/src/components/VAvatar/VAvatar.sass index 2ed652aab23..54f59eedf4b 100644 --- a/packages/vuetify/src/components/VAvatar/VAvatar.sass +++ b/packages/vuetify/src/components/VAvatar/VAvatar.sass @@ -19,6 +19,7 @@ @include avatar-sizes($avatar-sizes) @include avatar-density(('height', 'width'), $avatar-density) + @include tools.border($avatar-border...) @include tools.rounded($avatar-border-radius) @include tools.variant($avatar-variants...) diff --git a/packages/vuetify/src/components/VAvatar/VAvatar.tsx b/packages/vuetify/src/components/VAvatar/VAvatar.tsx index 7c0a0ebf9e3..245b205ebfb 100644 --- a/packages/vuetify/src/components/VAvatar/VAvatar.tsx +++ b/packages/vuetify/src/components/VAvatar/VAvatar.tsx @@ -7,6 +7,7 @@ import { VIcon } from '@/components/VIcon' import { VImg } from '@/components/VImg' // Composables +import { makeBorderProps, useBorder } from '@/composables/border' import { makeComponentProps } from '@/composables/component' import { makeDensityProps, useDensity } from '@/composables/density' import { IconValue } from '@/composables/icons' @@ -26,6 +27,7 @@ export const makeVAvatarProps = propsFactory({ image: String, text: String, + ...makeBorderProps(), ...makeComponentProps(), ...makeDensityProps(), ...makeRoundedProps(), @@ -42,6 +44,7 @@ export const VAvatar = genericComponent()({ setup (props, { slots }) { const { themeClasses } = provideTheme(props) + const { borderClasses } = useBorder(props) const { colorClasses, colorStyles, variantClasses } = useVariant(props) const { densityClasses } = useDensity(props) const { roundedClasses } = useRounded(props) @@ -56,6 +59,7 @@ export const VAvatar = genericComponent()({ 'v-avatar--end': props.end, }, themeClasses.value, + borderClasses.value, colorClasses.value, densityClasses.value, roundedClasses.value, diff --git a/packages/vuetify/src/components/VAvatar/_variables.scss b/packages/vuetify/src/components/VAvatar/_variables.scss index e3c5924d197..16d57130f51 100644 --- a/packages/vuetify/src/components/VAvatar/_variables.scss +++ b/packages/vuetify/src/components/VAvatar/_variables.scss @@ -1,10 +1,16 @@ @use "sass:map"; +@use '../../styles/settings'; @use "../../styles/settings/variables"; @use "../../styles/tools/functions"; // Defaults $avatar-background: var(--v-theme-surface) !default; $avatar-border-radius: map.get(variables.$rounded, 'circle') !default; +$avatar-border-color: settings.$border-color-root !default; +$avatar-border-radius: map.get(settings.$rounded, 0) !default; +$avatar-border-style: settings.$border-style-root !default; +$avatar-border-thin-width: thin !default; +$avatar-border-width: thin !default; $avatar-color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)) !default; $avatar-density: ('default': 0, 'comfortable': -1, 'compact': -2) !default; $avatar-elevation: 1 !default; @@ -26,6 +32,13 @@ $avatar-sizes: functions.map-deep-merge( $avatar-sizes ); +$avatar-border: ( + $avatar-border-color, + $avatar-border-style, + $avatar-border-width, + $avatar-border-thin-width +) !default; + $avatar-variants: ( $avatar-background, $avatar-color, From aee83f0e97d750e6d4056977862663a52b4ac626 Mon Sep 17 00:00:00 2001 From: John Leider Date: Mon, 13 May 2024 15:32:44 -0500 Subject: [PATCH 002/190] feat(VBtn): add support for active-color prop --- packages/vuetify/src/components/VBtn/VBtn.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/vuetify/src/components/VBtn/VBtn.tsx b/packages/vuetify/src/components/VBtn/VBtn.tsx index 1c9d0fff977..783eac82247 100644 --- a/packages/vuetify/src/components/VBtn/VBtn.tsx +++ b/packages/vuetify/src/components/VBtn/VBtn.tsx @@ -49,6 +49,7 @@ export const makeVBtnProps = propsFactory({ type: Boolean, default: undefined, }, + activeColor: String, baseColor: String, symbol: { type: null, @@ -123,13 +124,14 @@ export const VBtn = genericComponent()({ return group?.isSelected.value }) + const color = computed(() => isActive.value ? props.activeColor ?? props.color : props.color) const variantProps = computed(() => { const showColor = ( (group?.isSelected.value && (!link.isLink.value || link.isActive?.value)) || (!group || link.isActive?.value) ) return ({ - color: showColor ? props.color ?? props.baseColor : props.baseColor, + color: showColor ? color.value ?? props.baseColor : props.baseColor, variant: props.variant, }) }) From 14a2e8cdeef3cd88fb8f80e336ac923856f823bc Mon Sep 17 00:00:00 2001 From: John Leider Date: Tue, 28 May 2024 10:37:18 -0500 Subject: [PATCH 003/190] feat(VContainer): add dimension support --- packages/vuetify/src/components/VGrid/VContainer.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/vuetify/src/components/VGrid/VContainer.tsx b/packages/vuetify/src/components/VGrid/VContainer.tsx index 497ac18abfa..50f20c673c4 100644 --- a/packages/vuetify/src/components/VGrid/VContainer.tsx +++ b/packages/vuetify/src/components/VGrid/VContainer.tsx @@ -3,6 +3,7 @@ import './VGrid.sass' // Composables import { makeComponentProps } from '@/composables/component' +import { makeDimensionProps, useDimension } from '@/composables/dimensions' import { useRtl } from '@/composables/locale' import { makeTagProps } from '@/composables/tag' @@ -16,6 +17,7 @@ export const makeVContainerProps = propsFactory({ }, ...makeComponentProps(), + ...makeDimensionProps(), ...makeTagProps(), }, 'VContainer') @@ -26,6 +28,7 @@ export const VContainer = genericComponent()({ setup (props, { slots }) { const { rtlClasses } = useRtl() + const { dimensionStyles } = useDimension(props) useRender(() => ( )) From f842cd96d9ce8ba10acc14205d928f8f0eabef16 Mon Sep 17 00:00:00 2001 From: John Leider Date: Wed, 29 May 2024 09:04:41 -0500 Subject: [PATCH 004/190] feat(VImg): add absolute prop --- packages/vuetify/src/components/VImg/VImg.sass | 9 +++++++++ packages/vuetify/src/components/VImg/VImg.tsx | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/vuetify/src/components/VImg/VImg.sass b/packages/vuetify/src/components/VImg/VImg.sass index 00fa63324e7..e34149aa2e1 100644 --- a/packages/vuetify/src/components/VImg/VImg.sass +++ b/packages/vuetify/src/components/VImg/VImg.sass @@ -6,6 +6,15 @@ --v-theme-overlay-multiplier: 3 z-index: 0 + &.v-img--absolute + height: 100% + left: 0 + overflow: hidden + position: absolute + top: 0 + width: 100% + z-index: -1 + &--booting .v-responsive__sizer transition: none diff --git a/packages/vuetify/src/components/VImg/VImg.tsx b/packages/vuetify/src/components/VImg/VImg.tsx index 30c4926a80b..8ee7e43e307 100644 --- a/packages/vuetify/src/components/VImg/VImg.tsx +++ b/packages/vuetify/src/components/VImg/VImg.tsx @@ -54,6 +54,7 @@ export type VImgSlots = { } export const makeVImgProps = propsFactory({ + absolute: Boolean, alt: String, cover: Boolean, color: String, @@ -351,7 +352,10 @@ export const VImg = genericComponent()({ Date: Wed, 12 Jun 2024 13:20:03 -0500 Subject: [PATCH 005/190] feat(VExpansionPanelTitle): add dimension support --- .../src/components/VExpansionPanel/VExpansionPanelTitle.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/vuetify/src/components/VExpansionPanel/VExpansionPanelTitle.tsx b/packages/vuetify/src/components/VExpansionPanel/VExpansionPanelTitle.tsx index 98df96d9050..65a121405b8 100644 --- a/packages/vuetify/src/components/VExpansionPanel/VExpansionPanelTitle.tsx +++ b/packages/vuetify/src/components/VExpansionPanel/VExpansionPanelTitle.tsx @@ -6,6 +6,7 @@ import { VIcon } from '@/components/VIcon' // Composables import { useBackgroundColor } from '@/composables/color' import { makeComponentProps } from '@/composables/component' +import { makeDimensionProps, useDimension } from '@/composables/dimensions' import { IconValue } from '@/composables/icons' // Directives @@ -52,6 +53,7 @@ export const makeVExpansionPanelTitleProps = propsFactory({ readonly: Boolean, ...makeComponentProps(), + ...makeDimensionProps(), }, 'VExpansionPanelTitle') export const VExpansionPanelTitle = genericComponent()({ @@ -67,6 +69,7 @@ export const VExpansionPanelTitle = genericComponent( if (!expansionPanel) throw new Error('[Vuetify] v-expansion-panel-title needs to be placed inside v-expansion-panel') const { backgroundColorClasses, backgroundColorStyles } = useBackgroundColor(props, 'color') + const { dimensionStyles } = useDimension(props) const slotProps = computed(() => ({ collapseIcon: props.collapseIcon, @@ -92,6 +95,7 @@ export const VExpansionPanelTitle = genericComponent( ]} style={[ backgroundColorStyles.value, + dimensionStyles.value, props.style, ]} type="button" From 7e730fa2ad5effcab4e9aa0ed5245610f897aea3 Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 20 Jun 2024 18:27:18 +1000 Subject: [PATCH 006/190] feat(validation): add eager and invalid-input options --- .../docs/src/pages/en/components/forms.md | 32 ++++++++++++------- .../vuetify/src/composables/validation.ts | 24 ++++++++++---- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/packages/docs/src/pages/en/components/forms.md b/packages/docs/src/pages/en/components/forms.md index 01861e089c7..7a97bbe16b8 100644 --- a/packages/docs/src/pages/en/components/forms.md +++ b/packages/docs/src/pages/en/components/forms.md @@ -62,21 +62,29 @@ This also demonstrates the **validate-on** prop, which tells the `v-form` compon ## Validation state -By default, all inputs run their validation rules when mounted but do not display errors to the user. +When rules run is controlled with the **validate-on** prop which accepts a string containing `input`, `blur`, `submit`, `invalid-input`, `eager`, or `lazy`.
-When rules run is controlled with the **validate-on** prop which accepts a string containing `input`, `blur`, `submit`, or `lazy`. +`input`, `blur`, `submit`, and `eager` set when a validation error can first be displayed to the user, while `lazy` disables validation on mount (useful for async rules).
-`input`, `blur`, and `submit` set when a validation error can first be displayed to the user, while `lazy` disables validation on mount (useful for async rules). +By default, all inputs run their validation rules when mounted but do not display errors to the user. Adding `eager` will display errors immediately, or `lazy` to disable this.
-`lazy` can be combined with other options, and implies `input` on its own. - -| `validate-on=` | `"input"` | `"blur"` | `"submit"` | `"lazy"` | -|----------------|:---------:|:--------:|:----------:|:--------:| -| On mount | ✅ | ✅ | ✅ | ❌ | -| On input | ✅ | ❌ | ❌ | * | -| On blur | ✅ | ✅ | ❌ | * | -| On submit | ✅ | ✅ | ✅ | * | -

* Uses the behavior of whatever it's combined with.

+`eager` and `lazy` can be combined with other options but not each other, and both imply `input` on their own. +
+`invalid-input` behaves the same as `blur` unless the field is invalid, then it will run on input instead until validation passes again. + +| `validate-on=` | `"input"` | `"blur"` | `"submit"` | `"invalid-input"` | `"eager"` | `"lazy"` | +|----------------|:---------:|:--------:|:----------:|:-----------------:|:-------------:|:--------:| +| On mount | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | +| On input | ✅ | ❌ | ❌ | ‡ | * | * | +| On blur | ✅ | ✅ | ❌ | ✅ | * | * | +| On submit | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +

+* Uses the behavior of whatever it's combined with, the same as on="input" by default. +
+† Displays errors immediately on mount or reset. +
+‡ Only if the validation failed previously. +

The form's current validation status is accessed using `v-model` or the submit event. It can be in one of three states: diff --git a/packages/vuetify/src/composables/validation.ts b/packages/vuetify/src/composables/validation.ts index 9825007dc5f..5567e71f351 100644 --- a/packages/vuetify/src/composables/validation.ts +++ b/packages/vuetify/src/composables/validation.ts @@ -19,7 +19,15 @@ export type ValidationRule = | ((value: any) => ValidationResult) | ((value: any) => PromiseLike) -type ValidateOnValue = 'blur' | 'input' | 'submit' +type ValidateOnValue = 'blur' | 'input' | 'submit' | 'invalid-input' +type ValidateOn = + | ValidateOnValue + | `${ValidateOnValue} lazy` + | `${ValidateOnValue} eager` + | `lazy ${ValidateOnValue}` + | `eager ${ValidateOnValue}` + | 'lazy' + | 'eager' export interface ValidationProps { disabled: boolean | null @@ -33,7 +41,7 @@ export interface ValidationProps { rules: readonly ValidationRule[] modelValue: any 'onUpdate:modelValue': EventProp | undefined - validateOn?: ValidateOnValue | `${ValidateOnValue} lazy` | `lazy ${ValidateOnValue}` | 'lazy' + validateOn?: ValidateOn validationValue: any } @@ -92,13 +100,15 @@ export function useValidation ( const validateOn = computed(() => { let value = (props.validateOn ?? form?.validateOn.value) || 'input' if (value === 'lazy') value = 'input lazy' + if (value === 'eager') value = 'input eager' const set = new Set(value?.split(' ') ?? []) return { - blur: set.has('blur') || set.has('input'), input: set.has('input'), - submit: set.has('submit'), + blur: set.has('blur') || set.has('input') || set.has('invalid-input'), + invalidInput: set.has('invalid-input'), lazy: set.has('lazy'), + eager: set.has('eager'), } }) const isValid = computed(() => { @@ -139,12 +149,12 @@ export function useValidation ( onMounted(async () => { if (!validateOn.value.lazy) { - await validate(true) + await validate(!validateOn.value.eager) } form?.update(uid.value, isValid.value, errorMessages.value) }) - useToggleScope(() => validateOn.value.input, () => { + useToggleScope(() => validateOn.value.input || (validateOn.value.invalidInput && isValid.value === false), () => { watch(validationModel, () => { if (validationModel.value != null) { validate() @@ -177,7 +187,7 @@ export function useValidation ( async function resetValidation () { isPristine.value = true if (!validateOn.value.lazy) { - await validate(true) + await validate(!validateOn.value.eager) } else { internalErrorMessages.value = [] } From 3752de23e2f3640b823fd13edd2b901d36d5fa6b Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 20 Jun 2024 18:31:52 +1000 Subject: [PATCH 007/190] chore: remove unused import --- .../vuetify/src/components/VExpansionPanel/VExpansionPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/src/components/VExpansionPanel/VExpansionPanel.tsx b/packages/vuetify/src/components/VExpansionPanel/VExpansionPanel.tsx index 45c22192410..4741fad397d 100644 --- a/packages/vuetify/src/components/VExpansionPanel/VExpansionPanel.tsx +++ b/packages/vuetify/src/components/VExpansionPanel/VExpansionPanel.tsx @@ -12,7 +12,7 @@ import { makeRoundedProps, useRounded } from '@/composables/rounded' import { makeTagProps } from '@/composables/tag' // Utilities -import { computed, provide, toRef } from 'vue' +import { computed, provide } from 'vue' import { genericComponent, propsFactory, useRender } from '@/util' export const makeVExpansionPanelProps = propsFactory({ From 8ef6ff811278a990d45504c2987fac0afec8f43c Mon Sep 17 00:00:00 2001 From: Piotr <68294222+PiotrWasak@users.noreply.github.com> Date: Tue, 2 Jul 2024 19:56:07 +0200 Subject: [PATCH 008/190] feat(VSlideGroup): expose hasNext and hasPrev (#20050) Co-authored-by: Piotr Wasak --- packages/vuetify/src/components/VSlideGroup/VSlideGroup.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vuetify/src/components/VSlideGroup/VSlideGroup.tsx b/packages/vuetify/src/components/VSlideGroup/VSlideGroup.tsx index d0f809b3bcc..950df1a444a 100644 --- a/packages/vuetify/src/components/VSlideGroup/VSlideGroup.tsx +++ b/packages/vuetify/src/components/VSlideGroup/VSlideGroup.tsx @@ -451,6 +451,8 @@ export const VSlideGroup = genericComponent( scrollTo, scrollOffset, focus, + hasPrev, + hasNext, } }, }) From cb6b5ffd057fac94650c39b579488cc4621fcb91 Mon Sep 17 00:00:00 2001 From: Yuchao Date: Wed, 10 Jul 2024 01:48:30 +1000 Subject: [PATCH 009/190] feat(VTreeview): port open-on-click prop to v3 & enhancement (#20038) fixes #20009 fixes #20095 fixes #19414 fixes #20106 --- .../src/locale/en/VTreeview.json | 2 +- .../v-treeview/misc-search-and-filter.vue | 4 +- .../v-treeview/misc-selectable-icons.vue | 108 +--- .../examples/v-treeview/prop-activatable.vue | 1 + .../src/examples/v-treeview/prop-color.vue | 1 + .../v-treeview/prop-selection-type.vue | 10 +- .../v-treeview/slot-append-and-label.vue | 79 +-- .../docs/src/pages/en/components/treeview.md | 4 +- .../src/components/VList/VListItem.sass | 2 +- .../src/components/VList/VListItem.tsx | 5 +- .../vuetify/src/composables/nested/nested.ts | 6 +- .../src/composables/nested/openStrategies.ts | 7 +- .../composables/nested/selectStrategies.ts | 10 +- .../vuetify/src/labs/VTreeview/VTreeview.tsx | 15 +- .../src/labs/VTreeview/VTreeviewChildren.tsx | 31 +- .../src/labs/VTreeview/VTreeviewItem.tsx | 109 +--- .../VTreeview/__tests__/VTreeview.spec.cy.tsx | 582 +++++++++++++++++- 17 files changed, 667 insertions(+), 309 deletions(-) diff --git a/packages/api-generator/src/locale/en/VTreeview.json b/packages/api-generator/src/locale/en/VTreeview.json index 3025b82f42b..0d1efb4f350 100644 --- a/packages/api-generator/src/locale/en/VTreeview.json +++ b/packages/api-generator/src/locale/en/VTreeview.json @@ -25,7 +25,7 @@ "returnObject": "When `true` will make `v-model`, `active.sync` and `open.sync` return the complete object instead of just the key.", "rounded": "Provides an alternative active style for `v-treeview` node. Only visible when `activatable` is `true` and should not be used in conjunction with the `shaped` prop.", "search": "The search model for filtering results.", - "selectable": "Will render a checkbox next to each node allowing them to be selected.", + "selectable": "Will render a checkbox next to each node allowing them to be selected. Additionally, the **[openOnClick](/api/v-treeview/#props-open-on-click)** property will be applied internally.", "selectedColor": "The color of the selection checkbox.", "selectionType": "Controls how the treeview selects nodes. There are two modes available: 'leaf' and 'independent'.", "shaped": "Provides an alternative active style for `v-treeview` node. Only visible when `activatable` is `true` and should not be used in conjunction with the `rounded` prop.", diff --git a/packages/docs/src/examples/v-treeview/misc-search-and-filter.vue b/packages/docs/src/examples/v-treeview/misc-search-and-filter.vue index 7333aefc0cf..3e5c3e339be 100644 --- a/packages/docs/src/examples/v-treeview/misc-search-and-filter.vue +++ b/packages/docs/src/examples/v-treeview/misc-search-and-filter.vue @@ -23,10 +23,12 @@ diff --git a/packages/docs/src/examples/v-treeview/prop-selection-type.vue b/packages/docs/src/examples/v-treeview/prop-selection-type.vue index c4d3f4379ae..260f3abc9e3 100644 --- a/packages/docs/src/examples/v-treeview/prop-selection-type.vue +++ b/packages/docs/src/examples/v-treeview/prop-selection-type.vue @@ -2,16 +2,16 @@ @@ -29,7 +29,7 @@ v-for="node in selection" :key="node.id" > - {{ node.name }} + {{ node.title }} diff --git a/packages/docs/src/examples/v-treeview/slot-append-and-label.vue b/packages/docs/src/examples/v-treeview/slot-append-and-label.vue index e52f27851da..bde4d84e37a 100644 --- a/packages/docs/src/examples/v-treeview/slot-append-and-label.vue +++ b/packages/docs/src/examples/v-treeview/slot-append-and-label.vue @@ -1,15 +1,14 @@ diff --git a/packages/docs/src/components/doc/RelatedPages.vue b/packages/docs/src/components/doc/RelatedPages.vue index f48ac71df57..2e893bdb708 100644 --- a/packages/docs/src/components/doc/RelatedPages.vue +++ b/packages/docs/src/components/doc/RelatedPages.vue @@ -16,5 +16,6 @@ diff --git a/packages/docs/src/composables/frontmatter.ts b/packages/docs/src/composables/frontmatter.ts new file mode 100644 index 00000000000..b9a8bd2e256 --- /dev/null +++ b/packages/docs/src/composables/frontmatter.ts @@ -0,0 +1,39 @@ +type Frontmatter = { + meta: { + nav?: string + title: string + description?: string + keywords?: string[] + } + assets?: string[] + backmatter?: boolean + features?: { + figma?: boolean + label?: string + report?: string + github?: string + spec?: string + } + fluid?: boolean + related?: string[] + toc?: TocItem[] +} + +type TocItem = { + to: string + text: string + level: number +} + +export function useFrontmatter () { + const router = useRouter() + + const frontmatter = shallowRef() + watch(router.currentRoute, route => { + setTimeout(() => { + frontmatter.value = (route.matched.at(-1)!.instances.default as any)?.frontmatter + }) + }, { immediate: true }) + + return readonly(frontmatter) +} diff --git a/packages/docs/src/examples/v-overlay/misc-advanced.vue b/packages/docs/src/examples/v-overlay/misc-advanced.vue index 0885b31ba74..84e6901fa48 100644 --- a/packages/docs/src/examples/v-overlay/misc-advanced.vue +++ b/packages/docs/src/examples/v-overlay/misc-advanced.vue @@ -28,7 +28,7 @@ + const name = shallowRef('') + + +# {{ name }} API + + + + + + + + + + diff --git a/packages/docs/src/plugins/global-components.ts b/packages/docs/src/plugins/global-components.ts index f984e7ce05d..324f260af4c 100644 --- a/packages/docs/src/plugins/global-components.ts +++ b/packages/docs/src/plugins/global-components.ts @@ -1,102 +1,9 @@ -// Components -import AboutTeamMembers from '@/components/about/TeamMembers.vue' -import Alert from '@/components/Alert.vue' -import ApiInline from '@/components/api/Inline.vue' -import ApiSearch from '@/components/api/Search.vue' -import ApiSection from '@/components/api/Section.vue' -import AppDivider from '@/components/app/Divider.vue' -import AppHeading from '@/components/app/Heading.vue' -import AppFigure from '@/components/app/Figure.vue' -import AppMarkup from '@/components/app/Markup.vue' -import AppSettingsAdvancedOptions from '@/components/app/settings/AdvancedOptions.vue' -import AppSettingsOptions from '@/components/app/settings/Options.vue' -import AppSettingsPerksOptions from '@/components/app/settings/PerksOptions.vue' -import AppLink from '@/components/app/Link.vue' -import AppTable from '@/components/app/Table.vue' -import ComponentsListItem from '@/components/components/ListItem.vue' -import DocExplorer from '@/components/doc/Explorer.vue' -import DocIconList from '@/components/doc/IconList.vue' -import DocIconTable from '@/components/doc/IconTable.vue' -import DocTabs from '@/components/doc/Tabs.vue' -import DocVueJobs from '@/components/doc/VueJobs.vue' -import DocMadeWithVueAttribution from '@/components/doc/MadeWithVueAttribution.vue' -import DocMadeWithVuetifyGallery from '@/components/doc/MadeWithVuetifyGallery.vue' -import DocMadeWithVuetifyLink from '@/components/doc/MadeWithVuetifyLink.vue' -import DocPremiumThemesGallery from '@/components/doc/PremiumThemesGallery.vue' -import DocReleases from '@/components/doc/Releases.vue' -import DocThemeVendor from '@/components/doc/ThemeVendor.vue' -import ExamplesExample from '@/components/examples/Example.vue' -import ExamplesUsage from '@/components/examples/Usage.vue' -import FeaturesBreakpointsTable from '@/components/features/BreakpointsTable.vue' -import FeaturesColorPalette from '@/components/features/ColorPalette.vue' -import FeaturesSassApi from '@/components/features/SassApi.vue' -import GettingStartedWireframeExamples from '@/components/getting-started/WireframeExamples.vue' -import HomeEntry from '@/components/home/Entry.vue' -import HomeFeatures from '@/components/home/Features.vue' -import HomeSpecialSponsor from '@/components/home/SpecialSponsor.vue' -import HomeSponsors from '@/components/home/Sponsors.vue' -import IntroductionSlaDeck from '@/components/introduction/SlaDeck.vue' -import IntroductionDiscordDeck from '@/components/introduction/DiscordDeck.vue' -import IntroductionEnterpriseDeck from '@/components/introduction/EnterpriseDeck.vue' -import PageFeatures from '@/components/PageFeatures.vue' -import PromotedEntry from '@/components/promoted/Entry.vue' -import PromotedPromoted from '@/components/promoted/Promoted.vue' -import PromotedRandom from '@/components/promoted/Random.vue' -import ResourcesColorPalette from '@/components/resources/ColorPalette.vue' -import ResourcesLogos from '@/components/resources/Logos.vue' -import SponserSponsors from '@/components/sponsor/Sponsors.vue' +import { defineAsyncComponent } from 'vue' // Types import type { App } from 'vue' export function installGlobalComponents (app: App) { app - // Used by markdown-it to gen api pages, and needed to be globally loaded to work - .component('AboutTeamMembers', AboutTeamMembers) - .component('Alert', Alert) - .component('ApiInline', ApiInline) - .component('ApiSearch', ApiSearch) - .component('ApiSection', ApiSection) - .component('AppDivider', AppDivider) - .component('AppFigure', AppFigure) - .component('AppHeading', AppHeading) - .component('AppLink', AppLink) - .component('AppMarkup', AppMarkup) - .component('AppTable', AppTable) - .component('AppSettingsAdvancedOptions', AppSettingsAdvancedOptions) - .component('AppSettingsOptions', AppSettingsOptions) - .component('AppSettingsPerksOptions', AppSettingsPerksOptions) - .component('ComponentsListItem', ComponentsListItem) - .component('DocExplorer', DocExplorer) - .component('DocIconList', DocIconList) - .component('DocIconTable', DocIconTable) - .component('DocTabs', DocTabs) - .component('DocVueJobs', DocVueJobs) - .component('DocMadeWithVueAttribution', DocMadeWithVueAttribution) - .component('DocMadeWithVuetifyGallery', DocMadeWithVuetifyGallery) - .component('DocMadeWithVuetifyLink', DocMadeWithVuetifyLink) - .component('DocPremiumThemesGallery', DocPremiumThemesGallery) - .component('DocReleases', DocReleases) - .component('DocThemeVendor', DocThemeVendor) - .component('ExamplesExample', ExamplesExample) - .component('ExamplesUsage', ExamplesUsage) - .component('FeaturesBreakpointsTable', FeaturesBreakpointsTable) - .component('FeaturesColorPalette', FeaturesColorPalette) - .component('FeaturesSassApi', FeaturesSassApi) - .component('GettingStartedWireframeExamples', GettingStartedWireframeExamples) - .component('HomeEntry', HomeEntry) - .component('HomeFeatures', HomeFeatures) - .component('HomeSpecialSponsor', HomeSpecialSponsor) - .component('HomeSponsors', HomeSponsors) - .component('IntroductionSlaDeck', IntroductionSlaDeck) - .component('IntroductionDiscordDeck', IntroductionDiscordDeck) - .component('IntroductionEnterpriseDeck', IntroductionEnterpriseDeck) - .component('PageFeatures', PageFeatures) - .component('PromotedEntry', PromotedEntry) - .component('PromotedPromoted', PromotedPromoted) - .component('PromotedRandom', PromotedRandom) - .component('ResourcesColorPalette', ResourcesColorPalette) - .component('ResourcesLogos', ResourcesLogos) - .component('SponserSponsors', SponserSponsors) - .component('UnwrapMarkdown', (props, { slots }) => slots.default?.()?.[0].children) + .component('AppMarkdown', defineAsyncComponent(() => import('@/components/app/Markdown.vue'))) } diff --git a/packages/docs/src/plugins/icons.ts b/packages/docs/src/plugins/icons.ts index 5f50e64d639..12d28b89216 100644 --- a/packages/docs/src/plugins/icons.ts +++ b/packages/docs/src/plugins/icons.ts @@ -118,6 +118,7 @@ export { mdiContentSaveCogOutline, mdiControllerClassicOutline, mdiCookie, + mdiCreationOutline, mdiCreditCardOutline, mdiCrosshairsGps, mdiCrown, @@ -127,7 +128,6 @@ export { mdiDeleteOutline, mdiDesktopTowerMonitor, mdiDialpad, - mdiDiscord, mdiDomain, mdiDotsHorizontal, mdiDotsVertical, @@ -184,8 +184,6 @@ export { mdiFormatHeader1, mdiFormatItalic, mdiFormatListBulletedSquare, - mdiFormatTextdirectionLToR, - mdiFormatTextdirectionRToL, mdiFormatUnderline, mdiFormatWrapInline, mdiForum, @@ -399,4 +397,6 @@ export { mdiWrench, } from '@mdi/js' -export const mdiCreationOutline = 'M9 4L11.5 9.5L17 12L11.5 14.5L9 20L6.5 14.5L1 12L6.5 9.5L9 4M9 8.83L8 11L5.83 12L8 13L9 15.17L10 13L12.17 12L10 11L9 8.83M19 9L17.74 6.26L15 5L17.74 3.75L19 1L20.25 3.75L23 5L20.25 6.26L19 9M19 23L17.74 20.26L15 19L17.74 17.75L19 15L20.25 17.75L23 19L20.25 20.26L19 23Z' +export const mdiDiscord = 'M22,24L16.75,19L17.38,21H4.5A2.5,2.5 0 0,1 2,18.5V3.5A2.5,2.5 0 0,1 4.5,1H19.5A2.5,2.5 0 0,1 22,3.5V24M12,6.8C9.32,6.8 7.44,7.95 7.44,7.95C8.47,7.03 10.27,6.5 10.27,6.5L10.1,6.33C8.41,6.36 6.88,7.53 6.88,7.53C5.16,11.12 5.27,14.22 5.27,14.22C6.67,16.03 8.75,15.9 8.75,15.9L9.46,15C8.21,14.73 7.42,13.62 7.42,13.62C7.42,13.62 9.3,14.9 12,14.9C14.7,14.9 16.58,13.62 16.58,13.62C16.58,13.62 15.79,14.73 14.54,15L15.25,15.9C15.25,15.9 17.33,16.03 18.73,14.22C18.73,14.22 18.84,11.12 17.12,7.53C17.12,7.53 15.59,6.36 13.9,6.33L13.73,6.5C13.73,6.5 15.53,7.03 16.56,7.95C16.56,7.95 14.68,6.8 12,6.8M9.93,10.59C10.58,10.59 11.11,11.16 11.1,11.86C11.1,12.55 10.58,13.13 9.93,13.13C9.29,13.13 8.77,12.55 8.77,11.86C8.77,11.16 9.28,10.59 9.93,10.59M14.1,10.59C14.75,10.59 15.27,11.16 15.27,11.86C15.27,12.55 14.75,13.13 14.1,13.13C13.46,13.13 12.94,12.55 12.94,11.86C12.94,11.16 13.45,10.59 14.1,10.59Z' +export const mdiFormatTextdirectionLToR = 'M21,18L17,14V17H5V19H17V22M9,10V15H11V4H13V15H15V4H17V2H9A4,4 0 0,0 5,6A4,4 0 0,0 9,10Z' +export const mdiFormatTextdirectionRToL = 'M8,17V14L4,18L8,22V19H20V17M10,10V15H12V4H14V15H16V4H18V2H10A4,4 0 0,0 6,6A4,4 0 0,0 10,10Z' diff --git a/packages/docs/src/plugins/vuetify.ts b/packages/docs/src/plugins/vuetify.ts index 49ca8a3f19f..dc04e625a3d 100644 --- a/packages/docs/src/plugins/vuetify.ts +++ b/packages/docs/src/plugins/vuetify.ts @@ -3,9 +3,10 @@ import 'vuetify/styles' // Imports import { createVuetify } from 'vuetify' -import * as components from 'vuetify/components' -import * as directives from 'vuetify/directives' -import * as labs from 'vuetify/labs/components' +import { VChip } from 'vuetify/components/VChip' +import { VBtn } from 'vuetify/components/VBtn' +import { VSwitch } from 'vuetify/components/VSwitch' +import { VSvgIcon } from 'vuetify/components/VIcon' // Icons import { fa } from 'vuetify/iconsets/fa' @@ -24,17 +25,12 @@ import type { IconProps } from 'vuetify' export function installVuetify (app: App) { const vuetify = createVuetify({ aliases: { - BorderChip: components.VChip, - NewInChip: components.VChip, - PageFeatureChip: components.VChip, - PrimaryBtn: components.VBtn, - SettingsSwitch: components.VSwitch, + BorderChip: VChip, + NewInChip: VChip, + PageFeatureChip: VChip, + PrimaryBtn: VBtn, + SettingsSwitch: VSwitch, }, - components: { - ...components, - ...labs, - }, - directives, defaults: { global: { eager: false, @@ -109,7 +105,7 @@ export function installVuetify (app: App) { mdi: { component: (props: IconProps) => { const icon = mdiSvg[camelize(props.icon as string) as keyof typeof mdiSvg] - return h(components.VSvgIcon, { ...props, icon }) + return h(VSvgIcon, { ...props, icon }) }, }, }, diff --git a/packages/docs/src/shims.d.ts b/packages/docs/src/shims.d.ts index 8b24f072d17..fdfa6f3c1bc 100644 --- a/packages/docs/src/shims.d.ts +++ b/packages/docs/src/shims.d.ts @@ -10,17 +10,31 @@ declare module '*.vue' { export default component } +declare module 'virtual:mdi-js-icons' { + export interface IconEntry { + name: string + aliases: string[] + path: string + } + export const icons: IconEntry[] +} + +declare module 'virtual:api-list' { + const list: string[] + export default list +} + declare module 'markdown-it-header-sections' { - import type MarkdownIt from 'markdown-it' + import type { PluginSimple } from 'markdown-it' - const MarkdownItHeaderSections: MarkdownIt.PluginSimple + const MarkdownItHeaderSections: PluginSimple export default MarkdownItHeaderSections } declare module 'markdown-it-attrs' { - import type MarkdownIt from 'markdown-it' + import type { PluginWithOptions } from 'markdown-it' - const MarkdownItAttrs: MarkdownIt.PluginWithOptions<{ + const MarkdownItAttrs: PluginWithOptions<{ leftDelimiter?: string rightDelimiter?: string allowedAttributes?: string[] @@ -29,14 +43,14 @@ declare module 'markdown-it-attrs' { } declare module 'markdown-it-link-attributes' { - import type MarkdownIt from 'markdown-it' + import type { PluginWithOptions } from 'markdown-it' interface Config { pattern?: string attrs: Record } - const MarkdownItLinkAttributes: MarkdownIt.PluginWithOptions + const MarkdownItLinkAttributes: PluginWithOptions export default MarkdownItLinkAttributes } @@ -51,19 +65,4 @@ declare module 'virtual:examples' { }> } -declare module '@emailjs/browser' { - interface emailjs { - sendForm ( - service_id: string, - template_id: string, - el: HTMLFormElement, - public_key: string - ): Promise - } - - const client: emailjs - - export default client -} - declare module 'vue-instantsearch/vue3/es/src/instantsearch.js' diff --git a/packages/docs/src/stores/made-with-vuetify.ts b/packages/docs/src/stores/made-with-vuetify.ts index 0397bc019cc..23323405486 100644 --- a/packages/docs/src/stores/made-with-vuetify.ts +++ b/packages/docs/src/stores/made-with-vuetify.ts @@ -2,7 +2,9 @@ export const useMadeWithVuetifyStore = defineStore('made-with-vuetify', () => { const items = ref([]) onBeforeMount(async () => { - const res = await fetch('https://madewithvuejs.com/api/tag/vuetify') + const res = await fetch('https://madewithvuejs.com/api/tag/vuetify', { + priority: 'low', + }) .then(res => res.json()) items.value = res.data diff --git a/packages/docs/src/utils/helpers.ts b/packages/docs/src/utils/helpers.ts index 0e1a740c8eb..0f8bd0e8b1d 100644 --- a/packages/docs/src/utils/helpers.ts +++ b/packages/docs/src/utils/helpers.ts @@ -40,7 +40,7 @@ export async function waitForReadystate () { /** Jaro-Winkler distance between two strings */ // eslint-disable-next-line max-statements -export function distance (s1: string, s2: string) { +export function getDistance (s1: string, s2: string) { // Exit early if either are empty. if (s1.length === 0 || s2.length === 0) { return 0 diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json index 433e6b2fe8a..33062e52aa9 100644 --- a/packages/docs/tsconfig.json +++ b/packages/docs/tsconfig.json @@ -9,10 +9,10 @@ "esnext" ], "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "noUnusedLocals": true, "paths": { - "@/*": ["src/*"], + "@/*": ["src/*"] }, "resolveJsonModule": true, "skipLibCheck": true, @@ -29,6 +29,12 @@ ], "outDir": "./dist" }, - "include": ["../api-generator/src/shims.d.ts"], + "include": [ + "build", + "src", + "./auto-imports.d.ts", + "./components.d.ts", + "../api-generator/src/shims.d.ts" + ], "exclude": ["dist", "node_modules"], } diff --git a/packages/docs/vite.config.mts b/packages/docs/vite.config.mts index 4f651b15b23..0d777aa0d4d 100644 --- a/packages/docs/vite.config.mts +++ b/packages/docs/vite.config.mts @@ -15,11 +15,14 @@ import VueI18n from '@intlify/unplugin-vue-i18n/vite' import Inspect from 'vite-plugin-inspect' import Vuetify from 'vite-plugin-vuetify' import basicSsl from '@vitejs/plugin-basic-ssl' +import MagicString from 'magic-string' -import { configureMarkdown, parseMeta } from './build/markdown-it' +import { configureMarkdown } from './build/markdown-it' import Api from './build/api-plugin' import { Examples } from './build/examples-plugin' import { genAppMetaInfo } from './src/utils/metadata' +import { MdiJs } from './build/mdi-js' +import { frontmatterBuilder, getRouteMeta } from './build/frontmatterMeta' const resolve = (file: string) => fileURLToPath(new URL(file, import.meta.url)) @@ -41,7 +44,7 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { alias: [ { find: '@', replacement: `${resolve('src')}/` }, { find: 'node-fetch', replacement: 'isomorphic-fetch' }, - { find: /^vue$/, replacement: isSsrBuild ? 'vue' : 'vue/dist/vue.esm-bundler.js' }, + { find: /^vue$/, replacement: isSsrBuild ? 'vue' : 'vue/dist/vue.runtime.esm-bundler.js' }, { find: /^pinia$/, replacement: 'pinia/dist/pinia.mjs' }, ], }, @@ -49,11 +52,19 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { 'process.env.NODE_ENV': mode === 'production' || isSsrBuild ? '"production"' : '"development"', __INTLIFY_PROD_DEVTOOLS__: 'false', }, + css: { + preprocessorOptions: { + sass: { + api: 'modern' + } + }, + preprocessorMaxWorkers: true, + }, build: { - sourcemap: mode === 'development', + sourcemap: true, modulePreload: false, cssCodeSplit: false, - minify: false, + minify: true, rollupOptions: { output: isSsrBuild ? { inlineDynamicImports: true } : { // TODO: these options currently cause a request cascade @@ -69,15 +80,22 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { }, }, }, + esbuild: { + lineLimit: 1000, + }, plugins: [ // https://github.com/unplugin/unplugin-auto-import AutoImport({ + include: [/\.[tj]sx?$/, /\.vue$/, /\.vue\?vue/, /\.md$/], dirs: [ './src/composables/**', './src/stores/**', './src/utils/**', ], imports: [ + 'vue', + 'vue-router', + 'pinia', { '@vuetify/one': [ 'createOne', @@ -90,16 +108,10 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { 'useProductsStore', ], 'lodash-es': ['camelCase', 'kebabCase', 'upperFirst'], - pinia: ['defineStore', 'storeToRefs'], - vue: [ - 'camelize', 'computed', 'h', 'mergeProps', 'nextTick', - 'onBeforeMount', 'onBeforeUnmount', 'onMounted', 'onScopeDispose', 'onServerPrefetch', - 'ref', 'shallowRef', 'useAttrs', 'watch', 'watchEffect' - ], + vue: ['camelize', 'mergeProps'], vuetify: ['useDate', 'useDisplay', 'useGoTo', 'useRtl', 'useTheme'], 'vue-gtag-next': ['useGtag'], 'vue-i18n': ['useI18n'], - 'vue-router': ['onBeforeRouteLeave', 'onBeforeRouteUpdate', 'useRoute', 'useRouter'], } ], vueTemplate: true, @@ -120,7 +132,9 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { // https://github.com/antfu/unplugin-vue-components Components({ directoryAsNamespace: true, - include: [/\.vue$/, /\.vue\?vue/, /\.md$/], + include: [/\.vue$/, /\.vue\?vue/, /\.md$/, /\.md\?vue/], + exclude: [], + excludeNames: ['AppMarkdown'], }), // https://github.com/JohnCampionJr/vite-plugin-vue-layouts @@ -133,10 +147,11 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { // https://github.com/antfu/vite-plugin-md Markdown({ - wrapperComponent: 'unwrap-markdown', wrapperClasses: '', - headEnabled: true, + exposeFrontmatter: true, + exposeExcerpt: false, markdownItSetup: configureMarkdown, + builders: [frontmatterBuilder()] }), // https://github.com/hannoeru/vite-plugin-pages @@ -144,7 +159,6 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { extensions: ['vue', 'md'], dirs: [ { dir: 'src/pages', baseRoute: '' }, - { dir: 'node_modules/.cache/api-pages', baseRoute: '' }, ], extendRoute (route) { let [locale, category, ...rest] = route.path.split('/').slice(1) @@ -152,10 +166,7 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { const idx = route.component.toLowerCase().indexOf(locale) locale = ~idx ? route.component.slice(idx, idx + locale.length) : locale - const meta = { - layout: 'default', - ...parseMeta(route.component, locale), - } + const meta = getRouteMeta(route.component, locale) if (meta.disabled) { return { disabled: true } @@ -164,18 +175,26 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { return { ...route, path: '/' + [locale, category, ...rest].filter(Boolean).join('/') + '/', - // name: [`${category ?? meta.layout}`, ...rest].join('-'), meta: { ...meta, category, - page: rest.join('-'), locale, }, } }, onRoutesGenerated (routes) { allRoutes = routes.filter(route => !route.disabled) - return allRoutes + return allRoutes.map(route => ({ + ...route, + meta: JSON.parse(JSON.stringify({ // remove undefined + category: route.meta.category, + emphasized: route.meta.emphasized, + layout: route.meta.layout, + locale: route.meta.locale, + nav: route.meta.nav, + title: route.meta.title, + })) + })) }, importMode (filepath) { return [ @@ -230,12 +249,20 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { const options = /( @@ -19,4 +19,4 @@ meta: - + diff --git a/packages/docs/vite.config.mts b/packages/docs/vite.config.mts index 0d777aa0d4d..2936ac6687a 100644 --- a/packages/docs/vite.config.mts +++ b/packages/docs/vite.config.mts @@ -22,7 +22,7 @@ import Api from './build/api-plugin' import { Examples } from './build/examples-plugin' import { genAppMetaInfo } from './src/utils/metadata' import { MdiJs } from './build/mdi-js' -import { frontmatterBuilder, getRouteMeta } from './build/frontmatterMeta' +import { frontmatterBuilder, getRouteMeta, scriptFixer } from './build/markdownBuilders' const resolve = (file: string) => fileURLToPath(new URL(file, import.meta.url)) @@ -151,7 +151,7 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { exposeFrontmatter: true, exposeExcerpt: false, markdownItSetup: configureMarkdown, - builders: [frontmatterBuilder()] + builders: [frontmatterBuilder(), scriptFixer()] }), // https://github.com/hannoeru/vite-plugin-pages From 4c1f4b60f70e70cc5c7b82ad0ff4e222174b679b Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 15 Aug 2024 19:27:10 +1000 Subject: [PATCH 037/190] chore: use sass-embedded --- package.json | 1 + packages/docs/vite.config.mts | 3 +- packages/vuetify/vite.config.mjs | 9 +- pnpm-lock.yaml | 320 ++++++++++++++++++++++++++----- 4 files changed, 278 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index 3bde8511c65..ead12e22124 100755 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "moment": "^2.30.1", "rimraf": "^5.0.5", "sass": "^1.77.8", + "sass-embedded": "^1.77.8", "semver": "^7.6.0", "shelljs": "^0.8.5", "stringify-object": "^5.0.0", diff --git a/packages/docs/vite.config.mts b/packages/docs/vite.config.mts index 2936ac6687a..adbba51ff9c 100644 --- a/packages/docs/vite.config.mts +++ b/packages/docs/vite.config.mts @@ -55,10 +55,9 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { css: { preprocessorOptions: { sass: { - api: 'modern' + api: 'modern-compiler' } }, - preprocessorMaxWorkers: true, }, build: { sourcemap: true, diff --git a/packages/vuetify/vite.config.mjs b/packages/vuetify/vite.config.mjs index 437ecfb2687..1137403c27f 100644 --- a/packages/vuetify/vite.config.mjs +++ b/packages/vuetify/vite.config.mjs @@ -78,6 +78,13 @@ export default defineConfig(({ mode }) => { }, build: { minify: false, - } + }, + css: { + preprocessorOptions: { + sass: { + api: 'modern-compiler' + } + }, + }, } }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27b3e96f23d..dcfe287a0f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -150,6 +150,9 @@ importers: sass: specifier: ^1.77.8 version: 1.77.8 + sass-embedded: + specifier: ^1.77.8 + version: 1.77.8 semver: specifier: ^7.6.0 version: 7.6.0 @@ -167,10 +170,10 @@ importers: version: 2.0.1 vite-plugin-inspect: specifier: ^0.8.3 - version: 0.8.3(rollup@4.14.1)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 0.8.3(rollup@4.14.1)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-warmup: specifier: ^0.1.0 - version: 0.1.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 0.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vue: specifier: ^3.4.27 version: 3.4.27(typescript@5.5.4) @@ -328,10 +331,10 @@ importers: version: 1.26.3 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 1.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) '@vitejs/plugin-vue': specifier: ^5.0.4 - version: 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + version: 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) '@vue/compiler-sfc': specifier: ^3.4.27 version: 3.4.27 @@ -340,7 +343,7 @@ importers: version: link:../api-generator '@yankeeinlondon/builder-api': specifier: ^1.4.1 - version: 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) ajv: specifier: ^8.12.0 version: 8.12.0 @@ -403,28 +406,28 @@ importers: version: 0.17.5(rollup@4.14.1) unplugin-fonts: specifier: 1.0.3 - version: 1.0.3(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 1.0.3(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) unplugin-vue-components: specifier: ^0.27.4 version: 0.27.4(@babel/parser@7.25.3)(rollup@4.14.1)(vue@3.4.27(typescript@5.5.4)) vite: specifier: ^5.4.0 - version: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + version: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vite-plugin-md: specifier: ^0.21.5 - version: 0.21.5(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 0.21.5(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-pages: specifier: ^0.32.1 - version: 0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-pwa: specifier: ^0.17.4 - version: 0.17.5(@types/babel__core@7.1.19)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + version: 0.17.5(@types/babel__core@7.1.19)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-vue-layouts: specifier: ^0.11.0 - version: 0.11.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) + version: 0.11.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) vite-plugin-vuetify: specifier: ^2.0.4 - version: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify) + version: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify) vue-tsc: specifier: ^2.0.29 version: 2.0.29(typescript@5.5.4) @@ -484,10 +487,10 @@ importers: version: 0.1.11 '@vitejs/plugin-vue': specifier: ^5.0.4 - version: 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + version: 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) '@vitejs/plugin-vue-jsx': specifier: ^3.1.0 - version: 3.1.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + version: 3.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) '@vue/babel-plugin-jsx': specifier: ^1.2.2 version: 1.2.2(@babel/core@7.25.2) @@ -592,10 +595,10 @@ importers: version: 2.0.1 vite: specifier: ^5.4.0 - version: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + version: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vite-ssr: specifier: ^0.17.1 - version: 0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) + version: 0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) vue-i18n: specifier: ^9.7.1 version: 9.11.1(vue@3.4.27(typescript@5.5.4)) @@ -1288,6 +1291,9 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@bufbuild/protobuf@1.10.0': + resolution: {integrity: sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==} + '@cosmicjs/sdk@1.0.11': resolution: {integrity: sha512-Zm53TsyAGg2ytsJaBf06NcFA5FVG+tc39ZAYQgANi3uLkojnZFWGCIkwHVAn7CYVBac8dPF4tt0U6pYWNAA+Pg==} @@ -3317,6 +3323,9 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} @@ -7331,6 +7340,125 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass-embedded-android-arm64@1.77.8: + resolution: {integrity: sha512-EmWHLbEx0Zo/f/lTFzMeH2Du+/I4RmSRlEnERSUKQWVp3aBSO04QDvdxfFezgQ+2Yt/ub9WMqBpma9P/8MPsLg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + hasBin: true + + sass-embedded-android-arm@1.77.8: + resolution: {integrity: sha512-GpGL7xZ7V1XpFbnflib/NWbM0euRzineK0iwoo31/ntWKAXGj03iHhGzkSiOwWSFcXgsJJi3eRA5BTmBvK5Q+w==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + hasBin: true + + sass-embedded-android-ia32@1.77.8: + resolution: {integrity: sha512-+GjfJ3lDezPi4dUUyjQBxlNKXNa+XVWsExtGvVNkv1uKyaOxULJhubVo2G6QTJJU0esJdfeXf5Ca5/J0ph7+7w==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [android] + hasBin: true + + sass-embedded-android-x64@1.77.8: + resolution: {integrity: sha512-YZbFDzGe5NhaMCygShqkeCWtzjhkWxGVunc7ULR97wmxYPQLPeVyx7XFQZc84Aj0lKAJBJS4qRZeqphMqZEJsQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + hasBin: true + + sass-embedded-darwin-arm64@1.77.8: + resolution: {integrity: sha512-aifgeVRNE+i43toIkDFFJc/aPLMo0PJ5s5hKb52U+oNdiJE36n65n2L8F/8z3zZRvCa6eYtFY2b7f1QXR3B0LA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + hasBin: true + + sass-embedded-darwin-x64@1.77.8: + resolution: {integrity: sha512-/VWZQtcWIOek60Zj6Sxk6HebXA1Qyyt3sD8o5qwbTgZnKitB1iEBuNunyGoAgMNeUz2PRd6rVki6hvbas9hQ6w==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + hasBin: true + + sass-embedded-linux-arm64@1.77.8: + resolution: {integrity: sha512-6iIOIZtBFa2YfMsHqOb3qake3C9d/zlKxjooKKnTSo+6g6z+CLTzMXe1bOfayb7yxeenElmFoK1k54kWD/40+g==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + hasBin: true + + sass-embedded-linux-arm@1.77.8: + resolution: {integrity: sha512-2edZMB6jf0whx3T0zlgH+p131kOEmWp+I4wnKj7ZMUeokiY4Up05d10hSvb0Q63lOrSjFAWu6P5/pcYUUx8arQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + hasBin: true + + sass-embedded-linux-ia32@1.77.8: + resolution: {integrity: sha512-63GsFFHWN5yRLTWiSef32TM/XmjhCBx1DFhoqxmj+Yc6L9Z1h0lDHjjwdG6Sp5XTz5EmsaFKjpDgnQTP9hJX3Q==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + hasBin: true + + sass-embedded-linux-musl-arm64@1.77.8: + resolution: {integrity: sha512-j8cgQxNWecYK+aH8ESFsyam/Q6G+9gg8eJegiRVpA9x8yk3ykfHC7UdQWwUcF22ZcuY4zegrjJx8k+thsgsOVA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-musl-arm@1.77.8: + resolution: {integrity: sha512-nFkhSl3uu9btubm+JBW7uRglNVJ8W8dGfzVqh3fyQJKS1oyBC3vT3VOtfbT9YivXk28wXscSHpqXZwY7bUuopA==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-ia32@1.77.8: + resolution: {integrity: sha512-oWveMe+8TFlP8WBWPna/+Ec5TV0CE+PxEutyi0ltSruBds2zxRq9dPVOqrpPcDN9QUx50vNZC0Afgch0aQEd0g==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + + sass-embedded-linux-musl-x64@1.77.8: + resolution: {integrity: sha512-2NtRpMXHeFo9kaYxuZ+Ewwo39CE7BTS2JDfXkTjZTZqd8H+8KC53eBh516YQnn2oiqxSiKxm7a6pxbxGZGwXOQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-linux-x64@1.77.8: + resolution: {integrity: sha512-ND5qZLWUCpOn7LJfOf0gLSZUWhNIysY+7NZK1Ctq+pM6tpJky3JM5I1jSMplNxv5H3o8p80n0gSm+fcjsEFfjQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + hasBin: true + + sass-embedded-win32-arm64@1.77.8: + resolution: {integrity: sha512-7L8zT6xzEvTYj86MvUWnbkWYCNQP+74HvruLILmiPPE+TCgOjgdi750709BtppVJGGZSs40ZuN6mi/YQyGtwXg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + hasBin: true + + sass-embedded-win32-ia32@1.77.8: + resolution: {integrity: sha512-7Buh+4bP0WyYn6XPbthkIa3M2vtcR8QIsFVg3JElVlr+8Ng19jqe0t0SwggDgbMX6AdQZC+Wj4F1BprZSok42A==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [win32] + hasBin: true + + sass-embedded-win32-x64@1.77.8: + resolution: {integrity: sha512-rZmLIx4/LLQm+4GW39sRJW0MIlDqmyV0fkRzTmhFP5i/wVC7cuj8TUubPHw18rv2rkHFfBZKZJTCkPjCS5Z+SA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + hasBin: true + + sass-embedded@1.77.8: + resolution: {integrity: sha512-WGXA6jcaoBo5Uhw0HX/s6z/sl3zyYQ7ZOnLOJzqwpctFcFmU4L07zn51e2VSkXXFpQZFAdMZNqOGz/7h/fvcRA==} + engines: {node: '>=16.0.0'} + sass@1.77.8: resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==} engines: {node: '>=14.0.0'} @@ -8129,6 +8257,9 @@ packages: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + vee-validate@4.12.6: resolution: {integrity: sha512-EKM3YHy8t1miPh30d5X6xOrfG/Ctq0nbN4eMpCK7ezvI6T98/S66vswP+ihL4QqAK/k5KqreWOxof09+JG7N/A==} peerDependencies: @@ -9583,6 +9714,8 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@bufbuild/protobuf@1.10.0': {} + '@cosmicjs/sdk@1.0.11': dependencies: axios: 1.7.2 @@ -11338,23 +11471,23 @@ snapshots: unhead: 1.9.4 vue: 3.4.27(typescript@5.5.4) - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': dependencies: - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) - '@vitejs/plugin-vue-jsx@3.1.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': + '@vitejs/plugin-vue-jsx@3.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2) '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2) - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': + '@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': dependencies: - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) '@volar/language-core@2.4.0-alpha.18': @@ -11514,14 +11647,14 @@ snapshots: '@unhead/vue': 1.9.4(vue@3.4.27(typescript@5.5.4)) vue: 3.4.27(typescript@5.5.4) - '@yankeeinlondon/builder-api@1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))': + '@yankeeinlondon/builder-api@1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': dependencies: '@types/markdown-it': 12.2.3 '@yankeeinlondon/happy-wrapper': 2.10.1(encoding@0.1.13)(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3) fp-ts: 2.13.1 inferred-types: 0.37.6(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3) markdown-it: 13.0.2 - vite-plugin-md: 0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + vite-plugin-md: 0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) transitivePeerDependencies: - '@edge-runtime/vm' - '@vitejs/plugin-vue' @@ -12046,6 +12179,8 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-builder@0.2.0: {} + buffer-crc32@0.2.13: {} buffer-from@1.1.1: {} @@ -16904,6 +17039,84 @@ snapshots: safer-buffer@2.1.2: {} + sass-embedded-android-arm64@1.77.8: + optional: true + + sass-embedded-android-arm@1.77.8: + optional: true + + sass-embedded-android-ia32@1.77.8: + optional: true + + sass-embedded-android-x64@1.77.8: + optional: true + + sass-embedded-darwin-arm64@1.77.8: + optional: true + + sass-embedded-darwin-x64@1.77.8: + optional: true + + sass-embedded-linux-arm64@1.77.8: + optional: true + + sass-embedded-linux-arm@1.77.8: + optional: true + + sass-embedded-linux-ia32@1.77.8: + optional: true + + sass-embedded-linux-musl-arm64@1.77.8: + optional: true + + sass-embedded-linux-musl-arm@1.77.8: + optional: true + + sass-embedded-linux-musl-ia32@1.77.8: + optional: true + + sass-embedded-linux-musl-x64@1.77.8: + optional: true + + sass-embedded-linux-x64@1.77.8: + optional: true + + sass-embedded-win32-arm64@1.77.8: + optional: true + + sass-embedded-win32-ia32@1.77.8: + optional: true + + sass-embedded-win32-x64@1.77.8: + optional: true + + sass-embedded@1.77.8: + dependencies: + '@bufbuild/protobuf': 1.10.0 + buffer-builder: 0.2.0 + immutable: 4.0.0 + rxjs: 7.8.1 + supports-color: 8.1.1 + varint: 6.0.0 + optionalDependencies: + sass-embedded-android-arm: 1.77.8 + sass-embedded-android-arm64: 1.77.8 + sass-embedded-android-ia32: 1.77.8 + sass-embedded-android-x64: 1.77.8 + sass-embedded-darwin-arm64: 1.77.8 + sass-embedded-darwin-x64: 1.77.8 + sass-embedded-linux-arm: 1.77.8 + sass-embedded-linux-arm64: 1.77.8 + sass-embedded-linux-ia32: 1.77.8 + sass-embedded-linux-musl-arm: 1.77.8 + sass-embedded-linux-musl-arm64: 1.77.8 + sass-embedded-linux-musl-ia32: 1.77.8 + sass-embedded-linux-musl-x64: 1.77.8 + sass-embedded-linux-x64: 1.77.8 + sass-embedded-win32-arm64: 1.77.8 + sass-embedded-win32-ia32: 1.77.8 + sass-embedded-win32-x64: 1.77.8 + sass@1.77.8: dependencies: chokidar: 3.6.0 @@ -17633,11 +17846,11 @@ snapshots: transitivePeerDependencies: - rollup - unplugin-fonts@1.0.3(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)): + unplugin-fonts@1.0.3(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: fast-glob: 3.3.2 unplugin: 1.12.1 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) unplugin-vue-components@0.27.4(@babel/parser@7.25.3)(rollup@3.29.4)(vue@3.4.27(typescript@5.5.4)): dependencies: @@ -17734,6 +17947,8 @@ snapshots: validate-npm-package-name@5.0.1: {} + varint@6.0.0: {} + vee-validate@4.12.6(vue@3.4.27(typescript@5.5.4)): dependencies: '@vue/devtools-api': 6.5.1 @@ -17746,7 +17961,7 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.4.0 - vite-plugin-inspect@0.8.3(rollup@4.14.1)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-inspect@0.8.3(rollup@4.14.1)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.1.0(rollup@4.14.1) @@ -17757,19 +17972,19 @@ snapshots: perfect-debounce: 1.0.0 picocolors: 1.0.1 sirv: 2.0.4 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) transitivePeerDependencies: - rollup - supports-color - vite-plugin-md@0.21.5(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-md@0.21.5(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: - '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) '@yankeeinlondon/gray-matter': 6.1.1(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3) '@yankeeinlondon/happy-wrapper': 2.10.1(encoding@0.1.13)(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3) markdown-it: 13.0.2 source-map-js: 1.2.0 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) transitivePeerDependencies: - '@edge-runtime/vm' - '@vitest/browser' @@ -17785,15 +18000,15 @@ snapshots: - supports-color - terser - vite-plugin-md@0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-md@0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: - '@vitejs/plugin-vue': 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) - '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)) + '@vitejs/plugin-vue': 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) '@yankeeinlondon/gray-matter': 6.1.1(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3) '@yankeeinlondon/happy-wrapper': 2.10.1(encoding@0.1.13)(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3) markdown-it: 13.0.2 source-map-js: 1.2.0 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) transitivePeerDependencies: - '@edge-runtime/vm' - '@vitest/browser' @@ -17809,7 +18024,7 @@ snapshots: - supports-color - terser - vite-plugin-pages@0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-pages@0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: '@types/debug': 4.1.12 debug: 4.3.6(supports-color@8.1.1) @@ -17819,73 +18034,73 @@ snapshots: json5: 2.2.3 local-pkg: 0.5.0 picocolors: 1.0.1 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) yaml: 2.4.1 optionalDependencies: '@vue/compiler-sfc': 3.4.27 transitivePeerDependencies: - supports-color - vite-plugin-pwa@0.17.5(@types/babel__core@7.1.19)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-pwa@0.17.5(@types/babel__core@7.1.19)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: debug: 4.3.6(supports-color@8.1.1) fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) workbox-build: 7.0.0(@types/babel__core@7.1.19) workbox-window: 7.0.0 transitivePeerDependencies: - '@types/babel__core' - supports-color - vite-plugin-vue-layouts@0.11.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): + vite-plugin-vue-layouts@0.11.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): dependencies: debug: 4.3.6(supports-color@8.1.1) fast-glob: 3.3.2 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) vue-router: 4.3.0(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color - vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14): + vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14): dependencies: '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4))) debug: 4.3.6(supports-color@8.1.1) upath: 2.0.1 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) vuetify: 3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color optional: true - vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify): + vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify): dependencies: '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify) debug: 4.3.6(supports-color@8.1.1) upath: 2.0.1 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) vuetify: link:packages/vuetify transitivePeerDependencies: - supports-color - vite-plugin-warmup@0.1.0(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-warmup@0.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: fast-glob: 3.3.2 - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) - vite-ssr@0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): + vite-ssr@0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): dependencies: '@rollup/plugin-replace': 3.0.0(rollup@3.29.4) '@vue/server-renderer': 3.4.27(vue@3.4.27(typescript@5.5.4)) chalk: 4.1.2 connect: 3.7.0 node-fetch: 2.6.7(encoding@0.1.13) - vite: 5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) optionalDependencies: - '@vitejs/plugin-vue': 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + '@vitejs/plugin-vue': 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) '@vueuse/head': 1.3.1(vue@3.4.27(typescript@5.5.4)) vue: 3.4.27(typescript@5.5.4) vue-router: 4.3.0(vue@3.4.27(typescript@5.5.4)) @@ -17905,7 +18120,7 @@ snapshots: sass: 1.77.8 terser: 5.31.3 - vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3): + vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3): dependencies: esbuild: 0.21.5 postcss: 8.4.40 @@ -17914,6 +18129,7 @@ snapshots: '@types/node': 20.12.7 fsevents: 2.3.3 sass: 1.77.8 + sass-embedded: 1.77.8 terser: 5.31.3 vitest@0.25.8(happy-dom@8.9.0(encoding@0.1.13))(jsdom@19.0.0)(sass@1.77.8)(terser@5.31.3): @@ -18021,7 +18237,7 @@ snapshots: vue: 3.4.27(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 - vite-plugin-vuetify: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14) + vite-plugin-vuetify: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14) vue-i18n: 9.11.1(vue@3.4.27(typescript@5.5.4)) w3c-hr-time@1.0.2: From ff80220c867f01e6baca4ed8da24d8f9e054785d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Thu, 15 Aug 2024 11:33:59 +0200 Subject: [PATCH 038/190] chore: fix missing labs components css on Windows (#20336) --- packages/vuetify/build/rollup.config.mjs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/vuetify/build/rollup.config.mjs b/packages/vuetify/build/rollup.config.mjs index 36b6355f44e..9903704e960 100644 --- a/packages/vuetify/build/rollup.config.mjs +++ b/packages/vuetify/build/rollup.config.mjs @@ -220,10 +220,7 @@ export default [ }) // Individual CSS files - styleNodes = styleNodes.filter(node => { - return node.id.startsWith(labsDir) - } - ); + styleNodes = styleNodes.filter(node => path.normalize(node.id).startsWith(labsDir)); for (const { id, content } of styleNodes) { const relativePath = path.relative(srcDir, id) const out = path.parse(path.join(libDir, relativePath)) From 76af55c9d0598922de9a6e602b1b6256c4e6097e Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 15 Aug 2024 19:34:34 +1000 Subject: [PATCH 039/190] chore(release): publish v3.6.15 --- lerna.json | 2 +- packages/api-generator/package.json | 2 +- packages/docs/package.json | 2 +- packages/vuetify/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lerna.json b/lerna.json index adccaf732bf..b160b1693dc 100644 --- a/lerna.json +++ b/lerna.json @@ -13,5 +13,5 @@ } }, "npmClient": "pnpm", - "version": "3.6.14" + "version": "3.6.15" } \ No newline at end of file diff --git a/packages/api-generator/package.json b/packages/api-generator/package.json index 97a2dba0bf0..efd7b2b3ea3 100755 --- a/packages/api-generator/package.json +++ b/packages/api-generator/package.json @@ -1,6 +1,6 @@ { "name": "@vuetify/api-generator", - "version": "3.6.14", + "version": "3.6.15", "private": true, "description": "", "scripts": { diff --git a/packages/docs/package.json b/packages/docs/package.json index 1a70685d371..bf2ddf18468 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -3,7 +3,7 @@ "description": "A Vue.js project", "private": true, "author": "John Leider ", - "version": "3.6.14", + "version": "3.6.15", "repository": { "type": "git", "url": "git+https://github.com/vuetifyjs/vuetify.git", diff --git a/packages/vuetify/package.json b/packages/vuetify/package.json index 1dca03296f2..73759fe8b7d 100755 --- a/packages/vuetify/package.json +++ b/packages/vuetify/package.json @@ -1,7 +1,7 @@ { "name": "vuetify", "description": "Vue Material Component Framework", - "version": "3.6.14", + "version": "3.6.15", "author": { "name": "John Leider", "email": "john@vuetifyjs.com" From 08c3d4f62e7e9715dc7f256d794cd4682b7f7c52 Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 15 Aug 2024 21:48:55 +1000 Subject: [PATCH 040/190] Revert "fix(layout): use suspense to delay render of layout items (#15229)" This reverts commit 727bc1adba18d57b4d690b75c05db789539ba260. fixes #19800 --- packages/vuetify/src/components/VApp/VApp.tsx | 7 +-- .../src/components/VAppBar/VAppBar.tsx | 10 ++-- .../VBottomNavigation/VBottomNavigation.tsx | 4 +- .../src/components/VFooter/VFooter.tsx | 4 +- .../src/components/VLayout/VLayout.tsx | 7 +-- .../src/components/VLayout/VLayoutItem.tsx | 10 ++-- .../vuetify/src/components/VMain/VMain.tsx | 4 +- .../VNavigationDrawer/VNavigationDrawer.tsx | 6 ++- packages/vuetify/src/composables/layout.ts | 51 +++++++++++++------ 9 files changed, 57 insertions(+), 46 deletions(-) diff --git a/packages/vuetify/src/components/VApp/VApp.tsx b/packages/vuetify/src/components/VApp/VApp.tsx index 063152fc1f7..fdbb9870bc9 100644 --- a/packages/vuetify/src/components/VApp/VApp.tsx +++ b/packages/vuetify/src/components/VApp/VApp.tsx @@ -8,7 +8,6 @@ import { useRtl } from '@/composables/locale' import { makeThemeProps, provideTheme } from '@/composables/theme' // Utilities -import { Suspense } from 'vue' import { genericComponent, propsFactory, useRender } from '@/util' export const makeVAppProps = propsFactory({ @@ -42,11 +41,7 @@ export const VApp = genericComponent()({ ]} >
- - <> - { slots.default?.() } - - + { slots.default?.() }
)) diff --git a/packages/vuetify/src/components/VAppBar/VAppBar.tsx b/packages/vuetify/src/components/VAppBar/VAppBar.tsx index 87eb94ddb1e..905e180c1e9 100644 --- a/packages/vuetify/src/components/VAppBar/VAppBar.tsx +++ b/packages/vuetify/src/components/VAppBar/VAppBar.tsx @@ -106,8 +106,10 @@ export const VAppBar = genericComponent()({ : undefined )) const height = computed(() => { - const height = Number(vToolbarRef.value?.contentHeight ?? props.height) - const extensionHeight = Number(vToolbarRef.value?.extensionHeight ?? 0) + if (scrollBehavior.value.hide && scrollBehavior.value.inverted) return 0 + + const height = vToolbarRef.value?.contentHeight ?? 0 + const extensionHeight = vToolbarRef.value?.extensionHeight ?? 0 if (!canHide.value) return (height + extensionHeight) @@ -131,7 +133,7 @@ export const VAppBar = genericComponent()({ }) const { ssrBootStyles } = useSsrBoot() - const { layoutItemStyles, layoutIsReady } = useLayoutItem({ + const { layoutItemStyles } = useLayoutItem({ id: props.name, order: computed(() => parseInt(props.order, 10)), position: toRef(props, 'location'), @@ -171,7 +173,7 @@ export const VAppBar = genericComponent()({ ) }) - return layoutIsReady + return {} }, }) diff --git a/packages/vuetify/src/components/VBottomNavigation/VBottomNavigation.tsx b/packages/vuetify/src/components/VBottomNavigation/VBottomNavigation.tsx index bb05f006109..d4b24a860f1 100644 --- a/packages/vuetify/src/components/VBottomNavigation/VBottomNavigation.tsx +++ b/packages/vuetify/src/components/VBottomNavigation/VBottomNavigation.tsx @@ -85,7 +85,7 @@ export const VBottomNavigation = genericComponent( (props.density === 'compact' ? 16 : 0) )) const isActive = useProxiedModel(props, 'active', props.active) - const { layoutItemStyles, layoutIsReady } = useLayoutItem({ + const { layoutItemStyles } = useLayoutItem({ id: props.name, order: computed(() => parseInt(props.order, 10)), position: computed(() => 'bottom'), @@ -144,7 +144,7 @@ export const VBottomNavigation = genericComponent( ) }) - return layoutIsReady + return {} }, }) diff --git a/packages/vuetify/src/components/VFooter/VFooter.tsx b/packages/vuetify/src/components/VFooter/VFooter.tsx index 3fdafd49a8f..2da403e1268 100644 --- a/packages/vuetify/src/components/VFooter/VFooter.tsx +++ b/packages/vuetify/src/components/VFooter/VFooter.tsx @@ -41,7 +41,6 @@ export const VFooter = genericComponent()({ setup (props, { slots }) { const layoutItemStyles = ref() - const layoutIsReady = shallowRef() const { themeClasses } = provideTheme(props) const { backgroundColorClasses, backgroundColorStyles } = useBackgroundColor(toRef(props, 'color')) @@ -69,7 +68,6 @@ export const VFooter = genericComponent()({ watchEffect(() => { layoutItemStyles.value = layout.layoutItemStyles.value - layoutIsReady.value = layout.layoutIsReady }) }) @@ -96,7 +94,7 @@ export const VFooter = genericComponent()({ /> )) - return props.app ? layoutIsReady.value : {} + return {} }, }) diff --git a/packages/vuetify/src/components/VLayout/VLayout.tsx b/packages/vuetify/src/components/VLayout/VLayout.tsx index 065882a3e30..3b2f6085ad8 100644 --- a/packages/vuetify/src/components/VLayout/VLayout.tsx +++ b/packages/vuetify/src/components/VLayout/VLayout.tsx @@ -7,7 +7,6 @@ import { makeDimensionProps, useDimension } from '@/composables/dimensions' import { createLayout, makeLayoutProps } from '@/composables/layout' // Utilities -import { Suspense } from 'vue' import { genericComponent, propsFactory, useRender } from '@/util' export const makeVLayoutProps = propsFactory({ @@ -38,11 +37,7 @@ export const VLayout = genericComponent()({ props.style, ]} > - - <> - { slots.default?.() } - - + { slots.default?.() } )) diff --git a/packages/vuetify/src/components/VLayout/VLayoutItem.tsx b/packages/vuetify/src/components/VLayout/VLayoutItem.tsx index f7f9af525b0..b42c9379dca 100644 --- a/packages/vuetify/src/components/VLayout/VLayoutItem.tsx +++ b/packages/vuetify/src/components/VLayout/VLayoutItem.tsx @@ -7,7 +7,7 @@ import { makeLayoutItemProps, useLayoutItem } from '@/composables/layout' // Utilities import { computed, toRef } from 'vue' -import { genericComponent, propsFactory, useRender } from '@/util' +import { genericComponent, propsFactory } from '@/util' // Types import type { PropType } from 'vue' @@ -33,7 +33,7 @@ export const VLayoutItem = genericComponent()({ props: makeVLayoutItemProps(), setup (props, { slots }) { - const { layoutItemStyles, layoutIsReady } = useLayoutItem({ + const { layoutItemStyles } = useLayoutItem({ id: props.name, order: computed(() => parseInt(props.order, 10)), position: toRef(props, 'position'), @@ -43,7 +43,7 @@ export const VLayoutItem = genericComponent()({ absolute: toRef(props, 'absolute'), }) - useRender(() => ( + return () => (
{ slots.default?.() }
- )) - - return layoutIsReady + ) }, }) diff --git a/packages/vuetify/src/components/VMain/VMain.tsx b/packages/vuetify/src/components/VMain/VMain.tsx index b365cc6b3fe..86a0a05ebd9 100644 --- a/packages/vuetify/src/components/VMain/VMain.tsx +++ b/packages/vuetify/src/components/VMain/VMain.tsx @@ -26,7 +26,7 @@ export const VMain = genericComponent()({ setup (props, { slots }) { const { dimensionStyles } = useDimension(props) - const { mainStyles, layoutIsReady } = useLayout() + const { mainStyles } = useLayout() const { ssrBootStyles } = useSsrBoot() useRender(() => ( @@ -54,7 +54,7 @@ export const VMain = genericComponent()({
)) - return layoutIsReady + return {} }, }) diff --git a/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx b/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx index ef077b7c8da..83207b87ec4 100644 --- a/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx +++ b/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx @@ -178,7 +178,7 @@ export const VNavigationDrawer = genericComponent()({ return isDragging.value ? size * dragProgress.value : size }) const elementSize = computed(() => ['top', 'bottom'].includes(props.location) ? 0 : width.value) - const { layoutItemStyles, layoutItemScrimStyles, layoutIsReady } = useLayoutItem({ + const { layoutItemStyles, layoutItemScrimStyles } = useLayoutItem({ id: props.name, order: computed(() => parseInt(props.order, 10)), position: location, @@ -314,7 +314,9 @@ export const VNavigationDrawer = genericComponent()({ ) }) - return layoutIsReady.then(() => ({ isStuck })) + return { + isStuck, + } }, }) diff --git a/packages/vuetify/src/composables/layout.ts b/packages/vuetify/src/composables/layout.ts index b979daab7f6..e96b8e36fc8 100644 --- a/packages/vuetify/src/composables/layout.ts +++ b/packages/vuetify/src/composables/layout.ts @@ -5,16 +5,16 @@ import { useResizeObserver } from '@/composables/resizeObserver' import { computed, inject, - nextTick, onActivated, onBeforeUnmount, onDeactivated, + onMounted, provide, reactive, ref, shallowRef, } from 'vue' -import { convertToUnit, eagerComputed, findChildrenWithProvide, getCurrentInstance, getUid, propsFactory } from '@/util' +import { convertToUnit, findChildrenWithProvide, getCurrentInstance, getUid, propsFactory } from '@/util' // Types import type { ComponentInternalInstance, CSSProperties, InjectionKey, Prop, Ref } from 'vue' @@ -59,7 +59,6 @@ interface LayoutProvide { items: Ref layoutRect: Ref rootZIndex: Ref - layoutIsReady: Promise } export const VuetifyLayoutKey: InjectionKey = Symbol.for('vuetify:layout') @@ -92,10 +91,7 @@ export function useLayout () { if (!layout) throw new Error('[Vuetify] Could not find injected layout') - const layoutIsReady = nextTick() - return { - layoutIsReady, getLayoutItem: layout.getLayoutItem, mainRect: layout.mainRect, mainStyles: layout.mainStyles, @@ -126,8 +122,6 @@ export function useLayoutItem (options: { onDeactivated(() => isKeptAlive.value = true) onActivated(() => isKeptAlive.value = false) - const layoutIsReady = nextTick() - const { layoutItemStyles, layoutItemScrimStyles, @@ -139,7 +133,7 @@ export function useLayoutItem (options: { onBeforeUnmount(() => layout.unregister(id)) - return { layoutItemStyles, layoutRect: layout.layoutRect, layoutItemScrimStyles, layoutIsReady } + return { layoutItemStyles, layoutRect: layout.layoutRect, layoutItemScrimStyles } } const generateLayers = ( @@ -183,7 +177,28 @@ export function createLayout (props: { overlaps?: string[], fullHeight?: boolean const disabledTransitions = reactive(new Map>()) const { resizeRef, contentRect: layoutRect } = useResizeObserver() - const layers = eagerComputed(() => { + const computedOverlaps = computed(() => { + const map = new Map() + const overlaps = props.overlaps ?? [] + for (const overlap of overlaps.filter(item => item.includes(':'))) { + const [top, bottom] = overlap.split(':') + if (!registered.value.includes(top) || !registered.value.includes(bottom)) continue + + const topPosition = positions.get(top) + const bottomPosition = positions.get(bottom) + const topAmount = layoutSizes.get(top) + const bottomAmount = layoutSizes.get(bottom) + + if (!topPosition || !bottomPosition || !topAmount || !bottomAmount) continue + + map.set(bottom, { position: topPosition.value, amount: parseInt(topAmount.value, 10) }) + map.set(top, { position: bottomPosition.value, amount: -parseInt(bottomAmount.value, 10) }) + } + + return map + }) + + const layers = computed(() => { const uniquePriorities = [...new Set([...priorities.values()].map(p => p.value))].sort((a, b) => a - b) const layout = [] for (const p of uniquePriorities) { @@ -211,7 +226,7 @@ export function createLayout (props: { overlaps?: string[], fullHeight?: boolean } }) - const items = eagerComputed(() => { + const items = computed(() => { return layers.value.slice(1).map(({ id }, index) => { const { layer } = layers.value[index] const size = layoutSizes.get(id) @@ -232,7 +247,10 @@ export function createLayout (props: { overlaps?: string[], fullHeight?: boolean const rootVm = getCurrentInstance('createLayout') - const layoutIsReady = nextTick() + const isMounted = shallowRef(false) + onMounted(() => { + isMounted.value = true + }) provide(VuetifyLayoutKey, { register: ( @@ -278,12 +296,17 @@ export function createLayout (props: { overlaps?: string[], fullHeight?: boolean ...(transitionsEnabled.value ? undefined : { transition: 'none' }), } as const - if (index.value < 0) throw new Error(`Layout item "${id}" is missing`) + if (!isMounted.value) return styles const item = items.value[index.value] if (!item) throw new Error(`[Vuetify] Could not find layout item "${id}"`) + const overlap = computedOverlaps.value.get(id) + if (overlap) { + item[overlap.position] += overlap.amount + } + return { ...styles, height: @@ -321,7 +344,6 @@ export function createLayout (props: { overlaps?: string[], fullHeight?: boolean items, layoutRect, rootZIndex, - layoutIsReady, }) const layoutClasses = computed(() => [ @@ -341,7 +363,6 @@ export function createLayout (props: { overlaps?: string[], fullHeight?: boolean getLayoutItem, items, layoutRect, - layoutIsReady, layoutRef: resizeRef, } } From 4077948d64da983f938795c051e1327cf3aaf23c Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 15 Aug 2024 21:53:07 +1000 Subject: [PATCH 041/190] refactor(VSpeedDial): fix type error --- .../vuetify/src/components/VSpeedDial/VSpeedDial.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/vuetify/src/components/VSpeedDial/VSpeedDial.tsx b/packages/vuetify/src/components/VSpeedDial/VSpeedDial.tsx index c972636e12c..b88fa58cf42 100644 --- a/packages/vuetify/src/components/VSpeedDial/VSpeedDial.tsx +++ b/packages/vuetify/src/components/VSpeedDial/VSpeedDial.tsx @@ -15,7 +15,6 @@ import { computed, ref } from 'vue' import { genericComponent, propsFactory, useRender } from '@/util' // Types -import type { ComputedRef } from 'vue' import type { OverlaySlots } from '@/components/VOverlay/VOverlay' import type { Anchor } from '@/util' @@ -45,11 +44,11 @@ export const VSpeedDial = genericComponent()({ const menuRef = ref() - const location = computed(() => { - const [y, x = 'center'] = props.location.split(' ') + const location = computed(() => { + const [y, x = 'center'] = props.location?.split(' ') ?? [] - return `${y} ${x}` - }) as ComputedRef + return `${y} ${x}` as Anchor + }) const locationClasses = computed(() => ({ [`v-speed-dial__content--${location.value.replace(' ', '-')}`]: true, From 046da8d52fc6c99933b050b627e37647480a9eea Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 15 Aug 2024 22:26:07 +1000 Subject: [PATCH 042/190] docs: update emphasized pages --- packages/docs/src/pages/en/components/application.md | 1 - packages/docs/src/pages/en/components/avatars.md | 1 + packages/docs/src/pages/en/components/buttons.md | 1 + packages/docs/src/pages/en/components/calendars.md | 1 - packages/docs/src/pages/en/components/confirm-edit.md | 1 - packages/docs/src/pages/en/components/date-inputs.md | 1 - packages/docs/src/pages/en/components/empty-states.md | 1 - packages/docs/src/pages/en/components/floating-action-buttons.md | 1 - packages/docs/src/pages/en/components/forms.md | 1 + packages/docs/src/pages/en/components/menus.md | 1 + packages/docs/src/pages/en/components/number-inputs.md | 1 - packages/docs/src/pages/en/components/snackbar-queue.md | 1 - packages/docs/src/pages/en/components/sparklines.md | 1 - packages/docs/src/pages/en/components/speed-dials.md | 1 - packages/docs/src/pages/en/components/time-pickers.md | 1 - packages/docs/src/pages/en/components/vertical-steppers.md | 1 - packages/docs/src/pages/en/features/scrolling.md | 1 - packages/docs/src/pages/en/styles/borders.md | 1 - packages/docs/src/pages/en/styles/cursor.md | 1 - packages/docs/src/pages/en/styles/opacity.md | 1 - packages/docs/src/pages/en/styles/position.md | 1 - packages/docs/src/pages/en/styles/text-and-typography.md | 1 - 22 files changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/docs/src/pages/en/components/application.md b/packages/docs/src/pages/en/components/application.md index 95dd3a1a7c6..ac46804a5e6 100644 --- a/packages/docs/src/pages/en/components/application.md +++ b/packages/docs/src/pages/en/components/application.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Application description: Vuetify comes equipped with a default markup that makes it easy to create layouts (boilerplate) for any Vue application. diff --git a/packages/docs/src/pages/en/components/avatars.md b/packages/docs/src/pages/en/components/avatars.md index 60a41608999..57772364546 100644 --- a/packages/docs/src/pages/en/components/avatars.md +++ b/packages/docs/src/pages/en/components/avatars.md @@ -1,4 +1,5 @@ --- +emphasized: true meta: nav: Avatars title: Avatar component diff --git a/packages/docs/src/pages/en/components/buttons.md b/packages/docs/src/pages/en/components/buttons.md index 2391dc6349f..553b690f963 100644 --- a/packages/docs/src/pages/en/components/buttons.md +++ b/packages/docs/src/pages/en/components/buttons.md @@ -1,4 +1,5 @@ --- +emphasized: true meta: nav: Buttons title: Button component diff --git a/packages/docs/src/pages/en/components/calendars.md b/packages/docs/src/pages/en/components/calendars.md index b402895424f..8a1f415564a 100644 --- a/packages/docs/src/pages/en/components/calendars.md +++ b/packages/docs/src/pages/en/components/calendars.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Calendars title: Calendar component diff --git a/packages/docs/src/pages/en/components/confirm-edit.md b/packages/docs/src/pages/en/components/confirm-edit.md index 3facd46470d..36e44dedb13 100644 --- a/packages/docs/src/pages/en/components/confirm-edit.md +++ b/packages/docs/src/pages/en/components/confirm-edit.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Confirm Edit title: Confirm Edit diff --git a/packages/docs/src/pages/en/components/date-inputs.md b/packages/docs/src/pages/en/components/date-inputs.md index 0bf278bad86..896404417f1 100644 --- a/packages/docs/src/pages/en/components/date-inputs.md +++ b/packages/docs/src/pages/en/components/date-inputs.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Date inputs title: Date input component diff --git a/packages/docs/src/pages/en/components/empty-states.md b/packages/docs/src/pages/en/components/empty-states.md index ed47f908a6d..f1d8edd811d 100644 --- a/packages/docs/src/pages/en/components/empty-states.md +++ b/packages/docs/src/pages/en/components/empty-states.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Empty states description: The empty state component is used to indicate that a list is empty or that no search results were found. diff --git a/packages/docs/src/pages/en/components/floating-action-buttons.md b/packages/docs/src/pages/en/components/floating-action-buttons.md index 5cc714bdc82..6aa85e5f9be 100644 --- a/packages/docs/src/pages/en/components/floating-action-buttons.md +++ b/packages/docs/src/pages/en/components/floating-action-buttons.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Floating Action Buttons title: FAB component diff --git a/packages/docs/src/pages/en/components/forms.md b/packages/docs/src/pages/en/components/forms.md index 7a97bbe16b8..d61d7c218fc 100644 --- a/packages/docs/src/pages/en/components/forms.md +++ b/packages/docs/src/pages/en/components/forms.md @@ -1,4 +1,5 @@ --- +emphasized: true meta: nav: Forms title: Form component diff --git a/packages/docs/src/pages/en/components/menus.md b/packages/docs/src/pages/en/components/menus.md index e1249927039..0df5ec4ed40 100644 --- a/packages/docs/src/pages/en/components/menus.md +++ b/packages/docs/src/pages/en/components/menus.md @@ -1,4 +1,5 @@ --- +emphasized: true meta: nav: Menus title: Menu component diff --git a/packages/docs/src/pages/en/components/number-inputs.md b/packages/docs/src/pages/en/components/number-inputs.md index 823a6201340..8d18a3e09ff 100644 --- a/packages/docs/src/pages/en/components/number-inputs.md +++ b/packages/docs/src/pages/en/components/number-inputs.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Number inputs description: The Number input component is used for ... diff --git a/packages/docs/src/pages/en/components/snackbar-queue.md b/packages/docs/src/pages/en/components/snackbar-queue.md index 5037b56c290..2ce22bf86a2 100644 --- a/packages/docs/src/pages/en/components/snackbar-queue.md +++ b/packages/docs/src/pages/en/components/snackbar-queue.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Snackbar Queue title: Snackbar Queue component diff --git a/packages/docs/src/pages/en/components/sparklines.md b/packages/docs/src/pages/en/components/sparklines.md index 693c8e3a0af..972bfb1fa9a 100644 --- a/packages/docs/src/pages/en/components/sparklines.md +++ b/packages/docs/src/pages/en/components/sparklines.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Sparklines description: The sparkline component creates beautiful and expressive simple graphs for displaying numerical data. diff --git a/packages/docs/src/pages/en/components/speed-dials.md b/packages/docs/src/pages/en/components/speed-dials.md index f95a52d2eb8..02fbbe63b48 100644 --- a/packages/docs/src/pages/en/components/speed-dials.md +++ b/packages/docs/src/pages/en/components/speed-dials.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Speed Dials title: Speed Dial component diff --git a/packages/docs/src/pages/en/components/time-pickers.md b/packages/docs/src/pages/en/components/time-pickers.md index 28976898267..f04c22b7486 100644 --- a/packages/docs/src/pages/en/components/time-pickers.md +++ b/packages/docs/src/pages/en/components/time-pickers.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Time pickers title: Time picker component diff --git a/packages/docs/src/pages/en/components/vertical-steppers.md b/packages/docs/src/pages/en/components/vertical-steppers.md index 39d5aa4d5b1..799673a9ece 100644 --- a/packages/docs/src/pages/en/components/vertical-steppers.md +++ b/packages/docs/src/pages/en/components/vertical-steppers.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: nav: Steppers Vertical title: Vertical Stepper component diff --git a/packages/docs/src/pages/en/features/scrolling.md b/packages/docs/src/pages/en/features/scrolling.md index 94debb882d1..2f53b743766 100644 --- a/packages/docs/src/pages/en/features/scrolling.md +++ b/packages/docs/src/pages/en/features/scrolling.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Programmatic scrolling description: Handle scrolling within your application by using the goTo function diff --git a/packages/docs/src/pages/en/styles/borders.md b/packages/docs/src/pages/en/styles/borders.md index 3143e6f4b09..7c640801eae 100644 --- a/packages/docs/src/pages/en/styles/borders.md +++ b/packages/docs/src/pages/en/styles/borders.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Borders description: Use border utilities to quickly style the border of any element. diff --git a/packages/docs/src/pages/en/styles/cursor.md b/packages/docs/src/pages/en/styles/cursor.md index ec4e571a5b5..8ec7a94c746 100644 --- a/packages/docs/src/pages/en/styles/cursor.md +++ b/packages/docs/src/pages/en/styles/cursor.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Cursor description: Assign a custom cursor to any element. diff --git a/packages/docs/src/pages/en/styles/opacity.md b/packages/docs/src/pages/en/styles/opacity.md index 96d8e0ec46b..2f36d200364 100644 --- a/packages/docs/src/pages/en/styles/opacity.md +++ b/packages/docs/src/pages/en/styles/opacity.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Opacity description: Use opacity utilities to quickly style the opacity of any element. diff --git a/packages/docs/src/pages/en/styles/position.md b/packages/docs/src/pages/en/styles/position.md index 8d0906f3d4e..bf618e691fa 100644 --- a/packages/docs/src/pages/en/styles/position.md +++ b/packages/docs/src/pages/en/styles/position.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Position description: Use position utilities to quickly style the positioning of any element. diff --git a/packages/docs/src/pages/en/styles/text-and-typography.md b/packages/docs/src/pages/en/styles/text-and-typography.md index 7f192cfba36..4c6a0b1d354 100644 --- a/packages/docs/src/pages/en/styles/text-and-typography.md +++ b/packages/docs/src/pages/en/styles/text-and-typography.md @@ -1,5 +1,4 @@ --- -emphasized: true meta: title: Text and typography description: View the various typography styles. From headings to captions, with various weights, sizes and italics. From 219440372d5b4975dd25b3de9b24284f99742cf4 Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 15 Aug 2024 22:47:30 +1000 Subject: [PATCH 043/190] fix(VCardActions): space children with gap instead of margin closes #20239 closes #20262 --- packages/vuetify/src/components/VBtn/VBtn.sass | 6 ------ packages/vuetify/src/components/VBtn/_variables.scss | 1 - packages/vuetify/src/components/VCard/VCard.sass | 1 + packages/vuetify/src/components/VCard/_variables.scss | 10 +++++++--- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/vuetify/src/components/VBtn/VBtn.sass b/packages/vuetify/src/components/VBtn/VBtn.sass index 13984b4b2fa..680b2e3336d 100644 --- a/packages/vuetify/src/components/VBtn/VBtn.sass +++ b/packages/vuetify/src/components/VBtn/VBtn.sass @@ -231,12 +231,6 @@ pointer-events: none @include tools.absolute() - // VCard - .v-btn - ~ .v-btn:not(.v-btn-toggle .v-btn) - .v-card-actions & - margin-inline-start: $button-card-actions-margin - // VPagination .v-btn .v-pagination & diff --git a/packages/vuetify/src/components/VBtn/_variables.scss b/packages/vuetify/src/components/VBtn/_variables.scss index e5eab86adbf..2934256fc89 100644 --- a/packages/vuetify/src/components/VBtn/_variables.scss +++ b/packages/vuetify/src/components/VBtn/_variables.scss @@ -18,7 +18,6 @@ $button-border-radius: settings.$border-radius-root !default; $button-border-style: settings.$border-style-root !default; $button-border-thin-width: thin !default; $button-border-width: 0 !default; -$button-card-actions-margin: .5rem !default; $button-card-actions-padding: 0 8px !default; // @deprecated $button-content-transition: transform, opacity .2s settings.$standard-easing !default; $button-disabled-opacity: 0.26 !default; diff --git a/packages/vuetify/src/components/VCard/VCard.sass b/packages/vuetify/src/components/VCard/VCard.sass index 8da53349da2..e6fb7987567 100644 --- a/packages/vuetify/src/components/VCard/VCard.sass +++ b/packages/vuetify/src/components/VCard/VCard.sass @@ -77,6 +77,7 @@ flex: $card-actions-flex min-height: $card-actions-min-height padding: $card-actions-padding + gap: $card-actions-gap .v-card-item align-items: $card-item-align-items diff --git a/packages/vuetify/src/components/VCard/_variables.scss b/packages/vuetify/src/components/VCard/_variables.scss index b349673e0b1..1707e79aaa1 100644 --- a/packages/vuetify/src/components/VCard/_variables.scss +++ b/packages/vuetify/src/components/VCard/_variables.scss @@ -3,9 +3,6 @@ @use '../../styles/tools'; // VCard -$card-actions-flex: none !default; -$card-actions-min-height: 52px !default; -$card-actions-padding: .5rem !default; $card-append-padding-inline-start: .5rem !default; $card-background: rgb(var(--v-theme-surface)) !default; $card-border-color: settings.$border-color-root !default; @@ -31,6 +28,13 @@ $card-transition-duration: 0.28s !default; $card-transition-property: box-shadow, opacity, background !default; $card-transition-timing-function: settings.$standard-easing !default; +// VCardActions +$card-actions-flex: none !default; +$card-actions-min-height: 52px !default; +$card-actions-padding: .5rem !default; +$button-card-actions-margin: .5rem !default; // deprecated +$card-actions-gap: $button-card-actions-margin !default; + // VCardHeader $card-header-flex: none !default; From a0e7c3b00c61b049d2e3eacb90bc60fd6e51649e Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 15 Aug 2024 22:49:27 +1000 Subject: [PATCH 044/190] chore(release): publish v3.7.0 --- lerna.json | 4 ++-- packages/api-generator/package.json | 2 +- packages/docs/package.json | 2 +- packages/vuetify/package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lerna.json b/lerna.json index fa9d3a7f96d..d9f7b120394 100644 --- a/lerna.json +++ b/lerna.json @@ -13,5 +13,5 @@ } }, "npmClient": "pnpm", - "version": "3.7.0-beta.1" -} + "version": "3.7.0" +} \ No newline at end of file diff --git a/packages/api-generator/package.json b/packages/api-generator/package.json index f1e6745d156..626d084eca0 100755 --- a/packages/api-generator/package.json +++ b/packages/api-generator/package.json @@ -1,6 +1,6 @@ { "name": "@vuetify/api-generator", - "version": "3.7.0-beta.1", + "version": "3.7.0", "private": true, "description": "", "scripts": { diff --git a/packages/docs/package.json b/packages/docs/package.json index 844a3f2967e..7269c59ed2f 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -3,7 +3,7 @@ "description": "A Vue.js project", "private": true, "author": "John Leider ", - "version": "3.7.0-beta.1", + "version": "3.7.0", "repository": { "type": "git", "url": "git+https://github.com/vuetifyjs/vuetify.git", diff --git a/packages/vuetify/package.json b/packages/vuetify/package.json index 3fe04b70bce..c25f6b7902a 100755 --- a/packages/vuetify/package.json +++ b/packages/vuetify/package.json @@ -1,7 +1,7 @@ { "name": "vuetify", "description": "Vue Material Component Framework", - "version": "3.7.0-beta.1", + "version": "3.7.0", "author": { "name": "John Leider", "email": "john@vuetifyjs.com" From 836087f76b901ce2bc567e12979427ae6b56db8d Mon Sep 17 00:00:00 2001 From: Yuchao Wu Date: Fri, 16 Aug 2024 16:44:17 +1000 Subject: [PATCH 045/190] fix(VNumberInput): emit model when input is a number between max & min fixes #20337 --- .../src/labs/VNumberInput/VNumberInput.tsx | 9 ++++- .../__tests__/VNumberInput.spec.cy.tsx | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx b/packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx index 6cec9e96563..7835d768bd5 100644 --- a/packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx +++ b/packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx @@ -75,7 +75,14 @@ export const VNumberInput = genericComponent()({ const model = computed({ get: () => _model.value, set (val) { - if (typeof val !== 'string') _model.value = val + if (val === null) { + _model.value = null + return + } + + if (!isNaN(+val) && +val <= props.max && +val >= props.min) { + _model.value = +val + } }, }) diff --git a/packages/vuetify/src/labs/VNumberInput/__tests__/VNumberInput.spec.cy.tsx b/packages/vuetify/src/labs/VNumberInput/__tests__/VNumberInput.spec.cy.tsx index 6b3b3f0ea23..0e9a5c5307f 100644 --- a/packages/vuetify/src/labs/VNumberInput/__tests__/VNumberInput.spec.cy.tsx +++ b/packages/vuetify/src/labs/VNumberInput/__tests__/VNumberInput.spec.cy.tsx @@ -42,6 +42,46 @@ describe('VNumberInput', () => { expect(model.value).equal(null) }) }) + + // https://github.com/vuetifyjs/vuetify/issues/20337 + it('should emit model-value when input value is a legit number within range of the max and min', () => { + const model = ref(null) + + cy.mount(() => ( + <> + + + )) + .get('.v-number-input input') + .focus().realType('1') + .then(() => { + expect(model.value).equal(null) + }) + .get('.v-number-input input') + .realType('0') + .then(() => { + expect(model.value).equal(10) + }) + .realType('0') + .then(() => { + expect(model.value).equal(100) + }) + .realType('0') + .get('.v-number-input input') + .then(() => { + expect(model.value).equal(100) + }) + .get('.v-number-input input') + .blur() + .then(() => { + expect(model.value).equal(125) + }) + }) + describe('readonly', () => { it('should prevent mutation when readonly applied', () => { const value = ref(1) From a7a08ae18f5b8a10c4411f1f7cb1f9177a56fbc4 Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 16 Aug 2024 19:04:41 +1000 Subject: [PATCH 046/190] chore(ci): label closed issues --- .github/workflows/triage.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 6b25c9fe022..3f25be8c898 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -1,7 +1,7 @@ name: Issue triage on: issues: - types: [opened, labeled, unlabeled] + types: [opened, labeled, unlabeled, closed] jobs: triage: @@ -13,6 +13,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} triageLabel: 'S: triage' sponsorsFile: '.github/sponsors.yml' + duplicateLabel: 'duplicate' triagedLabels: |- T: documentation T: bug From 59782b2aac37a7b7e68cbb1cdbd3a331fa3bd9ef Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 16 Aug 2024 19:05:05 +1000 Subject: [PATCH 047/190] chore: install @vue/language-server --- package.json | 1 + pnpm-lock.yaml | 524 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 475 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index ead12e22124..47897c36a09 100755 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@typescript-eslint/parser": "^7.18.0", "@unhead/vue": "^1.9.4", "@vue/compiler-sfc": "^3.4.27", + "@vue/language-server": "^2.0.29", "@vue/runtime-core": "^3.4.27", "@vue/runtime-dom": "^3.4.27", "@vueuse/head": "^1.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcfe287a0f1..a88fae8d7ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,6 +51,9 @@ importers: '@vue/compiler-sfc': specifier: ^3.4.27 version: 3.4.27 + '@vue/language-server': + specifier: ^2.0.29 + version: 2.0.29(typescript@5.5.4) '@vue/runtime-core': specifier: ^3.4.27 version: 3.4.27 @@ -110,7 +113,7 @@ importers: version: 9.24.1(eslint@8.57.0) eslint-plugin-vuetify: specifier: ^2.3.0 - version: 2.3.0(eslint@8.57.0)(vuetify@3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4))) + version: 2.3.0(eslint@8.57.0)(vuetify@3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4))) glob: specifier: ^11.0.0 version: 11.0.0 @@ -155,7 +158,7 @@ importers: version: 1.77.8 semver: specifier: ^7.6.0 - version: 7.6.0 + version: 7.6.3 shelljs: specifier: ^0.8.5 version: 0.8.5 @@ -1327,6 +1330,27 @@ packages: resolution: {integrity: sha512-ltpt2S/WVREIBXptxYAVYBvXb2O6yTUYiRUWF8OLikMxlmiGsIgKpgHppikNd4Df0uAav7jCsQKcOJ3TJFUx5g==} engines: {node: '>=14.0.0'} + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.0': + resolution: {integrity: sha512-z7wkxRSZgrQHXVzObGkXG+Vmj3uRlpM11oCZ9pbaz0nFejvCDmAiNDpY75+wgXOcffKpj4rzGtwGaZxfJKsJxw==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + '@emnapi/core@1.2.0': resolution: {integrity: sha512-E7Vgw78I93we4ZWdYCb4DGAwRROGkMIXk7/y87UmANR+J6qsWusmC3gLt0H+O0KOt5e6O38U8oJamgbudrES/w==} @@ -1954,6 +1978,9 @@ packages: resolution: {integrity: sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + '@johnsoncodehk/pug-beautify@0.2.2': + resolution: {integrity: sha512-qqNS/YD0Nck5wtQLCPHAfGVgWbbGafxSPjNh0ekYPFSNNqnDH2kamnduzYly8IiADmeVx/MfAE1njMEjVeHTMA==} + '@jridgewell/gen-mapping@0.1.1': resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} @@ -2830,12 +2857,27 @@ packages: '@volar/language-core@2.4.0-alpha.18': resolution: {integrity: sha512-JAYeJvYQQROmVRtSBIczaPjP3DX4QW1fOqW1Ebs0d3Y3EwSNRglz03dSv0Dm61dzd0Yx3WgTW3hndDnTQqgmyg==} + '@volar/language-server@2.4.0-alpha.18': + resolution: {integrity: sha512-dciHEE/R5kzI0bY71QfkoCVQ3cQI6g9MHfA4oIP6UhnJy0CdleUalWSygOXoD3Nq7Yk6wn2BRrb1PP5MsadY/Q==} + + '@volar/language-service@2.4.0-alpha.18': + resolution: {integrity: sha512-EuetrtbEtudi9buinWAG5U3Jam5dY27zXd/7GYnx542kBwanWOBM8i4DAQd0z7M11fOxXgybxPA933uaSyaOog==} + + '@volar/snapshot-document@2.4.0-alpha.18': + resolution: {integrity: sha512-JAeclEly/wnILhR4Pu9MpgBLInZJH49O1zoy8fU+pk5I+zpv7JIEby5z2UFAS60+sIDnxBdAGd7rZ5VibE70vg==} + '@volar/source-map@2.4.0-alpha.18': resolution: {integrity: sha512-MTeCV9MUwwsH0sNFiZwKtFrrVZUK6p8ioZs3xFzHc2cvDXHWlYN3bChdQtwKX+FY2HG6H3CfAu1pKijolzIQ8g==} '@volar/typescript@2.4.0-alpha.18': resolution: {integrity: sha512-sXh5Y8sqGUkgxpMWUGvRXggxYHAVxg0Pa1C42lQZuPDrW6vHJPR0VCK8Sr7WJsAW530HuNQT/ZIskmXtxjybMQ==} + '@vscode/emmet-helper@2.9.3': + resolution: {integrity: sha512-rB39LHWWPQYYlYfpv9qCoZOVioPCftKXXqrsyqN1mTWZM6dTnONT63Db+03vgrBbHzJN45IrgS/AGxw9iiqfEw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + '@vue/babel-helper-vue-transform-on@1.2.2': resolution: {integrity: sha512-nOttamHUR3YzdEqdM/XXDyCSdxMA9VizUKoroLX6yTyRtggzQMHXcmwh8a7ZErcJttIBIc9s68a1B8GZ+Dmvsw==} @@ -2878,6 +2920,13 @@ packages: typescript: optional: true + '@vue/language-server@2.0.29': + resolution: {integrity: sha512-Nni7KwxQBzFVKJj9tLIDe1MVmFBFHtup8yC5LIrWq+8/LFNcznf9QHBjgEWEmwfz6PKtv46vH1hqHlmPrClf/w==} + hasBin: true + + '@vue/language-service@2.0.29': + resolution: {integrity: sha512-lY54t7KNp1WKXfYccTj9PizwE8zrswTZbYzYdLyoeLyLwcO/JlkMssTrt1G+64TLBwBptvV9PwvNw5Bp2YxJHg==} + '@vue/reactivity@3.4.27': resolution: {integrity: sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==} @@ -2898,6 +2947,9 @@ packages: '@vue/test-utils@2.4.6': resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} + '@vue/typescript-plugin@2.0.29': + resolution: {integrity: sha512-cO/cP467bGONkm/imEVvcRg77/VmoWpLyO94jSwLAt8QV0X9l414SwsRdsae+wGMPV+6k7rweer0SP16A0HYdw==} + '@vuelidate/core@2.0.3': resolution: {integrity: sha512-AN6l7KF7+mEfyWG0doT96z+47ljwPpZfi9/JrNMkOGLFv27XVZvKzRLXlmDPQjPl/wOB1GNnHuc54jlCLRNqGA==} peerDependencies: @@ -3454,6 +3506,9 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + character-parser@2.2.0: + resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==} + chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} @@ -4217,6 +4272,9 @@ packages: resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} engines: {node: '>=12'} + emmet@2.4.7: + resolution: {integrity: sha512-O5O5QNqtdlnQM2bmKHtJgyChcrFMgQuulI+WdiOw2NArzprUqqxUW6bgYtKvzKgrsYpuLWalOkdhNP+1jluhCA==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5251,6 +5309,9 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + is-expression@4.0.0: + resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==} + is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -5743,12 +5804,18 @@ packages: resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + jsonc-parser@2.3.1: + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} + jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} jsonc-parser@3.2.1: resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@6.0.1: resolution: {integrity: sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==} @@ -7009,6 +7076,15 @@ packages: psl@1.8.0: resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==} + pug-error@2.1.0: + resolution: {integrity: sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==} + + pug-lexer@5.0.1: + resolution: {integrity: sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==} + + pug-parser@6.0.0: + resolution: {integrity: sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==} + pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} @@ -7165,6 +7241,9 @@ packages: resolution: {integrity: sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==} engines: {node: '>=0.10.0'} + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + request-progress@3.0.0: resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} @@ -7493,8 +7572,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true @@ -7933,6 +8012,9 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + token-stream@1.0.0: + resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==} + totalist@3.0.0: resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==} engines: {node: '>=6'} @@ -8078,6 +8160,9 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + typescript-auto-import-cache@0.3.3: + resolution: {integrity: sha512-ojEC7+Ci1ij9eE6hp8Jl9VUNnsEKzztktP5gtYNRMrTmfXVwA1PITYYAkpxCvvupdSYa/Re51B6KMcv1CTZEUA==} + typescript@5.5.4: resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} engines: {node: '>=14.17'} @@ -8440,6 +8525,97 @@ packages: jsdom: optional: true + volar-service-css@0.0.59: + resolution: {integrity: sha512-gLNjJnECbalPvQB7qeJjhkDN8sR5M3ItbVYjnyio61aHaWptIiXm/HfDahcQ2ApwmvWidkMWWegjGq5L0BENDA==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-emmet@0.0.59: + resolution: {integrity: sha512-6EynHcuMwMBETpK29TbZvIMmvzdVG+Tkokk9VWfZeI+SwDptk2tgdhEqiXXvIkqYNgbuu73Itp66lpH76cAU+Q==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-html@0.0.59: + resolution: {integrity: sha512-hEXOsYpILDlITZxnqRLV9OepVWD63GZBsyjMxszwdzlxvGZjzbGcBBinJGGJRwFIV8djdJwnt91bkdg1V5tj6Q==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-json@0.0.59: + resolution: {integrity: sha512-LfDOQhCvUpDBjA6CP9EogO0dn1yEFbInvV3Yk4OsEdyxwWUEYPLVjDacPlVUYcjCIKQN6NcTOWbVwpg4vYjw6A==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-pug-beautify@0.0.59: + resolution: {integrity: sha512-SCLWHpBdgvWww3a9Vp8FX80ookozhnHx10gkKBTYW4wp7/rzEoVAPSyO7JKBwTdXmdKQv7YXfxLMVUGv0sYUKg==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-pug@0.0.59: + resolution: {integrity: sha512-kmch7yoqeGNlJuDzpw/YL2b89ilzBmWDd0lJbpG412/RXc3PJVA4usUK+SQHdVoF+qi5IcZL6IDxlvRiIrDgWg==} + + volar-service-typescript-twoslash-queries@0.0.59: + resolution: {integrity: sha512-skm8e6yhCIkqLwJB6S9MqT5lO9LNFuMD3dYxKpmOZs1CKbXmCZZTmLfEaD5VkJae1xdleEDZFFTHl2O5HLjOGQ==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-typescript@0.0.59: + resolution: {integrity: sha512-VCOpfiu+lUo5lapWLB5L5vmQGtwzmNWn5MueV915eku7blpphmE+Z7hCNcL1NApn7AetXWhiblv8ZhmUx/dGIA==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-css-languageservice@6.3.0: + resolution: {integrity: sha512-nU92imtkgzpCL0xikrIb8WvedV553F2BENzgz23wFuok/HLN5BeQmroMy26pUwFxV2eV8oNRmYCUv8iO7kSMhw==} + + vscode-html-languageservice@5.3.0: + resolution: {integrity: sha512-C4Z3KsP5Ih+fjHpiBc5jxmvCl+4iEwvXegIrzu2F5pktbWvQaBT3YkVPk8N+QlSSMk8oCG6PKtZ/Sq2YHb5e8g==} + + vscode-json-languageservice@5.4.0: + resolution: {integrity: sha512-NCkkCr63OHVkE4lcb0xlUAaix6vE5gHQW4NrswbLEh3ArXj81lrGuFTsGEYEUXlNHdnc53vWPcjeSy/nMTrfXg==} + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + + vscode-uri@2.1.2: + resolution: {integrity: sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==} + vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} @@ -8524,8 +8700,8 @@ packages: typescript: optional: true - vuetify@3.6.14: - resolution: {integrity: sha512-iSa3CgdTEt/7B0aGDmkBARe8rxDDycEYHu1zNtOf1Xpvs/Tv7Ql5yHGqM2XCY0h7SL8Dme39pJIovzg3q4JLbQ==} + vuetify@3.7.0: + resolution: {integrity: sha512-x+UaU4SPYNcJSE/voCTBFrNn0q9Spzx2EMfDdUj0NYgHGKb59OqnZte+AjaJaoOXy1AHYIGEpm5Ryk2BEfgWuw==} engines: {node: ^12.20 || >=14.13} peerDependencies: typescript: '>=4.7' @@ -9767,6 +9943,29 @@ snapshots: '@emailjs/browser@4.3.3': {} + '@emmetio/abbreviation@2.3.3': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-abbreviation@2.1.8': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-parser@0.4.0': + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + + '@emmetio/html-matcher@1.3.0': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/scanner@1.0.4': {} + + '@emmetio/stream-reader-utils@0.1.0': {} + + '@emmetio/stream-reader@2.2.0': {} + '@emnapi/core@1.2.0': dependencies: '@emnapi/wasi-threads': 1.0.1 @@ -10325,6 +10524,8 @@ snapshots: '@types/yargs': 17.0.13 chalk: 4.1.2 + '@johnsoncodehk/pug-beautify@0.2.2': {} + '@jridgewell/gen-mapping@0.1.1': dependencies: '@jridgewell/set-array': 1.2.1 @@ -10413,7 +10614,7 @@ snapshots: read-cmd-shim: 4.0.0 resolve-from: 5.0.0 rimraf: 4.4.1 - semver: 7.6.0 + semver: 7.6.3 set-blocking: 2.0.0 signal-exit: 3.0.7 slash: 3.0.0 @@ -10512,7 +10713,7 @@ snapshots: promise-all-reject-late: 1.0.1 promise-call-limit: 3.0.1 read-package-json-fast: 3.0.2 - semver: 7.6.0 + semver: 7.6.3 ssri: 10.0.6 treeverse: 3.0.0 walk-up-path: 3.0.1 @@ -10522,7 +10723,7 @@ snapshots: '@npmcli/fs@3.1.1': dependencies: - semver: 7.6.0 + semver: 7.6.3 '@npmcli/git@5.0.8': dependencies: @@ -10533,7 +10734,7 @@ snapshots: proc-log: 4.2.0 promise-inflight: 1.0.1 promise-retry: 2.0.1 - semver: 7.6.0 + semver: 7.6.3 which: 4.0.0 transitivePeerDependencies: - bluebird @@ -10556,7 +10757,7 @@ snapshots: json-parse-even-better-errors: 3.0.2 pacote: 18.0.6 proc-log: 4.2.0 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - bluebird - supports-color @@ -10573,7 +10774,7 @@ snapshots: json-parse-even-better-errors: 3.0.2 normalize-package-data: 6.0.2 proc-log: 4.2.0 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - bluebird @@ -10622,7 +10823,7 @@ snapshots: ignore: 5.3.1 minimatch: 9.0.3 nx: 19.5.2 - semver: 7.6.0 + semver: 7.6.3 tmp: 0.2.1 tslib: 2.6.2 yargs-parser: 21.1.1 @@ -11379,7 +11580,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.0 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 @@ -11394,7 +11595,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.0 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 @@ -11494,6 +11695,31 @@ snapshots: dependencies: '@volar/source-map': 2.4.0-alpha.18 + '@volar/language-server@2.4.0-alpha.18': + dependencies: + '@volar/language-core': 2.4.0-alpha.18 + '@volar/language-service': 2.4.0-alpha.18 + '@volar/snapshot-document': 2.4.0-alpha.18 + '@volar/typescript': 2.4.0-alpha.18 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + '@volar/language-service@2.4.0-alpha.18': + dependencies: + '@volar/language-core': 2.4.0-alpha.18 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + '@volar/snapshot-document@2.4.0-alpha.18': + dependencies: + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + '@volar/source-map@2.4.0-alpha.18': {} '@volar/typescript@2.4.0-alpha.18': @@ -11502,6 +11728,16 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.0.8 + '@vscode/emmet-helper@2.9.3': + dependencies: + emmet: 2.4.7 + jsonc-parser: 2.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 2.1.2 + + '@vscode/l10n@0.0.18': {} + '@vue/babel-helper-vue-transform-on@1.2.2': {} '@vue/babel-plugin-jsx@1.2.2(@babel/core@7.25.2)': @@ -11581,6 +11817,43 @@ snapshots: optionalDependencies: typescript: 5.5.4 + '@vue/language-server@2.0.29(typescript@5.5.4)': + dependencies: + '@volar/language-core': 2.4.0-alpha.18 + '@volar/language-server': 2.4.0-alpha.18 + '@vue/language-core': 2.0.29(typescript@5.5.4) + '@vue/language-service': 2.0.29(typescript@5.5.4) + '@vue/typescript-plugin': 2.0.29(typescript@5.5.4) + vscode-languageserver-protocol: 3.17.5 + vscode-uri: 3.0.8 + transitivePeerDependencies: + - typescript + + '@vue/language-service@2.0.29(typescript@5.5.4)': + dependencies: + '@volar/language-core': 2.4.0-alpha.18 + '@volar/language-service': 2.4.0-alpha.18 + '@volar/typescript': 2.4.0-alpha.18 + '@vue/compiler-dom': 3.4.27 + '@vue/language-core': 2.0.29(typescript@5.5.4) + '@vue/shared': 3.4.27 + '@vue/typescript-plugin': 2.0.29(typescript@5.5.4) + computeds: 0.0.1 + path-browserify: 1.0.1 + volar-service-css: 0.0.59(@volar/language-service@2.4.0-alpha.18) + volar-service-emmet: 0.0.59(@volar/language-service@2.4.0-alpha.18) + volar-service-html: 0.0.59(@volar/language-service@2.4.0-alpha.18) + volar-service-json: 0.0.59(@volar/language-service@2.4.0-alpha.18) + volar-service-pug: 0.0.59 + volar-service-pug-beautify: 0.0.59(@volar/language-service@2.4.0-alpha.18) + volar-service-typescript: 0.0.59(@volar/language-service@2.4.0-alpha.18) + volar-service-typescript-twoslash-queries: 0.0.59(@volar/language-service@2.4.0-alpha.18) + vscode-html-languageservice: 5.3.0 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + transitivePeerDependencies: + - typescript + '@vue/reactivity@3.4.27': dependencies: '@vue/shared': 3.4.27 @@ -11609,6 +11882,14 @@ snapshots: js-beautify: 1.14.11 vue-component-type-helpers: 2.0.11 + '@vue/typescript-plugin@2.0.29(typescript@5.5.4)': + dependencies: + '@volar/typescript': 2.4.0-alpha.18 + '@vue/language-core': 2.0.29(typescript@5.5.4) + '@vue/shared': 3.4.27 + transitivePeerDependencies: + - typescript + '@vuelidate/core@2.0.3(vue@3.4.27(typescript@5.5.4))': dependencies: vue: 3.4.27(typescript@5.5.4) @@ -11619,11 +11900,11 @@ snapshots: vue: 3.4.27(typescript@5.5.4) vue-demi: 0.13.11(vue@3.4.27(typescript@5.5.4)) - '@vuetify/loader-shared@2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)))': + '@vuetify/loader-shared@2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)))': dependencies: upath: 2.0.1 vue: 3.4.27(typescript@5.5.4) - vuetify: 3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) + vuetify: 3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) optional: true '@vuetify/loader-shared@2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify)': @@ -12194,7 +12475,7 @@ snapshots: builtins@5.0.1: dependencies: - semver: 7.6.0 + semver: 7.6.3 bumpp@8.2.1: dependencies: @@ -12203,7 +12484,7 @@ snapshots: fast-glob: 3.3.2 kleur: 4.1.5 prompts: 2.4.2 - semver: 7.6.0 + semver: 7.6.3 bundle-name@4.1.0: dependencies: @@ -12328,6 +12609,10 @@ snapshots: char-regex@1.0.2: {} + character-parser@2.2.0: + dependencies: + is-regex: 1.1.4 + chardet@0.7.0: {} check-error@1.0.2: {} @@ -12662,7 +12947,7 @@ snapshots: handlebars: 4.7.8 json-stringify-safe: 5.0.1 meow: 8.1.2 - semver: 7.6.0 + semver: 7.6.3 split: 1.0.1 conventional-changelog@2.0.3: @@ -12951,7 +13236,7 @@ snapshots: process: 0.11.10 proxy-from-env: 1.0.0 request-progress: 3.0.0 - semver: 7.6.0 + semver: 7.6.3 supports-color: 8.1.1 tmp: 0.2.1 untildify: 4.0.0 @@ -13196,7 +13481,7 @@ snapshots: '@one-ini/wasm': 0.1.1 commander: 10.0.1 minimatch: 9.0.1 - semver: 7.6.0 + semver: 7.6.3 ee-first@1.1.1: {} @@ -13210,6 +13495,11 @@ snapshots: emittery@0.10.2: {} + emmet@2.4.7: + dependencies: + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -13549,7 +13839,7 @@ snapshots: is-core-module: 2.13.1 minimatch: 3.1.2 resolve: 1.22.8 - semver: 7.6.0 + semver: 7.6.3 eslint-plugin-promise@6.1.1(eslint@8.57.0): dependencies: @@ -13589,18 +13879,18 @@ snapshots: natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.16 - semver: 7.6.0 + semver: 7.6.3 vue-eslint-parser: 9.4.2(eslint@8.57.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color - eslint-plugin-vuetify@2.3.0(eslint@8.57.0)(vuetify@3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4))): + eslint-plugin-vuetify@2.3.0(eslint@8.57.0)(vuetify@3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4))): dependencies: eslint: 8.57.0 eslint-plugin-vue: 9.24.1(eslint@8.57.0) requireindex: 1.2.0 - vuetify: 3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) + vuetify: 3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color @@ -14068,7 +14358,7 @@ snapshots: git-semver-tags@5.0.1: dependencies: meow: 8.1.2 - semver: 7.6.0 + semver: 7.6.3 git-up@7.0.0: dependencies: @@ -14424,7 +14714,7 @@ snapshots: npm-package-arg: 11.0.2 promzard: 1.0.2 read: 3.0.1 - semver: 7.6.0 + semver: 7.6.3 validate-npm-package-license: 3.0.4 validate-npm-package-name: 5.0.1 transitivePeerDependencies: @@ -14570,6 +14860,11 @@ snapshots: is-docker@3.0.0: {} + is-expression@4.0.0: + dependencies: + acorn: 7.4.1 + object-assign: 4.1.1 + is-extendable@0.1.1: {} is-extglob@2.1.1: {} @@ -15091,7 +15386,7 @@ snapshots: jest-util: 28.1.3 natural-compare: 1.4.0 pretty-format: 28.1.3 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -15247,12 +15542,16 @@ snapshots: acorn: 8.12.1 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - semver: 7.6.0 + semver: 7.6.3 + + jsonc-parser@2.3.1: {} jsonc-parser@3.2.0: {} jsonc-parser@3.2.1: {} + jsonc-parser@3.3.1: {} + jsonfile@6.0.1: dependencies: universalify: 1.0.0 @@ -15354,7 +15653,7 @@ snapshots: read-cmd-shim: 4.0.0 resolve-from: 5.0.0 rimraf: 4.4.1 - semver: 7.6.0 + semver: 7.6.3 set-blocking: 2.0.0 signal-exit: 3.0.7 slash: 3.0.0 @@ -15404,7 +15703,7 @@ snapshots: npm-package-arg: 11.0.2 npm-registry-fetch: 17.1.0 proc-log: 4.2.0 - semver: 7.6.0 + semver: 7.6.3 sigstore: 2.3.1 ssri: 10.0.6 transitivePeerDependencies: @@ -15571,7 +15870,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.6.0 + semver: 7.6.3 make-fetch-happen@13.0.1: dependencies: @@ -15938,7 +16237,7 @@ snapshots: make-fetch-happen: 13.0.1 nopt: 7.2.1 proc-log: 4.2.0 - semver: 7.6.0 + semver: 7.6.3 tar: 6.2.1 which: 4.0.0 transitivePeerDependencies: @@ -15969,13 +16268,13 @@ snapshots: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.13.1 - semver: 7.6.0 + semver: 7.6.3 validate-npm-package-license: 3.0.4 normalize-package-data@6.0.2: dependencies: hosted-git-info: 7.0.2 - semver: 7.6.0 + semver: 7.6.3 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} @@ -15994,7 +16293,7 @@ snapshots: npm-install-checks@6.3.0: dependencies: - semver: 7.6.0 + semver: 7.6.3 npm-normalize-package-bin@3.0.1: {} @@ -16002,7 +16301,7 @@ snapshots: dependencies: hosted-git-info: 7.0.2 proc-log: 4.2.0 - semver: 7.6.0 + semver: 7.6.3 validate-npm-package-name: 5.0.1 npm-packlist@8.0.2: @@ -16014,7 +16313,7 @@ snapshots: npm-install-checks: 6.3.0 npm-normalize-package-bin: 3.0.1 npm-package-arg: 11.0.2 - semver: 7.6.0 + semver: 7.6.3 npm-registry-fetch@17.1.0: dependencies: @@ -16073,7 +16372,7 @@ snapshots: npm-run-path: 4.0.1 open: 8.4.2 ora: 5.3.0 - semver: 7.6.0 + semver: 7.6.3 string-width: 4.2.3 strong-log-transformer: 2.1.0 tar-stream: 2.2.0 @@ -16681,6 +16980,19 @@ snapshots: psl@1.8.0: {} + pug-error@2.1.0: {} + + pug-lexer@5.0.1: + dependencies: + character-parser: 2.2.0 + is-expression: 4.0.0 + pug-error: 2.1.0 + + pug-parser@6.0.0: + dependencies: + pug-error: 2.1.0 + token-stream: 1.0.0 + pump@3.0.0: dependencies: end-of-stream: 1.4.4 @@ -16856,6 +17168,8 @@ snapshots: dependencies: is-finite: 1.0.2 + request-light@0.7.0: {} + request-progress@3.0.0: dependencies: throttleit: 1.0.0 @@ -17144,9 +17458,7 @@ snapshots: semver@6.3.1: {} - semver@7.6.0: - dependencies: - lru-cache: 6.0.0 + semver@7.6.3: {} serialize-javascript@4.0.0: dependencies: @@ -17617,6 +17929,8 @@ snapshots: dependencies: is-number: 7.0.0 + token-stream@1.0.0: {} + totalist@3.0.0: {} tough-cookie@4.1.3: @@ -17755,6 +18069,10 @@ snapshots: typedarray@0.0.6: {} + typescript-auto-import-cache@0.3.3: + dependencies: + semver: 7.6.3 + typescript@5.5.4: {} uc.micro@1.0.6: {} @@ -18063,14 +18381,14 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14): + vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.0): dependencies: - '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4))) + '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4))) debug: 4.3.6(supports-color@8.1.1) upath: 2.0.1 vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) - vuetify: 3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) + vuetify: 3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color optional: true @@ -18160,6 +18478,112 @@ snapshots: - supports-color - terser + volar-service-css@0.0.59(@volar/language-service@2.4.0-alpha.18): + dependencies: + vscode-css-languageservice: 6.3.0 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.0-alpha.18 + + volar-service-emmet@0.0.59(@volar/language-service@2.4.0-alpha.18): + dependencies: + '@emmetio/css-parser': 0.4.0 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.9.3 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.0-alpha.18 + + volar-service-html@0.0.59(@volar/language-service@2.4.0-alpha.18): + dependencies: + vscode-html-languageservice: 5.3.0 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.0-alpha.18 + + volar-service-json@0.0.59(@volar/language-service@2.4.0-alpha.18): + dependencies: + vscode-json-languageservice: 5.4.0 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.0-alpha.18 + + volar-service-pug-beautify@0.0.59(@volar/language-service@2.4.0-alpha.18): + dependencies: + '@johnsoncodehk/pug-beautify': 0.2.2 + optionalDependencies: + '@volar/language-service': 2.4.0-alpha.18 + + volar-service-pug@0.0.59: + dependencies: + '@volar/language-service': 2.4.0-alpha.18 + muggle-string: 0.4.1 + pug-lexer: 5.0.1 + pug-parser: 6.0.0 + volar-service-html: 0.0.59(@volar/language-service@2.4.0-alpha.18) + vscode-html-languageservice: 5.3.0 + vscode-languageserver-textdocument: 1.0.12 + + volar-service-typescript-twoslash-queries@0.0.59(@volar/language-service@2.4.0-alpha.18): + dependencies: + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.0-alpha.18 + + volar-service-typescript@0.0.59(@volar/language-service@2.4.0-alpha.18): + dependencies: + path-browserify: 1.0.1 + semver: 7.6.3 + typescript-auto-import-cache: 0.3.3 + vscode-languageserver-textdocument: 1.0.12 + vscode-nls: 5.2.0 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.0-alpha.18 + + vscode-css-languageservice@6.3.0: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.0.8 + + vscode-html-languageservice@5.3.0: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.0.8 + + vscode-json-languageservice@5.4.0: + dependencies: + '@vscode/l10n': 0.0.18 + jsonc-parser: 3.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.0.8 + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-nls@5.2.0: {} + + vscode-uri@2.1.2: {} + vscode-uri@3.0.8: {} vue-analytics@5.22.1: {} @@ -18183,7 +18607,7 @@ snapshots: espree: 9.6.1 esquery: 1.5.0 lodash: 4.17.21 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -18219,7 +18643,7 @@ snapshots: dependencies: '@volar/typescript': 2.4.0-alpha.18 '@vue/language-core': 2.0.29(typescript@5.5.4) - semver: 7.6.0 + semver: 7.6.3 typescript: 5.5.4 vue@3.4.27(typescript@5.5.4): @@ -18232,12 +18656,12 @@ snapshots: optionalDependencies: typescript: 5.5.4 - vuetify@3.6.14(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): + vuetify@3.7.0(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): dependencies: vue: 3.4.27(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 - vite-plugin-vuetify: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.6.14) + vite-plugin-vuetify: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.0) vue-i18n: 9.11.1(vue@3.4.27(typescript@5.5.4)) w3c-hr-time@1.0.2: From 7c8aeefdc097ff9b74a733ed17b6a8cd9e1f8575 Mon Sep 17 00:00:00 2001 From: Kael Date: Sat, 17 Aug 2024 20:38:17 +1000 Subject: [PATCH 048/190] fix(types): only augment module 'vue' nuxt/nuxt#28542 --- .../vuetify/build/rollup.types.config.mjs | 2 +- .../cypress/templates/generateStories.tsx | 3 +- packages/vuetify/src/composables/icons.tsx | 6 ++- packages/vuetify/src/composables/index.ts | 2 +- packages/vuetify/src/globals.d.ts | 24 +++++++--- packages/vuetify/src/shims.d.ts | 45 +++++++++---------- 6 files changed, 48 insertions(+), 34 deletions(-) diff --git a/packages/vuetify/build/rollup.types.config.mjs b/packages/vuetify/build/rollup.types.config.mjs index 87bd594f32b..678d084ebf2 100644 --- a/packages/vuetify/build/rollup.types.config.mjs +++ b/packages/vuetify/build/rollup.types.config.mjs @@ -83,7 +83,7 @@ async function getShims () { )).join('\n') return (await fs.readFile(fileURLToPath(new URL('../src/shims.d.ts', import.meta.url)), { encoding: 'utf8' })) - .replaceAll(/^\s*\/\/ @skip-build\s+.*$/gm, '') + .replaceAll(/^\s*\/\/ @skip-build\s[\s\S]*?\s$/gm, '') .replace(/^\s*\/\/ @generate-components$/gm, components) } diff --git a/packages/vuetify/cypress/templates/generateStories.tsx b/packages/vuetify/cypress/templates/generateStories.tsx index a6b796fc2bf..fdf32e476ca 100644 --- a/packages/vuetify/cypress/templates/generateStories.tsx +++ b/packages/vuetify/cypress/templates/generateStories.tsx @@ -2,7 +2,8 @@ * Utilities for generating formatted mount functions * Some utility functions for mounting these generated examples inside of tests */ -import { FunctionalComponent, JSXComponent } from 'vue' +import { FunctionalComponent } from 'vue' +import { JSXComponent } from '@/composables' const _ = Cypress._ diff --git a/packages/vuetify/src/composables/icons.tsx b/packages/vuetify/src/composables/icons.tsx index 76d3b28749b..9ede37abae9 100644 --- a/packages/vuetify/src/composables/icons.tsx +++ b/packages/vuetify/src/composables/icons.tsx @@ -6,7 +6,11 @@ import { computed, inject, unref } from 'vue' import { consoleWarn, defineComponent, genericComponent, mergeDeep, propsFactory } from '@/util' // Types -import type { InjectionKey, JSXComponent, PropType, Ref } from 'vue' +import type { ComponentPublicInstance, FunctionalComponent, InjectionKey, PropType, Ref } from 'vue' + +export type JSXComponent = + | { new (): ComponentPublicInstance } + | FunctionalComponent export type IconValue = | string diff --git a/packages/vuetify/src/composables/index.ts b/packages/vuetify/src/composables/index.ts index 231e1e3705a..8ad3cfab6e9 100644 --- a/packages/vuetify/src/composables/index.ts +++ b/packages/vuetify/src/composables/index.ts @@ -16,6 +16,6 @@ export type { DefaultsInstance } from './defaults' export type { DisplayBreakpoint, DisplayInstance, DisplayThresholds } from './display' export type { SubmitEventPromise } from './form' export type { GoToInstance } from './goto' -export type { IconAliases, IconProps, IconSet, IconOptions } from './icons' +export type { IconAliases, IconProps, IconSet, IconOptions, JSXComponent } from './icons' export type { LocaleInstance, LocaleMessages, RtlInstance, LocaleOptions, RtlOptions } from './locale' export type { ThemeDefinition, ThemeInstance } from './theme' diff --git a/packages/vuetify/src/globals.d.ts b/packages/vuetify/src/globals.d.ts index 44db0bfe7e3..e623269b6b0 100644 --- a/packages/vuetify/src/globals.d.ts +++ b/packages/vuetify/src/globals.d.ts @@ -1,7 +1,8 @@ import 'vue/jsx' // Types -import type { Events, VNode } from 'vue' +import type { ComponentInjectOptions, ComponentOptionsMixin, EmitsOptions, SlotsType } from 'vue' +import type { ComputedOptions, Events, MethodOptions, VNode } from 'vue' import type { TouchStoredHandlers } from './directives/touch' declare global { @@ -98,7 +99,7 @@ declare global { } } -declare module '@vue/runtime-core' { +declare module 'vue' { export interface ComponentCustomProperties { _: ComponentInternalInstance } @@ -112,8 +113,21 @@ declare module '@vue/runtime-core' { aliasName?: string } - // eslint-disable-next-line max-len - export interface ComponentOptionsBase { + export interface ComponentOptionsBase< + Props, + RawBindings, + D, + C extends ComputedOptions, + M extends MethodOptions, + Mixin extends ComponentOptionsMixin, + Extends extends ComponentOptionsMixin, + E extends EmitsOptions, + EE extends string = string, + Defaults = {}, + I extends ComponentInjectOptions = {}, + II extends string = string, + S extends SlotsType = {} + > { aliasName?: string } @@ -125,9 +139,7 @@ declare module '@vue/runtime-core' { ctx: ComponentInternalInstance | null ssContent: VNode | null } -} -declare module '@vue/runtime-dom' { type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never diff --git a/packages/vuetify/src/shims.d.ts b/packages/vuetify/src/shims.d.ts index 12ab5fb90dc..f9561fe5adb 100644 --- a/packages/vuetify/src/shims.d.ts +++ b/packages/vuetify/src/shims.d.ts @@ -1,13 +1,19 @@ /* eslint-disable local-rules/sort-imports */ import 'vue/jsx' -import type { FunctionalComponent, UnwrapNestedRefs, VNodeChild } from 'vue' +import type { UnwrapNestedRefs, VNodeChild } from 'vue' +// These already exist in scope in the final bundle // @skip-build -import type { ComponentPublicInstance } from 'vue' - -// @skip-build -import type { DateInstance, DefaultsInstance, DisplayInstance, IconOptions, LocaleInstance, RtlInstance, ThemeInstance } from './framework' +import type { + DateInstance, + DefaultsInstance, + DisplayInstance, + IconOptions, + LocaleInstance, + RtlInstance, + ThemeInstance, +} from './framework' declare global { namespace JSX { @@ -16,25 +22,8 @@ declare global { } } } -interface _GlobalComponents { - // @generate-components -} -declare module 'vue' { - export type JSXComponent = { new (): ComponentPublicInstance } | FunctionalComponent - export interface GlobalComponents extends _GlobalComponents {} -} -declare module '@vue/runtime-dom' { - export interface HTMLAttributes { - $children?: VNodeChild - } - export interface SVGAttributes { - $children?: VNodeChild - } - export interface GlobalComponents extends _GlobalComponents {} -} - -declare module '@vue/runtime-core' { +declare module 'vue' { interface Vuetify { defaults: DefaultsInstance display: UnwrapNestedRefs @@ -47,5 +36,13 @@ declare module '@vue/runtime-core' { export interface ComponentCustomProperties { $vuetify: Vuetify } - export interface GlobalComponents extends _GlobalComponents {} + export interface HTMLAttributes { + $children?: VNodeChild + } + export interface SVGAttributes { + $children?: VNodeChild + } + export interface GlobalComponents { + // @generate-components + } } From 6ea68b9136b371cd0e859735950c3b03b5dcf58f Mon Sep 17 00:00:00 2001 From: Kael Date: Sat, 17 Aug 2024 20:48:08 +1000 Subject: [PATCH 049/190] fix: remove vue-i18n peer dependency fixes #19720 --- packages/vuetify/package.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/vuetify/package.json b/packages/vuetify/package.json index c25f6b7902a..0ed6492b6e6 100755 --- a/packages/vuetify/package.json +++ b/packages/vuetify/package.json @@ -181,16 +181,12 @@ "typescript": ">=4.7", "vite-plugin-vuetify": ">=1.0.0", "vue": "^3.3.0", - "vue-i18n": "^9.0.0", "webpack-plugin-vuetify": ">=2.0.0" }, "peerDependenciesMeta": { "typescript": { "optional": true }, - "vue-i18n": { - "optional": true - }, "webpack-plugin-vuetify": { "optional": true }, From 32362f75b7ecf8f8b0be575df9b98adce289f365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Sat, 17 Aug 2024 14:02:18 +0200 Subject: [PATCH 050/190] docs: include modern sass vite options (#20325) Co-authored-by: Kael --- packages/docs/src/pages/en/features/sass-variables.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/docs/src/pages/en/features/sass-variables.md b/packages/docs/src/pages/en/features/sass-variables.md index 6238a1da46a..0e264ad74ec 100644 --- a/packages/docs/src/pages/en/features/sass-variables.md +++ b/packages/docs/src/pages/en/features/sass-variables.md @@ -273,6 +273,8 @@ Only put variables, mixins, and functions in the settings file, styles should be Vuetify loads precompiled CSS by default, enabling variable customization will switch to the base SASS files instead which must be recompiled with your project. This can be a performance hit if you're using more than a few vuetify components, and also forces you to use the same SASS compiler version as us. +Performance can be improved with Vite by using the modern sass compiler. Replace your `sass` dependency with `sass-embedded`, update vite to 5.4 or later, and set [`css.preprocessorOptions.sass.api`](https://vitejs.dev/config/shared-options#css-preprocessoroptions) to `'modern-compiler'` in the vite config. + ### Symlinks PNPM and Yarn 2+ create symlinks to library files instead of copying them to node_modules, sass doesn't seem to like this and sometimes doesn't apply the configuration. From c0ef60744d22caf57a41f72c376e52f4001fd4dd Mon Sep 17 00:00:00 2001 From: Kael Date: Wed, 21 Aug 2024 01:37:49 +1000 Subject: [PATCH 051/190] docs: load search dialog on shortcut press --- packages/docs/src/components/app/search/Search.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/docs/src/components/app/search/Search.vue b/packages/docs/src/components/app/search/Search.vue index 847e9da1eb7..7f836c1747d 100644 --- a/packages/docs/src/components/app/search/Search.vue +++ b/packages/docs/src/components/app/search/Search.vue @@ -73,6 +73,7 @@ if (!model.value && isSearchKey) { e.preventDefault() + shouldLoad.value = true model.value = true } else if (model.value && ['ArrowDown', 'ArrowUp'].includes(e.key)) { e.preventDefault() From c4bb85dab83ebf0e86e03996e3bf40ffc6bf0c8b Mon Sep 17 00:00:00 2001 From: John Leider Date: Tue, 20 Aug 2024 20:35:49 -0500 Subject: [PATCH 052/190] chore(roadmap): add missing TBD --- packages/docs/src/pages/en/introduction/roadmap.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/docs/src/pages/en/introduction/roadmap.md b/packages/docs/src/pages/en/introduction/roadmap.md index 657340e75ba..e10d6fbb5bd 100644 --- a/packages/docs/src/pages/en/introduction/roadmap.md +++ b/packages/docs/src/pages/en/introduction/roadmap.md @@ -33,10 +33,10 @@ Multiple components have been delayed until further notice due to reduced fundin | Component | Entering Labs | Production Release | | - | - | - | | [v3.7 (Odyssey)](https://github.com/vuetifyjs/vuetify/milestone/73) | | July 2024 { .bg-surface-light } | -| [v-treeview](/components/treeview/) | *️⃣ | July 2024 | -| [v-number-input](/components/number-inputs/) | *️⃣ | July 2024 | -| [v-time-picker](/components/time-pickers/) | *️⃣ | July 2024 | -| [v-date-input](/components/date-inputs/) | *️⃣ | July 2024 | +| [v-treeview](/components/treeview/) | *️⃣ | ~~July 2024~~ TBD | +| [v-number-input](/components/number-inputs/) | *️⃣ | ~~July 2024~~ TBD | +| [v-time-picker](/components/time-pickers/) | *️⃣ | ~~July 2024~~ TBD | +| [v-date-input](/components/date-inputs/) | *️⃣ | ~~July 2024~~ TBD | | [v-file-upload](https://github.com/vuetifyjs/vuetify/pull/19667) | ~~April~~ ~~May 2024~~ TBD | ~~July 2024~~ TBD | | [v-time-input](https://github.com/vuetifyjs/vuetify/pull/19709) | ~~April~~ ~~May 2024~~ TBD | ~~July 2024~~ TBD | | [v-stepper-vertical](https://github.com/vuetifyjs/vuetify/pull/19524) | *️⃣ | ~~July 2024~~ TBD | @@ -216,9 +216,9 @@ The following are the already released **minor** and **major** version updates. - **Released:** January 2020 - **Notes:** [v2.2 Release](/getting-started/release-notes/?version=v2.2.0) - **Overview:** - The introduction of Vuetify Presets. Will include the entire Material Design Studies collection and be _user customizable_. Will streamline the process for altering the default styles for the framework. Thousands of SASS variables will be added and a lookup tree for finding those variables will put into the documentation. For more information on Google's studies, please [navigate here](https://material.io/design/material-studies/about-our-material-studies.html). + The introduction of Vuetify Presets. Will include the entire Material Design Studies collection and be *user customizable*. Will streamline the process for altering the default styles for the framework. Thousands of SASS variables will be added and a lookup tree for finding those variables will put into the documentation. For more information on Google's studies, please [navigate here](https://material.io/design/material-studies/about-our-material-studies.html). - **Objectives:** - - Add _thousands_ of new SASS variables + - Add *thousands* of new SASS variables - Create a new Vuetify Service for bootstrapping pre-configured framework options; **Preset** - Create presets for the official [Material Design Studies](https://material.io/design/material-studies/about-our-material-studies.html) - Add new features and improve code styling of `v-badge` From b861d8ce6dd5fdfa8d5063550c1b1655eced0ad7 Mon Sep 17 00:00:00 2001 From: Kael Date: Wed, 21 Aug 2024 20:22:26 +1000 Subject: [PATCH 053/190] docs: fix sponsors page --- .../pages/en/introduction/sponsors-and-backers.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/docs/src/pages/en/introduction/sponsors-and-backers.md b/packages/docs/src/pages/en/introduction/sponsors-and-backers.md index 3efd6c343ca..3e931d995ba 100644 --- a/packages/docs/src/pages/en/introduction/sponsors-and-backers.md +++ b/packages/docs/src/pages/en/introduction/sponsors-and-backers.md @@ -41,7 +41,7 @@ We thank all of our project sponsors for their continued support of Vuetify. If Thank you to our special sponsor. Your support is greatly appreciated. - +
@@ -49,7 +49,7 @@ Thank you to our special sponsor. Your support is greatly appreciated. These sponsors have pledged $1,500 per month. - +
@@ -57,7 +57,7 @@ These sponsors have pledged $1,500 per month. These sponsors have pledged $500 per month. - +
@@ -65,7 +65,7 @@ These sponsors have pledged $500 per month. These sponsors have pledged $250 per month. - +
@@ -73,7 +73,7 @@ These sponsors have pledged $250 per month. These sponsors help keep the lights on by providing free services to the Vuetify project. - +
@@ -81,7 +81,7 @@ These sponsors help keep the lights on by providing free services to the Vuetify We work with these companies to provide you with the best possible experience. - +
From 7e9a1b71805ad7d8d3284909a324d1edae74c751 Mon Sep 17 00:00:00 2001 From: Kael Date: Wed, 21 Aug 2024 23:08:21 +1000 Subject: [PATCH 054/190] fix(VDialog): emit afterEnter before setting focus --- packages/vuetify/src/components/VDialog/VDialog.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vuetify/src/components/VDialog/VDialog.tsx b/packages/vuetify/src/components/VDialog/VDialog.tsx index 4dcdea83b59..6391b95df15 100644 --- a/packages/vuetify/src/components/VDialog/VDialog.tsx +++ b/packages/vuetify/src/components/VDialog/VDialog.tsx @@ -43,6 +43,7 @@ export const VDialog = genericComponent()({ emits: { 'update:modelValue': (value: boolean) => true, + afterEnter: () => true, afterLeave: () => true, }, @@ -89,6 +90,7 @@ export const VDialog = genericComponent()({ } function onAfterEnter () { + emit('afterEnter') if (overlay.value?.contentEl && !overlay.value.contentEl.contains(document.activeElement)) { overlay.value.contentEl.focus({ preventScroll: true }) } From 42dba04743421d5f8032f598ccacb613b8f78ba3 Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 22 Aug 2024 03:58:55 +1000 Subject: [PATCH 055/190] docs: show exposed properties for components forwarding Elements closes #19180 --- .../api-generator/templates/component.d.ts | 35 ++++++------------- .../vuetify/src/composables/forwardRefs.ts | 31 ++++++++++++---- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/packages/api-generator/templates/component.d.ts b/packages/api-generator/templates/component.d.ts index 545f9deed73..a559dd7b0f9 100644 --- a/packages/api-generator/templates/component.d.ts +++ b/packages/api-generator/templates/component.d.ts @@ -1,4 +1,5 @@ -import type { AllowedComponentProps, ComponentPublicInstance, FunctionalComponent, RenderFunction, VNodeChild, VNodeProps } from 'vue' +import type { AllowedComponentProps, ComponentOptionsBase, VNodeChild, VNodeProps, UnwrapRef } from 'vue' +import type { UnionToIntersection } from '@/util' import type { __component__ } from '@/__name__' type StripProps = keyof VNodeProps | keyof AllowedComponentProps | 'v-slots' | '$children' | `v-slot:${string}` @@ -26,17 +27,6 @@ type Events = T extends { $props: infer P extends object } export type ComponentProps = Props<__component__> export type ComponentEvents = Events<__component__> -type RemoveIndex = { - [K in keyof T as string extends K - ? never - : number extends K - ? never - : symbol extends K - ? never - : K - ]: T[K] -} - type Slot = (...args: T) => VNodeChild type Slots< T extends { $props: any }, @@ -50,18 +40,13 @@ type ExcludeEmpty = T extends AtLeastOne ? T : never export type ComponentSlots = Slots<__component__> -type ExtractExposed = T extends (...args: any[]) => infer R - ? R extends Promise - ? never - : R extends RenderFunction - ? never - : R extends void - ? never - : R extends HTMLElement - ? never - : R extends object - ? RemoveIndex - : never +type ExtractExposed = T extends ComponentOptionsBase + ? B extends void ? never + : B extends { _allExposed: infer E } ? E + : B extends object ? B + : never : never -export type ComponentExposed = ExtractExposed<__component__['$options']['setup']> +type Pretty = { [K in keyof T]: UnwrapRef } + +export type ComponentExposed = Pretty>> diff --git a/packages/vuetify/src/composables/forwardRefs.ts b/packages/vuetify/src/composables/forwardRefs.ts index d2ecba5db4d..1889a30162f 100644 --- a/packages/vuetify/src/composables/forwardRefs.ts +++ b/packages/vuetify/src/composables/forwardRefs.ts @@ -1,12 +1,18 @@ // Types -import type { ComponentPublicInstance, Ref, UnwrapRef } from 'vue' +import type { ComponentOptionsBase, ComponentPublicInstance, Ref, UnwrapRef } from 'vue' import type { UnionToIntersection } from '@/util' const Refs = Symbol('Forwarded refs') /** Omit properties starting with P */ -type OmitPrefix = [Extract] extends [never] ? T : Omit - +type OmitPrefix< + T, + P extends string, + E = Extract, +> = [E] extends [never] ? T : Omit +type OmitPrivate = OmitPrefix + +/** Omit keyof $props from T */ type OmitProps = T extends { $props: any } ? Omit : T function getDescriptor (obj: any, key: PropertyKey) { @@ -19,10 +25,21 @@ function getDescriptor (obj: any, key: PropertyKey) { return undefined } -export function forwardRefs | undefined>[]> ( - target: T, - ...refs: U -): T & UnionToIntersection<{ [K in keyof U]: OmitPrefix>>, '$'> }[number]> { +export function forwardRefs< + T extends {}, + U extends Ref | undefined>[], + UU = { [K in keyof U]: NonNullable> }[number], + UC = { [K in keyof U]: OmitPrivate>>> }[number], + R = T & UnionToIntersection & { + _allExposed: T | ( + UU extends { $options: infer O } + ? O extends ComponentOptionsBase + ? E + : never + : never + ) + } +> (target: T, ...refs: U): R { (target as any)[Refs] = refs return new Proxy(target, { From 0b018d996055fea6bc50859ea5a3d20a434a8e10 Mon Sep 17 00:00:00 2001 From: Kael Date: Mon, 26 Aug 2024 19:48:14 +1000 Subject: [PATCH 056/190] chore: remove old treeview files --- .../src/components/VTreeview/VTreeview.sass | 128 -- .../src/components/VTreeview/VTreeview.ts | 441 ------- .../src/components/VTreeview/VTreeviewNode.ts | 376 ------ .../VTreeview/__tests__/VTreeview.spec.ts | 881 -------------- .../VTreeview/__tests__/VTreeviewNode.spec.ts | 192 --- .../__snapshots__/VTreeview.spec.ts.snap | 1058 ----------------- .../__snapshots__/VTreeviewNode.spec.ts.snap | 142 --- .../src/components/VTreeview/_mixins.sass | 18 - .../src/components/VTreeview/_variables.scss | 10 - .../vuetify/src/components/VTreeview/index.ts | 11 - .../util/__tests__/filterTreeItems.spec.ts | 23 - .../VTreeview/util/filterTreeItems.ts | 42 - packages/vuetify/src/components/index.ts | 1 - 13 files changed, 3323 deletions(-) delete mode 100644 packages/vuetify/src/components/VTreeview/VTreeview.sass delete mode 100644 packages/vuetify/src/components/VTreeview/VTreeview.ts delete mode 100644 packages/vuetify/src/components/VTreeview/VTreeviewNode.ts delete mode 100644 packages/vuetify/src/components/VTreeview/__tests__/VTreeview.spec.ts delete mode 100644 packages/vuetify/src/components/VTreeview/__tests__/VTreeviewNode.spec.ts delete mode 100644 packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeview.spec.ts.snap delete mode 100644 packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeviewNode.spec.ts.snap delete mode 100755 packages/vuetify/src/components/VTreeview/_mixins.sass delete mode 100644 packages/vuetify/src/components/VTreeview/_variables.scss delete mode 100644 packages/vuetify/src/components/VTreeview/index.ts delete mode 100644 packages/vuetify/src/components/VTreeview/util/__tests__/filterTreeItems.spec.ts delete mode 100755 packages/vuetify/src/components/VTreeview/util/filterTreeItems.ts diff --git a/packages/vuetify/src/components/VTreeview/VTreeview.sass b/packages/vuetify/src/components/VTreeview/VTreeview.sass deleted file mode 100644 index 6bcb24ae90e..00000000000 --- a/packages/vuetify/src/components/VTreeview/VTreeview.sass +++ /dev/null @@ -1,128 +0,0 @@ -@import './_variables.scss' -@import './_mixins.sass' - -// Theme -@include theme(v-treeview) using ($material) - color: map-deep-get($material, 'text', 'primary') - - &--hoverable .v-treeview-node__root, - .v-treeview-node--click > .v-treeview-node__root - @include states($material) - - .v-treeview-node__root.v-treeview-node--active - @include active-states($material) - - .v-treeview-node--disabled - > .v-treeview-node__root > .v-treeview-node__content - color: map-deep-get($material, 'text', 'disabled') !important - -.v-treeview-node - &.v-treeview-node--shaped - @include treeview-shaped($treeview-node-height, $treeview-node-shaped-margin) - - &.v-treeview-node--rounded - @include treeview-rounded($treeview-node-height, $treeview-node-shaped-margin) - - &--click - > .v-treeview-node__root, - > .v-treeview-node__root > .v-treeview-node__content > * - cursor: pointer - user-select: none - - &.v-treeview-node--active .v-treeview-node__content .v-icon - color: inherit - -.v-treeview-node__root - display: flex - align-items: center - min-height: $treeview-node-height - padding-left: $treeview-node-padding - padding-right: $treeview-node-padding - position: relative - - &::before - background-color: currentColor - bottom: 0 - content: '' - left: 0 - opacity: 0 - pointer-events: none - position: absolute - right: 0 - top: 0 - transition: $primary-transition - - // Fix for IE11 where min-height does not work with - // align-items: center in flex containers - // https://github.com/philipwalton/flexbugs/issues/231 - &::after - content: '' - font-size: 0 - min-height: inherit - -.v-treeview-node__children - transition: all $treeview-transition - -.v-treeview--dense - .v-treeview-node__root - min-height: $treeview-node-height-dense - - &.v-treeview-node--shaped - @include treeview-shaped($treeview-node-height-dense, $treeview-node-shaped-margin) - - &.v-treeview-node--rounded - @include treeview-rounded($treeview-node-height-dense, $treeview-node-shaped-margin) - -.v-treeview-node__checkbox - width: $treeview-node-level-width - user-select: none - margin-inline-start: $treeview-node-margin - -.v-treeview-node__toggle - width: $treeview-node-level-width - user-select: none - - &--loading - animation: progress-circular-rotate 1s linear infinite - - @include ltr() - transform: rotate(-90deg) - &--open - transform: none - - @include rtl() - transform: rotate(90deg) - &--open - transform: none - -.v-treeview-node__prepend - min-width: $treeview-node-level-width - margin-inline-end: $treeview-node-margin - -.v-treeview-node__append - min-width: $treeview-node-level-width - margin-inline-start: $treeview-node-margin - -.v-treeview-node__level - width: $treeview-node-level-width - -.v-treeview-node__label - flex: 1 - font-size: $treeview-label-font-size - overflow: hidden - text-overflow: ellipsis - white-space: nowrap - -.v-treeview-node__content - align-items: center - display: flex - flex-basis: 0% - flex-grow: 1 - flex-shrink: 0 - min-width: 0 - margin-inline-start: $treeview-node-margin - - // TODO: this is temporary fix for d-flex * shenanigans - .v-btn - flex-grow: 0 !important - flex-shrink: 1 !important diff --git a/packages/vuetify/src/components/VTreeview/VTreeview.ts b/packages/vuetify/src/components/VTreeview/VTreeview.ts deleted file mode 100644 index 0c5b0feed73..00000000000 --- a/packages/vuetify/src/components/VTreeview/VTreeview.ts +++ /dev/null @@ -1,441 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// Styles -import './VTreeview.sass' - -// Types -import { VNode, VNodeChildrenArrayContents, PropType } from 'vue' -import { PropValidator } from 'vue/types/options' -import { TreeviewItemFunction } from 'vuetify/types' - -// Components -import VTreeviewNode, { VTreeviewNodeProps } from './VTreeviewNode' - -// Mixins -import Themeable from '../../mixins/themeable' -import { provide as RegistrableProvide } from '../../mixins/registrable' - -// Utils -import { - arrayDiff, - deepEqual, - getObjectValueByPath, -} from '../../util/helpers' -import mixins from '../../util/mixins' -import { consoleWarn } from '../../util/console' -import { - filterTreeItems, - filterTreeItem, -} from './util/filterTreeItems' - -type VTreeviewNodeInstance = InstanceType - -type NodeCache = Set -type NodeArray = (string | number)[] - -type NodeState = { - parent: number | string | null - children: (number | string)[] - vnode: VTreeviewNodeInstance | null - isActive: boolean - isSelected: boolean - isIndeterminate: boolean - isOpen: boolean - item: any -} - -export default mixins( - RegistrableProvide('treeview'), - Themeable - /* @vue/component */ -).extend({ - name: 'v-treeview', - - provide (): object { - return { treeview: this } - }, - - props: { - active: { - type: Array, - default: () => ([]), - } as PropValidator, - dense: Boolean, - disabled: Boolean, - filter: Function as PropType, - hoverable: Boolean, - items: { - type: Array, - default: () => ([]), - } as PropValidator, - multipleActive: Boolean, - open: { - type: Array, - default: () => ([]), - } as PropValidator, - openAll: Boolean, - returnObject: { - type: Boolean, - default: false, // TODO: Should be true in next major - }, - search: String, - value: { - type: Array, - default: () => ([]), - } as PropValidator, - ...VTreeviewNodeProps, - }, - - data: () => ({ - level: -1, - activeCache: new Set() as NodeCache, - nodes: {} as Record, - openCache: new Set() as NodeCache, - selectedCache: new Set() as NodeCache, - }), - - computed: { - excludedItems (): Set { - const excluded = new Set() - - if (!this.search) return excluded - - for (let i = 0; i < this.items.length; i++) { - filterTreeItems( - this.filter || filterTreeItem, - this.items[i], - this.search, - this.itemKey, - this.itemText, - this.itemChildren, - excluded - ) - } - - return excluded - }, - }, - - watch: { - items: { - handler () { - const oldKeys = Object.keys(this.nodes).map(k => getObjectValueByPath(this.nodes[k].item, this.itemKey)) - const newKeys = this.getKeys(this.items) - const diff = arrayDiff(newKeys, oldKeys) - - // We only want to do stuff if items have changed - if (!diff.length && newKeys.length < oldKeys.length) return - - // If nodes are removed we need to clear them from this.nodes - diff.forEach(k => delete this.nodes[k]) - - const oldSelectedCache = [...this.selectedCache] - this.selectedCache = new Set() - this.activeCache = new Set() - this.openCache = new Set() - this.buildTree(this.items) - - // Only emit selected if selection has changed - // as a result of items changing. This fixes a - // potential double emit when selecting a node - // with dynamic children - if (!deepEqual(oldSelectedCache, [...this.selectedCache])) this.emitSelected() - }, - deep: true, - }, - active (value: (string | number | any)[]) { - this.handleNodeCacheWatcher(value, this.activeCache, this.updateActive, this.emitActive) - }, - value (value: (string | number | any)[]) { - this.handleNodeCacheWatcher(value, this.selectedCache, this.updateSelected, this.emitSelected) - }, - open (value: (string | number | any)[]) { - this.handleNodeCacheWatcher(value, this.openCache, this.updateOpen, this.emitOpen) - }, - }, - - created () { - const getValue = (key: string | number) => this.returnObject ? getObjectValueByPath(key, this.itemKey) : key - - this.buildTree(this.items) - - for (const value of this.value.map(getValue)) { - this.updateSelected(value, true, true) - } - - for (const active of this.active.map(getValue)) { - this.updateActive(active, true) - } - }, - - mounted () { - // Save the developer from themselves - if (this.$slots.prepend || this.$slots.append) { - consoleWarn('The prepend and append slots require a slot-scope attribute', this) - } - - if (this.openAll) { - this.updateAll(true) - } else { - this.open.forEach(key => this.updateOpen(this.returnObject ? getObjectValueByPath(key, this.itemKey) : key, true)) - this.emitOpen() - } - }, - - methods: { - /** @public */ - updateAll (value: boolean) { - Object.keys(this.nodes).forEach(key => this.updateOpen(getObjectValueByPath(this.nodes[key].item, this.itemKey), value)) - this.emitOpen() - }, - getKeys (items: any[], keys: any[] = []) { - for (let i = 0; i < items.length; i++) { - const key = getObjectValueByPath(items[i], this.itemKey) - keys.push(key) - const children = getObjectValueByPath(items[i], this.itemChildren) - if (children) { - keys.push(...this.getKeys(children)) - } - } - - return keys - }, - buildTree (items: any[], parent: (string | number | null) = null) { - for (let i = 0; i < items.length; i++) { - const item = items[i] - const key = getObjectValueByPath(item, this.itemKey) - const children = getObjectValueByPath(item, this.itemChildren) ?? [] - const oldNode = this.nodes.hasOwnProperty(key) ? this.nodes[key] : { - isSelected: false, isIndeterminate: false, isActive: false, isOpen: false, vnode: null, - } as NodeState - - const node: any = { - vnode: oldNode.vnode, - parent, - children: children.map((c: any) => getObjectValueByPath(c, this.itemKey)), - item, - } - - this.buildTree(children, key) - - // This fixed bug with dynamic children resetting selected parent state - if ( - this.selectionType !== 'independent' && - parent !== null && - !this.nodes.hasOwnProperty(key) && - this.nodes.hasOwnProperty(parent) - ) { - node.isSelected = this.nodes[parent].isSelected - } else { - node.isSelected = oldNode.isSelected - node.isIndeterminate = oldNode.isIndeterminate - } - - node.isActive = oldNode.isActive - node.isOpen = oldNode.isOpen - - this.nodes[key] = node - - if (children.length && this.selectionType !== 'independent') { - const { isSelected, isIndeterminate } = this.calculateState(key, this.nodes) - - node.isSelected = isSelected - node.isIndeterminate = isIndeterminate - } - - // Don't forget to rebuild cache - if (this.nodes[key].isSelected && (this.selectionType === 'independent' || node.children.length === 0)) this.selectedCache.add(key) - if (this.nodes[key].isActive) this.activeCache.add(key) - if (this.nodes[key].isOpen) this.openCache.add(key) - - this.updateVnodeState(key) - } - }, - calculateState (node: string | number, state: Record) { - const children = state[node].children - const counts = children.reduce((counts: number[], child: string | number) => { - counts[0] += +Boolean(state[child].isSelected) - counts[1] += +Boolean(state[child].isIndeterminate) - - return counts - }, [0, 0]) - - const isSelected = !!children.length && counts[0] === children.length - const isIndeterminate = !isSelected && (counts[0] > 0 || counts[1] > 0) - - return { - isSelected, - isIndeterminate, - } - }, - emitOpen () { - this.emitNodeCache('update:open', this.openCache) - }, - emitSelected () { - this.emitNodeCache('input', this.selectedCache) - }, - emitActive () { - this.emitNodeCache('update:active', this.activeCache) - }, - emitNodeCache (event: string, cache: NodeCache) { - this.$emit(event, this.returnObject ? [...cache].map(key => this.nodes[key].item) : [...cache]) - }, - handleNodeCacheWatcher (value: any[], cache: NodeCache, updateFn: Function, emitFn: Function) { - value = this.returnObject ? value.map(v => getObjectValueByPath(v, this.itemKey)) : value - const old = [...cache] - if (deepEqual(old, value)) return - - old.forEach(key => updateFn(key, false)) - value.forEach(key => updateFn(key, true)) - - emitFn() - }, - getDescendants (key: string | number, descendants: NodeArray = []) { - const children = this.nodes[key].children - - descendants.push(...children) - - for (let i = 0; i < children.length; i++) { - descendants = this.getDescendants(children[i], descendants) - } - - return descendants - }, - getParents (key: string | number) { - let parent = this.nodes[key].parent - - const parents = [] - while (parent !== null) { - parents.push(parent) - parent = this.nodes[parent].parent - } - - return parents - }, - register (node: VTreeviewNodeInstance) { - const key = getObjectValueByPath(node.item, this.itemKey) - this.nodes[key].vnode = node - - this.updateVnodeState(key) - }, - unregister (node: VTreeviewNodeInstance) { - const key = getObjectValueByPath(node.item, this.itemKey) - if (this.nodes[key]) this.nodes[key].vnode = null - }, - isParent (key: string | number) { - return this.nodes[key].children && this.nodes[key].children.length - }, - updateActive (key: string | number, isActive: boolean) { - if (!this.nodes.hasOwnProperty(key)) return - - if (!this.multipleActive) { - this.activeCache.forEach(active => { - this.nodes[active].isActive = false - this.updateVnodeState(active) - this.activeCache.delete(active) - }) - } - - const node = this.nodes[key] - if (!node) return - - if (isActive) this.activeCache.add(key) - else this.activeCache.delete(key) - - node.isActive = isActive - - this.updateVnodeState(key) - }, - updateSelected (key: string | number, isSelected: boolean, isForced = false) { - if (!this.nodes.hasOwnProperty(key)) return - - const changed = new Map() - - if (this.selectionType !== 'independent') { - for (const descendant of this.getDescendants(key)) { - if (!getObjectValueByPath(this.nodes[descendant].item, this.itemDisabled) || isForced) { - this.nodes[descendant].isSelected = isSelected - this.nodes[descendant].isIndeterminate = false - changed.set(descendant, isSelected) - } - } - - const calculated = this.calculateState(key, this.nodes) - this.nodes[key].isSelected = isSelected - this.nodes[key].isIndeterminate = calculated.isIndeterminate - changed.set(key, isSelected) - - for (const parent of this.getParents(key)) { - const calculated = this.calculateState(parent, this.nodes) - this.nodes[parent].isSelected = calculated.isSelected - this.nodes[parent].isIndeterminate = calculated.isIndeterminate - changed.set(parent, calculated.isSelected) - } - } else { - this.nodes[key].isSelected = isSelected - this.nodes[key].isIndeterminate = false - changed.set(key, isSelected) - } - - for (const [key, value] of changed.entries()) { - this.updateVnodeState(key) - - if (this.selectionType === 'leaf' && this.isParent(key)) continue - - value === true ? this.selectedCache.add(key) : this.selectedCache.delete(key) - } - }, - updateOpen (key: string | number, isOpen: boolean) { - if (!this.nodes.hasOwnProperty(key)) return - - const node = this.nodes[key] - const children = getObjectValueByPath(node.item, this.itemChildren) - - if (children && !children.length && node.vnode && !node.vnode.hasLoaded) { - node.vnode.checkChildren().then(() => this.updateOpen(key, isOpen)) - } else if (children && children.length) { - node.isOpen = isOpen - - node.isOpen ? this.openCache.add(key) : this.openCache.delete(key) - - this.updateVnodeState(key) - } - }, - updateVnodeState (key: string | number) { - const node = this.nodes[key] - - if (node && node.vnode) { - node.vnode.isSelected = node.isSelected - node.vnode.isIndeterminate = node.isIndeterminate - node.vnode.isActive = node.isActive - node.vnode.isOpen = node.isOpen - } - }, - isExcluded (key: string | number) { - return !!this.search && this.excludedItems.has(key) - }, - }, - - render (h): VNode { - const children: VNodeChildrenArrayContents = this.items.length - ? this.items.filter(item => { - return !this.isExcluded(getObjectValueByPath(item, this.itemKey)) - }).map(item => { - const genChild = VTreeviewNode.options.methods.genChild.bind(this) - - return genChild(item, this.disabled || getObjectValueByPath(item, this.itemDisabled)) - }) - /* istanbul ignore next */ - : this.$slots.default! // TODO: remove type annotation with TS 3.2 - - return h('div', { - staticClass: 'v-treeview', - class: { - 'v-treeview--hoverable': this.hoverable, - 'v-treeview--dense': this.dense, - ...this.themeClasses, - }, - }, children) - }, -}) diff --git a/packages/vuetify/src/components/VTreeview/VTreeviewNode.ts b/packages/vuetify/src/components/VTreeview/VTreeviewNode.ts deleted file mode 100644 index a87da474c94..00000000000 --- a/packages/vuetify/src/components/VTreeview/VTreeviewNode.ts +++ /dev/null @@ -1,376 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// Components -import { VExpandTransition } from '../transitions' -import { VIcon } from '../VIcon' -import VTreeview from './VTreeview' - -// Mixins -import { inject as RegistrableInject } from '../../mixins/registrable' -import Colorable from '../../mixins/colorable' - -// Utils -import mixins, { ExtractVue } from '../../util/mixins' -import { getObjectValueByPath, createRange } from '../../util/helpers' - -// Types -import { VNode, VNodeChildren, PropType } from 'vue' -import { PropValidator } from 'vue/types/options' - -type VTreeViewInstance = InstanceType - -const baseMixins = mixins( - Colorable, - RegistrableInject('treeview') -) - -interface options extends ExtractVue { - treeview: VTreeViewInstance -} - -export const VTreeviewNodeProps = { - activatable: Boolean, - activeClass: { - type: String, - default: 'v-treeview-node--active', - }, - color: { - type: String, - default: 'primary', - }, - disablePerNode: Boolean, - expandIcon: { - type: String, - default: '$subgroup', - }, - indeterminateIcon: { - type: String, - default: '$checkboxIndeterminate', - }, - itemChildren: { - type: String, - default: 'children', - }, - itemDisabled: { - type: String, - default: 'disabled', - }, - itemKey: { - type: String, - default: 'id', - }, - itemText: { - type: String, - default: 'name', - }, - loadChildren: Function as PropType<(item: any) => Promise>, - loadingIcon: { - type: String, - default: '$loading', - }, - offIcon: { - type: String, - default: '$checkboxOff', - }, - onIcon: { - type: String, - default: '$checkboxOn', - }, - openOnClick: Boolean, - rounded: Boolean, - selectable: Boolean, - selectedColor: { - type: String, - default: 'accent', - }, - shaped: Boolean, - transition: Boolean, - selectionType: { - type: String as PropType<'leaf' | 'independent'>, - default: 'leaf', - validator: (v: string) => ['leaf', 'independent'].includes(v), - }, -} - -/* @vue/component */ -const VTreeviewNode = baseMixins.extend().extend({ - name: 'v-treeview-node', - - inject: { - treeview: { - default: null, - }, - }, - - props: { - level: Number, - item: { - type: Object, - default: () => null, - } as PropValidator | null>, - parentIsDisabled: Boolean, - ...VTreeviewNodeProps, - }, - - data: () => ({ - hasLoaded: false, - isActive: false, // Node is selected (row) - isIndeterminate: false, // Node has at least one selected child - isLoading: false, - isOpen: false, // Node is open/expanded - isSelected: false, // Node is selected (checkbox) - }), - - computed: { - disabled (): boolean { - return ( - getObjectValueByPath(this.item, this.itemDisabled) || - (!this.disablePerNode && (this.parentIsDisabled && this.selectionType === 'leaf')) - ) - }, - key (): string { - return getObjectValueByPath(this.item, this.itemKey) - }, - children (): any[] | null { - const children = getObjectValueByPath(this.item, this.itemChildren) - return children && children.filter((child: any) => !this.treeview.isExcluded(getObjectValueByPath(child, this.itemKey))) - }, - text (): string { - return getObjectValueByPath(this.item, this.itemText) - }, - scopedProps (): object { - return { - item: this.item, - leaf: !this.children, - selected: this.isSelected, - indeterminate: this.isIndeterminate, - active: this.isActive, - open: this.isOpen, - } - }, - computedIcon (): string { - if (this.isIndeterminate) return this.indeterminateIcon - else if (this.isSelected) return this.onIcon - else return this.offIcon - }, - hasChildren (): boolean { - return !!this.children && (!!this.children.length || !!this.loadChildren) - }, - }, - - created () { - this.treeview.register(this) - }, - - beforeDestroy () { - this.treeview.unregister(this) - }, - - methods: { - checkChildren (): Promise { - return new Promise(resolve => { - // TODO: Potential issue with always trying - // to load children if response is empty? - if (!this.children || this.children.length || !this.loadChildren || this.hasLoaded) return resolve() - - this.isLoading = true - resolve(this.loadChildren(this.item)) - }).then(() => { - this.isLoading = false - this.hasLoaded = true - }) - }, - open () { - this.isOpen = !this.isOpen - this.treeview.updateOpen(this.key, this.isOpen) - this.treeview.emitOpen() - }, - genLabel () { - const children = [] - - if (this.$scopedSlots.label) children.push(this.$scopedSlots.label(this.scopedProps)) - else children.push(this.text) - - return this.$createElement('div', { - slot: 'label', - staticClass: 'v-treeview-node__label', - }, children) - }, - genPrependSlot () { - if (!this.$scopedSlots.prepend) return null - - return this.$createElement('div', { - staticClass: 'v-treeview-node__prepend', - }, this.$scopedSlots.prepend(this.scopedProps)) - }, - genAppendSlot () { - if (!this.$scopedSlots.append) return null - - return this.$createElement('div', { - staticClass: 'v-treeview-node__append', - }, this.$scopedSlots.append(this.scopedProps)) - }, - genContent () { - const children = [ - this.genPrependSlot(), - this.genLabel(), - this.genAppendSlot(), - ] - - return this.$createElement('div', { - staticClass: 'v-treeview-node__content', - }, children) - }, - genToggle () { - return this.$createElement(VIcon, { - staticClass: 'v-treeview-node__toggle', - class: { - 'v-treeview-node__toggle--open': this.isOpen, - 'v-treeview-node__toggle--loading': this.isLoading, - }, - slot: 'prepend', - on: { - click: (e: MouseEvent) => { - e.stopPropagation() - - if (this.isLoading) return - - this.checkChildren().then(() => this.open()) - }, - }, - }, [this.isLoading ? this.loadingIcon : this.expandIcon]) - }, - genCheckbox () { - return this.$createElement(VIcon, { - staticClass: 'v-treeview-node__checkbox', - props: { - color: this.isSelected || this.isIndeterminate ? this.selectedColor : undefined, - disabled: this.disabled, - }, - on: { - click: (e: MouseEvent) => { - e.stopPropagation() - - if (this.isLoading) return - - this.checkChildren().then(() => { - // We nextTick here so that items watch in VTreeview has a chance to run first - this.$nextTick(() => { - this.isSelected = !this.isSelected - this.isIndeterminate = false - - this.treeview.updateSelected(this.key, this.isSelected) - this.treeview.emitSelected() - }) - }) - }, - }, - }, [this.computedIcon]) - }, - genLevel (level: number) { - return createRange(level).map(() => this.$createElement('div', { - staticClass: 'v-treeview-node__level', - })) - }, - genNode () { - const children = [this.genContent()] - - if (this.selectable) children.unshift(this.genCheckbox()) - - if (this.hasChildren) { - children.unshift(this.genToggle()) - } else { - children.unshift(...this.genLevel(1)) - } - - children.unshift(...this.genLevel(this.level)) - - return this.$createElement('div', this.setTextColor(this.isActive && this.color, { - staticClass: 'v-treeview-node__root', - class: { - [this.activeClass]: this.isActive, - }, - on: { - click: () => { - if (this.openOnClick && this.hasChildren) { - this.checkChildren().then(this.open) - } else if (this.activatable && !this.disabled) { - this.isActive = !this.isActive - this.treeview.updateActive(this.key, this.isActive) - this.treeview.emitActive() - } - }, - }, - }), children) - }, - genChild (item: any, parentIsDisabled: boolean) { - return this.$createElement(VTreeviewNode, { - key: getObjectValueByPath(item, this.itemKey), - props: { - activatable: this.activatable, - activeClass: this.activeClass, - item, - selectable: this.selectable, - selectedColor: this.selectedColor, - color: this.color, - disablePerNode: this.disablePerNode, - expandIcon: this.expandIcon, - indeterminateIcon: this.indeterminateIcon, - offIcon: this.offIcon, - onIcon: this.onIcon, - loadingIcon: this.loadingIcon, - itemKey: this.itemKey, - itemText: this.itemText, - itemDisabled: this.itemDisabled, - itemChildren: this.itemChildren, - loadChildren: this.loadChildren, - transition: this.transition, - openOnClick: this.openOnClick, - rounded: this.rounded, - shaped: this.shaped, - level: this.level + 1, - selectionType: this.selectionType, - parentIsDisabled, - }, - scopedSlots: this.$scopedSlots, - }) - }, - genChildrenWrapper () { - if (!this.isOpen || !this.children) return null - - const children = [this.children.map(c => this.genChild(c, this.disabled))] - - return this.$createElement('div', { - staticClass: 'v-treeview-node__children', - }, children) - }, - genTransition () { - return this.$createElement(VExpandTransition, [this.genChildrenWrapper()]) - }, - }, - - render (h): VNode { - const children: VNodeChildren = [this.genNode()] - - if (this.transition) children.push(this.genTransition()) - else children.push(this.genChildrenWrapper()) - - return h('div', { - staticClass: 'v-treeview-node', - class: { - 'v-treeview-node--leaf': !this.hasChildren, - 'v-treeview-node--click': this.openOnClick, - 'v-treeview-node--disabled': this.disabled, - 'v-treeview-node--rounded': this.rounded, - 'v-treeview-node--shaped': this.shaped, - 'v-treeview-node--selected': this.isSelected, - }, - attrs: { - 'aria-expanded': String(this.isOpen), - }, - }, children) - }, -}) - -export default VTreeviewNode diff --git a/packages/vuetify/src/components/VTreeview/__tests__/VTreeview.spec.ts b/packages/vuetify/src/components/VTreeview/__tests__/VTreeview.spec.ts deleted file mode 100644 index c06d247399f..00000000000 --- a/packages/vuetify/src/components/VTreeview/__tests__/VTreeview.spec.ts +++ /dev/null @@ -1,881 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// import Vue from 'vue' -import { - mount, - Wrapper, - MountOptions, -} from '@vue/test-utils' -// import VTreeview from '../VTreeview' -// import { ExtractVue } from '../../../util/mixins' -// import { wait } from '../../../../test' - -const singleRootTwoChildren = [ - { id: 0, name: 'Root', children: [{ id: 1, name: 'Child' }, { id: 2, name: 'Child 2' }] }, -] - -const threeLevels = [ - { id: 0, name: 'Root', children: [{ id: 1, name: 'Child', children: [{ id: 2, name: 'Grandchild' }] }, { id: 3, name: 'Child' }] }, -] - -describe.skip('VTreeView.ts', () => { // eslint-disable-line max-statements - type Instance = ExtractVue - let mountFunction: (options?: MountOptions) => Wrapper - beforeEach(() => { - mountFunction = (options?: MountOptions) => { - return mount(VTreeview, { - // https://github.com/vuejs/vue-test-utils/issues/1130 - sync: false, - ...options, - }) - } - }) - - it('should render items', async () => { - const wrapper = mountFunction({ - propsData: { - items: singleRootTwoChildren, - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should render items in dense mode', async () => { - const wrapper = mountFunction({ - propsData: { - items: singleRootTwoChildren, - dense: true, - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - }) - - // TODO: this fails without sync, nextTick doesn't help - // https://github.com/vuejs/vue-test-utils/issues/1130 - it.skip('should select all leaf nodes', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - selectable: true, - }, - }) - - const fn = jest.fn() - wrapper.vm.$on('input', fn) - - wrapper.find('.v-treeview-node__checkbox').trigger('click') - await wrapper.vm.$nextTick() - - expect(fn).toHaveBeenCalledTimes(1) - expect(fn).toHaveBeenCalledWith([3, 2]) - expect(wrapper.html()).toMatchSnapshot() - }) - - // TODO: this fails without sync, nextTick doesn't help - // https://github.com/vuejs/vue-test-utils/issues/1130 - it.skip('should select only leaf nodes', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - selectable: true, - }, - }) - - const fn = jest.fn() - wrapper.vm.$on('input', fn) - - wrapper.find('.v-treeview-node__toggle').trigger('click') - await wrapper.vm.$nextTick() - - wrapper.findAll('.v-treeview-node__checkbox').at(2).trigger('click') - await wrapper.vm.$nextTick() - - expect(fn).toHaveBeenCalledTimes(1) - expect(fn).toHaveBeenCalledWith([3]) - expect(wrapper.html()).toMatchSnapshot() - }) - - // TODO: this fails without sync, nextTick doesn't help - // https://github.com/vuejs/vue-test-utils/issues/1130 - it.skip('should select only root node', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - selectable: true, - selectionType: 'independent', - }, - }) - - const fn = jest.fn() - wrapper.vm.$on('input', fn) - - wrapper.find('.v-treeview-node__checkbox').trigger('click') - await wrapper.vm.$nextTick() - - expect(fn).toHaveBeenCalledTimes(1) - expect(fn).toHaveBeenCalledWith([0]) - expect(wrapper.html()).toMatchSnapshot() - }) - - // TODO: fails with TS 3.9 - it.skip('should load children when expanding', async () => { - const loadChildren = item => { - item.children.push({ id: 1, name: 'Child' }) - } - - const wrapper = mountFunction({ - propsData: { - items: [{ id: 0, name: 'Root', children: [] }], - loadChildren, - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.find('.v-treeview-node__toggle').trigger('click') - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - expect(`[Vue warn]: Error in created hook: "TypeError: Cannot set property 'vnode' of undefined"`).toHaveBeenWarned() - expect(`TypeError: Cannot set property 'vnode' of undefined`).toHaveBeenWarned() - }) - - it('should load children when selecting, but not render', async () => { - const loadChildren = item => { - item.children = [{ id: 1, name: 'Child' }] - } - - const wrapper = mountFunction({ - propsData: { - items: [{ id: 0, name: 'Root', children: [] }], - selectable: true, - loadChildren, - }, - }) - - const fn = jest.fn() - wrapper.vm.$on('input', fn) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.find('.v-treeview-node__checkbox').trigger('click') - await wait() - - expect(fn).toHaveBeenCalledTimes(1) - expect(fn).toHaveBeenCalledWith([0]) - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should emit active node when clicking on it', async () => { - const wrapper = mountFunction({ - propsData: { - items: [{ id: 0, name: 'Root' }, { id: 1, name: 'Root' }], - activatable: true, - }, - }) - - const fn = jest.fn() - wrapper.vm.$on('update:active', fn) - - wrapper.find('.v-treeview-node__root').trigger('click') - await wrapper.vm.$nextTick() - - expect(fn).toHaveBeenCalledTimes(1) - expect(fn).toHaveBeenCalledWith([0]) - - wrapper.find('.v-treeview-node__root').trigger('click') - await wrapper.vm.$nextTick() - - expect(fn).toHaveBeenCalledWith([]) - }) - - it('should allow multiple active nodes with prop multipleActive', async () => { - const wrapper = mountFunction({ - propsData: { - items: [{ id: 0, name: 'Root' }, { id: 1, name: 'Root' }], - multipleActive: true, - activatable: true, - }, - }) - - const fn = jest.fn() - wrapper.vm.$on('update:active', fn) - - wrapper.findAll('.v-treeview-node__root').wrappers.forEach(vm => vm.trigger('click')) - await wrapper.vm.$nextTick() - - expect(fn).toHaveBeenCalledTimes(2) - expect(fn).toHaveBeenLastCalledWith([0, 1]) - }) - - // TODO: fails with TS 3.9 - it.skip('should update selection when selected prop changes', async () => { - const wrapper = mountFunction({ - propsData: { - items: [{ id: 0, name: 'Root', children: [{ id: 1, name: 'Child' }] }], - value: [], - selectable: true, - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.find('.v-treeview-node__toggle').trigger('click') - wrapper.setProps({ value: [1] }) - await wrapper.vm.$nextTick() - - expect(wrapper.findAll('.v-treeview-node')).toHaveLength(2) - expect(wrapper.findAll('.v-treeview-node--selected')).toHaveLength(2) - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ value: [] }) - await wrapper.vm.$nextTick() - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should open all children when using open-all prop', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - openAll: true, - }, - }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should open/close all children when using updateAll', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - }, - }) - - const updateOpen = jest.fn() - wrapper.vm.$on('update:open', updateOpen) - - wrapper.vm.updateAll(true) - expect(updateOpen).toHaveBeenCalledTimes(1) - expect(updateOpen).toHaveBeenCalledWith([0, 1]) - - wrapper.vm.updateAll(false) - expect(updateOpen).toHaveBeenCalledTimes(2) - expect(updateOpen).toHaveBeenCalledWith([]) - }) - - it('should react to open changes', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - open: [1], - }, - }) - - const fn = jest.fn() - - wrapper.vm.$on('update:open', fn) - wrapper.setProps({ open: [0, 1] }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ open: [0] }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ open: [0, 1] }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - - expect(fn).toHaveBeenCalledWith([0, 1]) - - // Should not update open values that do not exist in the tree - wrapper.setProps({ open: [7] }) - - await wrapper.vm.$nextTick() - expect(wrapper.html()).toMatchSnapshot() - - expect(fn).toHaveBeenCalledWith([]) - }) - - it('should update selected and active on created', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - active: [2], - value: [1], - }, - }) - - // TODO: I can not find away in avoriaz - // to catch events being emitted from a - // lifecycle hook. We should not assert - // internal state. - expect([...wrapper.vm.activeCache]).toEqual([2]) - expect([...wrapper.vm.selectedCache]).toEqual([2]) - }) - - it('should react to changes for active items', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - active: [2], - }, - }) - - const active = jest.fn() - wrapper.vm.$on('update:active', active) - - wrapper.setProps({ active: [] }) - await wrapper.vm.$nextTick() - expect(active).toHaveBeenCalledWith([]) - - // without multiple-active, it will use last value in array - wrapper.setProps({ active: [1, 3] }) - await wrapper.vm.$nextTick() - expect(active).toHaveBeenCalledWith([3]) - - wrapper.setProps({ multipleActive: true, active: [1, 3] }) - await wrapper.vm.$nextTick() - expect(active).toHaveBeenCalledWith([1, 3]) - - // 7 does not exist, we get nothing back - wrapper.setProps({ active: [7] }) - await wrapper.vm.$nextTick() - expect(active).toHaveBeenCalledWith([]) - - wrapper.setProps({ active: [0], items: singleRootTwoChildren }) - await wrapper.vm.$nextTick() - expect(active).toHaveBeenCalledWith([0]) - }) - - it('should react to changes for selected items', async () => { - const wrapper = mountFunction({ - propsData: { - items: threeLevels, - value: [2], - }, - }) - - const value = jest.fn() - wrapper.vm.$on('input', value) - - wrapper.setProps({ value: [] }) - await wrapper.vm.$nextTick() - expect(value).toHaveBeenCalledWith([]) - - wrapper.setProps({ value: [3] }) - await wrapper.vm.$nextTick() - expect(value).toHaveBeenCalledWith([3]) - - // 7 does not exist, we get nothing back - wrapper.setProps({ value: [7] }) - await wrapper.vm.$nextTick() - expect(value).toHaveBeenCalledWith([]) - - wrapper.setProps({ value: [0] }) - await wrapper.vm.$nextTick() - expect(value).toHaveBeenLastCalledWith([3, 2]) - }) - - it('should accept string value for id', async () => { - const wrapper = mountFunction({ - propsData: { itemKey: 'name' }, - }) - - wrapper.setProps({ items: [{ name: 'Foobar' }] }) - - await wrapper.vm.$nextTick() - - expect(wrapper.vm.nodes.Foobar).toBeTruthy() - - wrapper.setProps({ value: ['Foobar'] }) - - await wrapper.vm.$nextTick() - }) - - it('should warn developer when using non-scoped slots', () => { - mountFunction({ - slots: { - prepend: [{ render: h => h('div') }], - append: [{ render: h => h('div') }], - }, - }) - - expect('[Vuetify] The prepend and append slots require a slot-scope attribute').toHaveBeenTipped() - }) - - it('should not show expand icon when children is empty', () => { - const wrapper = mountFunction({ - propsData: { - items: [ - { - text: 'root', - children: [], - }, - ], - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - expect(wrapper.findAll('.v-treeview-node__toggle')).toHaveLength(0) - }) - - it('should show expand icon when children is empty and load-children prop used', () => { - const wrapper = mountFunction({ - propsData: { - loadChildren: () => {}, - items: [ - { - text: 'root', - children: [], - }, - ], - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - expect(wrapper.findAll('.v-treeview-node__toggle')).toHaveLength(1) - }) - - it('should recalculate tree when loading async children using custom key', async () => { - const items = [ - { - id: 1, - name: 'One', - __children: [], - }, - ] - - const wrapper = mountFunction({ - propsData: { - items, - itemChildren: '__children', - loadChildren: () => { - const newItems = [...items] - items[0].__children.push({ id: 2, name: 'Two' }) - wrapper.setProps({ - items: newItems, - }) - }, - }, - }) - - wrapper.find('.v-treeview-node__toggle').trigger('click') - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should remove old nodes', async () => { - const wrapper = mountFunction({ - propsData: { - items: [ - { - id: 1, - name: 'one', - }, - { - id: 2, - name: 'two', - }, - ], - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ - items: [ - { - id: 1, - name: 'one', - }, - ], - }) - - await wrapper.vm.$nextTick() - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ - items: [ - { - id: 1, - name: 'one', - }, - { - id: 3, - name: 'three', - }, - ], - }) - - await wrapper.vm.$nextTick() - expect(wrapper.html()).toMatchSnapshot() - - expect(Object.keys(wrapper.vm.nodes)).toHaveLength(2) - }) - - it('should filter items', async () => { - const wrapper = mountFunction({ - propsData: { - items: [ - { - id: 1, - name: 'one', - }, - { - id: 2, - name: 'two', - }, - ], - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ - search: 'two', - }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should filter items using custom item filter', async () => { - const wrapper = mountFunction({ - propsData: { - filter: (item, search, textKey) => item.special === search, - items: [ - { - id: 1, - name: 'one', - special: 'yes', - }, - { - id: 2, - name: 'two', - special: 'no', - }, - ], - search: 'NO', - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ - search: 'yes', - }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - }) - - // TODO: fails with TS 3.9 - it.skip('should emit objects when return-object prop is used', async () => { - const items = [{ id: 0, name: 'Root', children: [{ id: 1, name: 'Child' }] }] - - const wrapper = mountFunction({ - propsData: { - items, - activatable: true, - selectable: true, - returnObject: true, - }, - }) - - const active = jest.fn() - wrapper.vm.$on('update:active', active) - const selected = jest.fn() - wrapper.vm.$on('input', selected) - const open = jest.fn() - wrapper.vm.$on('update:open', open) - - wrapper.find('.v-treeview-node__root').trigger('click') - await wrapper.vm.$nextTick() - - expect(active).toHaveBeenCalledTimes(1) - expect(active).toHaveBeenCalledWith([items[0]]) - - wrapper.find('.v-treeview-node__checkbox').trigger('click') - await wrapper.vm.$nextTick() - - expect(selected).toHaveBeenCalledTimes(1) - expect(selected).toHaveBeenCalledWith([items[0].children[0]]) - - wrapper.find('.v-treeview-node__toggle').trigger('click') - await wrapper.vm.$nextTick() - - expect(open).toHaveBeenCalledTimes(1) - expect(open).toHaveBeenCalledWith([items[0]]) - }) - - it('should handle replacing items with new array of equal length', async () => { - const wrapper = mountFunction({ - propsData: { - items: [ - { - id: 1, - name: 'one', - }, - { - id: 2, - name: 'two', - }, - ], - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.setProps({ - items: [ - { - id: 1, - name: 'one', - }, - { - id: 3, - name: 'three', - }, - ], - }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - }) - - // https://github.com/vuetifyjs/vuetify/issues/8709 - it('should handle initial active/open/selected values when using return-object prop', async () => { - const one = { id: '1', name: 'One' } - const three = { id: '3', name: 'Three' } - const two = { id: '2', name: 'Two', children: [three] } - - const wrapper = mountFunction({ - propsData: { - returnObject: true, - selectable: true, - activatable: true, - items: [one, two], - value: [one], - open: [two], - active: [three], - }, - }) - - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should set correct state when updating nodes', async () => { - const children = [ - { id: 2, name: 'Bar' }, - { id: 3, name: 'Fizz' }, - { id: 4, name: 'Buzz' }, - ] - const item = { - id: 1, - name: 'Foo', - } - const wrapper = mountFunction({ - propsData: { - items: [{ ...item, children }], - value: [4], - }, - }) - - wrapper.setProps({ - items: [{ - ...item, - children: [ - ...children, - { id: 5, name: 'FizzBuzz' }, - ], - }], - }) - - await wrapper.vm.$nextTick() - - expect(wrapper.vm.nodes['5'].isIndeterminate).toBeUndefined() - }) - - // https://github.com/vuetifyjs/vuetify/issues/8720 - it('should set correct selection when updating items', async () => { - const items = [{ - id: 1, - name: 'Foo', - children: [ - { id: 2, name: 'Bar' }, - { id: 3, name: 'Fizz' }, - { id: 4, name: 'Buzz' }, - ], - }] - - const input = jest.fn() - - const wrapper = mountFunction({ - propsData: { - items, - value: [2, 3, 4], - selectionType: 'leaf', - selectable: true, - }, - listeners: { - input, - }, - }) - - wrapper.setProps({ - items: [{ - id: 1, - name: 'Foo', - children: [ - { id: 2, name: 'Bar' }, - { id: 3, name: 'Fizz' }, - { id: 4, name: 'Buzz' }, - ], - }], - }) - - await wrapper.vm.$nextTick() - - expect(input).not.toHaveBeenCalled() - }) - - // https://github.com/vuetifyjs/vuetify/issues/8244 - // TODO: fails with TS 3.9 - it.skip('should not touch disabled items when selecting', async () => { - const items = [{ - id: 1, - name: 'Foo', - children: [ - { id: 2, name: 'Bar', disabled: true }, - { id: 3, name: 'Fizz' }, - { id: 4, name: 'Buzz' }, - ], - }] - - const input = jest.fn() - - const wrapper = mountFunction({ - propsData: { - items, - value: [], - selectionType: 'leaf', - selectable: true, - }, - listeners: { - input, - }, - }) - - wrapper.find('.v-treeview-node__checkbox').trigger('click') - await wrapper.vm.$nextTick() - - expect(input).toHaveBeenLastCalledWith([3, 4]) - - wrapper.setProps({ - value: [2, 3, 4], - items: [{ - id: 1, - name: 'Foo', - children: [ - { id: 2, name: 'Bar', disabled: true }, - { id: 3, name: 'Fizz' }, - { id: 4, name: 'Buzz' }, - ], - }], - }) - await wrapper.vm.$nextTick() - - wrapper.find('.v-treeview-node__checkbox').trigger('click') - await wrapper.vm.$nextTick() - - expect(input).toHaveBeenLastCalledWith([2]) - }) - - // https://github.com/vuetifyjs/vuetify/issues/10990 - // https://github.com/vuetifyjs/vuetify/issues/10770 - // TODO: fails with TS 3.9 - it.skip('should not disable children of disabled parent when in independent mode', async () => { - const items = [{ - id: 1, - name: 'Foo', - disabled: true, - children: [ - { id: 2, name: 'Bar' }, - { id: 3, name: 'Fizz', disabled: true }, - { id: 4, name: 'Buzz' }, - ], - }] - - const input = jest.fn() - - const wrapper = mountFunction({ - propsData: { - items, - value: [], - open: [1], - selectionType: 'independent', - selectable: true, - }, - listeners: { - input, - }, - }) - - await wrapper.vm.$nextTick() - - wrapper.findAll('.v-treeview-node__checkbox').at(1).trigger('click') - await wrapper.vm.$nextTick() - - expect(input).toHaveBeenLastCalledWith([2]) - - wrapper.findAll('.v-treeview-node__checkbox').at(2).trigger('click') - await wrapper.vm.$nextTick() - - expect(input).toHaveBeenCalledTimes(1) - }) - - // https://github.com/vuetifyjs/vuetify/issues/9693 - // TODO: fails with TS 3.9 - it.skip('should emit opened node when using open-on-click and load-children', async () => { - const open = jest.fn() - - const wrapper = mountFunction({ - propsData: { - items: [{ id: 0, name: 'Root', children: [] }], - loadChildren: () => wrapper.setProps({ - items: [{ id: 0, name: 'Root', children: [{ id: 1, name: 'Child' }] }], - }), - openOnClick: true, - }, - listeners: { - 'update:open': open, - }, - }) - - expect(wrapper.html()).toMatchSnapshot() - - wrapper.find('.v-treeview-node__root').trigger('click') - await wrapper.vm.$nextTick() - - expect(wrapper.html()).toMatchSnapshot() - expect(open).toHaveBeenLastCalledWith([0]) - }) -}) diff --git a/packages/vuetify/src/components/VTreeview/__tests__/VTreeviewNode.spec.ts b/packages/vuetify/src/components/VTreeview/__tests__/VTreeviewNode.spec.ts deleted file mode 100644 index db36b8cf800..00000000000 --- a/packages/vuetify/src/components/VTreeview/__tests__/VTreeviewNode.spec.ts +++ /dev/null @@ -1,192 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// import Vue from 'vue' -// import VTreeviewNode from '../VTreeviewNode' -import { - mount, - MountOptions, - Wrapper, -} from '@vue/test-utils' - -// Vue.prototype.$vuetify = { -// icons: { -// values: { -// subgroup: 'arrow_drop_down', -// }, -// }, -// } - -const singleRootTwoChildren = { id: 0, name: 'Root', children: [{ id: 1, name: 'Child' }, { id: 2, name: 'Child 2' }] } - -// const vm = new Vue() -// const defaultSlot = () => vm.$createElement('div', 'foobar') - -const Mock = { - name: 'test', - - render: h => h(VTreeviewNode, { - scopedSlots: { - prepend: defaultSlot, - append: defaultSlot, - }, - }), -} - -const MockScopedLabel = { - name: 'test', - - render: h => h(VTreeviewNode, { - props: { - item: singleRootTwoChildren, - }, - scopedSlots: { - label: props => vm.$createElement('div', [props.item.name.toUpperCase()]), - }, - }), -} - -describe.skip('VTreeViewNode.ts', () => { - type Instance = InstanceType - let mountFunction: (options?: MountOptions) => Wrapper - let treeview - - beforeEach(() => { - treeview = { - register: jest.fn(), - unregister: jest.fn(), - isExcluded: () => false, - updateActive: () => {}, - emitActive: () => {}, - updateOpen: () => {}, - emitOpen: () => {}, - } - - mountFunction = (options?: MountOptions) => { - return mount(VTreeviewNode, { - // https://github.com/vuejs/vue-test-utils/issues/1130 - sync: false, - ...options, - }) - } - }) - - it('should return indeterminate icon', async () => { - const wrapper = mountFunction({ - provide: { treeview }, - }) - - expect(wrapper.vm.computedIcon).toBe('$checkboxOff') - - wrapper.setData({ isIndeterminate: true }) - - expect(wrapper.vm.computedIcon).toBe('$checkboxIndeterminate') - }) - - it('should use scoped slots', () => { - const wrapper = mount(Mock, { - // https://github.com/vuejs/vue-test-utils/issues/1130 - sync: false, - provide: { treeview }, - }) - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should generate a transition element', () => { - const wrapper = mountFunction({ - propsData: { transition: true }, - provide: { treeview }, - }) - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should use label slot', () => { - const wrapper = mount(MockScopedLabel, { - // https://github.com/vuejs/vue-test-utils/issues/1130 - sync: false, - provide: { treeview }, - }) - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should render disabled item', () => { - const wrapper = mount({ - name: 'test', - - render: h => h(VTreeviewNode, { - scopedSlots: { - prepend: defaultSlot, - append: defaultSlot, - }, - props: { - item: { ...singleRootTwoChildren, disabled: true }, - }, - }), - }, { - // https://github.com/vuejs/vue-test-utils/issues/1130 - sync: false, - provide: { treeview }, - }) - - expect(wrapper.html()).toMatchSnapshot() - }) - - const singleRootWithEmptyChildrens = { id: 1, name: 'Child', children: [] } - it('should be able to have active children with empty array', () => { - const wrapper = mountFunction({ - provide: { treeview }, - propsData: { - item: singleRootWithEmptyChildrens, - activatable: true, - openOnClick: true, - }, - }) - - expect(wrapper.vm.isActive).toBe(false) - const selectedLeaf = wrapper.find('.v-treeview-node__root') - selectedLeaf.trigger('click') - expect(wrapper.vm.isActive).toBe(true) - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should not be able to have active children with empty array when loadChildren is specified', () => { - const wrapper = mountFunction({ - provide: { treeview }, - propsData: { - item: singleRootWithEmptyChildrens, - activatable: true, - openOnClick: true, - loadChildren: () => {}, - }, - }) - - expect(wrapper.vm.isActive).toBe(false) - const selectedLeaf = wrapper.find('.v-treeview-node__root') - selectedLeaf.trigger('click') - expect(wrapper.vm.isActive).toBe(false) - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should not be able to have active children with empty array when disabled', () => { - const wrapper = mountFunction({ - provide: { treeview }, - propsData: { - item: { ...singleRootWithEmptyChildrens, disabled: true }, - activatable: true, - openOnClick: true, - }, - }) - - expect(wrapper.vm.isActive).toBe(false) - const selectedLeaf = wrapper.find('.v-treeview-node__root') - selectedLeaf.trigger('click') - expect(wrapper.vm.isActive).toBe(false) - - expect(wrapper.html()).toMatchSnapshot() - }) -}) diff --git a/packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeview.spec.ts.snap b/packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeview.spec.ts.snap deleted file mode 100644 index 5b0b4f90253..00000000000 --- a/packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeview.spec.ts.snap +++ /dev/null @@ -1,1058 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`VTreeView.ts should emit opened node when using open-on-click and load-children 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should emit opened node when using open-on-click and load-children 2`] = ` -
- -
-`; - -exports[`VTreeView.ts should filter items 1`] = ` -
- - -
-`; - -exports[`VTreeView.ts should filter items 2`] = ` -
- -
-`; - -exports[`VTreeView.ts should filter items using custom item filter 1`] = ` -
-
-`; - -exports[`VTreeView.ts should filter items using custom item filter 2`] = ` -
- -
-`; - -exports[`VTreeView.ts should handle initial active/open/selected values when using return-object prop 1`] = ` -
- -
-
- - -
-
- Two -
-
-
-
- -
-
-
-`; - -exports[`VTreeView.ts should handle replacing items with new array of equal length 1`] = ` -
- - -
-`; - -exports[`VTreeView.ts should handle replacing items with new array of equal length 2`] = ` -
- - -
-`; - -exports[`VTreeView.ts should load children when expanding 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should load children when expanding 2`] = ` -
- -
-`; - -exports[`VTreeView.ts should load children when selecting, but not render 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should load children when selecting, but not render 2`] = ` -
- -
-`; - -exports[`VTreeView.ts should not show expand icon when children is empty 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should open all children when using open-all prop 1`] = ` -
-
-
- -
-
- Root -
-
-
-
-
-
-
-
- -
-
- Child -
-
-
-
- -
-
- -
-
-
-`; - -exports[`VTreeView.ts should react to open changes 1`] = ` -
-
-
- -
-
- Root -
-
-
-
-
-
-
-
- -
-
- Child -
-
-
-
- -
-
- -
-
-
-`; - -exports[`VTreeView.ts should react to open changes 2`] = ` -
-
-
- -
-
- Root -
-
-
-
- - -
-
-
-`; - -exports[`VTreeView.ts should react to open changes 3`] = ` -
-
-
- -
-
- Root -
-
-
-
-
-
-
-
- -
-
- Child -
-
-
-
- -
-
- -
-
-
-`; - -exports[`VTreeView.ts should react to open changes 4`] = ` -
- -
-`; - -exports[`VTreeView.ts should recalculate tree when loading async children using custom key 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should remove old nodes 1`] = ` -
- - -
-`; - -exports[`VTreeView.ts should remove old nodes 2`] = ` -
- -
-`; - -exports[`VTreeView.ts should remove old nodes 3`] = ` -
- - -
-`; - -exports[`VTreeView.ts should render items 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should render items in dense mode 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should select all leaf nodes 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should select only leaf nodes 1`] = ` -
-
-
- - arrow_drop_down - - - $checkboxIndeterminate - -
-
- Root -
-
-
-
- - -
-
-
-`; - -exports[`VTreeView.ts should select only root node 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should show expand icon when children is empty and load-children prop used 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should update selection when selected prop changes 1`] = ` -
- -
-`; - -exports[`VTreeView.ts should update selection when selected prop changes 2`] = ` -
-
-
- - -
-
- Root -
-
-
-
- -
-
-
-`; - -exports[`VTreeView.ts should update selection when selected prop changes 3`] = ` -
-
-
- - -
-
- Root -
-
-
-
- -
-
-
-`; diff --git a/packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeviewNode.spec.ts.snap b/packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeviewNode.spec.ts.snap deleted file mode 100644 index a79b542a958..00000000000 --- a/packages/vuetify/src/components/VTreeview/__tests__/__snapshots__/VTreeviewNode.spec.ts.snap +++ /dev/null @@ -1,142 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`VTreeViewNode.ts should be able to have active children with empty array 1`] = ` - -`; - -exports[`VTreeViewNode.ts should generate a transition element 1`] = ` - -`; - -exports[`VTreeViewNode.ts should not be able to have active children with empty array when disabled 1`] = ` - -`; - -exports[`VTreeViewNode.ts should not be able to have active children with empty array when loadChildren is specified 1`] = ` - -`; - -exports[`VTreeViewNode.ts should render disabled item 1`] = ` - -`; - -exports[`VTreeViewNode.ts should use label slot 1`] = ` - -`; - -exports[`VTreeViewNode.ts should use scoped slots 1`] = ` - -`; diff --git a/packages/vuetify/src/components/VTreeview/_mixins.sass b/packages/vuetify/src/components/VTreeview/_mixins.sass deleted file mode 100755 index 01a1a25df95..00000000000 --- a/packages/vuetify/src/components/VTreeview/_mixins.sass +++ /dev/null @@ -1,18 +0,0 @@ -@mixin treeview-shaped($size, $margin) - .v-treeview-node__root, - .v-treeview-node__root:before - border-bottom-right-radius: #{$size * .5} !important - border-top-right-radius: #{$size * .5} !important - - .v-treeview-node__root - margin-top: $margin - margin-bottom: $margin - -@mixin treeview-rounded($size, $margin) - .v-treeview-node__root, - .v-treeview-node__root:before - border-radius: #{$size * .5} !important - - .v-treeview-node__root - margin-top: $margin - margin-bottom: $margin diff --git a/packages/vuetify/src/components/VTreeview/_variables.scss b/packages/vuetify/src/components/VTreeview/_variables.scss deleted file mode 100644 index 463c37e3929..00000000000 --- a/packages/vuetify/src/components/VTreeview/_variables.scss +++ /dev/null @@ -1,10 +0,0 @@ -@import '../../styles/styles.sass'; - -$treeview-transition: .2s map-get($transition, 'linear-out-slow-in') !default; -$treeview-label-font-size: inherit !default; -$treeview-node-height: 48px !default; -$treeview-node-height-dense: 40px !default; -$treeview-node-shaped-margin: 8px !default; -$treeview-node-padding: 8px !default; -$treeview-node-margin: 6px !default; -$treeview-node-level-width: 24px !default; diff --git a/packages/vuetify/src/components/VTreeview/index.ts b/packages/vuetify/src/components/VTreeview/index.ts deleted file mode 100644 index eac51942eec..00000000000 --- a/packages/vuetify/src/components/VTreeview/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import VTreeview from './VTreeview' -import VTreeviewNode from './VTreeviewNode' - -export { VTreeview, VTreeviewNode } - -export default { - $_vuetify_subcomponents: { - VTreeview, - VTreeviewNode, - }, -} diff --git a/packages/vuetify/src/components/VTreeview/util/__tests__/filterTreeItems.spec.ts b/packages/vuetify/src/components/VTreeview/util/__tests__/filterTreeItems.spec.ts deleted file mode 100644 index b89d4022404..00000000000 --- a/packages/vuetify/src/components/VTreeview/util/__tests__/filterTreeItems.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// import { filterTreeItem, filterTreeItems } from '../filterTreeItems' - -describe.skip('filterTreeItems.ts', () => { - it('should filter single tree item', () => { - expect(filterTreeItem({ text: 'foo' }, 'foo', 'text')).toBeTruthy() - expect(filterTreeItem({ text: 'foo' }, 'bar', 'text')).toBeFalsy() - expect(filterTreeItem({ text: 'foobar' }, 'foo', 'text')).toBeTruthy() - expect(filterTreeItem({ text: 'FoObAr' }, 'foo', 'text')).toBeTruthy() - expect(filterTreeItem({ text: 'oof' }, 'bar', 'text')).toBeFalsy() - expect(filterTreeItem({ data: 'foo' }, 'foo', 'data')).toBeTruthy() - }) - - it('should filter all tree items', () => { - expect(filterTreeItems(filterTreeItem, { text: 'foo' }, 'foo', 'id', 'text', 'children', new Set())).toBeTruthy() - expect(filterTreeItems(filterTreeItem, { text: 'bar' }, 'foo', 'id', 'text', 'children', new Set())).toBeFalsy() - expect(filterTreeItems(filterTreeItem, { text: 'bar', children: [{ text: 'foo' }] }, 'foo', 'id', 'text', 'children', new Set())).toBeTruthy() - expect(filterTreeItems(filterTreeItem, { text: 'foo', children: [{ text: 'foo' }] }, 'foo', 'id', 'text', 'children', new Set())).toBeTruthy() - expect(filterTreeItems(filterTreeItem, { text: 'bar', children: [{ text: 'baz' }] }, 'foo', 'id', 'text', 'children', new Set())).toBeFalsy() - }) -}) diff --git a/packages/vuetify/src/components/VTreeview/util/filterTreeItems.ts b/packages/vuetify/src/components/VTreeview/util/filterTreeItems.ts deleted file mode 100755 index 946940d498e..00000000000 --- a/packages/vuetify/src/components/VTreeview/util/filterTreeItems.ts +++ /dev/null @@ -1,42 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -import { getObjectValueByPath } from '../../../util/helpers' -import { TreeviewItemFunction } from 'vuetify/types' - -export function filterTreeItem (item: object, search: string, textKey: string): boolean { - const text = getObjectValueByPath(item, textKey) - - return text.toLocaleLowerCase().indexOf(search.toLocaleLowerCase()) > -1 -} - -export function filterTreeItems ( - filter: TreeviewItemFunction, - item: any, - search: string, - idKey: string, - textKey: string, - childrenKey: string, - excluded: Set -): boolean { - if (filter(item, search, textKey)) { - return true - } - - const children = getObjectValueByPath(item, childrenKey) - - if (children) { - let match = false - for (let i = 0; i < children.length; i++) { - if (filterTreeItems(filter, children[i], search, idKey, textKey, childrenKey, excluded)) { - match = true - } - } - - if (match) return true - } - - excluded.add(getObjectValueByPath(item, idKey)) - - return false -} diff --git a/packages/vuetify/src/components/index.ts b/packages/vuetify/src/components/index.ts index 9460f5197cb..d8173d050ce 100644 --- a/packages/vuetify/src/components/index.ts +++ b/packages/vuetify/src/components/index.ts @@ -19,7 +19,6 @@ export * from './VChip' export * from './VChipGroup' export * from './VCode' export * from './VColorPicker' -// export * from './VContent' export * from './VCombobox' export * from './VConfirmEdit' export * from './VCounter' From e821d5d8aabf21a7e90a0802e34f43ce181f78e3 Mon Sep 17 00:00:00 2001 From: Kael Date: Tue, 27 Aug 2024 17:35:21 +1000 Subject: [PATCH 057/190] fix(VAvatar): remove default border fixes #20345 --- packages/vuetify/src/components/VAvatar/_variables.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/src/components/VAvatar/_variables.scss b/packages/vuetify/src/components/VAvatar/_variables.scss index 16d57130f51..9f0ad431234 100644 --- a/packages/vuetify/src/components/VAvatar/_variables.scss +++ b/packages/vuetify/src/components/VAvatar/_variables.scss @@ -10,7 +10,7 @@ $avatar-border-color: settings.$border-color-root !default; $avatar-border-radius: map.get(settings.$rounded, 0) !default; $avatar-border-style: settings.$border-style-root !default; $avatar-border-thin-width: thin !default; -$avatar-border-width: thin !default; +$avatar-border-width: 0 !default; $avatar-color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)) !default; $avatar-density: ('default': 0, 'comfortable': -1, 'compact': -2) !default; $avatar-elevation: 1 !default; From 8af59fc466a13f4f6813226cff21a951db375069 Mon Sep 17 00:00:00 2001 From: "Carlos G.B." Date: Tue, 27 Aug 2024 10:28:13 +0200 Subject: [PATCH 058/190] fix(helpers): only deep merge plain objects (#20284) Co-authored-by: Kael fixes #20278 --- .../vuetify/src/util/__tests__/helpers.spec.ts | 10 ++++++++++ packages/vuetify/src/util/helpers.ts | 17 +++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/vuetify/src/util/__tests__/helpers.spec.ts b/packages/vuetify/src/util/__tests__/helpers.spec.ts index 3cc83f69be9..8eddf040cf6 100644 --- a/packages/vuetify/src/util/__tests__/helpers.spec.ts +++ b/packages/vuetify/src/util/__tests__/helpers.spec.ts @@ -288,6 +288,16 @@ describe('helpers', () => { it('should use arrayFn function if provided', () => { expect(mergeDeep({ a: ['foo'] }, { a: ['bar'] }, (a, b) => [...a, ...b])).toEqual({ a: ['foo', 'bar'] }) }) + + it('should not recursively merge non-plain objects', () => { + const plain = { a: 'foo' } + const div = document.createElement('div') + const span = document.createElement('span') + + expect(mergeDeep({ a: plain }, { a: div }).a).toBe(div) + expect(mergeDeep({ a: div }, { a: plain }).a).toBe(plain) + expect(mergeDeep({ a: div }, { a: span }).a).toBe(span) + }) }) describe('destructComputed', () => { diff --git a/packages/vuetify/src/util/helpers.ts b/packages/vuetify/src/util/helpers.ts index 089e4ca8418..bd8eddea62e 100644 --- a/packages/vuetify/src/util/helpers.ts +++ b/packages/vuetify/src/util/helpers.ts @@ -135,6 +135,14 @@ export function isObject (obj: any): obj is Record { return obj !== null && typeof obj === 'object' && !Array.isArray(obj) } +export function isPlainObject (obj: any): obj is Record { + let proto + return obj !== null && typeof obj === 'object' && ( + (proto = Object.getPrototypeOf(obj)) === Object.prototype || + proto === null + ) +} + export function refElement (obj?: ComponentPublicInstance | HTMLElement): HTMLElement | undefined { if (obj && '$el' in obj) { const el = obj.$el as HTMLElement @@ -487,17 +495,14 @@ export function mergeDeep ( const targetProperty = target[key] // Only continue deep merging if - // both properties are objects - if ( - isObject(sourceProperty) && - isObject(targetProperty) - ) { + // both properties are plain objects + if (isPlainObject(sourceProperty) && isPlainObject(targetProperty)) { out[key] = mergeDeep(sourceProperty, targetProperty, arrayFn) continue } - if (Array.isArray(sourceProperty) && Array.isArray(targetProperty) && arrayFn) { + if (arrayFn && Array.isArray(sourceProperty) && Array.isArray(targetProperty)) { out[key] = arrayFn(sourceProperty, targetProperty) continue From b81919df228888367bebfaf72522b1c69ec51d9d Mon Sep 17 00:00:00 2001 From: Kael Date: Tue, 27 Aug 2024 23:15:16 +1000 Subject: [PATCH 059/190] fix(VInfiniteScroll): respect margin when root element is scrollable fixes #17583 --- .../VInfiniteScroll/VInfiniteScroll.sass | 11 +++++++++- .../VInfiniteScroll/VInfiniteScroll.tsx | 20 +++++++++---------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.sass b/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.sass index 01984da82b8..9ef914c7e32 100644 --- a/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.sass +++ b/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.sass @@ -9,7 +9,7 @@ .v-infinite-scroll-intersect height: 100% - width: 1px + width: var(--v-infinite-margin-size, 1px) .v-infinite-scroll--vertical display: flex @@ -20,6 +20,15 @@ height: 1px width: 100% + .v-infinite-scroll-intersect + pointer-events: none + margin-top: var(--v-infinite-margin) + margin-bottom: calc(var(--v-infinite-margin) * -1) + &:nth-child(2) // TODO: "1 of &" would be more stable if structure changes + --v-infinite-margin: var(--v-infinite-margin-size, 1px) + &:nth-last-child(2) + --v-infinite-margin: calc(var(--v-infinite-margin-size, 1px) * -1) + .v-infinite-scroll__side align-items: center display: flex diff --git a/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.tsx b/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.tsx index 50924090ab9..5f500097619 100644 --- a/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.tsx +++ b/packages/vuetify/src/components/VInfiniteScroll/VInfiniteScroll.tsx @@ -73,7 +73,6 @@ export const VInfiniteScrollIntersect = defineComponent({ type: String as PropType, required: true, }, - rootRef: null, rootMargin: String, }, @@ -82,17 +81,20 @@ export const VInfiniteScrollIntersect = defineComponent({ }, setup (props, { emit }) { - const { intersectionRef, isIntersecting } = useIntersectionObserver(entries => { - }, props.rootMargin ? { - rootMargin: props.rootMargin, - } : undefined) + const { intersectionRef, isIntersecting } = useIntersectionObserver() watch(isIntersecting, async val => { emit('intersect', props.side, val) }) useRender(() => ( -
 
+
 
)) return {} @@ -264,24 +266,22 @@ export const VInfiniteScroll = genericComponent()({ { renderSide('start', startStatus.value) } - { rootEl.value && hasStartIntersect && intersectMode && ( + { hasStartIntersect && intersectMode && ( )} { slots.default?.() } - { rootEl.value && hasEndIntersect && intersectMode && ( + { hasEndIntersect && intersectMode && ( )} From 7e94fd5eb27632850ff80359326770473e456940 Mon Sep 17 00:00:00 2001 From: roncsak <809675+roncsak@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:16:56 +0200 Subject: [PATCH 060/190] docs(VAppBar): remove shrink references from prominent section (#20388) --- packages/docs/src/pages/en/components/app-bars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/pages/en/components/app-bars.md b/packages/docs/src/pages/en/components/app-bars.md index b6e6b5fb50f..222e91dea61 100644 --- a/packages/docs/src/pages/en/components/app-bars.md +++ b/packages/docs/src/pages/en/components/app-bars.md @@ -116,6 +116,6 @@ You can make **app-bar** dense. A dense app bar has lower height than regular on #### Prominent -An `v-app-bar` with the `density="prominent"` prop can opt to have its height shrunk as the user scrolls down. This provides a smooth transition to taking up less visual space when the user is scrolling through content. Shrink height has 2 possible options, **compact** (48px) and **comfortable** (56px) sizes. +An `v-app-bar` with the `density="prominent"` prop can be used for longer titles, to house imagery, or to provide a stronger presence to the top app bar. From 9737e4a162af635530e67098d34a6bd0f57d9067 Mon Sep 17 00:00:00 2001 From: santarosalia <94663227+santarosalia@users.noreply.github.com> Date: Tue, 27 Aug 2024 22:18:41 +0900 Subject: [PATCH 061/190] docs(VTooltip): fix usage example button text (#20379) --- packages/docs/src/examples/v-tooltip/usage.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/examples/v-tooltip/usage.vue b/packages/docs/src/examples/v-tooltip/usage.vue index ae2032e54b1..120c0ca5c47 100644 --- a/packages/docs/src/examples/v-tooltip/usage.vue +++ b/packages/docs/src/examples/v-tooltip/usage.vue @@ -45,7 +45,7 @@ const slots = computed(() => { return ` ` }) From dbc812c5813a955c63a1e83f9734801703266c53 Mon Sep 17 00:00:00 2001 From: Kael Date: Wed, 28 Aug 2024 02:15:21 +1000 Subject: [PATCH 062/190] chore(release): publish v3.7.1 --- lerna.json | 2 +- packages/api-generator/package.json | 2 +- packages/docs/package.json | 2 +- packages/vuetify/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lerna.json b/lerna.json index d9f7b120394..1619bdbb4c4 100644 --- a/lerna.json +++ b/lerna.json @@ -13,5 +13,5 @@ } }, "npmClient": "pnpm", - "version": "3.7.0" + "version": "3.7.1" } \ No newline at end of file diff --git a/packages/api-generator/package.json b/packages/api-generator/package.json index 626d084eca0..a13880132c3 100755 --- a/packages/api-generator/package.json +++ b/packages/api-generator/package.json @@ -1,6 +1,6 @@ { "name": "@vuetify/api-generator", - "version": "3.7.0", + "version": "3.7.1", "private": true, "description": "", "scripts": { diff --git a/packages/docs/package.json b/packages/docs/package.json index 7269c59ed2f..576eed5dea9 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -3,7 +3,7 @@ "description": "A Vue.js project", "private": true, "author": "John Leider ", - "version": "3.7.0", + "version": "3.7.1", "repository": { "type": "git", "url": "git+https://github.com/vuetifyjs/vuetify.git", diff --git a/packages/vuetify/package.json b/packages/vuetify/package.json index 0ed6492b6e6..618ebff3b14 100755 --- a/packages/vuetify/package.json +++ b/packages/vuetify/package.json @@ -1,7 +1,7 @@ { "name": "vuetify", "description": "Vue Material Component Framework", - "version": "3.7.0", + "version": "3.7.1", "author": { "name": "John Leider", "email": "john@vuetifyjs.com" From f95a405042f7da57b472fd38208dd61e7ab63bd3 Mon Sep 17 00:00:00 2001 From: J-Sek Date: Thu, 29 Aug 2024 03:22:10 +0200 Subject: [PATCH 063/190] fix(VTreeview): Load children when expanded (#20364) Co-authored-by: jsek --- packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx b/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx index 8d749d14678..d5d0d05ff79 100644 --- a/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx +++ b/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx @@ -132,7 +132,7 @@ export const VTreeviewChildren = genericComponent checkChildren(item), activatorProps.onClick] as any, onClick: isClickOnOpen.value ? [() => checkChildren(item), activatorProps.onClick] as any : undefined, } From 970f827828b2e488ad5bb2e8f1363fd38c5a6102 Mon Sep 17 00:00:00 2001 From: J-Sek Date: Sat, 31 Aug 2024 15:26:12 +0200 Subject: [PATCH 064/190] fix(nested): Prevent infinite loops when resolving path (#20390) closes #20389 Co-authored-by: jsek Co-authored-by: Kael --- .../vuetify/src/components/VList/VList.tsx | 3 +- .../src/components/VList/VListItem.tsx | 3 ++ .../vuetify/src/composables/nested/nested.ts | 17 ++++++++++- .../vuetify/src/labs/VTreeview/VTreeview.tsx | 16 ++-------- .../src/labs/VTreeview/VTreeviewItem.tsx | 29 +++++-------------- 5 files changed, 32 insertions(+), 36 deletions(-) diff --git a/packages/vuetify/src/components/VList/VList.tsx b/packages/vuetify/src/components/VList/VList.tsx index f5c492fd9eb..cbdc04b2cce 100644 --- a/packages/vuetify/src/components/VList/VList.tsx +++ b/packages/vuetify/src/components/VList/VList.tsx @@ -162,7 +162,7 @@ export const VList = genericComponent props.lines ? `v-list--${props.lines}-line` : undefined) const activeColor = toRef(props, 'activeColor') const baseColor = toRef(props, 'baseColor') @@ -288,6 +288,7 @@ export const VList = genericComponent()({ root, parent, openOnSelect, + id: uid, } = useNestedItem(id, false) const list = useList() const isActive = computed(() => @@ -368,6 +369,8 @@ export const VListItem = genericComponent()({ isSelected, list, select, + root, + id: uid, } }, }) diff --git a/packages/vuetify/src/composables/nested/nested.ts b/packages/vuetify/src/composables/nested/nested.ts index 5f80f4da090..c5b013a3de0 100644 --- a/packages/vuetify/src/composables/nested/nested.ts +++ b/packages/vuetify/src/composables/nested/nested.ts @@ -17,7 +17,7 @@ import { leafSelectStrategy, leafSingleSelectStrategy, } from './selectStrategies' -import { getCurrentInstance, getUid, propsFactory } from '@/util' +import { consoleError, getCurrentInstance, getUid, propsFactory } from '@/util' // Types import type { InjectionKey, PropType, Ref } from 'vue' @@ -76,6 +76,7 @@ type NestedProvide = { activate: (id: unknown, value: boolean, event?: Event) => void select: (id: unknown, value: boolean, event?: Event) => void openOnSelect: (id: unknown, value: boolean, event?: Event) => void + getPath: (id: unknown) => unknown[] } } @@ -98,6 +99,7 @@ export const emptyNested: NestedProvide = { activated: ref(new Set()), selected: ref(new Map()), selectedValues: ref([]), + getPath: () => [], }, } @@ -191,6 +193,8 @@ export const useNested = (props: NestedProps) => { const vm = getCurrentInstance('nested') + const nodeIds = new Set() + const nested: NestedProvide = { id: shallowRef(), root: { @@ -209,6 +213,15 @@ export const useNested = (props: NestedProps) => { return arr }), register: (id, parentId, isGroup) => { + if (nodeIds.has(id)) { + const path = getPath(id).join(' -> ') + const newPath = getPath(parentId).concat(id).join(' -> ') + consoleError(`Multiple nodes with the same ID\n\t${path}\n\t${newPath}`) + return + } else { + nodeIds.add(id) + } + parentId && id !== parentId && parents.value.set(id, parentId) isGroup && children.value.set(id, []) @@ -220,6 +233,7 @@ export const useNested = (props: NestedProps) => { unregister: id => { if (isUnmounted) return + nodeIds.delete(id) children.value.delete(id) const parent = parents.value.get(id) if (parent) { @@ -289,6 +303,7 @@ export const useNested = (props: NestedProps) => { }, children, parents, + getPath, }, } diff --git a/packages/vuetify/src/labs/VTreeview/VTreeview.tsx b/packages/vuetify/src/labs/VTreeview/VTreeview.tsx index d4079447da0..172deddbc10 100644 --- a/packages/vuetify/src/labs/VTreeview/VTreeview.tsx +++ b/packages/vuetify/src/labs/VTreeview/VTreeview.tsx @@ -86,24 +86,14 @@ export const VTreeview = genericComponent( const search = toRef(props, 'search') const { filteredItems } = useFilter(props, flatItems, search) const visibleIds = computed(() => { - if (!search.value) { - return null - } + if (!search.value) return null + const getPath = vListRef.value?.getPath + if (!getPath) return null return new Set(filteredItems.value.flatMap(item => { return [...getPath(item.props.value), ...getChildren(item.props.value)] })) }) - function getPath (id: unknown) { - const path: unknown[] = [] - let parent: unknown = id - while (parent != null) { - path.unshift(parent) - parent = vListRef.value?.parents.get(parent) - } - return path - } - function getChildren (id: unknown) { const arr: unknown[] = [] const queue = ((vListRef.value?.children.get(id) ?? []).slice()) diff --git a/packages/vuetify/src/labs/VTreeview/VTreeviewItem.tsx b/packages/vuetify/src/labs/VTreeview/VTreeviewItem.tsx index aaa6aa59b2b..c3a33eee6ba 100644 --- a/packages/vuetify/src/labs/VTreeview/VTreeviewItem.tsx +++ b/packages/vuetify/src/labs/VTreeview/VTreeviewItem.tsx @@ -9,7 +9,6 @@ import { VProgressCircular } from '@/components/VProgressCircular' // Composables import { IconValue } from '@/composables/icons' -import { useNestedItem } from '@/composables/nested/nested' import { useLink } from '@/composables/router' // Utilities @@ -35,20 +34,11 @@ export const VTreeviewItem = genericComponent()({ setup (props, { attrs, slots, emit }) { const link = useLink(props, attrs) - const rawId = computed(() => props.value === undefined ? link.href.value : props.value) const vListItemRef = ref() - const { - activate, - isActivated, - isGroupActivator, - root, - id, - } = useNestedItem(rawId, false) - const isActivatableGroupActivator = computed(() => - (root.activatable.value) && - isGroupActivator + (vListItemRef.value?.root.activatable.value) && + vListItemRef.value?.isGroupActivator ) const isClickable = computed(() => @@ -60,15 +50,11 @@ export const VTreeviewItem = genericComponent()({ function activateItem (e: MouseEvent | KeyboardEvent) { if ( !isClickable.value || - (!isActivatableGroupActivator.value && isGroupActivator) + (!isActivatableGroupActivator.value && vListItemRef.value?.isGroupActivator) ) return - if (root.activatable.value) { - if (isActivatableGroupActivator.value) { - activate(!isActivated.value, e) - } else { - vListItemRef.value?.activate(!vListItemRef.value?.isActivated, e) - } + if (vListItemRef.value?.root.activatable.value) { + vListItemRef.value?.activate(!vListItemRef.value?.isActivated, e) } } @@ -80,13 +66,14 @@ export const VTreeviewItem = genericComponent()({ return ( Date: Mon, 2 Sep 2024 20:48:28 +1000 Subject: [PATCH 065/190] docs: update roadmap --- .../docs/src/pages/en/introduction/roadmap.md | 92 ++++++++----------- 1 file changed, 36 insertions(+), 56 deletions(-) diff --git a/packages/docs/src/pages/en/introduction/roadmap.md b/packages/docs/src/pages/en/introduction/roadmap.md index e10d6fbb5bd..5fa5614ef2a 100644 --- a/packages/docs/src/pages/en/introduction/roadmap.md +++ b/packages/docs/src/pages/en/introduction/roadmap.md @@ -22,37 +22,39 @@ Vuetify is always under development. We are constantly working towards improving The following is a list of all planned components for the year 2024. -::: info - -**UPDATE: July 18th, 2024** - -Multiple components have been delayed until further notice due to reduced funding and team support. We are still working on features and fixes but at a reduced rate. We are actively seeking new funding and will update the roadmap as soon as we have more information. If you're interested in supporting Vuetify development, please consider becoming a [Sponsor](/introduction/sponsors-and-backers/). - -::: - -| Component | Entering Labs | Production Release | -| - | - | - | -| [v3.7 (Odyssey)](https://github.com/vuetifyjs/vuetify/milestone/73) | | July 2024 { .bg-surface-light } | -| [v-treeview](/components/treeview/) | *️⃣ | ~~July 2024~~ TBD | -| [v-number-input](/components/number-inputs/) | *️⃣ | ~~July 2024~~ TBD | -| [v-time-picker](/components/time-pickers/) | *️⃣ | ~~July 2024~~ TBD | -| [v-date-input](/components/date-inputs/) | *️⃣ | ~~July 2024~~ TBD | -| [v-file-upload](https://github.com/vuetifyjs/vuetify/pull/19667) | ~~April~~ ~~May 2024~~ TBD | ~~July 2024~~ TBD | -| [v-time-input](https://github.com/vuetifyjs/vuetify/pull/19709) | ~~April~~ ~~May 2024~~ TBD | ~~July 2024~~ TBD | -| [v-stepper-vertical](https://github.com/vuetifyjs/vuetify/pull/19524) | *️⃣ | ~~July 2024~~ TBD | -| [v3.8 (Andromeda)](https://github.com/vuetifyjs/vuetify/milestone/74) | | TBD { .bg-surface-light } | -| [v-calendar](/components/calendars/) | *️⃣ | Q4 | -| v-date-time-picker | ~~May 2024~~ TBD | ~~Q4~~ TBD | -| v-date-range-picker | ~~June 2024~~ TBD | ~~Q4~~ TBD | -| v-video | ~~July 2024~~ TBD | ~~Q4~~ TBD | -| v-feature-discovery | ~~August 2024~~ TBD | ~~Q4~~ TBD | - -*️⃣ Already in Labs { .text-caption } +| Component | Entering Labs | Production Release | +|-------------------------------------------------------------------------|----------------|-------------------------------------| +| [v3.8 (Andromeda)](https://github.com/vuetifyjs/vuetify/milestone/74) | | October 2024 { .bg-surface-light } | +| [v-number-input](/components/number-inputs/) | * | | +| [v-snackbar-queue](/components/snackbar-queue/) | * | | +| [v-time-picker](/components/time-pickers/) | * | | +| [v-treeview](/components/treeview/) | * | | +| [v-stepper-vertical](/components/vertical-steppers/) | * | | +| [v4.0 (Revisionist)](https://github.com/vuetifyjs/vuetify/milestone/62) | | December 2024 { .bg-surface-light } | +| [v-date-input](/components/date-inputs/) | * | | +| [v-calendar](/components/calendars/) | * | | +| [v-time-input](https://github.com/vuetifyjs/vuetify/pull/19709) | September 2024 | | +| Future - v4.1+ | | TBD { .bg-surface-light } | +| [v-file-upload](https://github.com/vuetifyjs/vuetify/pull/19667) | September 2024 | | +| v-date-time-picker | Q1 2025 | | +| v-date-range-picker | Q1 2025 | | +| v-video | TBD | | +| v-feature-discovery | TBD | | + +\* Already in Labs { .text-caption } ## Released The following are the already released **minor** and **major** version updates. Find more information on the [latest releases](https://github.com/vuetifyjs/vuetify/releases/latest) on GitHub. +### v3.7 (Odyssey) + +- **Released:** August 2024 +- **Target Release:** Q3 2024 +- **Notes:** [v3.7 Release](/getting-started/release-notes/?version=v3.7.0) +- **Overview:** Added more validation options and proper submenu support. +- **Milestone Issues:** [Github Issues](https://github.com/vuetifyjs/vuetify/milestone/73) + ### v3.6 (Nebula) - **Released:** April 2024 @@ -94,16 +96,6 @@ The following are the already released **minor** and **major** version updates. - [v-stepper](/components/steppers/). - **Milestone Issues:** [Github Issues](https://github.com/vuetifyjs/vuetify/milestone/61) -### v2.7 (Nirvana) - -- **Released:** July 2023 -- **Target Release:** Q2 2023 -- **Notes:** [v2.7 Release](/getting-started/release-notes/?version=v2.7.0) -- **LTS Support until:** January 2025 -- **Milestone Issues:** [Github Issues](https://github.com/vuetifyjs/vuetify/milestone/59) - ----- - ### v3.3 (Icarus) - **Released:** May 2023 @@ -112,8 +104,6 @@ The following are the already released **minor** and **major** version updates. - **Overview:** A small intermediary minor that will release alongside Vue v3.3 and include a few small features. - **Milestone Issues:** [Github Issues](https://github.com/vuetifyjs/vuetify/milestone/67) ----- - ### v3.2 (Orion) - **Released:** April 2023 @@ -122,8 +112,6 @@ The following are the already released **minor** and **major** version updates. - **Overview:** New and ported components from v2. Exposed defaults system for public use, allowing you to hook into the global default configuration with your components. More information in the [release notes](/getting-started/release-notes/?version=v3.2.0) - **Milestone Issues:** [Github Issues](https://github.com/vuetifyjs/vuetify/milestone/53) ----- - ### v3.1 (Valkyrie) - **Released:** January 2023 @@ -132,16 +120,12 @@ The following are the already released **minor** and **major** version updates. - **Overview:** First post v3 release that will focus on porting remaining missing v2 components and general bug fixing. - **Milestone Issues:** [Github Issues](https://github.com/vuetifyjs/vuetify/milestone/56) ----- - ### Vuetify Labs { id="labs" } - **Released:** January 2023 - **Target Release:** Q4 2022 - **Overview:** Labs is a new package that includes large components from Vuetify 2 in a pre-production state. More information is located on the [Labs introduction](/labs/introduction/) page. ----- - ### v3.0 (Titan) - **Released:** October 2022 @@ -157,6 +141,14 @@ The following are the already released **minor** and **major** version updates. ---- +### v2.7 (Nirvana) + +- **Released:** July 2023 +- **Target Release:** Q2 2023 +- **Notes:** [v2.7 Release](/getting-started/release-notes/?version=v2.7.0) +- **LTS Support until:** January 2025 +- **Milestone Issues:** [Github Issues](https://github.com/vuetifyjs/vuetify/milestone/59) + ### v2.6 (Horizon) - **Released**: November 2021 @@ -164,8 +156,6 @@ The following are the already released **minor** and **major** version updates. - **Overview**: New [v-otp-input](/components/otp-input/) component, calendar event and scrolling improvements, minor features for other components. ----- - ### v2.5 (Avalon) - **Released:** May 2021 @@ -177,8 +167,6 @@ The following are the already released **minor** and **major** version updates. - Quality of life improvements - General bug fixes ----- - ### v2.4 (Endurance) - **Released:** December 2020 @@ -195,8 +183,6 @@ The following are the already released **minor** and **major** version updates. - Support for a globally defined icon components - Improved accessibility in the `v-menu` component ----- - ### v2.3 (Liberator) - **Released:** June 2020 @@ -209,8 +195,6 @@ The following are the already released **minor** and **major** version updates. - Improve *Date Pickers, Data Tables, and Calendars* - Harden framework in preparation for **LTS version** ----- - ### v2.2 (Tigris) - **Released:** January 2020 @@ -225,8 +209,6 @@ The following are the already released **minor** and **major** version updates. - Add new features and improve code styling of `v-expansion-panels` - new `v-theme-provider` component ----- - ### v2.1 (Vanguard) - **Released:** October 2019 @@ -242,8 +224,6 @@ The following are the already released **minor** and **major** version updates. - `v-mutate` - Add lazy loading support for `v-img` ----- - ### v2.0 (Arcadia) - **Released:** July 2019 From 3bc72297ea00b19701841f446c314f0379aa5fae Mon Sep 17 00:00:00 2001 From: Kael Date: Mon, 2 Sep 2024 22:26:02 +1000 Subject: [PATCH 066/190] docs: hide inactive sponsors --- packages/docs/src/stores/sponsors.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/docs/src/stores/sponsors.ts b/packages/docs/src/stores/sponsors.ts index 8b04021c73c..e09a11f2a7b 100644 --- a/packages/docs/src/stores/sponsors.ts +++ b/packages/docs/src/stores/sponsors.ts @@ -20,7 +20,10 @@ export const useSponsorsStore = defineStore('sponsors', () => { const { bucket } = useCosmic() const { objects = [] }: { objects: Sponsor[] } = ( await bucket?.objects - .find({ type: 'sponsors' }) + .find({ + type: 'sponsors', + 'metadata.active': true, + }) .props('metadata,slug,title') .sort('created_at') ) || {} From 1c40ed484c31def71b0a587f8e39cd6101762de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Th=C3=A9baud?= Date: Tue, 3 Sep 2024 06:48:35 +0200 Subject: [PATCH 067/190] fix(VDialog): remove `aria-expanded` from activator (#20414) --- packages/vuetify/src/components/VDialog/VDialog.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vuetify/src/components/VDialog/VDialog.tsx b/packages/vuetify/src/components/VDialog/VDialog.tsx index 6391b95df15..10063444860 100644 --- a/packages/vuetify/src/components/VDialog/VDialog.tsx +++ b/packages/vuetify/src/components/VDialog/VDialog.tsx @@ -111,7 +111,6 @@ export const VDialog = genericComponent()({ const overlayProps = VOverlay.filterProps(props) const activatorProps = mergeProps({ 'aria-haspopup': 'dialog', - 'aria-expanded': String(isActive.value), }, props.activatorProps) const contentProps = mergeProps({ tabindex: -1, From eb0c99e4f13272367a983abac9473b943f065ee1 Mon Sep 17 00:00:00 2001 From: Jesse205 <51242302+Jesse205@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:06:37 +0800 Subject: [PATCH 068/190] fix(VDialog): add height to form in fullscreen dialog (#20417) fixes #20416 --- packages/vuetify/src/components/VDialog/VDialog.sass | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vuetify/src/components/VDialog/VDialog.sass b/packages/vuetify/src/components/VDialog/VDialog.sass index c9aeb41f5e3..9241f6e3bc6 100644 --- a/packages/vuetify/src/components/VDialog/VDialog.sass +++ b/packages/vuetify/src/components/VDialog/VDialog.sass @@ -54,7 +54,6 @@ margin: 0 padding: 0 width: 100% - height: 100% max-width: 100% max-height: 100% overflow-y: auto @@ -63,6 +62,8 @@ &, > form + height: 100% + > .v-card, > .v-sheet min-height: 100% From 45e0c8af029ffcbcb318f10a2e263b35671dbdc6 Mon Sep 17 00:00:00 2001 From: Kael Date: Tue, 3 Sep 2024 17:18:05 +1000 Subject: [PATCH 069/190] fix(v-tooltip): use default location from VTooltip --- packages/vuetify/src/directives/tooltip/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/src/directives/tooltip/index.ts b/packages/vuetify/src/directives/tooltip/index.ts index 597955fdc3a..a8848f7297f 100644 --- a/packages/vuetify/src/directives/tooltip/index.ts +++ b/packages/vuetify/src/directives/tooltip/index.ts @@ -16,7 +16,7 @@ export interface TooltipDirectiveBinding extends Omit, export const Tooltip = useDirectiveComponent(VTooltip, binding => { return { activator: 'parent', - location: binding.arg?.replace('-', ' ') ?? 'top', + location: binding.arg?.replace('-', ' '), text: typeof binding.value === 'boolean' ? undefined : binding.value, } }) From bc647f6853c6415fc928aff2774134f7eed26b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Th=C3=A9baud?= Date: Tue, 3 Sep 2024 09:27:24 +0200 Subject: [PATCH 070/190] fix(a11y): add `aria-current="page"` attribute to links (#20413) closes #20399 Co-authored-by: Kael --- .../VBreadcrumbs/VBreadcrumbsItem.tsx | 3 +-- packages/vuetify/src/components/VBtn/VBtn.tsx | 2 +- .../vuetify/src/components/VCard/VCard.tsx | 2 +- .../vuetify/src/components/VChip/VChip.tsx | 2 +- .../src/components/VList/VListItem.tsx | 2 +- packages/vuetify/src/composables/router.tsx | 27 ++++++++++++------- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbsItem.tsx b/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbsItem.tsx index 3d85047d7e6..403bd0c6487 100644 --- a/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbsItem.tsx +++ b/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbsItem.tsx @@ -55,9 +55,8 @@ export const VBreadcrumbsItem = genericComponent()({ { !link.isLink.value ? slots.default?.() ?? props.title : ( { slots.default?.() ?? props.title } diff --git a/packages/vuetify/src/components/VBtn/VBtn.tsx b/packages/vuetify/src/components/VBtn/VBtn.tsx index fb8166d7919..cf87067a7a8 100644 --- a/packages/vuetify/src/components/VBtn/VBtn.tsx +++ b/packages/vuetify/src/components/VBtn/VBtn.tsx @@ -212,10 +212,10 @@ export const VBtn = genericComponent()({ ]} aria-busy={ props.loading ? true : undefined } disabled={ isDisabled.value || undefined } - href={ link.href.value } tabindex={ props.loading || props.readonly ? -1 : undefined } onClick={ onClick } value={ valueAttr.value } + { ...link.linkProps } > { genOverlays(true, 'v-btn') } diff --git a/packages/vuetify/src/components/VCard/VCard.tsx b/packages/vuetify/src/components/VCard/VCard.tsx index ba0d8303f07..6141643375b 100644 --- a/packages/vuetify/src/components/VCard/VCard.tsx +++ b/packages/vuetify/src/components/VCard/VCard.tsx @@ -149,10 +149,10 @@ export const VCard = genericComponent()({ locationStyles.value, props.style, ]} - href={ link.href.value } onClick={ isClickable.value && link.navigate } v-ripple={ isClickable.value && props.ripple } tabindex={ props.disabled ? -1 : undefined } + { ...link.linkProps } > { hasImage && (
diff --git a/packages/vuetify/src/components/VChip/VChip.tsx b/packages/vuetify/src/components/VChip/VChip.tsx index 958332a03f0..bbaedfd2842 100644 --- a/packages/vuetify/src/components/VChip/VChip.tsx +++ b/packages/vuetify/src/components/VChip/VChip.tsx @@ -204,11 +204,11 @@ export const VChip = genericComponent()({ ]} disabled={ props.disabled || undefined } draggable={ props.draggable } - href={ link.href.value } tabindex={ isClickable.value ? 0 : undefined } onClick={ onClick } onKeydown={ isClickable.value && !isLink.value && onKeyDown } v-ripple={[isClickable.value && props.ripple, null]} + { ...link.linkProps } > { genOverlays(isClickable.value, 'v-chip') } diff --git a/packages/vuetify/src/components/VList/VListItem.tsx b/packages/vuetify/src/components/VList/VListItem.tsx index 510a30e91a3..fae894279cd 100644 --- a/packages/vuetify/src/components/VList/VListItem.tsx +++ b/packages/vuetify/src/components/VList/VListItem.tsx @@ -243,11 +243,11 @@ export const VListItem = genericComponent()({ dimensionStyles.value, props.style, ]} - href={ link.href.value } tabindex={ isClickable.value ? (list ? -2 : 0) : undefined } onClick={ onClick } onKeydown={ isClickable.value && !isLink.value && onKeyDown } v-ripple={ isClickable.value && props.ripple } + { ...link.linkProps } > { genOverlays(isClickable.value || isActive.value, 'v-list-item') } diff --git a/packages/vuetify/src/composables/router.tsx b/packages/vuetify/src/composables/router.tsx index 09742bf0537..c3e086f126b 100644 --- a/packages/vuetify/src/composables/router.tsx +++ b/packages/vuetify/src/composables/router.tsx @@ -2,7 +2,7 @@ import { computed, nextTick, - onScopeDispose, + onScopeDispose, reactive, resolveDynamicComponent, toRef, } from 'vue' @@ -47,6 +47,7 @@ export interface UseLink extends Omit>, 'hre isLink: ComputedRef isClickable: ComputedRef href: Ref + linkProps: Record } export function useLink (props: LinkProps & LinkListeners, attrs: SetupContext['attrs']): UseLink { @@ -58,10 +59,12 @@ export function useLink (props: LinkProps & LinkListeners, attrs: SetupContext[' }) if (typeof RouterLink === 'string' || !('useLink' in RouterLink)) { + const href = toRef(props, 'href') return { isLink, isClickable, - href: toRef(props, 'href'), + href, + linkProps: reactive({ href }), } } // vue-router useLink `to` prop needs to be reactive and useLink will crash if undefined @@ -74,20 +77,26 @@ export function useLink (props: LinkProps & LinkListeners, attrs: SetupContext[' // Actual link needs to be undefined when to prop is not used const link = computed(() => props.to ? routerLink : undefined) const route = useRoute() + const isActive = computed(() => { + if (!link.value) return false + if (!props.exact) return link.value.isActive?.value ?? false + if (!route.value) return link.value.isExactActive?.value ?? false + + return link.value.isExactActive?.value && deepEqual(link.value.route.value.query, route.value.query) + }) + const href = computed(() => props.to ? link.value?.route.value.href : props.href) return { isLink, isClickable, + isActive, route: link.value?.route, navigate: link.value?.navigate, - isActive: computed(() => { - if (!link.value) return false - if (!props.exact) return link.value.isActive?.value ?? false - if (!route.value) return link.value.isExactActive?.value ?? false - - return link.value.isExactActive?.value && deepEqual(link.value.route.value.query, route.value.query) + href, + linkProps: reactive({ + href, + 'aria-current': computed(() => isActive.value ? 'page' : undefined), }), - href: computed(() => props.to ? link.value?.route.value.href : props.href), } } From ca49443c6b7302c9dcb14b9be29f3872f512b320 Mon Sep 17 00:00:00 2001 From: Kael Date: Tue, 3 Sep 2024 17:48:26 +1000 Subject: [PATCH 071/190] fix(v-tooltip): use textContent instead of innerHTML --- packages/vuetify/src/composables/directiveComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/src/composables/directiveComponent.ts b/packages/vuetify/src/composables/directiveComponent.ts index fe383e8fbca..342efa046b1 100644 --- a/packages/vuetify/src/composables/directiveComponent.ts +++ b/packages/vuetify/src/composables/directiveComponent.ts @@ -70,7 +70,7 @@ function mountComponent (component: ConcreteComponent, props?: Record text ?? el.innerHTML + const children = () => text ?? el.textContent // If vnode.ctx is the same as the instance, then we're bound to a plain element // and need to find the nearest parent component instance to inherit provides from From 115edcae38fd734e4a7b5ead6464692913ea1478 Mon Sep 17 00:00:00 2001 From: Kael Date: Tue, 3 Sep 2024 17:48:59 +1000 Subject: [PATCH 072/190] docs(v-tooltip): update examples closes #19739 --- .../src/examples/v-tooltip-directive/args.vue | 4 ++++ .../examples/v-tooltip-directive/modifiers.vue | 5 ----- .../v-tooltip-directive/object-literals.vue | 18 +++++++++++++----- .../src/examples/v-tooltip-directive/text.vue | 15 +++++++++++++++ .../docs/src/pages/en/directives/tooltip.md | 16 ++++++++-------- 5 files changed, 40 insertions(+), 18 deletions(-) delete mode 100644 packages/docs/src/examples/v-tooltip-directive/modifiers.vue create mode 100644 packages/docs/src/examples/v-tooltip-directive/text.vue diff --git a/packages/docs/src/examples/v-tooltip-directive/args.vue b/packages/docs/src/examples/v-tooltip-directive/args.vue index 0144dfa746c..7f6be045f83 100644 --- a/packages/docs/src/examples/v-tooltip-directive/args.vue +++ b/packages/docs/src/examples/v-tooltip-directive/args.vue @@ -15,5 +15,9 @@ Bottom + + + Bottom end +
diff --git a/packages/docs/src/examples/v-tooltip-directive/modifiers.vue b/packages/docs/src/examples/v-tooltip-directive/modifiers.vue deleted file mode 100644 index 7150bc7bb97..00000000000 --- a/packages/docs/src/examples/v-tooltip-directive/modifiers.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/packages/docs/src/examples/v-tooltip-directive/object-literals.vue b/packages/docs/src/examples/v-tooltip-directive/object-literals.vue index d990da4ed31..7abcf8f5954 100644 --- a/packages/docs/src/examples/v-tooltip-directive/object-literals.vue +++ b/packages/docs/src/examples/v-tooltip-directive/object-literals.vue @@ -1,13 +1,17 @@ @@ -15,8 +19,12 @@ export default { data: () => ({ tooltip: { - text: 'Tooltip', - scrollStrategy: 'block', + text: 'Scroll up ↑', + scrollStrategy: 'close', + scrim: true, + persistent: false, + openOnClick: true, + openOnHover: false, }, }), } diff --git a/packages/docs/src/examples/v-tooltip-directive/text.vue b/packages/docs/src/examples/v-tooltip-directive/text.vue new file mode 100644 index 00000000000..7c604a1408a --- /dev/null +++ b/packages/docs/src/examples/v-tooltip-directive/text.vue @@ -0,0 +1,15 @@ + diff --git a/packages/docs/src/pages/en/directives/tooltip.md b/packages/docs/src/pages/en/directives/tooltip.md index 312dd5ec6ad..681f9954d2a 100644 --- a/packages/docs/src/pages/en/directives/tooltip.md +++ b/packages/docs/src/pages/en/directives/tooltip.md @@ -35,22 +35,22 @@ The `v-tooltip` directive makes it easy to add a tooltip to any element in your ## Guide -The `v-tooltip` directive is a simple way to add a tooltip to any element in your application. It is a wrapper around the `v-tooltip`. +The `v-tooltip` directive is a simple way to add a tooltip to any element in your application. It is a wrapper around the `v-tooltip` component. -### Args +### Location -The `v-tooltip` directive has a number of args that can be used to customize the behavior of the tooltip. +Location is set as a directive argument with the same syntax as the component's `location` prop separated by a hyphen instead of a space. -### Modifiers +### Tooltip text -Modifiers are values that are passed to the `v-tooltip` component. This is an easy way to make small modifications to boolean [v-tooltip](/api/v-tooltip/) props. +By default the tooltip will use the target element's [`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext), or you can pass another string as a directive value. Remember directive values are expressions so static strings must be quoted. - + -### Object literals +### Other props -The `v-tooltip` directive can also accept an object literal as a value. This is useful when you need to pass multiple props to the `v-tooltip` component. +The `v-tooltip` directive can also accept an object of [VTooltip props](/api/v-tooltip/#props) as a value (use camelCase keys). From 1979fd7bf49a9a73c5b7f90c72245410ff8da028 Mon Sep 17 00:00:00 2001 From: Kael Date: Tue, 3 Sep 2024 22:56:09 +1000 Subject: [PATCH 073/190] chore: replace jest with vitest --- .github/workflows/ci.yml | 14 +- .pnpmfile.cjs | 4 + eslint-local-rules.js | 2 +- package.json | 8 +- packages/vuetify/.eslintrc.js | 2 +- packages/vuetify/dev/vuetify.js | 6 +- packages/vuetify/dev/vuetify/icons.js | 6 +- packages/vuetify/dev/vuetify/locale.js | 2 +- packages/vuetify/jest.config.js | 10 - packages/vuetify/package.json | 12 +- .../vuetify/src/__tests__/framework.spec.ts | 2 +- packages/vuetify/src/auto-imports.d.ts | 17 + packages/vuetify/src/components.d.ts | 13 + .../VColorPicker/util/__tests__/index.spec.ts | 2 +- .../VDataTable/__tests__/VDataTable.spec.ts | 2 +- .../VDataTable/__tests__/headers.spec.ts | 5 +- .../VDataTable/__tests__/sort.spec.ts | 2 +- .../__tests__/VDatePicker.date.spec.ts | 2 +- .../createNativeLocaleFormatter.spec.ts | 30 - .../util/__tests__/monthChange.spec.ts | 13 - .../VDatePicker/util/__tests__/pad.spec.ts | 21 - .../util/__tests__/sanitizeDateString.spec.ts | 12 - .../util/createNativeLocaleFormatter.ts | 43 - .../VDatePicker/util/eventHelpers.ts | 24 - .../src/components/VDatePicker/util/index.ts | 20 - .../VDatePicker/util/isDateAllowed.ts | 10 - .../VDatePicker/util/monthChange.ts | 20 - .../src/components/VDatePicker/util/pad.ts | 19 - .../VDatePicker/util/sanitizeDateString.ts | 8 - .../VFileInput/__tests__/VFileInput.spec.tsx | 10 +- .../components/VGrid/__tests__/VCol.spec.ts | 2 +- .../VItemGroup/__tests__/VItemGroup.spec.ts | 4 +- .../__snapshots__/VItemGroup.spec.ts.snap | 9 +- .../components/VList/__tests__/VList.spec.ts | 2 +- .../VList/__tests__/VListItemMedia.spec.ts | 2 +- .../__snapshots__/VList.spec.ts.snap | 10 +- .../__snapshots__/VListItemMedia.spec.ts.snap | 7 +- .../components/VMenu/__tests__/VMenu.spec.ts | 2 +- .../VResponsive/__tests__/VResponsive.spec.ts | 2 +- .../__snapshots__/VResponsive.spec.ts.snap | 42 +- .../__tests__/VSelectionControl.spec.tsx | 6 +- .../VTextField/__tests__/VTextField.spec.tsx | 10 +- .../VTextarea/__tests__/VTextarea.spec.tsx | 10 +- .../__snapshots__/group.spec.ts.snap | 96 +- .../__snapshots__/theme.spec.ts.snap | 6 +- .../src/composables/__tests__/border.spec.ts | 2 +- .../src/composables/__tests__/color.spec.ts | 2 +- .../composables/__tests__/defaults.spec.ts | 2 +- .../src/composables/__tests__/delay.spec.ts | 10 +- .../composables/__tests__/dimensions.spec.ts | 2 +- .../src/composables/__tests__/display.spec.ts | 6 +- .../composables/__tests__/elevation.spec.ts | 4 +- .../src/composables/__tests__/filter.spec.ts | 2 +- .../__tests__/forwardRefs.spec.tsx | 2 +- .../src/composables/__tests__/group.spec.ts | 5 +- .../src/composables/__tests__/icons.spec.ts | 2 +- .../src/composables/__tests__/items.spec.ts | 2 +- .../src/composables/__tests__/loader.spec.ts | 2 +- .../composables/__tests__/location.spec.ts | 2 +- .../__tests__/mutationObserver.spec.ts | 6 +- .../composables/__tests__/position.spec.ts | 2 +- .../__tests__/proxiedModel.spec.ts | 2 +- .../__tests__/resizeObserver.spec.ts | 4 +- .../src/composables/__tests__/rounded.spec.ts | 2 +- .../src/composables/__tests__/scroll.spec.ts | 10 +- .../src/composables/__tests__/size.spec.ts | 4 +- .../src/composables/__tests__/tag.spec.ts | 2 +- .../src/composables/__tests__/theme.spec.ts | 2 +- .../composables/__tests__/validation.spec.ts | 2 +- .../src/composables/__tests__/variant.spec.ts | 4 +- .../composables/date/__tests__/date.spec.ts | 2 +- .../date/adapters/__tests__/vuetify.spec.ts | 2 +- .../nested/__tests__/selectStrategies.spec.ts | 2 +- .../click-outside-shadow-dom.spec.ts | 14 +- .../__tests__/click-outside.spec.ts | 10 +- .../intersect/__tests__/intersect.spec.ts | 6 +- .../mutate/__tests__/mutate.spec.ts | 12 +- .../resize/__tests__/resize.spec.ts | 25 +- .../ripple/__tests__/ripple.spec.ts | 17 +- .../scroll/__tests__/scroll.spec.ts | 22 +- .../directives/touch/__tests__/touch.spec.ts | 30 +- packages/vuetify/src/globals.d.ts | 14 +- .../src/labs/VTimePicker/VTimePicker.tsx | 2 +- .../labs/VTimePicker/VTimePickerControls.tsx | 2 +- packages/vuetify/src/labs/VTimePicker/util.ts | 3 + .../src/locale/__tests__/index.spec.ts | 2 +- .../goto/__tests__/easing-patterns.spec.ts | 26 - .../src/services/goto/__tests__/goto.spec.ts | 73 - .../src/services/goto/easing-patterns.ts | 28 - packages/vuetify/src/services/goto/index.ts | 94 - packages/vuetify/src/services/goto/util.ts | 52 - .../src/util/__tests__/colorUtils.spec.ts | 13 +- .../vuetify/src/util/__tests__/dom.spec.ts | 2 +- .../__tests__/getCurrentInstance.spec.tsx | 2 +- .../src/util/__tests__/helpers.spec.ts | 19 +- .../src/util/__tests__/propsFactory.spec.ts | 5 +- .../vuetify/test/util/to-have-been-warned.ts | 19 +- packages/vuetify/tsconfig.dev.json | 5 +- .../{vite.config.mjs => vite.config.mts} | 23 +- packages/vuetify/vitest.config.mts | 39 + pnpm-lock.yaml | 1620 +++++++---------- scripts/rules/sort-imports.js | 2 +- ...al-imports.js => vitest-global-imports.js} | 10 +- tsconfig.json | 2 +- 104 files changed, 997 insertions(+), 1838 deletions(-) delete mode 100644 packages/vuetify/jest.config.js create mode 100644 packages/vuetify/src/auto-imports.d.ts create mode 100644 packages/vuetify/src/components.d.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/__tests__/createNativeLocaleFormatter.spec.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/__tests__/monthChange.spec.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/__tests__/pad.spec.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/__tests__/sanitizeDateString.spec.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/createNativeLocaleFormatter.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/eventHelpers.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/index.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/isDateAllowed.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/monthChange.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/pad.ts delete mode 100644 packages/vuetify/src/components/VDatePicker/util/sanitizeDateString.ts create mode 100644 packages/vuetify/src/labs/VTimePicker/util.ts delete mode 100644 packages/vuetify/src/services/goto/__tests__/easing-patterns.spec.ts delete mode 100644 packages/vuetify/src/services/goto/__tests__/goto.spec.ts delete mode 100644 packages/vuetify/src/services/goto/easing-patterns.ts delete mode 100644 packages/vuetify/src/services/goto/index.ts delete mode 100644 packages/vuetify/src/services/goto/util.ts rename packages/vuetify/{vite.config.mjs => vite.config.mts} (85%) create mode 100644 packages/vuetify/vitest.config.mts rename scripts/rules/{jest-global-imports.js => vitest-global-imports.js} (72%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70ae55916d4..02caa559414 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,19 +59,19 @@ jobs: env: SCOPES: ${{ matrix.scopes }} - test-jest: - name: Test (Jest) + test-unit: + name: Test (Unit) needs: pre_job if: needs.pre_job.outputs.should_skip != 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: ./.github/actions/pnpm-install - - run: pnpm run test:coverage -i + - run: pnpm run test working-directory: ./packages/vuetify - test-cypress: - name: Test (Cypress) + test-e2e: + name: Test (e2e) needs: pre_job if: needs.pre_job.outputs.should_skip != 'true' runs-on: ubuntu-latest @@ -94,7 +94,7 @@ jobs: if-no-files-found: ignore deploy: - needs: [lint, test-jest, test-cypress, build-vuetify] + needs: [lint, test-unit, test-e2e, build-vuetify] runs-on: ubuntu-latest if: github.event_name == 'push' && startswith(github.ref, 'refs/tags/v') && github.repository_owner == 'vuetifyjs' steps: @@ -152,7 +152,7 @@ jobs: path: packages/docs/dist publish-docs: - needs: [lint, test-jest, build-docs] + needs: [lint, test-unit, build-docs] runs-on: ubuntu-latest if: github.event_name == 'push' && github.repository_owner == 'vuetifyjs' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/next') steps: diff --git a/.pnpmfile.cjs b/.pnpmfile.cjs index 5ef62d5594e..e7e3c5af05a 100644 --- a/.pnpmfile.cjs +++ b/.pnpmfile.cjs @@ -14,6 +14,10 @@ module.exports = { if (['@rollup/pluginutils', 'rollup-plugin-terser', '@rollup/plugin-replace'].includes(pkg.name)) { pkg.peerDependencies.rollup = '*' } + if (pkg.name === 'brilliant-errors') { + delete pkg.dependencies.bumpp + delete pkg.dependencies.vitest + } return pkg } } diff --git a/eslint-local-rules.js b/eslint-local-rules.js index da775cc19cb..ca3301bfd2b 100644 --- a/eslint-local-rules.js +++ b/eslint-local-rules.js @@ -5,7 +5,7 @@ module.exports = { 'no-components-index': require('./scripts/rules/no-components-index'), 'jsx-condition-key': require('./scripts/rules/jsx-condition-key'), 'jsx-curly-spacing': require('./scripts/rules/jsx-curly-spacing'), - 'jest-global-imports': require('./scripts/rules/jest-global-imports'), + 'vitest-global-imports': require('./scripts/rules/vitest-global-imports'), 'cypress-types-reference': require('./scripts/rules/cypress-types-reference'), 'sort-imports': require('./scripts/rules/sort-imports'), 'no-nullish-coalescing-in-condition': require('./scripts/rules/no-nullish-coalescing-in-condition'), diff --git a/package.json b/package.json index 47897c36a09..5ba44417d02 100755 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "@vue/runtime-dom": "^3.4.27", "@vueuse/head": "^1.3.1", "babel-eslint": "^10.1.0", - "babel-jest": "^28.1.3", "conventional-changelog-cli": "^3.0.0", "conventional-changelog-vuetify": "^1.2.1", "conventional-github-releaser": "^3.1.5", @@ -66,10 +65,6 @@ "glob": "^11.0.0", "husky": "^3.1.0", "inquirer": "^6.5.2", - "jest": "^28.1.3", - "jest-cli": "^28.1.3", - "jest-environment-jsdom": "^28.1.3", - "jest-serializer-html": "^7.1.0", "lerna": "^8.1.7", "magic-string": "^0.30.9", "mkdirp": "^3.0.1", @@ -94,6 +89,9 @@ "pnpm": { "patchedDependencies": { "@mdi/js@7.4.47": "patches/@mdi__js@7.4.47.patch" + }, + "overrides": { + "tough-cookie": "5.0.0-rc.4" } } } diff --git a/packages/vuetify/.eslintrc.js b/packages/vuetify/.eslintrc.js index 544bb482bdb..f2a2419c247 100644 --- a/packages/vuetify/.eslintrc.js +++ b/packages/vuetify/.eslintrc.js @@ -51,7 +51,7 @@ module.exports = { plugins: ['jest'], extends: ['plugin:jest/recommended'], rules: { - 'local-rules/jest-global-imports': 'error', + 'local-rules/vitest-global-imports': 'error', 'no-restricted-imports': 'off', diff --git a/packages/vuetify/dev/vuetify.js b/packages/vuetify/dev/vuetify.js index acb3f99b3cc..38148f5541e 100644 --- a/packages/vuetify/dev/vuetify.js +++ b/packages/vuetify/dev/vuetify.js @@ -1,8 +1,8 @@ import '@mdi/font/css/materialdesignicons.css' -import 'vuetify/src/styles/main.sass' +import '@/styles/main.sass' -import { createVuetify } from 'vuetify/src/framework' -import * as directives from 'vuetify/src/directives' +import { createVuetify } from '@/framework' +import * as directives from '@/directives' import date from './vuetify/date' import defaults from './vuetify/defaults' diff --git a/packages/vuetify/dev/vuetify/icons.js b/packages/vuetify/dev/vuetify/icons.js index e4f68621ac8..81c74f0ac54 100644 --- a/packages/vuetify/dev/vuetify/icons.js +++ b/packages/vuetify/dev/vuetify/icons.js @@ -1,6 +1,6 @@ -import { aliases } from 'vuetify/src/iconsets/mdi-svg' -import { mdi } from 'vuetify/src/iconsets/mdi' -import { fa } from 'vuetify/src/iconsets/fa-svg' +import { aliases } from '@/iconsets/mdi-svg' +import { mdi } from '@/iconsets/mdi' +import { fa } from '@/iconsets/fa-svg' export default { defaultSet: 'mdi', diff --git a/packages/vuetify/dev/vuetify/locale.js b/packages/vuetify/dev/vuetify/locale.js index c3d3e5d6766..acf4e7d7480 100644 --- a/packages/vuetify/dev/vuetify/locale.js +++ b/packages/vuetify/dev/vuetify/locale.js @@ -1,4 +1,4 @@ -import { ar, en, ja, sv } from 'vuetify/src/locale' +import { ar, en, ja, sv } from '@/locale' export default { messages: { diff --git a/packages/vuetify/jest.config.js b/packages/vuetify/jest.config.js deleted file mode 100644 index 1b4261219f3..00000000000 --- a/packages/vuetify/jest.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const base = require('../../jest.config') - -module.exports = { - ...base, - id: 'Vuetify', - displayName: 'Vuetify', - setupFiles: [ - 'jest-canvas-mock', - ], -} diff --git a/packages/vuetify/package.json b/packages/vuetify/package.json index 618ebff3b14..8def3ada4c8 100755 --- a/packages/vuetify/package.json +++ b/packages/vuetify/package.json @@ -108,10 +108,7 @@ "build:lib": "NODE_ENV=lib babel src --out-dir lib --source-maps --extensions \".ts\",\".tsx\",\".snap\" --copy-files --no-copy-ignored --out-file-extension .mjs", "build:types": "rimraf types-temp && tsc --pretty --emitDeclarationOnly -p tsconfig.dist.json && rollup --config build/rollup.types.config.mjs && rimraf types-temp", "tsc": "tsc", - "debug:test": "NODE_ENV=test node --inspect --inspect-brk ../../node_modules/jest/bin/jest.js --no-cache -i --verbose", - "test": "node build/run-tests.js", - "test:unix": "NODE_ENV=test jest", - "test:win32": "NODE_ENV=test jest -i", + "test": "vitest", "test:coverage": "pnpm run test --coverage", "lint": "concurrently -n \"tsc,eslint\" --kill-others-on-fail \"tsc -p tsconfig.checks.json --noEmit --pretty\" \"eslint src -f codeframe --max-warnings 0\"", "lint:fix": "concurrently -n \"tsc,eslint\" \"tsc -p tsconfig.checks.json --noEmit --pretty\" \"eslint --fix src\"", @@ -126,18 +123,17 @@ "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@fortawesome/vue-fontawesome": "^3.0.6", - "@jest/globals": "^28.1.3", "@percy/cli": "^1.28.2", "@percy/cypress": "^3.1.2", "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-typescript": "^11.1.6", - "@types/jest": "^28.1.8", "@types/node": "^20.12.7", "@types/resize-observer-browser": "^0.1.11", "@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue-jsx": "^3.1.0", + "@vitest/coverage-v8": "^2.0.5", "@vue/babel-plugin-jsx": "^1.2.2", "@vue/shared": "^3.4.27", "@vue/test-utils": "2.4.6", @@ -161,7 +157,7 @@ "expect": "^28.1.3", "fast-glob": "^3.3.2", "identity-obj-proxy": "^3.0.0", - "jest-canvas-mock": "^2.5.2", + "jsdom": "^25.0.0", "micromatch": "^4.0.5", "postcss": "^8.4.38", "rollup": "^3.20.7", @@ -170,10 +166,12 @@ "rollup-plugin-sourcemaps": "^0.6.3", "rollup-plugin-terser": "^7.0.2", "timezone-mock": "^1.3.6", + "unplugin-auto-import": "0.17.5", "unplugin-vue-components": "^0.27.4", "upath": "^2.0.1", "vite": "^5.4.0", "vite-ssr": "^0.17.1", + "vitest": "^2.0.5", "vue-i18n": "^9.7.1", "vue-router": "^4.3.0" }, diff --git a/packages/vuetify/src/__tests__/framework.spec.ts b/packages/vuetify/src/__tests__/framework.spec.ts index 5ff9ec1cdf3..14031435f5a 100644 --- a/packages/vuetify/src/__tests__/framework.spec.ts +++ b/packages/vuetify/src/__tests__/framework.spec.ts @@ -1,6 +1,6 @@ // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { expect, it } from 'vitest' import { createVuetify } from '@/framework' describe('framework', () => { diff --git a/packages/vuetify/src/auto-imports.d.ts b/packages/vuetify/src/auto-imports.d.ts new file mode 100644 index 00000000000..7e43e9a13f5 --- /dev/null +++ b/packages/vuetify/src/auto-imports.d.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + const afterAll: typeof import('vitest')['afterAll'] + const afterEach: typeof import('vitest')['afterEach'] + const assert: typeof import('vitest')['assert'] + const beforeAll: typeof import('vitest')['beforeAll'] + const beforeEach: typeof import('vitest')['beforeEach'] + const describe: typeof import('vitest')['describe'] + const expect: typeof import('vitest')['expect'] + const it: typeof import('vitest')['it'] + const vi: typeof import('vitest')['vi'] +} diff --git a/packages/vuetify/src/components.d.ts b/packages/vuetify/src/components.d.ts new file mode 100644 index 00000000000..4edc351177c --- /dev/null +++ b/packages/vuetify/src/components.d.ts @@ -0,0 +1,13 @@ +/* eslint-disable */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +/* prettier-ignore */ +declare module 'vue' { + export interface GlobalComponents { + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + } +} diff --git a/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts b/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts index 972af43efd7..e45f3ef7758 100644 --- a/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts +++ b/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts @@ -1,5 +1,5 @@ // Utilities -import { describe, expect, it } from '@jest/globals' +import { expect, it } from 'vitest' import { extractColor } from '../' const red = { h: 0, s: 1, v: 1, a: 1 } diff --git a/packages/vuetify/src/components/VDataTable/__tests__/VDataTable.spec.ts b/packages/vuetify/src/components/VDataTable/__tests__/VDataTable.spec.ts index 0e2851aea08..658cb89b15f 100644 --- a/packages/vuetify/src/components/VDataTable/__tests__/VDataTable.spec.ts +++ b/packages/vuetify/src/components/VDataTable/__tests__/VDataTable.spec.ts @@ -12,7 +12,7 @@ import { // import Vue from 'vue' // import { Lang } from '../../../services/lang' // import { preset } from '../../../presets/default' -// import { resizeWindow } from '../../../../test' +// import { resizeWindow } from '@/../test' // Vue.prototype.$vuetify = { // icons: {}, diff --git a/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts b/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts index bf5f25a463c..ba5dc1899d1 100644 --- a/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts +++ b/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts @@ -1,7 +1,6 @@ -import { createHeaders } from '../composables/headers' - // Utilities -import { describe, expect, it } from '@jest/globals' +import { expect, it } from 'vitest' +import { createHeaders } from '../composables/headers' describe('VDataTable headers', () => { it('flattens 2d headers', () => { diff --git a/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts b/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts index dc5853d6d9a..477aa4e8dc7 100644 --- a/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts +++ b/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts @@ -4,8 +4,8 @@ import { transformItems as _transformItems } from '../composables/items' import { sortItems as _sortItems } from '../composables/sort' // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { expect, it } from 'vitest' // Types import type { SortItem } from '../composables/sort' diff --git a/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.date.spec.ts b/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.date.spec.ts index 21a70a7eade..00d509fd238 100644 --- a/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.date.spec.ts +++ b/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.date.spec.ts @@ -1,7 +1,7 @@ // @ts-nocheck /* eslint-disable */ -// import { touch } from '../../../../test' +// import { touch } from '@/../test' import { mount, MountOptions, diff --git a/packages/vuetify/src/components/VDatePicker/util/__tests__/createNativeLocaleFormatter.spec.ts b/packages/vuetify/src/components/VDatePicker/util/__tests__/createNativeLocaleFormatter.spec.ts deleted file mode 100644 index e39441f95a5..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/__tests__/createNativeLocaleFormatter.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// import createNativeLocaleFormatter from '../createNativeLocaleFormatter' - -describe.skip('VDatePicker/util/createNativeLocaleFormatter.ts', () => { - it('should format dates', () => { - const formatter = createNativeLocaleFormatter(undefined, { day: 'numeric', timeZone: 'UTC' }) - expect(formatter('2013-2-07')).toBe('7') - }) - - it('should format date with year < 1000', () => { - const formatter = createNativeLocaleFormatter(undefined, { year: 'numeric', timeZone: 'UTC' }) - expect(formatter('13-2-07')).toBe('13') - }) - - it('should format dates if Intl is not defined', () => { - const oldIntl = global.Intl - - global.Intl = null - const formatter = createNativeLocaleFormatter(undefined, { day: 'numeric', timeZone: 'UTC' }, { start: 0, length: 10 }) - expect(formatter('2013-2-7')).toBe('2013-02-07') - expect(formatter('2013-2')).toBe('2013-02-01') - expect(formatter('2013')).toBe('2013-01-01') - - const nullFormatter = createNativeLocaleFormatter(undefined, { day: 'numeric', timeZone: 'UTC' }) - expect(nullFormatter).toBeUndefined() - global.Intl = oldIntl - }) -}) diff --git a/packages/vuetify/src/components/VDatePicker/util/__tests__/monthChange.spec.ts b/packages/vuetify/src/components/VDatePicker/util/__tests__/monthChange.spec.ts deleted file mode 100644 index 8e33d1abb74..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/__tests__/monthChange.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// import monthChange from '../monthChange' - -describe.skip('VDatePicker/util/monthChange.ts', () => { - it('should change month', () => { - expect(monthChange('2000-01', -1)).toBe('1999-12') - expect(monthChange('2000-01', +1)).toBe('2000-02') - expect(monthChange('2000-12', -1)).toBe('2000-11') - expect(monthChange('2000-12', +1)).toBe('2001-01') - }) -}) diff --git a/packages/vuetify/src/components/VDatePicker/util/__tests__/pad.spec.ts b/packages/vuetify/src/components/VDatePicker/util/__tests__/pad.spec.ts deleted file mode 100644 index 0190093d9d2..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/__tests__/pad.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// import pad from '../pad' - -describe.skip('VDatePicker/util/pad.ts', () => { - it('should pad 1-digit numbers', () => { - expect(pad(0)).toBe('00') - expect(pad('3', 3)).toBe('003') - }) - - it('should pad 2-digit numbers', () => { - expect(pad(40)).toBe('40') - expect(pad('98')).toBe('98') - }) - - it('should not pad 3-digit numbers', () => { - expect(pad(400)).toBe('400') - expect(pad('998')).toBe('998') - }) -}) diff --git a/packages/vuetify/src/components/VDatePicker/util/__tests__/sanitizeDateString.spec.ts b/packages/vuetify/src/components/VDatePicker/util/__tests__/sanitizeDateString.spec.ts deleted file mode 100644 index 2e688a6c287..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/__tests__/sanitizeDateString.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Utilities -import { describe, expect, it } from '@jest/globals' -import sanitizeDateString from '../sanitizeDateString' - -describe('VDatePicker/util/sanitizeDateString.ts', () => { - it('should sanitize date string based upon type', () => { - expect(sanitizeDateString('2000-01-02T14:48:00.000Z', 'date')).toBe('2000-01-02') - expect(sanitizeDateString('2000-01-02T14:48:00.000Z', 'month')).toBe('2000-01') - expect(sanitizeDateString('2000-01-02T14:48:00.000Z', 'year')).toBe('2000') - expect(sanitizeDateString('2000-1-2', 'date')).toBe('2000-01-02') - }) -}) diff --git a/packages/vuetify/src/components/VDatePicker/util/createNativeLocaleFormatter.ts b/packages/vuetify/src/components/VDatePicker/util/createNativeLocaleFormatter.ts deleted file mode 100644 index d26787ce784..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/createNativeLocaleFormatter.ts +++ /dev/null @@ -1,43 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -import pad from './pad' -import { DatePickerFormatter } from 'vuetify/types' - -interface SubstrOptions { - start?: number - length: number -} - -function createNativeLocaleFormatter ( - local: string | undefined, - options: Intl.DateTimeFormatOptions -): DatePickerFormatter | undefined - -function createNativeLocaleFormatter ( - local: string | undefined, - options: Intl.DateTimeFormatOptions, - substrOptions: SubstrOptions -): DatePickerFormatter - -function createNativeLocaleFormatter ( - locale: string | undefined, - options: Intl.DateTimeFormatOptions, - substrOptions: SubstrOptions = { start: 0, length: 0 } -): DatePickerFormatter | undefined { - const makeIsoString = (dateString: string) => { - const [year, month, date] = dateString.trim().split(' ')[0].split('-') - return [pad(year, 4), pad(month || 1), pad(date || 1)].join('-') - } - - try { - const intlFormatter = new Intl.DateTimeFormat(locale || undefined, options) - return (dateString: string) => intlFormatter.format(new Date(`${makeIsoString(dateString)}T00:00:00+00:00`)) - } catch (e) { - return (substrOptions.start || substrOptions.length) - ? (dateString: string) => makeIsoString(dateString).substr(substrOptions.start || 0, substrOptions.length) - : undefined - } -} - -export default createNativeLocaleFormatter diff --git a/packages/vuetify/src/components/VDatePicker/util/eventHelpers.ts b/packages/vuetify/src/components/VDatePicker/util/eventHelpers.ts deleted file mode 100644 index 9bee354c0a8..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/eventHelpers.ts +++ /dev/null @@ -1,24 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -// import Vue from 'vue' - -export function createItemTypeNativeListeners (instance: /*Vue*/any, itemTypeSuffix: string, value: any) { - return Object.keys(instance.$listeners).reduce((on, eventName) => { - if (eventName.endsWith(itemTypeSuffix)) { - on[eventName.slice(0, -itemTypeSuffix.length)] = (event: Event) => instance.$emit(eventName, value, event) - } - - return on - }, {} as typeof instance.$listeners) -} - -export function createItemTypeListeners (instance: /*Vue*/any, itemTypeSuffix: string) { - return Object.keys(instance.$listeners).reduce((on, eventName) => { - if (eventName.endsWith(itemTypeSuffix)) { - on[eventName] = instance.$listeners[eventName] - } - - return on - }, {} as typeof instance.$listeners) -} diff --git a/packages/vuetify/src/components/VDatePicker/util/index.ts b/packages/vuetify/src/components/VDatePicker/util/index.ts deleted file mode 100644 index c379581d911..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -import { - createItemTypeListeners, - createItemTypeNativeListeners, -} from './eventHelpers' -import createNativeLocaleFormatter from './createNativeLocaleFormatter' -import monthChange from './monthChange' -import sanitizeDateString from './sanitizeDateString' -import pad from './pad' - -export { - createItemTypeListeners, - createItemTypeNativeListeners, - createNativeLocaleFormatter, - monthChange, - sanitizeDateString, - pad, -} diff --git a/packages/vuetify/src/components/VDatePicker/util/isDateAllowed.ts b/packages/vuetify/src/components/VDatePicker/util/isDateAllowed.ts deleted file mode 100644 index d1ad1eeaa6b..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/isDateAllowed.ts +++ /dev/null @@ -1,10 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -import { DatePickerAllowedDatesFunction } from 'vuetify/types' - -export default function isDateAllowed (date: string, min: string, max: string, allowedFn: DatePickerAllowedDatesFunction | undefined) { - return (!allowedFn || allowedFn(date)) && - (!min || date >= min.substr(0, 10)) && - (!max || date <= max) -} diff --git a/packages/vuetify/src/components/VDatePicker/util/monthChange.ts b/packages/vuetify/src/components/VDatePicker/util/monthChange.ts deleted file mode 100644 index 178f7fb3741..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/monthChange.ts +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -import pad from './pad' - -/** - * @param {String} value YYYY-MM format - * @param {Number} sign -1 or +1 - */ -export default (value: string, sign: number) => { - const [year, month] = value.split('-').map(Number) - - if (month + sign === 0) { - return `${year - 1}-12` - } else if (month + sign === 13) { - return `${year + 1}-01` - } else { - return `${year}-${pad(month + sign)}` - } -} diff --git a/packages/vuetify/src/components/VDatePicker/util/pad.ts b/packages/vuetify/src/components/VDatePicker/util/pad.ts deleted file mode 100644 index eede14aea94..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/pad.ts +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-nocheck -/* eslint-disable */ - -const padStart = (string: number | string, targetLength: number, padString: string) => { - targetLength = targetLength >> 0 - string = String(string) - padString = String(padString) - if (string.length > targetLength) { - return String(string) - } - - targetLength = targetLength - string.length - if (targetLength > padString.length) { - padString += padString.repeat(targetLength / padString.length) - } - return padString.slice(0, targetLength) + String(string) -} - -export default (n: string | number, length = 2) => padStart(n, length, '0') diff --git a/packages/vuetify/src/components/VDatePicker/util/sanitizeDateString.ts b/packages/vuetify/src/components/VDatePicker/util/sanitizeDateString.ts deleted file mode 100644 index 00e65cdf6dd..00000000000 --- a/packages/vuetify/src/components/VDatePicker/util/sanitizeDateString.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Adds leading zero to month/day if necessary, returns 'YYYY' if type = 'year', -// 'YYYY-MM' if 'month' and 'YYYY-MM-DD' if 'date' -import pad from './pad' - -export default (dateString: string, type: 'date' | 'month' | 'year'): string => { - const [year, month = 1, date = 1] = dateString.split('-') - return `${year}-${pad(month)}-${pad(date)}`.substr(0, { date: 10, month: 7, year: 4 }[type]) -} diff --git a/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx b/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx index 67295922958..0b129da50d4 100644 --- a/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx +++ b/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx @@ -1,8 +1,8 @@ import { VFileInput } from '../VFileInput' // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { describe, expect, it, vi } from 'vitest' import { createVuetify } from '@/framework' describe('VFileInput', () => { @@ -45,10 +45,10 @@ describe('VFileInput', () => { }) it('has affixed icons with actions', () => { - const onClickPrepend = jest.fn() - const onClickPrependInner = jest.fn() - const onClickAppendInner = jest.fn() - const onClickAppend = jest.fn() + const onClickPrepend = vi.fn() + const onClickPrependInner = vi.fn() + const onClickAppendInner = vi.fn() + const onClickAppend = vi.fn() const wrapper = mountFunction( { // https://github.com/vuetifyjs/vuetify/issues/5384 it('should not unregister children when is destroyed', async () => { - const change = jest.fn() + const change = vi.fn() const wrapper = mountFunction({ props: { modelValue: 'foo', diff --git a/packages/vuetify/src/components/VItemGroup/__tests__/__snapshots__/VItemGroup.spec.ts.snap b/packages/vuetify/src/components/VItemGroup/__tests__/__snapshots__/VItemGroup.spec.ts.snap index 5b13b579f25..b1438a1141c 100644 --- a/packages/vuetify/src/components/VItemGroup/__tests__/__snapshots__/VItemGroup.spec.ts.snap +++ b/packages/vuetify/src/components/VItemGroup/__tests__/__snapshots__/VItemGroup.spec.ts.snap @@ -1,6 +1,7 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`VItemGroup should render with a specified tag when the tag prop is provided with a value 1`] = ` - +exports[`VItemGroup > should render with a specified tag when the tag prop is provided with a value 1`] = ` +"" `; diff --git a/packages/vuetify/src/components/VList/__tests__/VList.spec.ts b/packages/vuetify/src/components/VList/__tests__/VList.spec.ts index 5e5c9986fb8..58a6a31d5d2 100644 --- a/packages/vuetify/src/components/VList/__tests__/VList.spec.ts +++ b/packages/vuetify/src/components/VList/__tests__/VList.spec.ts @@ -2,8 +2,8 @@ import { VList } from '..' // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { expect, it } from 'vitest' import { createVuetify } from '@/framework' describe('VList', () => { diff --git a/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts b/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts index 0fcf032f775..bd799bd8200 100644 --- a/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts +++ b/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts @@ -2,8 +2,8 @@ import { VListItemMedia } from '..' // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { expect, it } from 'vitest' import { createVuetify } from '@/framework' describe('VListItemMedia', () => { diff --git a/packages/vuetify/src/components/VList/__tests__/__snapshots__/VList.spec.ts.snap b/packages/vuetify/src/components/VList/__tests__/__snapshots__/VList.spec.ts.snap index 7c65a62b36a..185a47d2033 100644 --- a/packages/vuetify/src/components/VList/__tests__/__snapshots__/VList.spec.ts.snap +++ b/packages/vuetify/src/components/VList/__tests__/__snapshots__/VList.spec.ts.snap @@ -1,9 +1,3 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`VList should match a snapshot 1`] = ` -
-
-`; +exports[`VList > should match a snapshot 1`] = `"
"`; diff --git a/packages/vuetify/src/components/VList/__tests__/__snapshots__/VListItemMedia.spec.ts.snap b/packages/vuetify/src/components/VList/__tests__/__snapshots__/VListItemMedia.spec.ts.snap index c61febfcbf4..5ca2a776d0a 100644 --- a/packages/vuetify/src/components/VList/__tests__/__snapshots__/VListItemMedia.spec.ts.snap +++ b/packages/vuetify/src/components/VList/__tests__/__snapshots__/VListItemMedia.spec.ts.snap @@ -1,6 +1,3 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`VListItemMedia should match a snapshot 1`] = ` -
-
-`; +exports[`VListItemMedia > should match a snapshot 1`] = `"
"`; diff --git a/packages/vuetify/src/components/VMenu/__tests__/VMenu.spec.ts b/packages/vuetify/src/components/VMenu/__tests__/VMenu.spec.ts index cbf97c80cb2..6b551ec3e59 100644 --- a/packages/vuetify/src/components/VMenu/__tests__/VMenu.spec.ts +++ b/packages/vuetify/src/components/VMenu/__tests__/VMenu.spec.ts @@ -12,7 +12,7 @@ import { Wrapper, } from '@vue/test-utils' // import { keyCodes } from '../../../util/helpers' -// import { waitAnimationFrame } from '../../../../test' +// import { waitAnimationFrame } from '@/../test' describe.skip('VMenu.ts', () => { type Instance = InstanceType diff --git a/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts b/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts index 45210d6fe06..5257be49b7b 100644 --- a/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts +++ b/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts @@ -2,8 +2,8 @@ import { VResponsive } from '..' // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { expect, it } from 'vitest' import { h } from 'vue' import { createVuetify } from '@/framework' diff --git a/packages/vuetify/src/components/VResponsive/__tests__/__snapshots__/VResponsive.spec.ts.snap b/packages/vuetify/src/components/VResponsive/__tests__/__snapshots__/VResponsive.spec.ts.snap index a7163b6fdde..1c08dd65da1 100644 --- a/packages/vuetify/src/components/VResponsive/__tests__/__snapshots__/VResponsive.spec.ts.snap +++ b/packages/vuetify/src/components/VResponsive/__tests__/__snapshots__/VResponsive.spec.ts.snap @@ -1,31 +1,27 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`VResponsive should force aspect ratio 1`] = ` -
-
-
-
+exports[`VResponsive > should force aspect ratio 1`] = ` +"
+
+ + +
" `; -exports[`VResponsive should render content 1`] = ` -
-
-
+exports[`VResponsive > should render content 1`] = ` +"
+
+
-
- content -
+
content
-
+
" `; -exports[`VResponsive should set height 1`] = ` -
-
-
-
+exports[`VResponsive > should set height 1`] = ` +"
+
+ + +
" `; diff --git a/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx b/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx index 33abc49aa23..c42bd239f69 100644 --- a/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx +++ b/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx @@ -2,8 +2,8 @@ import { makeVSelectionControlProps, useSelectionControl } from '../VSelectionControl' // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { describe, expect, it, vi } from 'vitest' import { defineComponent, nextTick } from 'vue' import { createVuetify } from '@/framework' @@ -36,7 +36,7 @@ describe('VSelectionControl', () => { }) it('should use trueValue', async () => { - const update = jest.fn() + const update = vi.fn() const wrapper = mountFunction({ props: { trueValue: 'on', @@ -52,7 +52,7 @@ describe('VSelectionControl', () => { }) it('should use falseValue', async () => { - const update = jest.fn() + const update = vi.fn() const wrapper = mountFunction({ props: { trueValue: 'on', diff --git a/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx b/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx index 7402048b710..2532399c57e 100644 --- a/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx +++ b/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx @@ -1,8 +1,8 @@ import { VTextField } from '../VTextField' // Utilities -import { describe, expect, it } from '@jest/globals' import { mount } from '@vue/test-utils' +import { describe, expect, it, vi } from 'vitest' import { createVuetify } from '@/framework' describe('VTextField', () => { @@ -45,10 +45,10 @@ describe('VTextField', () => { }) it('has affixed icons with actions', () => { - const onClickPrepend = jest.fn() - const onClickPrependInner = jest.fn() - const onClickAppendInner = jest.fn() - const onClickAppend = jest.fn() + const onClickPrepend = vi.fn() + const onClickPrependInner = vi.fn() + const onClickAppendInner = vi.fn() + const onClickAppend = vi.fn() const wrapper = mountFunction( { @@ -45,10 +45,10 @@ describe('VTextarea', () => { }) it('has affixed icons with actions', () => { - const onClickPrepend = jest.fn() - const onClickPrependInner = jest.fn() - const onClickAppendInner = jest.fn() - const onClickAppend = jest.fn() + const onClickPrepend = vi.fn() + const onClickPrependInner = vi.fn() + const onClickAppendInner = vi.fn() + const onClickAppend = vi.fn() const wrapper = mountFunction( -
- {"foo":1} -
-
- {"bar":2} -
- +exports[`group > with complex values > should accept new value 1`] = ` +"
+
{"foo":1}
+
{"bar":2}
+
" `; -exports[`group with complex values should accept new value 2`] = ` -
-
- {"foo":1} -
-
- {"bar":2} -
-
+exports[`group > with complex values > should accept new value 2`] = ` +"
+
{"foo":1}
+
{"bar":2}
+
" `; -exports[`group with complex values should emit selected value 1`] = ` -
-
- {"foo":1} -
-
- {"bar":2} -
-
+exports[`group > with complex values > should emit selected value 1`] = ` +"
+
{"foo":1}
+
{"bar":2}
+
" `; -exports[`group with explicit values should emit new selection 1`] = ` -
-
- one -
-
- two -
-
+exports[`group > with explicit values > should emit new selection 1`] = ` +"
+
one
+
two
+
" `; -exports[`group with explicit values should not emit new selection if clicking disabled item 1`] = ` -
-
- one -
-
- two -
-
+exports[`group > with explicit values > should not emit new selection if clicking disabled item 1`] = ` +"
+
one
+
two
+
" `; -exports[`group with implicit values should emit new selection 1`] = ` -
-
-
-
-
-
+exports[`group > with implicit values > should emit new selection 1`] = ` +"
+
+
+
" `; -exports[`group with implicit values should set first non-disabled item as value when forced mandatory 1`] = ` -
-
-
-
-
-
+exports[`group > with implicit values > should set first non-disabled item as value when forced mandatory 1`] = ` +"
+
+
+
" `; diff --git a/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap b/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap index 87b59f42da9..c8531ed3b4c 100644 --- a/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap +++ b/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap @@ -1,6 +1,6 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`createTheme should create style element 1`] = ` +exports[`createTheme > should create style element 1`] = ` diff --git a/packages/docs/src/components/app/bar/Bar.vue b/packages/docs/src/components/app/bar/Bar.vue index 09084f40c30..418ffa3d06d 100644 --- a/packages/docs/src/components/app/bar/Bar.vue +++ b/packages/docs/src/components/app/bar/Bar.vue @@ -20,6 +20,8 @@ From 196e8a7968e8943ccef63445c2ec33ad10dae89d Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 20 Sep 2024 16:53:31 +1000 Subject: [PATCH 095/190] chore(ci): delay promoting docs deployment --- scripts/deploy-and-alias.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/deploy-and-alias.js b/scripts/deploy-and-alias.js index 6e2fcebc8c0..a949de7fd44 100644 --- a/scripts/deploy-and-alias.js +++ b/scripts/deploy-and-alias.js @@ -25,4 +25,6 @@ if (child.code !== 0) { } const instanceUrl = child.stdout -shell.exec(`vercel alias set ${instanceUrl} ${alias} --scope=vuetifyjs --token=$NOW_TOKEN`, options) +setTimeout(() => { + shell.exec(`vercel alias set ${instanceUrl} ${alias} --scope=vuetifyjs --token=$NOW_TOKEN`, options) +}, 15_000) From 1b3ed5a2e72d04119df89b5440fe4bd4e6955fc2 Mon Sep 17 00:00:00 2001 From: Yuchao Date: Sun, 22 Sep 2024 20:52:25 +1000 Subject: [PATCH 096/190] fix(VTreeview): search doesn't work with return-object (#20508) --- .../vuetify/src/labs/VTreeview/VTreeview.tsx | 6 +- .../VTreeview/__tests__/VTreeview.spec.cy.tsx | 103 +++++++++++++++++- 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/packages/vuetify/src/labs/VTreeview/VTreeview.tsx b/packages/vuetify/src/labs/VTreeview/VTreeview.tsx index 172deddbc10..3ada9eb33f8 100644 --- a/packages/vuetify/src/labs/VTreeview/VTreeview.tsx +++ b/packages/vuetify/src/labs/VTreeview/VTreeview.tsx @@ -90,7 +90,11 @@ export const VTreeview = genericComponent( const getPath = vListRef.value?.getPath if (!getPath) return null return new Set(filteredItems.value.flatMap(item => { - return [...getPath(item.props.value), ...getChildren(item.props.value)] + const itemVal = props.returnObject ? item.raw : item.props.value + return [ + ...getPath(itemVal), + ...getChildren(itemVal), + ].map(toRaw) })) }) diff --git a/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx b/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx index 541b9f929df..a3e5aebf144 100644 --- a/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx +++ b/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx @@ -2,9 +2,10 @@ // Components import { VTreeview } from '../VTreeview' +import { VTextField } from '@/components/VTextField' // Utilities -import { ref } from 'vue' +import { ref, shallowRef } from 'vue' function compareItemObject (a: any, b: any) { return a.id - b.id @@ -849,6 +850,106 @@ describe('VTreeview', () => { }) }) }) + describe('search', () => { + // https://github.com/vuetifyjs/vuetify/issues/20488 + it('should filter items based on the search text and return the correct result', () => { + const items = ref([ + { + id: 1, + title: 'Vuetify Human Resources', + children: [ + { + id: 2, + title: 'Core team', + children: [ + { + id: 201, + title: 'John', + }, + { + id: 202, + title: 'Kael', + }, + { + id: 203, + title: 'Nekosaur', + }, + { + id: 204, + title: 'Jacek', + }, + { + id: 205, + title: 'Andrew', + }, + ], + }, + { + id: 3, + title: 'Administrators', + children: [ + { + id: 301, + title: 'Mike', + }, + { + id: 302, + title: 'Hunt', + }, + ], + }, + { + id: 4, + title: 'Contributors', + children: [ + { + id: 401, + title: 'Phlow', + }, + { + id: 402, + title: 'Brandon', + }, + { + id: 403, + title: 'Sean', + }, + ], + }, + ], + }, + ]) + const search = shallowRef('') + + function filterFn (value: string, search: string) { + return value.toLowerCase().includes(search.toLowerCase()) + } + cy.mount(() => ( + <> + + + + )) + .get('.v-text-field input') + .type('j') + .get('.v-treeview-item').eq(0).should('be.visible') // { id: 1, title: 'Vuetify Human Resources' } + .get('.v-treeview-item').eq(1).should('be.visible') // { id: 2, title: 'Core team' } + .get('.v-treeview-item').eq(2).should('be.visible') // { id: 201, title: 'John' } + .get('.v-treeview-item').eq(3).should('not.be.visible') + .get('.v-treeview-item').eq(4).should('not.be.visible') + .get('.v-treeview-item').eq(5).should('be.visible') // { id: 204, title: 'Jacek' } + .get('.v-treeview-item').eq(9).should('not.be.visible') + .get('.v-treeview-item').eq(13).should('not.be.visible') + }) + }) }) it('should have all items visible when open-all is applied', () => { From 4fb1513ce6cf71161685ec8041489c4d4a724370 Mon Sep 17 00:00:00 2001 From: Kael Date: Wed, 25 Sep 2024 23:55:59 +1000 Subject: [PATCH 097/190] chore: replace cypress with vitest (#20445) Co-authored-by: John Leider --- .github/actions/pnpm-install/action.yml | 16 +- .github/workflows/ci.yml | 16 +- .gitignore | 3 + eslint-local-rules.js | 1 - package.json | 7 +- packages/docs/package.json | 2 +- packages/vuetify/.eslintignore | 2 + packages/vuetify/.eslintrc.js | 44 +- packages/vuetify/cypress.config.ts | 16 - .../vuetify/cypress/fixtures/example.json | 5 - packages/vuetify/cypress/fixtures/text.txt | 1 - .../cypress/support/component-index.html | 13 - packages/vuetify/cypress/support/index.ts | 7 - packages/vuetify/cypress/support/mount.ts | 74 - packages/vuetify/cypress/support/selector.ts | 5 - packages/vuetify/package.json | 35 +- ...work.spec.ts => framework.spec.browser.ts} | 1 - packages/vuetify/src/components.d.ts | 13 - ...rt.spec.cy.tsx => VAlert.spec.browser.tsx} | 25 +- .../__tests__/VAutocomplete.spec.browser.tsx | 639 ++++ .../__tests__/VAutocomplete.spec.cy.tsx | 658 ---- .../VBadge/__tests__/VBadge.spec.browser.tsx | 79 + .../VBadge/__tests__/VBadge.spec.cy.tsx | 122 - .../VBtn/__tests__/VBtn.spec.browser.tsx | 241 ++ .../VBtn/__tests__/VBtn.spec.cy.tsx | 301 -- .../__tests__/VCheckboxBtn.spec.browser.tsx | 60 + .../__tests__/VCheckboxBtn.spec.cy.tsx | 63 - .../vuetify/src/components/VChip/VChip.tsx | 1 + .../VChip/__tests__/VChip.spec.browser.tsx | 49 + .../VChip/__tests__/VChip.spec.cy.tsx | 33 - .../components/VColorPicker/VColorPicker.tsx | 4 +- .../__tests__/VColorPicker.spec.browser.tsx | 170 + .../__tests__/VColorPicker.spec.cy.tsx | 315 -- .../VColorPicker/util/__tests__/index.spec.ts | 1 - .../__tests__/VCombobox.spec.browser.tsx | 741 ++++ .../VCombobox/__tests__/VCombobox.spec.cy.tsx | 816 ---- .../__test__/VConfirmEdit.spec.browser.tsx | 88 + .../__test__/VConfirmEdit.spec.cy.tsx | 83 - .../VDataTable/__tests__/headers.spec.ts | 1 - .../VDataTable/__tests__/sort.spec.ts | 1 - .../__tests__/VFileInput.spec.browser.tsx | 191 + .../__tests__/VFileInput.spec.cy.tsx | 237 -- .../VFileInput/__tests__/VFileInput.spec.tsx | 1 - .../components/VFileInput/__tests__/text.txt | 1 + .../components/VGrid/__tests__/VCol.spec.ts | 1 - ...ut.spec.cy.tsx => VInput.spec.browser.tsx} | 5 +- .../VItemGroup/__tests__/VItemGroup.spec.ts | 1 - .../src/components/VList/VListItem.tsx | 1 + .../components/VList/__tests__/VList.spec.ts | 1 - .../VList/__tests__/VListItemMedia.spec.ts | 1 - .../VMain/__tests__/VMain.spec.cy.tsx | 17 - .../VResponsive/__tests__/VResponsive.spec.ts | 1 - .../__tests__/VSelect.spec.browser.tsx | 596 +++ .../VSelect/__tests__/VSelect.spec.cy.tsx | 643 ---- .../__tests__/VSelectionControl.spec.cy.tsx | 30 - .../__tests__/VSelectionControl.spec.tsx | 1 - ...h.spec.cy.tsx => VSwitch.spec.browser.tsx} | 13 +- .../__tests__/VSystemBar.spec.cy.tsx | 21 - .../__tests__/VTextField.spec.browser.tsx | 96 + .../__tests__/VTextField.spec.cy.tsx | 95 - .../VTextField/__tests__/VTextField.spec.tsx | 1 - .../VTextarea/__tests__/VTextarea.spec.tsx | 1 - .../__tests__/VVirtualScroll.spec.browser.tsx | 51 + .../__tests__/VVirtualScroll.spec.cy.tsx | 47 - .../src/composables/__tests__/border.spec.ts | 1 - .../__tests__/calendar.spec.cy.tsx | 38 - .../composables/__tests__/calendar.spec.ts | 73 + .../src/composables/__tests__/color.spec.ts | 1 - .../composables/__tests__/defaults.spec.ts | 1 - .../src/composables/__tests__/delay.spec.ts | 1 - .../composables/__tests__/dimensions.spec.ts | 1 - .../display-components.spec.browser.tsx | 49 + ...isplay.spec.ts => display.spec.browser.ts} | 21 +- .../composables/__tests__/display.spec.cy.tsx | 38 - .../composables/__tests__/elevation.spec.ts | 1 - .../src/composables/__tests__/filter.spec.ts | 1 - .../__tests__/forwardRefs.spec.tsx | 1 - .../__tests__/goto.spec.browser.tsx | 82 + .../composables/__tests__/goto.spec.cy.tsx | 89 - .../src/composables/__tests__/group.spec.ts | 1 - .../src/composables/__tests__/icons.spec.ts | 1 - .../src/composables/__tests__/items.spec.ts | 1 - .../src/composables/__tests__/loader.spec.ts | 1 - .../composables/__tests__/location.spec.ts | 1 - .../__tests__/mutationObserver.spec.ts | 1 - .../composables/__tests__/position.spec.ts | 1 - .../__tests__/proxiedModel.spec.ts | 1 - .../__tests__/resizeObserver.spec.browser.tsx | 25 + .../__tests__/resizeObserver.spec.ts | 24 - .../src/composables/__tests__/rounded.spec.ts | 1 - .../__tests__/scroll.spec.browser.tsx | 98 + .../src/composables/__tests__/scroll.spec.ts | 125 - .../src/composables/__tests__/size.spec.ts | 1 - .../src/composables/__tests__/tag.spec.ts | 1 - .../src/composables/__tests__/theme.spec.ts | 3 +- .../composables/__tests__/validation.spec.ts | 1 - .../src/composables/__tests__/variant.spec.ts | 1 - .../composables/date/__tests__/date.spec.ts | 1 - .../date/adapters/__tests__/vuetify.spec.ts | 1 - .../nested/__tests__/selectStrategies.spec.ts | 1 - .../click-outside-shadow-dom.spec.ts | 1 - .../__tests__/click-outside.spec.ts | 1 - .../__tests__/intersect.spec.browser.tsx | 92 + .../intersect/__tests__/intersect.spec.ts | 62 - .../mutate/__tests__/mutate.spec.ts | 1 - .../resize/__tests__/resize.spec.ts | 1 - .../ripple/__tests__/ripple.spec.ts | 1 - .../vuetify/src/directives/ripple/index.ts | 4 +- .../scroll/__tests__/scroll.spec.browser.tsx | 49 + .../scroll/__tests__/scroll.spec.ts | 102 - .../touch/__tests__/touch.spec.browser.tsx | 96 + .../directives/touch/__tests__/touch.spec.ts | 105 - packages/vuetify/src/globals.d.ts | 10 - .../__tests__/VTreeview.spec.browser.tsx | 654 ++++ .../VTreeview/__tests__/VTreeview.spec.cy.tsx | 970 ----- .../src/locale/__tests__/index.spec.ts | 1 - .../src/util/__tests__/colorUtils.spec.ts | 1 - .../vuetify/src/util/__tests__/dom.spec.ts | 1 - .../__tests__/getCurrentInstance.spec.tsx | 1 - .../src/util/__tests__/helpers.spec.ts | 1 - .../src/util/__tests__/propsFactory.spec.ts | 1 - packages/vuetify/test/globals.d.ts | 15 + packages/vuetify/test/index.ts | 113 +- .../vuetify/test/setup/browser-commands.ts | 73 + packages/vuetify/test/setup/browser-setup.ts | 12 + packages/vuetify/test/setup/percy.d.ts | 13 + .../vuetify/test/setup/to-have-been-warned.ts | 68 + packages/vuetify/test/setup/unit-setup.ts | 6 + .../templates/Application.tsx | 0 .../templates/CenteredGrid.tsx | 0 .../templates/generateStories.tsx | 107 +- .../{cypress => test}/templates/gridOn.tsx | 0 .../{cypress => test}/templates/index.ts | 0 .../vuetify/test/util/to-have-been-warned.ts | 74 - packages/vuetify/tsconfig.dev.json | 9 +- packages/vuetify/tsconfig.dist.json | 2 +- packages/vuetify/tsconfig.json | 20 +- packages/vuetify/types/cypress.d.ts | 49 - packages/vuetify/vite.config.mts | 16 +- packages/vuetify/vitest.config.mts | 85 +- packages/vuetify/vitest.workspace.mts | 43 + patches/@testing-library__vue.patch | 39 + pnpm-lock.yaml | 3302 +++++++++++------ scripts/rules/cypress-types-reference.js | 33 - scripts/rules/sort-imports.js | 2 +- scripts/rules/vitest-global-imports.js | 30 +- tsconfig.json | 1 + 147 files changed, 6904 insertions(+), 6857 deletions(-) delete mode 100644 packages/vuetify/cypress.config.ts delete mode 100644 packages/vuetify/cypress/fixtures/example.json delete mode 100644 packages/vuetify/cypress/fixtures/text.txt delete mode 100644 packages/vuetify/cypress/support/component-index.html delete mode 100644 packages/vuetify/cypress/support/index.ts delete mode 100644 packages/vuetify/cypress/support/mount.ts delete mode 100644 packages/vuetify/cypress/support/selector.ts rename packages/vuetify/src/__tests__/{framework.spec.ts => framework.spec.browser.ts} (97%) delete mode 100644 packages/vuetify/src/components.d.ts rename packages/vuetify/src/components/VAlert/__tests__/{VAlert.spec.cy.tsx => VAlert.spec.browser.tsx} (61%) create mode 100644 packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VChip/__tests__/VChip.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VChip/__tests__/VChip.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VFileInput/__tests__/text.txt rename packages/vuetify/src/components/VInput/__tests__/{VInput.spec.cy.tsx => VInput.spec.browser.tsx} (83%) delete mode 100644 packages/vuetify/src/components/VMain/__tests__/VMain.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.cy.tsx delete mode 100644 packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.cy.tsx rename packages/vuetify/src/components/VSwitch/__tests__/{VSwitch.spec.cy.tsx => VSwitch.spec.browser.tsx} (78%) delete mode 100644 packages/vuetify/src/components/VSystemBar/__tests__/VSystemBar.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.cy.tsx create mode 100644 packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.browser.tsx delete mode 100644 packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.cy.tsx delete mode 100644 packages/vuetify/src/composables/__tests__/calendar.spec.cy.tsx create mode 100644 packages/vuetify/src/composables/__tests__/calendar.spec.ts create mode 100644 packages/vuetify/src/composables/__tests__/display-components.spec.browser.tsx rename packages/vuetify/src/composables/__tests__/{display.spec.ts => display.spec.browser.ts} (91%) delete mode 100644 packages/vuetify/src/composables/__tests__/display.spec.cy.tsx create mode 100644 packages/vuetify/src/composables/__tests__/goto.spec.browser.tsx delete mode 100644 packages/vuetify/src/composables/__tests__/goto.spec.cy.tsx create mode 100644 packages/vuetify/src/composables/__tests__/resizeObserver.spec.browser.tsx delete mode 100644 packages/vuetify/src/composables/__tests__/resizeObserver.spec.ts create mode 100644 packages/vuetify/src/composables/__tests__/scroll.spec.browser.tsx delete mode 100644 packages/vuetify/src/composables/__tests__/scroll.spec.ts create mode 100644 packages/vuetify/src/directives/intersect/__tests__/intersect.spec.browser.tsx delete mode 100644 packages/vuetify/src/directives/intersect/__tests__/intersect.spec.ts create mode 100644 packages/vuetify/src/directives/scroll/__tests__/scroll.spec.browser.tsx delete mode 100644 packages/vuetify/src/directives/scroll/__tests__/scroll.spec.ts create mode 100644 packages/vuetify/src/directives/touch/__tests__/touch.spec.browser.tsx delete mode 100644 packages/vuetify/src/directives/touch/__tests__/touch.spec.ts create mode 100644 packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.browser.tsx delete mode 100644 packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx create mode 100644 packages/vuetify/test/globals.d.ts create mode 100644 packages/vuetify/test/setup/browser-commands.ts create mode 100644 packages/vuetify/test/setup/browser-setup.ts create mode 100644 packages/vuetify/test/setup/percy.d.ts create mode 100644 packages/vuetify/test/setup/to-have-been-warned.ts create mode 100644 packages/vuetify/test/setup/unit-setup.ts rename packages/vuetify/{cypress => test}/templates/Application.tsx (100%) rename packages/vuetify/{cypress => test}/templates/CenteredGrid.tsx (100%) rename packages/vuetify/{cypress => test}/templates/generateStories.tsx (66%) rename packages/vuetify/{cypress => test}/templates/gridOn.tsx (100%) rename packages/vuetify/{cypress => test}/templates/index.ts (100%) delete mode 100644 packages/vuetify/test/util/to-have-been-warned.ts delete mode 100644 packages/vuetify/types/cypress.d.ts create mode 100644 packages/vuetify/vitest.workspace.mts create mode 100644 patches/@testing-library__vue.patch delete mode 100644 scripts/rules/cypress-types-reference.js diff --git a/.github/actions/pnpm-install/action.yml b/.github/actions/pnpm-install/action.yml index fa18384a880..db110e7a22d 100644 --- a/.github/actions/pnpm-install/action.yml +++ b/.github/actions/pnpm-install/action.yml @@ -4,18 +4,12 @@ description: Restore node_modules and cache, then run pnpm install runs: using: composite steps: - - uses: actions/cache@v4 - with: - path: | - node_modules - **/node_modules - /home/runner/.cache/pnpm - /home/runner/.cache/Cypress - /home/runner/.pnpm-store - key: pnpm-${{ runner.os }}-${{ hashFiles('./pnpm-lock.yaml') }} + - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - node-version-file: .nvmrc - - uses: pnpm/action-setup@v4 + cache: 'pnpm' + node-version-file: '.nvmrc' + - run: pnpm --version + shell: bash - run: pnpm i --frozen-lockfile shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02caa559414..f00c0a5f41c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ./.github/actions/pnpm-install - - run: pnpm run test + - run: pnpm run test --project unit working-directory: ./packages/vuetify test-e2e: @@ -78,20 +78,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ./.github/actions/pnpm-install - - run: pnpm cy:run --record --parallel --ci-build-id $GITHUB_RUN_ID - if: ${{ !startswith(github.ref, 'refs/tags/v') && github.repository_owner == 'vuetifyjs' }} + - run: pnpm run test --project browser working-directory: ./packages/vuetify - env: - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - - run: pnpm cy:run - if: ${{ !startswith(github.ref, 'refs/tags/v') && github.repository_owner != 'vuetifyjs' }} - working-directory: ./packages/vuetify - - uses: actions/upload-artifact@v3 - if: failure() - with: - name: cypress-screenshots - path: ./packages/vuetify/cypress/screenshots/ - if-no-files-found: ignore deploy: needs: [lint, test-unit, test-e2e, build-vuetify] diff --git a/.gitignore b/.gitignore index e556fb4f513..f433d067efa 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,8 @@ coverage/ cypress/screenshots cypress/videos +# vitest +__screenshots__/ + .vercel .now diff --git a/eslint-local-rules.js b/eslint-local-rules.js index ca3301bfd2b..8bbba50c890 100644 --- a/eslint-local-rules.js +++ b/eslint-local-rules.js @@ -6,7 +6,6 @@ module.exports = { 'jsx-condition-key': require('./scripts/rules/jsx-condition-key'), 'jsx-curly-spacing': require('./scripts/rules/jsx-curly-spacing'), 'vitest-global-imports': require('./scripts/rules/vitest-global-imports'), - 'cypress-types-reference': require('./scripts/rules/cypress-types-reference'), 'sort-imports': require('./scripts/rules/sort-imports'), 'no-nullish-coalescing-in-condition': require('./scripts/rules/no-nullish-coalescing-in-condition'), } diff --git a/package.json b/package.json index 5ba44417d02..037d29e737f 100755 --- a/package.json +++ b/package.json @@ -85,12 +85,15 @@ "vue-tsc": "^2.0.29", "yargs": "^17.7.2" }, - "packageManager": "pnpm@9.6.0", + "packageManager": "pnpm@9.10.0", "pnpm": { "patchedDependencies": { - "@mdi/js@7.4.47": "patches/@mdi__js@7.4.47.patch" + "@mdi/js@7.4.47": "patches/@mdi__js@7.4.47.patch", + "@testing-library/vue": "patches/@testing-library__vue.patch" }, "overrides": { + "@testing-library/dom": "npm:@vuetify/testing-library-dom@1.0.2", + "@types/node": "22.5.4", "tough-cookie": "5.0.0-rc.4" } } diff --git a/packages/docs/package.json b/packages/docs/package.json index 0e41fdd00c2..d1d85d7ac40 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -81,7 +81,7 @@ "unplugin-auto-import": "0.17.5", "unplugin-fonts": "1.0.3", "unplugin-vue-components": "^0.27.4", - "vite": "^5.4.0", + "vite": "^5.4.3", "vite-plugin-md": "^0.21.5", "vite-plugin-pages": "^0.32.1", "vite-plugin-pwa": "^0.17.4", diff --git a/packages/vuetify/.eslintignore b/packages/vuetify/.eslintignore index e0a4dbe295d..bb42ae50b64 100644 --- a/packages/vuetify/.eslintignore +++ b/packages/vuetify/.eslintignore @@ -9,3 +9,5 @@ /lib-temp/ /dist/ /cypress/ +*.spec.cy.ts +*.spec.cy.tsx diff --git a/packages/vuetify/.eslintrc.js b/packages/vuetify/.eslintrc.js index f2a2419c247..78f656db0c4 100644 --- a/packages/vuetify/.eslintrc.js +++ b/packages/vuetify/.eslintrc.js @@ -44,46 +44,20 @@ module.exports = { }, }, { - files: '**/*.spec.{ts,tsx}', - env: { - 'jest/globals': true, - }, - plugins: ['jest'], - extends: ['plugin:jest/recommended'], + files: '**/*.spec.?(browser.){ts,tsx}', + plugins: ['vitest'], + extends: ['plugin:vitest/recommended'], rules: { 'local-rules/vitest-global-imports': 'error', 'no-restricted-imports': 'off', - 'jest/no-disabled-tests': 'off', - 'jest/no-large-snapshots': 'warn', - 'jest/prefer-spy-on': 'warn', - 'jest/prefer-to-be': 'warn', - 'jest/prefer-to-contain': 'warn', - 'jest/prefer-to-have-length': 'warn', - 'jest/no-standalone-expect': 'off', - 'jest/no-conditional-expect': 'off', - 'jest/no-identical-title': 'off', - }, - }, - { - files: '**/*.spec.cy.{ts,tsx}', - env: { - 'cypress/globals': true, - }, - plugins: ['cypress'], - extends: ['plugin:cypress/recommended'], - rules: { - 'local-rules/cypress-types-reference': 'error', - - 'no-restricted-imports': 'off', - - 'no-unused-expressions': 'off', - 'cypress/no-assigning-return-values': 'error', - 'cypress/no-unnecessary-waiting': 'warn', - 'cypress/assertion-before-screenshot': 'warn', - 'cypress/no-async-tests': 'error', - 'cypress/unsafe-to-chain-command': 'off', + 'vitest/no-commented-out-tests': 'off', + 'vitest/no-large-snapshots': 'warn', + 'vitest/prefer-spy-on': 'warn', + 'vitest/prefer-to-be': 'warn', + 'vitest/prefer-to-contain': 'warn', + 'vitest/prefer-to-have-length': 'warn', }, }, ], diff --git a/packages/vuetify/cypress.config.ts b/packages/vuetify/cypress.config.ts deleted file mode 100644 index 7d17f380bca..00000000000 --- a/packages/vuetify/cypress.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from 'cypress' - -export default defineConfig({ - projectId: '5w5r1i', - component: { - devServer: { - framework: 'vue', - bundler: 'vite', - }, - specPattern: './src/**/*.spec.cy.{js,jsx,ts,tsx}', - supportFile: './cypress/support/index.ts', - video: false, - }, - viewportWidth: 1280, - viewportHeight: 825, -}) diff --git a/packages/vuetify/cypress/fixtures/example.json b/packages/vuetify/cypress/fixtures/example.json deleted file mode 100644 index 02e4254378e..00000000000 --- a/packages/vuetify/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/packages/vuetify/cypress/fixtures/text.txt b/packages/vuetify/cypress/fixtures/text.txt deleted file mode 100644 index 5b9c8aaf391..00000000000 --- a/packages/vuetify/cypress/fixtures/text.txt +++ /dev/null @@ -1 +0,0 @@ -This is just a simple text file. diff --git a/packages/vuetify/cypress/support/component-index.html b/packages/vuetify/cypress/support/component-index.html deleted file mode 100644 index 959c8bce4aa..00000000000 --- a/packages/vuetify/cypress/support/component-index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - -
- - diff --git a/packages/vuetify/cypress/support/index.ts b/packages/vuetify/cypress/support/index.ts deleted file mode 100644 index c4970b35c36..00000000000 --- a/packages/vuetify/cypress/support/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import '@percy/cypress' -import 'cypress-file-upload' -import 'cy-mobile-commands' -import 'cypress-real-events/support' -import '@mdi/font/css/materialdesignicons.css' -import './mount' -import './selector' diff --git a/packages/vuetify/cypress/support/mount.ts b/packages/vuetify/cypress/support/mount.ts deleted file mode 100644 index bd328bc9ad6..00000000000 --- a/packages/vuetify/cypress/support/mount.ts +++ /dev/null @@ -1,74 +0,0 @@ -/// -import '../../src/styles/main.sass' -import type { VueWrapper } from '@vue/test-utils' -import { mount as cyMount } from 'cypress/vue' -import { createVuetify } from '../../src/framework' -import { mergeDeep } from '../../src/util' -import { aliases } from '../../src/iconsets/mdi-svg' - -/** - * @example - * cy.mount(My button) - */ -Cypress.Commands.add('mount', (component, options, vuetifyOptions) => { - const root = document.getElementById('cy-root')! - - // add the v-application class that allows Vuetify styles to work - if (!root.classList.contains('v-locale--is-rtl')) { - root.classList.add('v-locale--is-ltr') - } - - const vuetify = createVuetify(mergeDeep({ - icons: { aliases }, - }, vuetifyOptions)) - const defaultOptions = { - global: { - stubs: { - transition: false, - 'transition-group': false, - }, - plugins: [vuetify], - }, - } - - const mountOptions = mergeDeep(defaultOptions, options!, (a, b) => a.concat(b)) - - return cyMount(component, mountOptions) - .then(({ wrapper }) => { - cy.wrap(wrapper).as('wrapper') - }) -}) - -Cypress.Commands.add('vue', () => { - return cy.get>('@wrapper') -}) - -/** - * Update the props and wait for Vue to re-render. - * Must be chained of a chain that starts with `cy.mount`. - * - * @example - * cy.mount(My button) - * .get('button'). - * .should('not.have.class', 'v-btn--disabled') - * .setProps({ disabled: true }). - * .get('button') - * .should('have.class', 'v-btn--disabled') - */ - -Cypress.Commands.add('setProps', (props: Record = {}) => { - return cy.get>('@wrapper').then(async wrapper => { - await wrapper.setProps(props) - return wrapper - }) -}) - -Cypress.Commands.add('emitted', (selector: Parameters[0], event?: string) => { - return cy.get>('@wrapper').then(wrapper => { - const cmp = wrapper.findComponent(selector) - - if (!cmp) return cy.wrap({}) - - return cy.wrap(event ? cmp.emitted(event) : cmp.emitted()) - }) -}) diff --git a/packages/vuetify/cypress/support/selector.ts b/packages/vuetify/cypress/support/selector.ts deleted file mode 100644 index 390bf47612c..00000000000 --- a/packages/vuetify/cypress/support/selector.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// - -Cypress.Commands.add('getBySel', (selector, ...args) => { - return cy.get(`[data-test=${selector}]`, ...args) as any -}) diff --git a/packages/vuetify/package.json b/packages/vuetify/package.json index 684ece314c8..9b2ac769d3c 100755 --- a/packages/vuetify/package.json +++ b/packages/vuetify/package.json @@ -109,11 +109,14 @@ "build:types": "rimraf types-temp && tsc --pretty --emitDeclarationOnly -p tsconfig.dist.json && rollup --config build/rollup.types.config.mjs && rimraf types-temp", "tsc": "tsc", "test": "vitest", + "test:unit": "vitest --project unit", + "test:browser": "vitest --project browser", + "test:open": "TEST_BAIL=1 vitest --project browser -w", "test:coverage": "pnpm run test --coverage", + "test:percy": "percy exec -- vitest --project browser", + "test:all": "concurrently -gr 'vitest --project unit' 'vitest --project browser --shard=1/5' 'vitest --project browser --shard=2/5' 'vitest --project browser --shard=3/5' 'vitest --project browser --shard=4/5' 'vitest --project browser --shard=5/5'", "lint": "concurrently -n \"tsc,eslint\" --kill-others-on-fail \"tsc -p tsconfig.checks.json --noEmit --pretty\" \"eslint src -f codeframe --max-warnings 0\"", - "lint:fix": "concurrently -n \"tsc,eslint\" \"tsc -p tsconfig.checks.json --noEmit --pretty\" \"eslint --fix src\"", - "cy:open": "cypress open --component -b electron", - "cy:run": "percy exec -- cypress run --component" + "lint:fix": "concurrently -n \"tsc,eslint\" \"tsc -p tsconfig.checks.json --noEmit --pretty\" \"eslint --fix src\"" }, "devDependencies": { "@date-io/core": "3.0.0", @@ -123,17 +126,22 @@ "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@fortawesome/vue-fontawesome": "^3.0.6", - "@percy/cli": "^1.28.2", - "@percy/cypress": "^3.1.2", + "@percy/cli": "^1.29.3", + "@percy/sdk-utils": "^1.29.3", "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-typescript": "^11.1.6", - "@types/node": "^20.12.7", + "@testing-library/dom": "npm:@vuetify/testing-library-dom@1.0.2", + "@testing-library/user-event": "^14.5.2", + "@testing-library/vue": "^8.1.0", + "@types/node": "^22.5.4", "@types/resize-observer-browser": "^0.1.11", "@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue-jsx": "^3.1.0", - "@vitest/coverage-v8": "^2.0.5", + "@vitest/browser": "^2.1.1", + "@vitest/coverage-v8": "^2.1.1", + "@vitest/ui": "^2.1.1", "@vue/babel-plugin-jsx": "^1.2.2", "@vue/shared": "^3.4.27", "@vue/test-utils": "2.4.6", @@ -147,19 +155,17 @@ "cssnano": "^6.1.2", "csstype": "^3.1.3", "cy-mobile-commands": "^0.3.0", - "cypress": "^13.7.2", - "cypress-file-upload": "^5.0.8", - "cypress-real-events": "^1.12.0", "date-fns": "^3.6.0", "dotenv": "^16.4.5", - "eslint-plugin-cypress": "^2.15.1", "eslint-plugin-jest": "^28.7.0", + "eslint-plugin-vitest": "0.4.1", "expect": "^28.1.3", "fast-glob": "^3.3.2", "identity-obj-proxy": "^3.0.0", "jsdom": "^25.0.0", "micromatch": "^4.0.5", "postcss": "^8.4.38", + "roboto-fontface": "^0.10.0", "rollup": "^3.20.7", "rollup-plugin-dts": "^6.1.0", "rollup-plugin-sass": "^1.12.21", @@ -169,11 +175,12 @@ "unplugin-auto-import": "0.17.5", "unplugin-vue-components": "^0.27.4", "upath": "^2.0.1", - "vite": "^5.4.0", + "vite": "^5.4.3", "vite-ssr": "^0.17.1", - "vitest": "^2.0.5", + "vitest": "^2.1.1", "vue-i18n": "^9.7.1", - "vue-router": "^4.3.0" + "vue-router": "^4.3.0", + "webdriverio": "^8.40.5" }, "peerDependencies": { "typescript": ">=4.7", diff --git a/packages/vuetify/src/__tests__/framework.spec.ts b/packages/vuetify/src/__tests__/framework.spec.browser.ts similarity index 97% rename from packages/vuetify/src/__tests__/framework.spec.ts rename to packages/vuetify/src/__tests__/framework.spec.browser.ts index 14031435f5a..49835d33266 100644 --- a/packages/vuetify/src/__tests__/framework.spec.ts +++ b/packages/vuetify/src/__tests__/framework.spec.browser.ts @@ -1,6 +1,5 @@ // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { createVuetify } from '@/framework' describe('framework', () => { diff --git a/packages/vuetify/src/components.d.ts b/packages/vuetify/src/components.d.ts deleted file mode 100644 index 4edc351177c..00000000000 --- a/packages/vuetify/src/components.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* eslint-disable */ -// @ts-nocheck -// Generated by unplugin-vue-components -// Read more: https://github.com/vuejs/core/pull/3399 -export {} - -/* prettier-ignore */ -declare module 'vue' { - export interface GlobalComponents { - RouterLink: typeof import('vue-router')['RouterLink'] - RouterView: typeof import('vue-router')['RouterView'] - } -} diff --git a/packages/vuetify/src/components/VAlert/__tests__/VAlert.spec.cy.tsx b/packages/vuetify/src/components/VAlert/__tests__/VAlert.spec.browser.tsx similarity index 61% rename from packages/vuetify/src/components/VAlert/__tests__/VAlert.spec.cy.tsx rename to packages/vuetify/src/components/VAlert/__tests__/VAlert.spec.browser.tsx index 92889871975..dde9b7fdce6 100644 --- a/packages/vuetify/src/components/VAlert/__tests__/VAlert.spec.cy.tsx +++ b/packages/vuetify/src/components/VAlert/__tests__/VAlert.spec.browser.tsx @@ -1,7 +1,7 @@ -/// - import { VAlert } from '..' -import { generate } from '@/../cypress/templates' + +// Utilities +import { generate, render } from '@test' const defaultColors = ['success', 'info', 'warning', 'error', 'invalid'] @@ -19,8 +19,8 @@ const stories = { // Tests describe('VAlert', () => { describe('color', () => { - it('supports default color props', () => { - cy.mount(() => ( + it('supports default color props', async () => { + const { container } = render(() => ( <> { defaultColors.map((color, idx) => ( @@ -29,13 +29,14 @@ describe('VAlert', () => { ))} )) - .get('.v-alert') - .should('have.length', defaultColors.length) - .then(subjects => { - Array.from(subjects).forEach((subject, idx) => { - expect(subject).to.contain(defaultColors[idx]) - }) - }) + + const alerts = container.querySelectorAll('.v-alert') + expect(alerts).toHaveLength(defaultColors.length) + + Array.from(alerts).forEach((alert, idx) => { + // TODO: useless assert + expect(alert).toHaveTextContent(defaultColors[idx]) + }) }) }) diff --git a/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.browser.tsx b/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.browser.tsx new file mode 100644 index 00000000000..65c516a4df2 --- /dev/null +++ b/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.browser.tsx @@ -0,0 +1,639 @@ +// Components +import { VAutocomplete } from '../VAutocomplete' +import { VForm } from '@/components/VForm' + +// Utilities +import { generate, render, screen, userEvent, waitAnimationFrame, waitIdle } from '@test' +import { findAllByRole, queryAllByRole, within } from '@testing-library/vue' +import { cloneVNode, ref } from 'vue' + +const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const +const densities = ['default', 'comfortable', 'compact'] as const +const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const + +const stories = Object.fromEntries(Object.entries({ + 'Default input': , + Disabled: , + Affixes: , + 'Prepend/append': , + 'Prepend/append inner': , + Placeholder: , +}).map(([k, v]) => [k, ( +
+ { variants.map(variant => ( + densities.map(density => ( +
+ { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } + { cloneVNode(v, { variant, density, label: `with value`, modelValue: ['California'] }) } + { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: ['California'] }) } + {{ + selection: ({ item }) => { + return item.title + }, + }} + +
+ )) + )).flat()} +
+)])) + +describe('VAutocomplete', () => { + it('should close only first chip', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = ref(['Item 1', 'Item 2', 'Item 3']) + + render(() => ( + + )) + + const closeButtons = await screen.findAllByTestId('close-chip') + await userEvent.click(closeButtons[0]) + + expect(selectedItems.value).toEqual(['Item 2', 'Item 3']) + }) + + it('should have selected chip with array of strings', async () => { + const items = ref(['California', 'Colorado', 'Florida']) + + const selectedItems = ref(['California', 'Colorado']) + + const { container } = render(() => ( + + )) + + await userEvent.click(container) + + const menu = await screen.findByRole('listbox') + + let activeItems = await findAllByRole(menu, 'option', { selected: true }) + expect(activeItems).toHaveLength(2) + + await userEvent.click(activeItems[0]) + activeItems = await findAllByRole(menu, 'option', { selected: true }) + expect(activeItems).toHaveLength(1) + expect(selectedItems.value).toEqual(['Colorado']) + + await userEvent.click(await screen.findByTestId('close-chip')) + expect(screen.queryAllByTestId('close-chip')).toHaveLength(0) + expect(selectedItems.value).toEqual([]) + }) + + it('should have selected chip with return-object', async () => { + const items = ref([ + { + title: 'Item 1', + value: 'item1', + }, + { + title: 'Item 2', + value: 'item2', + }, + ]) + + const selectedItems = ref([ + { + title: 'Item 1', + value: 'item1', + }, + ]) + + const { container } = render(() => ( + + )) + + await userEvent.click(container) + + const menu = await screen.findByRole('listbox') + + let activeItems = await findAllByRole(menu, 'option', { selected: true }) + expect(activeItems).toHaveLength(1) + + await userEvent.click(activeItems[0]) + expect(selectedItems.value).toHaveLength(0) + activeItems = queryAllByRole(menu, 'option', { selected: true }) + expect(activeItems).toHaveLength(0) + }) + + it('should work with objects when using multiple and item-value', async () => { + const items = ref([ + { + text: 'Item 1', + id: 'item1', + }, + { + text: 'Item 2', + id: 'item2', + }, + { + text: 'Item 3', + id: 'item3', + }, + ]) + + const selectedItems = ref([ + { + text: 'Item 1', + id: 'item1', + }, + { + text: 'Item 2', + id: 'item2', + }, + ]) + + const { container } = render(() => ( + + )) + + await userEvent.click(container) + + const menu = await screen.findByRole('listbox') + + const activeItems = await findAllByRole(menu, 'option', { selected: true }) + expect(activeItems).toHaveLength(2) + + const input = await screen.findByRole('combobox') + expect(input).toHaveTextContent('Item 1') + expect(input).toHaveTextContent('Item 2') + + await userEvent.click(activeItems[0]) + + expect(input).not.toHaveTextContent('Item 1') + expect(input).toHaveTextContent('Item 2') + expect(selectedItems.value).toEqual([{ + text: 'Item 2', + id: 'item2', + }]) + }) + + it('should not be clickable when in readonly', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = 'Item 1' + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + expect(element).not.toHaveClass('v-select--active-menu') + + screen.getByCSS('input').focus() + await userEvent.keyboard('{ArrowDown}') + + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + expect(element).not.toHaveClass('v-select--active-menu') + }) + + it('should not be clickable when in readonly form', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = 'Item 1' + + render(() => ( + + + + )) + + const element = screen.getByCSS('.v-autocomplete') + + await userEvent.click(element) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + expect(element).not.toHaveClass('v-select--active-menu') + + screen.getByCSS('input').focus() + await userEvent.keyboard('{ArrowDown}') + + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + expect(element).not.toHaveClass('v-select--active-menu') + }) + + it('should remove selection if search is cleared', async () => { + const items = ref([ + { title: 'Item 1', value: 'Item 1' }, + { title: 'Item 2', value: 'Item 2' }, + ]) + + const selectedItems = ref(null) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + const options = await screen.findAllByRole('option') + expect(options).toHaveLength(2) + + await userEvent.click(options[0]) + + await userEvent.click(element) + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.click(document.body) + + expect(element).not.toHaveTextContent('Item 1') + }) + + // https://github.com/vuetifyjs/vuetify/issues/16210 + it('should return item object as the argument of item-title function', async () => { + const items = [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + ] + + const selectedItems = ref(null) + + const itemTitle = vi.fn((item: any) => { + return 'Item: ' + JSON.stringify(item) + }) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + await userEvent.click(screen.getAllByRole('option')[0]) + expect(selectedItems.value).toBe(1) + + expect(itemTitle).toHaveBeenCalledWith({ id: 1, name: 'a' }, expect.anything()) + + expect(element).toHaveTextContent('Item: {"id":1,"name":"a"}') + }) + + // https://github.com/vuetifyjs/vuetify/issues/16442 + describe('null value', () => { + it('should allow null as legit itemValue', async () => { + const items = [ + { name: 'Default Language', code: null }, + { code: 'en-US', name: 'English' }, + { code: 'de-DE', name: 'German' }, + ] + + const selectedItems = null + + const { element } = render(() => ( + + )) + + expect(element).toHaveTextContent('Default Language') + }) + + it('should mark input as "not dirty" when the v-model is null, but null is not present in the items', async () => { + const items = [ + { code: 'en-US', name: 'English' }, + { code: 'de-DE', name: 'German' }, + ] + + const { container } = render(() => ( + + )) + + expect(container.querySelector('.v-field')).not.toHaveClass('v-field--dirty') + }) + }) + + describe('hide-selected', () => { + it('should hide selected item(s)', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + const selectedItems = ['Item 1', 'Item 2'] + + render(() => ( + + )) + + const menuIcon = screen.getByRole('button', { name: /open/i }) + await userEvent.click(menuIcon) + + const listItems = screen.getAllByRole('option') + expect(listItems).toHaveLength(2) + expect(listItems[0]).toHaveTextContent('Item 3') + expect(listItems[1]).toHaveTextContent('Item 4') + }) + }) + + // https://github.com/vuetifyjs/vuetify/issues/16055 + it('should not replicate html select hotkeys in v-autocomplete', async () => { + const items = ref(['aaa', 'foo', 'faa']) + + const selectedItems = ref(undefined) + + const { element } = render(() => ( + + )) + + await userEvent.type(element, 'f') + const listItems = screen.getAllByRole('option') + expect(listItems).toHaveLength(2) + expect(selectedItems.value).toBeUndefined() + }) + + it('should conditionally show placeholder', async () => { + const { rerender, getByCSS } = render(VAutocomplete, { + props: { placeholder: 'Placeholder' }, + }) + + const input = getByCSS('input') + expect(input).toHaveAttribute('placeholder', 'Placeholder') + + await rerender({ label: 'Label' }) + expect(input).not.toBeVisible() + + input.focus() + await waitAnimationFrame() + expect(input).toHaveAttribute('placeholder', 'Placeholder') + expect(input).toBeVisible() + + input.blur() + await rerender({ persistentPlaceholder: true }) + expect(input).toHaveAttribute('placeholder', 'Placeholder') + expect(input).toBeVisible() + + await rerender({ modelValue: 'Foobar' }) + expect(input).not.toHaveAttribute('placeholder') + + await rerender({ multiple: true, modelValue: ['Foobar'] }) + expect(input).not.toHaveAttribute('placeholder') + }) + + it('should keep TextField focused while selecting items from open menu', async () => { + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + await userEvent.keyboard('{ArrowDown}{ArrowDown}{ArrowDown}c') + + expect(document.activeElement).toBe(within(element).getByCSS('input')) + }) + + it('should not open menu when closing a chip', async () => { + const { element } = render(() => ( + + )) + + expect(screen.queryByRole('listbox')).toBeNull() + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + await waitAnimationFrame() + expect(screen.queryByRole('listbox')).toBeNull() + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + await waitAnimationFrame() + expect(screen.queryByRole('listbox')).toBeNull() + + await userEvent.click(element) + await screen.findByRole('listbox') + + await userEvent.keyboard('{Escape}') + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + }) + + describe('auto-select-first', () => { + async function setup () { + const selectedItems = ref() + const { element } = render(() => ( + + )) + const getItems = () => screen.queryAllByRole('option') + + await userEvent.click(element) + await expect.poll(getItems).toHaveLength(6) + + await userEvent.keyboard('Cal') + await expect.poll(() => getItems()[0]).toHaveClass('v-list-item--active') + + return { selectedItems, element, getItems } + } + + it('should auto-select-first item when pressing enter', async () => { + const { selectedItems, getItems } = await setup() + + await userEvent.keyboard('{Enter}') + await expect.poll(getItems).toHaveLength(1) + expect(selectedItems.value).toStrictEqual(['California']) + }) + + it('should auto-select-first item when pressing tab', async () => { + const { selectedItems, getItems } = await setup() + + await userEvent.keyboard('{Tab}') + await expect.poll(getItems).toHaveLength(0) + expect(selectedItems.value).toStrictEqual(['California']) + }) + + it('should not auto-select-first item when blur', async () => { + const { selectedItems, getItems } = await setup() + + await userEvent.click(document.body) + await expect.poll(getItems).toHaveLength(0) + expect(selectedItems.value).toBeUndefined() + }) + }) + + // https://github.com/vuetifyjs/vuetify/issues/18796 + // https://github.com/vuetifyjs/vuetify/issues/19235 + it('should allow deleting single selection via closable-chips', async () => { + const selectedItem = ref('California') + + const { getByTestId } = render(() => ( + + )) + + await userEvent.click(getByTestId('close-chip')) + expect(selectedItem.value).toBeNull() + }) + + it('should allow deleting multiple selection via closable-chips', async () => { + const selectedItem = ref(['California']) + + const { getByTestId } = render(() => ( + + )) + + await userEvent.click(getByTestId('close-chip')) + expect(selectedItem.value).toHaveLength(0) + }) + + // https://github.com/vuetifyjs/vuetify/issues/19261 + it('should not remove single selection on list item click', async () => { + const selectedItem = ref('abc') + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + const items = await screen.findAllByRole('option') + expect(items).toHaveLength(2) + + await userEvent.click(items[0]) + await waitAnimationFrame() + expect(selectedItem.value).toBe('abc') + }) + + // https://github.com/vuetifyjs/vuetify/issues/18556 + it('should show menu if focused and items are added', async () => { + const { rerender } = render(VAutocomplete) + + await userEvent.keyboard('{Tab}') + await waitAnimationFrame() + expect(screen.queryByRole('listbox')).toBeNull() + + await rerender({ items: ['Foo', 'Bar'] }) + expect(await screen.findByRole('listbox')).toBeInTheDocument() + }) + + // https://github.com/vuetifyjs/vuetify/issues/19346 + it('should not show menu when focused and existing non-empty items are changed', async () => { + const { element, rerender } = render(VAutocomplete, { + props: { items: ['Foo', 'Bar'] }, + }) + + await userEvent.click(element) + expect(await screen.findByRole('listbox')).toBeInTheDocument() + + await userEvent.click(screen.getAllByRole('option')[0]) + await rerender({ items: ['Foo', 'Bar', 'test', 'test 2'] }) + await waitIdle() + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + }) + + // https://github.com/vuetifyjs/vuetify/issues/17573 + // When using selection slot or chips, input displayed next to chip/selection slot should be always empty + it('should always have empty input value when it is unfocused and when using selection slot or chips', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + const selectedItem = ref('Item 1') + + const { element, getByCSS } = render(() => ( + + )) + + await userEvent.click(element) + const input = getByCSS('input') + expect(input).toHaveValue('') + + // Blur input with a custom search input value + await userEvent.keyboard('test') + input.blur() + await expect.poll(() => selectedItem.value).toBe('Item 1') + expect(input).toHaveValue('') + + // Search existing item and click to select + await userEvent.click(element) + expect(input).toHaveValue('') + await userEvent.keyboard('Item 1') + await userEvent.click(await screen.findByRole('option')) + await expect.poll(() => selectedItem.value).toBe('Item 1') + }) + + describe('Showcase', () => { + generate({ stories }) + }) +}) diff --git a/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx b/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx deleted file mode 100644 index bfc87cf239f..00000000000 --- a/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx +++ /dev/null @@ -1,658 +0,0 @@ -/// - -// Components -import { VAutocomplete } from '../VAutocomplete' -import { VForm } from '@/components/VForm' - -// Utilities -import { cloneVNode, ref } from 'vue' -import { generate } from '../../../../cypress/templates' -import { keyValues } from '@/util' - -const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const -const densities = ['default', 'comfortable', 'compact'] as const -const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const - -const stories = Object.fromEntries(Object.entries({ - 'Default input': , - Disabled: , - Affixes: , - 'Prepend/append': , - 'Prepend/append inner': , - Placeholder: , -}).map(([k, v]) => [k, ( -
- { variants.map(variant => ( - densities.map(density => ( -
- { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } - { cloneVNode(v, { variant, density, label: `with value`, modelValue: ['California'] }) } - { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: ['California'] }) } - {{ - selection: ({ item }) => { - return item.title - }, - }} - -
- )) - )).flat()} -
-)])) - -describe('VAutocomplete', () => { - it('should close only first chip', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = ['Item 1', 'Item 2', 'Item 3'] - - cy.mount(() => ( - - )) - - cy.get('.v-chip__close').eq(0).click() - cy.get('input').should('exist') - cy.get('.v-chip').should('have.length', 2) - }) - - it('should have selected chip with array of strings', () => { - const items = ref(['California', 'Colorado', 'Florida']) - - const selectedItems = ref(['California', 'Colorado']) - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete__menu-icon').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('.v-list-item--active input').eq(0).click() - cy.then(() => { - expect(selectedItems.value).to.deep.equal(['Colorado']) - }) - - cy.get('.v-list-item--active').should('have.length', 1) - - cy.get('.v-chip__close').eq(0).click() - cy.get('.v-chip') - .should('have.length', 0) - .should(() => expect(selectedItems.value).to.be.empty) - }) - - it('should have selected chip with return-object', () => { - const items = ref([ - { - title: 'Item 1', - value: 'item1', - }, - { - title: 'Item 2', - value: 'item2', - }, - ]) - - const selectedItems = ref([ - { - title: 'Item 1', - value: 'item1', - }, - ]) - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete__menu-icon').click() - - cy.get('.v-list-item--active').should('have.length', 1) - cy.get('.v-list-item--active input').click() - cy.then(() => { - expect(selectedItems.value).to.be.empty - }) - cy.get('.v-list-item--active').should('have.length', 0) - }) - - it('should work with objects when using multiple and item-value', () => { - const items = ref([ - { - text: 'Item 1', - id: 'item1', - }, - { - text: 'Item 2', - id: 'item2', - }, - { - text: 'Item 3', - id: 'item3', - }, - ]) - - const selectedItems = ref([ - { - text: 'Item 1', - id: 'item1', - }, - { - text: 'Item 2', - id: 'item2', - }, - ]) - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('.v-field__input').should('include.text', 'Item 1') - cy.get('.v-field__input').should('include.text', 'Item 2') - - cy.get('.v-list-item--active input') - .eq(0) - .click() - .get('.v-field__input') - .should(() => expect(selectedItems.value).to.deep.equal([{ - text: 'Item 2', - id: 'item2', - }])) - }) - - it('should not be clickable when in readonly', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = 'Item 1' - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete').click() - cy.get('.v-list-item').should('have.length', 0) - cy.get('.v-select--active-menu').should('have.length', 0) - - cy.get('.v-autocomplete input').as('input') - .focus() - cy.get('@input').type('{downarrow}', { force: true }) - cy.get('.v-list-item').should('have.length', 0) - cy.get('.v-select--active-menu').should('have.length', 0) - }) - - it('should not be clickable when in readonly form', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = 'Item 1' - - cy.mount(() => ( - - - - )) - - cy.get('.v-autocomplete').click() - cy.get('.v-list-item').should('have.length', 0) - cy.get('.v-select--active-menu').should('have.length', 0) - - cy.get('.v-autocomplete input').as('input') - .focus() - cy.get('@input').type('{downarrow}', { force: true }) - cy.get('.v-list-item').should('have.length', 0) - cy.get('.v-select--active-menu').should('have.length', 0) - }) - - it('should be empty when delete the selected option', () => { - const items = ref([ - { title: 'Item 1', value: 'Item 1' }, - { title: 'Item 2', value: 'Item 2' }, - ]) - - const selectedItems = ref(null) - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete').click() - cy.get('.v-list-item').should('have.length', 2) - cy.get('.v-list-item').contains('Item 1').click() - - cy.get('.v-field__input').clear() - cy.get('body').click('bottomLeft') - cy.get('.v-field__input').should('not.include.text', 'Item 1') - }) - - // https://github.com/vuetifyjs/vuetify/issues/16210 - it('should return item object as the argument of item-title function', () => { - const items = [ - { id: 1, name: 'a' }, - { id: 2, name: 'b' }, - ] - - const selectedItems = ref(null) - - function itemTitleFunc (item: any) { - return 'Item: ' + JSON.stringify(item) - } - - const itemTitleFuncSpy = cy.spy(itemTitleFunc).as('itemTitleFunc') - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete').click() - - cy.get('.v-list-item').eq(0).click({ waitForAnimations: false }).should(() => { - expect(selectedItems.value).to.deep.equal(1) - }) - - cy.get('@itemTitleFunc') - .should('have.been.calledWith', { id: 1, name: 'a' }) - - cy.get('.v-autocomplete__selection-text').should('have.text', `Item: {"id":1,"name":"a"}`) - }) - - // https://github.com/vuetifyjs/vuetify/issues/16442 - describe('null value', () => { - it('should allow null as legit itemValue', () => { - const items = [ - { name: 'Default Language', code: null }, - { code: 'en-US', name: 'English' }, - { code: 'de-DE', name: 'German' }, - ] - - const selectedItems = null - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete__selection').eq(0).invoke('text').should('equal', 'Default Language') - }) - it('should mark input as "not dirty" when the v-model is null, but null is not present in the items', () => { - const items = [ - { code: 'en-US', name: 'English' }, - { code: 'de-DE', name: 'German' }, - ] - - cy.mount(() => ( - - )) - - cy.get('.v-field').should('not.have.class', 'v-field--dirty') - }) - }) - - describe('hide-selected', () => { - it('should hide selected item(s)', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = ['Item 1', 'Item 2'] - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete__menu-icon').click() - - cy.get('.v-overlay__content .v-list-item').should('have.length', 2) - cy.get('.v-overlay__content .v-list-item .v-list-item-title').eq(0).should('have.text', 'Item 3') - cy.get('.v-overlay__content .v-list-item .v-list-item-title').eq(1).should('have.text', 'Item 4') - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/16055 - it('should not replicate html select hotkeys in v-autocomplete', () => { - const items = ref(['aaa', 'foo', 'faa']) - - const selectedItems = ref(undefined) - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete') - .click() - .get('.v-autocomplete input') - .focus() - .type('f', { force: true }) - .get('.v-list-item').should('have.length', 2) - .then(_ => { - expect(selectedItems.value).equal(undefined) - }) - }) - - it('should conditionally show placeholder', () => { - cy.mount(props => ( - - )) - .get('.v-autocomplete input') - .should('have.attr', 'placeholder', 'Placeholder') - .setProps({ label: 'Label' }) - .get('.v-autocomplete input') - .should('not.be.visible') - .get('.v-autocomplete input') - .focus() - .should('have.attr', 'placeholder', 'Placeholder') - .should('be.visible') - .blur() - .setProps({ persistentPlaceholder: true }) - .get('.v-autocomplete input') - .should('have.attr', 'placeholder', 'Placeholder') - .should('be.visible') - .setProps({ modelValue: 'Foobar' }) - .get('.v-autocomplete input') - .should('not.have.attr', 'placeholder') - .setProps({ multiple: true, modelValue: ['Foobar'] }) - .get('.v-autocomplete input') - .should('not.have.attr', 'placeholder') - }) - - it('should keep TextField focused while selecting items from open menu', () => { - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete') - .click() - - cy.get('.v-list') - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - - cy.get('.v-field').should('have.class', 'v-field--focused') - }) - - it('should not open menu when closing a chip', () => { - cy - .mount(() => ( - - )) - .get('.v-autocomplete') - .should('not.have.class', 'v-autocomplete--active-menu') - .get('.v-chip__close').eq(1) - .click() - .get('.v-autocomplete') - .should('not.have.class', 'v-autocomplete--active-menu') - .get('.v-chip__close') - .click() - .get('.v-autocomplete') - .should('not.have.class', 'v-autocomplete--active-menu') - .click() - .should('have.class', 'v-autocomplete--active-menu') - .trigger('keydown', { key: keyValues.esc }) - .should('not.have.class', 'v-autocomplete--active-menu') - }) - - describe('auto-select-first', () => { - it('should auto-select-first item when pressing enter', () => { - const selectedItems = ref(undefined) - - cy - .mount(() => ( - - )) - .get('.v-autocomplete') - .click() - .get('.v-list-item') - .should('have.length', 6) - .get('.v-autocomplete input') - .type('Cal') - .get('.v-list-item').eq(0) - .should('have.class', 'v-list-item--active') - .get('.v-autocomplete input') - .trigger('keydown', { key: keyValues.enter, waitForAnimations: false }) - .get('.v-list-item') - .should('have.length', 1) - .then(_ => { - expect(selectedItems.value).to.deep.equal(['California']) - }) - }) - - it('should auto-select-first item when pressing tab', () => { - const selectedItems = ref([]) - - cy - .mount(() => ( - - )) - .get('.v-autocomplete') - .click() - .get('.v-list-item') - .should('have.length', 6) - .get('.v-autocomplete input') - .type('Cal') - .get('.v-list-item').eq(0) - .should('have.class', 'v-list-item--active') - .realPress('Tab') - .get('.v-list-item') - .should('have.length', 0) - .then(_ => { - expect(selectedItems.value).to.deep.equal(['California']) - }) - }) - - it('should not auto-select-first item when blur', () => { - const selectedItems = ref(undefined) - - cy - .mount(() => ( - - )) - .get('.v-autocomplete') - .click() - .get('.v-list-item') - .should('have.length', 6) - .get('.v-autocomplete input') - .type('Cal') - .get('.v-list-item').eq(0) - .should('have.class', 'v-list-item--active') - .get('.v-autocomplete input') - .blur() - .get('.v-list-item') - .should('have.length', 0) - .should(_ => { - expect(selectedItems.value).to.deep.equal(undefined) - }) - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/18796 - // https://github.com/vuetifyjs/vuetify/issues/19235 - it('should allow deleting selection via closable-chips', () => { - const selectedItem = ref('California') - - cy.mount(() => ( - - )) - .get('.v-chip__close') - .click() - .then(_ => { - expect(selectedItem.value).to.equal(null) - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/19261 - it('should not toggle v-model to null when clicking already selected item in single selection mode', () => { - const selectedItem = ref('abc') - - cy.mount(() => ( - - )) - - cy.get('.v-autocomplete').click() - - cy.get('.v-list-item').should('have.length', 2) - cy.get('.v-list-item').eq(0).click({ waitForAnimations: false }).should(() => { - expect(selectedItem.value).equal('abc') - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/18556 - it('should show menu if focused and items are added', () => { - cy - .mount(props => ()) - .get('.v-autocomplete input') - .focus() - .get('.v-overlay') - .should('not.exist') - .setProps({ items: ['Foo', 'Bar'] }) - .get('.v-overlay') - .should('exist') - }) - - // https://github.com/vuetifyjs/vuetify/issues/19346 - it('should not show menu when focused and existing non-empty items are changed', () => { - cy - .mount((props: any) => ()) - .setProps({ items: ['Foo', 'Bar'] }) - .get('.v-autocomplete') - .click() - .get('.v-overlay') - .should('exist') - .get('.v-list-item').eq(1).click({ waitForAnimations: false }) - .setProps({ items: ['Foo', 'Bar', 'test', 'test 2'] }) - .get('.v-overlay') - .should('not.exist') - }) - - // https://github.com/vuetifyjs/vuetify/issues/17573 - // When using selection slot or chips, input displayed next to chip/selection slot should be always empty - it('should always have empty input value when it is unfocused and when using selection slot or chips', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - const selectedItem = ref('Item 1') - - cy - .mount(() => ( - - )) - .get('.v-autocomplete').click() - .get('.v-autocomplete input').should('have.value', '') - // Blur input with a custom search input value - .type('test') - .blur() - .should('have.value', '') - .should(() => { - expect(selectedItem.value).to.equal('Item 1') - }) - // Search existing item and click to select - .get('.v-autocomplete').click() - .get('.v-autocomplete input').should('have.value', '') - .type('Item 1') - .get('.v-list-item').eq(0).click({ waitForAnimations: false }) - .should(() => { - expect(selectedItem.value).to.equal('Item 1') - }) - }) - - describe('Showcase', () => { - generate({ stories }) - }) -}) diff --git a/packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.browser.tsx b/packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.browser.tsx new file mode 100644 index 00000000000..b2a83b96750 --- /dev/null +++ b/packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.browser.tsx @@ -0,0 +1,79 @@ +// Components +import { VBadge } from '..' +import { VBtn } from '@/components/VBtn' + +// Utilities +import { generate, gridOn, render, screen } from '@test' + +const defaultColors = ['success', 'info', 'warning', 'error', 'invalid'] +const location = ['bottom start', 'bottom end', 'top start', 'top end'] +const rounded = ['circle', 'pill', 'shaped', 'tr-xl', 'br-lg', 0] // TODO: fix pill +const offset = [8, -8, '4', '-4', undefined] + +const props = { + bordered: true, + color: defaultColors, + content: ['content'], + dot: true, + icon: ['$vuetify'], + floating: true, + inline: true, + location, + modelValue: true, + rounded, +} + +const stories = { + 'Default badge': , + 'Icon badge': , + 'Offset badge': gridOn(['offsetX', 'offsetY'], offset, (xy, offset) => ( + + + { String(offset) } + + + )), + Color: gridOn([null], defaultColors, (_, color) => ( + + + { color } + + + )), + 'Text color': gridOn([null], defaultColors, (_, color) => ( + + + { color } + + + )), +} + +// Tests +describe('VBadge', () => { + describe('label', () => { + it('should have the designated aria label', async () => { + render(label) + expect(await screen.findByLabelText('label-badge')).toBeDefined() + }) + }) + + describe('max', () => { + it('should add a suffix if the content value is greater than the max value', () => { + const { container } = render() + expect(container).toHaveTextContent('+') + }) + }) + + describe('tag', () => { + it('renders the proper tag instead of a div', () => { + const { wrapper } = render(tag) + const el = wrapper.find('custom-tag').element + expect(el).toHaveTextContent('tag') + }) + }) + + describe('Showcase', () => { + generate({ stories, props, component: VBadge }) + }) +}) diff --git a/packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.cy.tsx b/packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.cy.tsx deleted file mode 100644 index 2d70fe102fe..00000000000 --- a/packages/vuetify/src/components/VBadge/__tests__/VBadge.spec.cy.tsx +++ /dev/null @@ -1,122 +0,0 @@ -/// - -// Components -import { VBadge } from '..' -import { VBtn } from '@/components/VBtn' - -// Utilities -import { generate, gridOn } from '@/../cypress/templates' - -const defaultColors = ['success', 'info', 'warning', 'error', 'invalid'] -const location = ['bottom start', 'bottom end', 'top start', 'top end'] -const rounded = ['circle', 'pill', 'shaped', 'tr-xl', 'br-lg', 0] // TODO: fix pill -const offset = [8, -8, '4', '-4', undefined] - -const props = { - bordered: true, - color: defaultColors, - content: ['content'], - dot: true, - icon: ['$vuetify'], - floating: true, - inline: true, - location, - modelValue: true, - rounded, -} - -const stories = { - 'Default badge': , - 'Icon badge': , - 'Offset badge': gridOn(['offsetX', 'offsetY'], offset, (xy, offset) => ( - - - { xy } - - - )), - 'Text color': gridOn(defaultColors, [null], color => ( - - - { color } - - - )), -} - -// Tests -describe('VBadge', () => { - describe('color', () => { - it('supports default color props', () => { - cy.mount(() => ( - <> - { defaultColors.map((color, idx) => ( - - { color } badge - - ))} - - )) - .get('.v-badge') - .should('have.length', defaultColors.length) - .then(subjects => { - Array.from(subjects).forEach((subject, idx) => { - // TODO: refactor - expect(subject.querySelector(`.bg-${defaultColors[idx]}`)).to.be.instanceOf(HTMLSpanElement) - expect(subject).to.contain(defaultColors[idx]) - }) - }) - }) - }) - - describe('label', () => { - it('should have the designated aria label', () => { - cy.mount(label) - .get('.v-badge__badge') - .should('have.attr', 'aria-label', 'label-badge') - }) - }) - - describe('max', () => { - it('should add a suffix if the content value is greater than the max value', () => { - cy.mount() - .get('.v-badge') - .should('contain.text', '+') - }) - }) - - describe('tag', () => { - it('renders the proper tag instead of a div', () => { - cy.mount(tag) - .get('custom-tag') - .should('have.text', 'tag') - }) - }) - - describe('textColor', () => { - it('supports default text color props', () => { - cy.mount(() => ( - <> - { defaultColors.map((color, idx) => ( - - { color } text badge - - ))} - - )) - .get('.v-badge') - .should('have.length', defaultColors.length) - .then(subjects => { - Array.from(subjects).forEach((subject, idx) => { - // TODO: refactor - expect(subject.querySelector(`.text-${defaultColors[idx]}`)).to.be.instanceOf(HTMLSpanElement) - expect(subject).to.contain(defaultColors[idx]) - }) - }) - }) - }) - - describe('Showcase', () => { - generate({ stories, props, component: VBadge }) - }) -}) diff --git a/packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.browser.tsx b/packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.browser.tsx new file mode 100644 index 00000000000..e4472762c15 --- /dev/null +++ b/packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.browser.tsx @@ -0,0 +1,241 @@ +import { VBtn } from '../VBtn' + +// Utilities +import { generate, gridOn, render } from '@test' +import { userEvent } from '@vitest/browser/context' +import { createRouter, createWebHistory } from 'vue-router' + +// TODO: generate these from types +const colors = ['success', 'info', 'warning', 'error', 'invalid'] +const sizes = ['x-small', 'small', 'default', 'large', 'x-large'] as const +const densities = ['default', 'comfortable', 'compact'] as const +const variants = ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain'] as const +const props = { + color: colors, + // variant: variants, + // disabled: false, + // loading: false, +} + +const stories = { + 'Default button': Basic button, + 'Small success button': Completed!, + 'Large, plain button w/ error': Whoops, + Loading: ( +
+ {{ loader: () => Loading..., default: () => 'Default Content' }} + {{ loader: () => Loading..., default: () => 'Default Content' }} + {{ loader: () => Loading... }} + Default Content +
+ ), + Icon: , + 'Density + size': gridOn(densities, sizes, (density, size) => + { size } + ), + Variants: gridOn(['no color', 'primary'], variants, (color, variant) => + { variant } + ), + 'Disabled variants': gridOn(['no color', 'primary'], variants, (color, variant) => + { variant } + ), + Stacked: gridOn([undefined], variants, (_, variant) => + { variant } + ), +} + +// Actual tests +describe('VBtn', () => { + describe('color', () => { + it('supports default color props', async () => { + const { container } = render(() => ( + <> + { colors.map(color => ( + + { color } button + + ))} + + )) + + const buttons = container.querySelectorAll('button') + expect(buttons).toHaveLength(colors.length) + buttons.forEach((button, idx) => { + expect(button).toHaveTextContent(colors[idx]) + }) + }) + }) + + describe('tag', () => { + it('renders the proper tag instead of a button', async () => { + const { container } = render(Click me) + const customTag = container.querySelector('custom-tag') + expect(customTag).toHaveTextContent('Click me') + }) + }) + + describe('elevation', () => { + it('should have the correct elevation', async () => { + const { container } = render() + const button = container.querySelector('button') + expect(button).toHaveClass('elevation-24') + }) + }) + + describe('events', () => { + it('emits native click events', async () => { + const click = vi.fn() + + const { container, rerender } = render(() => ( + Click me + )) + + await userEvent.click(container.querySelector('button')!) + expect(click).toHaveBeenCalledTimes(1) + + await rerender({ to: '#my-anchor' }) + + await userEvent.click(container.querySelector('button')!) + expect(click).toHaveBeenCalledTimes(2) + }) + + // Pending test, is "toggle" even going to be emitted anymore? + it.skip('emits toggle when used within a button group', () => { + // const register = jest.fn() + // const unregister = jest.fn() + // const toggle = jest.fn() + // const wrapper = mountFunction({ + // provide: { + // btnToggle: { register, unregister }, + // }, + // methods: { toggle }, + // }) + + // wrapper.trigger('click') + // expect(toggle).toHaveBeenCalled() + }) + }) + + // These tests were copied over from the previous Jest tests, + // but they are breaking because the features have not been implemented + describe.skip('activeClass', () => { + it('should use custom active-class', async () => { + const { wrapper } = render(Active Class) + expect(wrapper.element).toHaveClass('my-active-class') + }) + }) + + describe('href', () => { + it.skip('should render an tag when using href prop', async () => { + const anchor = { href: '#anchor', hash: 'anchor' } + const { container } = render(Click me) + const link = container.querySelector('a')! + + await userEvent.click(link) + expect(link).toHaveTextContent('Click me') + expect(link).toHaveFocus() + expect(window.location.hash).toContain(anchor.hash) + }) + + it('should change route when using to prop', async () => { + const router = createRouter({ + history: createWebHistory(), + routes: [ + { path: '/', component: { template: 'Home' } }, + { path: '/about', component: { template: 'About' } }, + ], + }) + + await router.replace('/') + + const result = render(() => ( + Click me + ), { global: { plugins: [router] } }) + + const link = result.wrapper.element + + await userEvent.click(link) + expect(link).toHaveFocus() + await result.findByText('Click me') + expect(window.location.pathname).toBe('/about') + }) + }) + + describe('value', () => { + it('should pass string values', async () => { + const stringValue = 'Foobar' + const { wrapper } = render(() => ( + + )) + expect(wrapper.element).toHaveValue(stringValue) + }) + + it('should stringify object', async () => { + const objectValue = { value: {} } + const { wrapper } = render(() => ( + + )) + expect(wrapper.element).toHaveValue(JSON.stringify(objectValue, null, 0)) + }) + + it('should stringify number', async () => { + const numberValue = 15 + const { wrapper } = render(() => ( + + )) + expect(wrapper.element).toHaveValue(JSON.stringify(numberValue, null, 0)) + }) + + it('should stringify array', async () => { + const arrayValue = ['foo', 'bar'] + const { wrapper } = render(() => ( + + )) + expect(wrapper.element).toHaveValue(JSON.stringify(arrayValue, null, 0)) + }) + + it('should not generate a fallback value when not provided', async () => { + const { wrapper } = render() + expect(wrapper.element).not.toHaveValue() + }) + }) + + describe('Reactivity', () => { + it('disabled', async () => { + const { wrapper } = render(() => ( + + )) + expect(wrapper.element).toHaveClass('v-btn--disabled') + + await wrapper.setProps({ disabled: false }) + expect.poll(() => wrapper.element as HTMLElement).not.toHaveClass('v-btn--disabled') + }) + + it.skip('activeClass', async () => { + const { container, wrapper } = render(() => ( + Active Class + )) + + await wrapper.setProps({ activeClass: 'different-class' }) + + const activeClassElement = container.querySelector('.different-class') + expect(activeClassElement).not.toBeInTheDocument() + }) + + it('plain', async () => { + const { wrapper } = render(() => ( + Plain + )) + + expect(wrapper.element).toHaveClass('v-btn--variant-plain') + + await wrapper.setProps({ variant: 'default' }) + + expect.poll(() => wrapper.element as HTMLElement).not.toHaveClass('v-btn--variant-plain') + }) + }) + + describe('Showcase', () => { + generate({ stories, props, component: VBtn }) + }) +}) diff --git a/packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.cy.tsx b/packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.cy.tsx deleted file mode 100644 index 6273c356eb9..00000000000 --- a/packages/vuetify/src/components/VBtn/__tests__/VBtn.spec.cy.tsx +++ /dev/null @@ -1,301 +0,0 @@ -/// - -import { VBtn } from '../VBtn' - -// Utilities -import { createRouter, createWebHistory } from 'vue-router' -import { generate, gridOn } from '@/../cypress/templates' - -const anchor = { - href: '#my-anchor', - hash: 'my-anchor', -} - -// TODO: generate these from types -const colors = ['success', 'info', 'warning', 'error', 'invalid'] -const sizes = ['x-small', 'small', 'default', 'large', 'x-large'] as const -const densities = ['default', 'comfortable', 'compact'] as const -const variants = ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain'] as const -const props = { - color: colors, - // variant: variants, - // disabled: false, - // loading: false, -} - -const stories = { - 'Default button': Basic button, - 'Small success button': Completed!, - 'Large, plain button w/ error': Whoops, - Loading: ( -
- {{ loader: () => Loading..., default: () => 'Default Content' }} - {{ loader: () => Loading..., default: () => 'Default Content' }} - {{ loader: () => Loading... }} - Default Content -
- ), - Icon: , - 'Density + size': gridOn(densities, sizes, (density, size) => - { size } - ), - Variants: gridOn(['no color', 'primary'], variants, (color, variant) => - { variant } - ), - 'Disabled variants': gridOn(['no color', 'primary'], variants, (color, variant) => - { variant } - ), - Stacked: gridOn([undefined], variants, (_, variant) => - { variant } - ), -} - -// Actual tests -describe('VBtn', () => { - describe('color', () => { - it('supports default color props', () => { - cy.mount(() => ( - <> - { colors.map(color => ( - - { color } button - - ))} - - )) - .get('button') - .should('have.length', colors.length) - .then(subjects => { - Array.from(subjects).forEach((subject, idx) => { - expect(subject).to.contain(colors[idx]) - }) - }) - }) - }) - - describe('icons', () => { - it('adds the icon class when true', () => { - cy.mount() - .get('button') - .should('have.class', 'v-btn--icon') - }) - - it('renders an icon inside', () => { - // TODO: Render VIcon instead of emoji - cy.mount(🐻) - .get('button') - .should('have.text', '🐻') - }) - }) - - describe('plain', () => { - it('should have the plain class when variant is plain', () => { - cy.mount(Plain) - .get('button') - .should('have.class', 'v-btn--variant-plain') - }) - }) - - describe('tag', () => { - it('renders the proper tag instead of a button', () => { - cy.mount(Click me) - .get('button') - .should('not.exist') - .get('custom-tag') - .should('have.text', 'Click me') - }) - }) - - describe('elevation', () => { - it('should have the correct elevation', () => { - cy.mount() - .get('button') - .should('have.class', 'elevation-24') - }) - }) - - describe('events', () => { - it('emits native click events', () => { - const click = cy.stub().as('click') - cy.mount(Click me) - .get('button') - .click() - cy.get('@click') - .should('have.been.called', 1) - cy.setProps({ href: undefined, to: '#my-anchor' }) - cy.get('@click') - .should('have.been.called', 2) - }) - - // Pending test, is "toggle" even going to be emitted anymore? - it.skip('emits toggle when used within a button group', () => { - // const register = jest.fn() - // const unregister = jest.fn() - // const toggle = jest.fn() - // const wrapper = mountFunction({ - // provide: { - // btnToggle: { register, unregister }, - // }, - // methods: { toggle }, - // }) - - // wrapper.trigger('click') - // expect(toggle).toHaveBeenCalled() - }) - }) - - // These tests were copied over from the previous Jest tests, - // but they are breaking because the features have not been implemented - describe.skip('disabled', () => { - // The actual behavior here is working, but the color class name isn't being removed - // We can _technically_ test that the background is NOT the color's background, - // but it's a bit brittle and I think it'll be better to check against the class name - it('should not add color classes if disabled', () => { - cy.mount() - .get('button') - .should('have.class', 'bg-success') - .get('button') - .should('have.class', 'v-btn--disabled') - .should('not.have.class', 'bg-success') - }) - }) - - describe.skip('activeClass', () => { - it('should use custom active-class', () => { - cy.mount(Active Class) - .get('.my-active-class') - .should('exist') - }) - }) - - // v-btn--tile isn't implemented at all - describe.skip('tile', () => { - it('applies the tile class when true', () => { - cy.mount() - .get('button') - .should('contain.class', 'v-btn--tile') - }) - - it('does not apply the tile class when false', () => { - cy.mount() - .get('button') - .should('not.contain.class', 'v-btn--tile') - }) - }) - - describe('href', () => { - it('should render an
tag when using href prop', () => { - cy.mount(Click me) - .get('.v-btn') - .click() - cy.get('a') - .should('contain.text', 'Click me') - .should('have.focus') - cy.hash() - .should('contain', anchor.hash) - }) - - it('should change route when using to prop', () => { - const router = createRouter({ - history: createWebHistory(), - routes: [ - { - path: '/', - component: { template: 'Home' }, - }, - { - path: '/about', - component: { template: 'About' }, - }, - ], - }) - - cy.mount(Click me, { global: { plugins: [router] } }) - .get('.v-btn') - .click() - cy.get('a') - .should('contain.text', 'Click me') - .should('have.focus') - cy.url() - .should('contain', '/about') - }) - }) - - describe('value', () => { - it('should pass string values', () => { - const stringValue = 'Foobar' - - cy.mount() - .get('button') - .should('have.value', stringValue) - }) - - it('should stringify object', () => { - const objectValue = { value: {} } - cy.mount() - .get('button') - .should('have.value', JSON.stringify(objectValue, null, 0)) - }) - - it('should stringify number', () => { - const numberValue = 15 - cy.mount() - .get('button') - .should('have.value', JSON.stringify(numberValue, null, 0)) - }) - - it('should stringify array', () => { - const arrayValue = ['foo', 'bar'] - cy.mount() - .get('button') - .should('have.value', JSON.stringify(arrayValue, null, 0)) - }) - - it('should not generate a fallback value when not provided', () => { - cy.mount() - .get('button') - .should('not.have.value') - }) - }) - - describe('Reactivity', () => { - // tile is not implemented. - it.skip('tile', () => { - cy.mount(My button) - .get('button') - .should('contain.class', 'v-btn--tile') - cy.setProps({ tile: false }) - cy.get('button') - .should('not.contain.class', 'v-btn--tile') - }) - - it('disabled', () => { - cy.mount() - .get('button') - .should('have.class', 'v-btn--disabled') - cy.setProps({ disabled: false }) - cy.get('button') - .should('not.have.class', 'v-btn--disabled') - }) - - it('activeClass', () => { - cy.mount(Active Class) - .setProps({ activeClass: 'different-class' }) - cy.get('.different-class') - .should('not.exist') - }) - - it('plain', () => { - cy.mount(Plain) - .get('button') - .should('have.class', 'v-btn--variant-plain') - cy.setProps({ variant: 'default' }) - cy.get('button') - .should('not.have.class', 'v-btn--variant-plain') - }) - }) - - describe('Showcase', () => { - generate({ stories, props, component: VBtn }) - }) -}) diff --git a/packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.browser.tsx b/packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.browser.tsx new file mode 100644 index 00000000000..a4744c4efdb --- /dev/null +++ b/packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.browser.tsx @@ -0,0 +1,60 @@ +import { VCheckboxBtn } from '../' + +// Utilities +import { render, screen, userEvent } from '@test' +import { ref } from 'vue' + +describe('VCheckboxBtn', () => { + it('should function without v-model', async () => { + render(() => ( + + )) + + const input = screen.getByCSS('input') + + await userEvent.click(input) + expect(input).toBeChecked() + + await userEvent.click(input) + expect(input).not.toBeChecked() + }) + + it('should function with v-model', async () => { + const model = ref(false) + render(() => ( + + )) + + const input = screen.getByCSS('input') + + await userEvent.click(input) + expect(input).toBeChecked() + expect(model.value).toBe(true) + + await userEvent.click(input) + expect(input).not.toBeChecked() + expect(model.value).toBe(false) + }) + + it('should display indeterminate status', async () => { + render(() => ( + + )) + + const input = screen.getByCSS('input') + expect(input).toBePartiallyChecked() + }) + + it('should not update input checked state when it is readonly', async () => { + const model = ref(false) + render(() => ( + + )) + + const input = screen.getByCSS('input') + + await userEvent.click(input!) + expect(input).not.toBeChecked() + expect(model.value).toBe(false) + }) +}) diff --git a/packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.cy.tsx b/packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.cy.tsx deleted file mode 100644 index 851f99fcfa9..00000000000 --- a/packages/vuetify/src/components/VCheckbox/__tests__/VCheckboxBtn.spec.cy.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/// - -// Components -import { VCheckboxBtn } from '../' - -// Utilities -import { ref } from 'vue' - -describe('VCheckboxBtn', () => { - it('should function without v-model', () => { - cy.mount(() => ( - - )) - - cy.get('.v-checkbox-btn').click(20, 20) - - cy.get('input').should('be.checked') - - cy.get('.v-checkbox-btn').click(20, 20) - - cy.get('input').should('not.be.checked') - }) - - it('should function with v-model', () => { - const model = ref(false) - cy.mount(() => ( - - )) - - cy.get('.v-checkbox-btn').click(20, 20) - - cy.get('input').should('be.checked').then(() => { - expect(model.value).to.be.true - }) - - cy.get('.v-checkbox-btn').click(20, 20) - - cy.get('input').should('not.be.checked').then(() => { - expect(model.value).to.be.false - }) - }) - - it('should display indeterminate status', () => { - cy.mount(() => ( - - )) - - cy.get('input').should('have.attr', 'aria-checked', 'mixed') - }) - - it('should not update input checked state when it is readonly', () => { - const model = ref(false) - cy.mount(() => ( - - )) - - cy.get('.v-checkbox-btn').click(20, 20) - - cy.get('input').should('not.be.checked').then(() => { - expect(model.value).to.be.false - }) - }) -}) diff --git a/packages/vuetify/src/components/VChip/VChip.tsx b/packages/vuetify/src/components/VChip/VChip.tsx index bbaedfd2842..8c38e4e7bf6 100644 --- a/packages/vuetify/src/components/VChip/VChip.tsx +++ b/packages/vuetify/src/components/VChip/VChip.tsx @@ -333,6 +333,7 @@ export const VChip = genericComponent()({ key="close" class="v-chip__close" type="button" + data-testid="close-chip" { ...closeProps.value } > { !slots.close ? ( diff --git a/packages/vuetify/src/components/VChip/__tests__/VChip.spec.browser.tsx b/packages/vuetify/src/components/VChip/__tests__/VChip.spec.browser.tsx new file mode 100644 index 00000000000..cfea3967483 --- /dev/null +++ b/packages/vuetify/src/components/VChip/__tests__/VChip.spec.browser.tsx @@ -0,0 +1,49 @@ +import { VChip } from '../' + +// Utilities +import { render, screen, userEvent } from '@test' +import { nextTick, shallowRef } from 'vue' + +describe('VChip', () => { + it('should emit events when closed', async () => { + const close = vi.fn() + const update = vi.fn() + + render(() => ( + + )) + + await userEvent.click(screen.getByTestId('close-chip')) + expect(close).toHaveBeenCalled() + expect(update).toHaveBeenCalled() + }) + + it('should have aria-label', async () => { + const closeLabel = shallowRef('Foo') + + render(() => ( + + )) + + const button = screen.getByTestId('close-chip') + + expect(button).toHaveAttribute('aria-label', 'Foo') + + closeLabel.value = 'Bar' + await nextTick() + expect(button).toHaveAttribute('aria-label', 'Bar') + + closeLabel.value = undefined + await nextTick() + expect(button).toHaveAttribute('aria-label', 'Close') + }) +}) diff --git a/packages/vuetify/src/components/VChip/__tests__/VChip.spec.cy.tsx b/packages/vuetify/src/components/VChip/__tests__/VChip.spec.cy.tsx deleted file mode 100644 index 5e3481dc47a..00000000000 --- a/packages/vuetify/src/components/VChip/__tests__/VChip.spec.cy.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/// - -import { VChip } from '../' - -describe('VChip', () => { - it('should emit events when closed', () => { - cy.mount(() => ( - chip - )) - - cy.get('.v-chip__close') - .click() - cy.emitted(VChip) - .then(emitted => { - expect(emitted).to.have.property('click:close') - expect(emitted).to.have.property('update:modelValue') - }) - }) - - it('should have aria-label', () => { - cy.mount(({ closeLabel }: any) => ( - chip - )) - - cy.get('.v-chip__close') - .should('have.attr', 'aria-label') - cy.setProps({ - closeLabel: 'Hello', - }) - cy.get('.v-chip__close') - .should('have.attr', 'aria-label', 'Hello') - }) -}) diff --git a/packages/vuetify/src/components/VColorPicker/VColorPicker.tsx b/packages/vuetify/src/components/VColorPicker/VColorPicker.tsx index df290c1e5a3..d9f9bf4e10a 100644 --- a/packages/vuetify/src/components/VColorPicker/VColorPicker.tsx +++ b/packages/vuetify/src/components/VColorPicker/VColorPicker.tsx @@ -14,7 +14,7 @@ import { useRtl } from '@/composables/locale' import { useProxiedModel } from '@/composables/proxiedModel' // Utilities -import { computed, onMounted, ref, watch } from 'vue' +import { computed, onBeforeMount, ref, watch } from 'vue' import { extractColor, modes, nullColor } from './util' import { consoleWarn, defineComponent, HSVtoCSS, omit, parseColor, propsFactory, RGBtoHSV, useRender } from '@/util' @@ -125,7 +125,7 @@ export const VColorPicker = defineComponent({ model.value = hsva } - onMounted(() => { + onBeforeMount(() => { if (!props.modes.includes(mode.value)) mode.value = props.modes[0] }) diff --git a/packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.browser.tsx b/packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.browser.tsx new file mode 100644 index 00000000000..677b750d134 --- /dev/null +++ b/packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.browser.tsx @@ -0,0 +1,170 @@ +import { VColorPicker } from '../VColorPicker' + +// Utilities +import { render, screen, userEvent } from '@test' +import { within } from '@testing-library/vue' + +describe('VColorPicker', () => { + it('should default to emitting hex value if no value is provided', async () => { + const update = vi.fn() + render(() => ( + + )) + + const canvas = screen.getByCSS('canvas') + await userEvent.click(canvas) + expect(update).toHaveBeenCalledTimes(1) + expect(update).toHaveBeenCalledWith(expect.stringMatching(/^#[A-F0-9]{6}$/)) + }) + + it('should emit hexa value if hexa value is provided', async () => { + const update = vi.fn() + render(() => ( + + )) + + const canvas = screen.getByCSS('canvas') + await userEvent.click(canvas) + expect(update).toHaveBeenCalledTimes(1) + expect(update).toHaveBeenCalledWith(expect.stringMatching(/^#[A-F0-9]{8}$/)) + }) + + it('should emit hex value if hex value is provided', async () => { + const update = vi.fn() + render(() => ( + + )) + + const canvas = screen.getByCSS('canvas') + await userEvent.click(canvas) + expect(update).toHaveBeenCalledTimes(1) + expect(update).toHaveBeenCalledWith(expect.stringMatching(/^#[A-F0-9]{6}$/)) + }) + + it('should emit hsla value if hsla value is provided', async () => { + const update = vi.fn() + render(() => ( + + )) + + const canvas = screen.getByCSS('canvas') + await userEvent.click(canvas) + expect(update).toHaveBeenCalledTimes(1) + expect(update).toHaveBeenCalledWith(expect.objectContaining({ + h: expect.any(Number), + s: expect.any(Number), + l: expect.any(Number), + a: expect.any(Number), + })) + }) + + it('should emit rgba value if rgba value is provided', async () => { + const update = vi.fn() + render(() => ( + + )) + + const canvas = screen.getByCSS('canvas') + await userEvent.click(canvas) + expect(update).toHaveBeenCalledTimes(1) + expect(update).toHaveBeenCalledWith(expect.objectContaining({ + r: expect.any(Number), + g: expect.any(Number), + b: expect.any(Number), + a: expect.any(Number), + })) + }) + + it('should hide mode switch if only one mode is enabled', () => { + render(() => ( + + )) + expect(screen.queryByCSS('.v-color-picker-edit > .v-btn')).toBeNull() + }) + + it('should hide alpha slider if mode does not include alpha', () => { + render(() => ( + + )) + expect(screen.queryByCSS('.v-color-picker-preview__alpha')).toBeNull() + }) + + it('should emit value when changing hue slider', async () => { + const update = vi.fn() + render(() => ( + + )) + + await userEvent.click(screen.getByCSS('.v-color-picker-preview__hue')) + expect(update).toHaveBeenCalledTimes(1) + expect(update).not.toHaveBeenCalledWith('#0000ff') + }) + + it('should emit value when changing alpha slider', async () => { + const update = vi.fn() + render(() => ( + + )) + + await userEvent.click(screen.getByCSS('.v-color-picker-preview__alpha')) + // expect(update).toHaveBeenCalledTimes(1) // TODO: fix double update + expect(update).not.toHaveBeenCalledWith('#0000ff') + }) + + it('should emit value when clicking on swatch', async () => { + const update = vi.fn() + render(() => ( + + )) + + const color = screen.getByCSS( + '.v-color-picker-swatches__swatch:nth-of-type(5) .v-color-picker-swatches__color:nth-of-type(1)' + ) + await userEvent.click(color) + within(color).findByCSS('.v-icon') + expect(update).toHaveBeenCalledTimes(1) + }) + + it('should not use global defaults for slider color', async () => { + render(VColorPicker, null, { + defaults: { + VSlider: { + color: 'primary', + trackColor: 'primary', + trackFillColor: 'primary', + }, + }, + }) + + expect(screen.queryByCSS('.bg-primary')).toBeNull() + expect(screen.queryByCSS('.text-primary')).toBeNull() + }) + + it('should not show dot or input values if no color is set', async () => { + render(VColorPicker) + + expect(screen.queryByCSS('.v-color-picker-canvas__dot')).toBeNull() + screen.getAllByCSS('.v-color-picker-edit__input input').forEach(el => { + expect(el).not.toHaveValue() + }) + + await userEvent.click(screen.getByCSS('canvas')) + expect(screen.getByCSS('.v-color-picker-canvas__dot')).toBeInTheDocument() + screen.getAllByCSS('.v-color-picker-edit__input input').forEach(el => { + expect(el).toHaveValue() + }) + }) + + it('should emit correct color when typing in hex field', async () => { + const update = vi.fn() + render(() => ( + + )) + + const input = screen.getByCSS('.v-color-picker-edit__input input') + await userEvent.type(input, 'FF00CC') + await userEvent.click(document.body) + expect(update).toHaveBeenCalledTimes(1) + expect(update).toHaveBeenCalledWith('#FF00CC') + }) +}) diff --git a/packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.cy.tsx b/packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.cy.tsx deleted file mode 100644 index ba89a4f6946..00000000000 --- a/packages/vuetify/src/components/VColorPicker/__tests__/VColorPicker.spec.cy.tsx +++ /dev/null @@ -1,315 +0,0 @@ -/* eslint-disable sonarjs/no-identical-functions */ -/// - -import { VColorPicker } from '../VColorPicker' -import { Application } from '@/../cypress/templates' - -describe('VColorPicker', () => { - it('should should render correctly in dark theme', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker').should('exist') - }) - - it('should should render correctly in rtl locale', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker').should('exist') - }) - - it('should show swatches', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-swatches').should('exist') - }) - - it('should hide inputs', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-edit').should('not.exist') - }) - - it('should hide canvas', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-canvas').should('not.exist') - }) - - it('should hide preview and sliders', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-preview').should('not.exist') - }) - - it('should support elevation', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker').should('have.class', 'elevation-0') - }) - - it('should support rounded', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker').should('have.class', 'rounded-0') - }) - - it('should default to emitting hex value if no value is provided', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-canvas canvas') - .then(canvas => { - const width = canvas.width() ?? 0 - const height = canvas.height() ?? 0 - - cy.wrap(canvas).click(width / 2, height / 2) - }) - cy.emitted(VColorPicker, 'update:modelValue') - .should('have.length', 1) - .then(arr => expect(arr[0][0]).to.match(/^#[A-F0-9]{6}$/)) - }) - - it('should emit hexa value if hexa value is provided', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-canvas canvas') - .then(canvas => { - const width = canvas.width() ?? 0 - const height = canvas.height() ?? 0 - - cy.wrap(canvas).click(width / 2, height / 2) - }) - cy.emitted(VColorPicker, 'update:modelValue') - .should('have.length', 1) - .then(arr => expect(arr[0][0]).to.match(/^#[A-F0-9]{8}$/)) - }) - - it('should emit hex value if hex value is provided', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-canvas canvas') - .then(canvas => { - const width = canvas.width() ?? 0 - const height = canvas.height() ?? 0 - - cy.wrap(canvas).click(width / 2, height / 2) - }) - cy.emitted(VColorPicker, 'update:modelValue') - .should('have.length', 1) - .then(arr => expect(arr[0][0]).to.match(/^#[A-F0-9]{6}$/)) - }) - - it('should emit hsla value if hsla value is provided', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-canvas canvas') - .then(canvas => { - const width = canvas.width() ?? 0 - const height = canvas.height() ?? 0 - - cy.wrap(canvas).click(width / 2, height / 2) - }) - cy.emitted(VColorPicker, 'update:modelValue') - .should('have.length', 1) - .then(emits => { - expect(emits[0][0]).to.haveOwnProperty('h') - expect(emits[0][0]).to.haveOwnProperty('s') - expect(emits[0][0]).to.haveOwnProperty('l') - expect(emits[0][0]).to.haveOwnProperty('a') - }) - }) - - it('should emit rgba value if rgba value is provided', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-canvas canvas') - .then(canvas => { - const width = canvas.width() ?? 0 - const height = canvas.height() ?? 0 - - cy.wrap(canvas).click(width / 2, height / 2) - }) - cy.emitted(VColorPicker, 'update:modelValue') - .should('have.length', 1) - .then(emits => { - expect(emits[0][0]).to.haveOwnProperty('r') - expect(emits[0][0]).to.haveOwnProperty('g') - expect(emits[0][0]).to.haveOwnProperty('b') - expect(emits[0][0]).to.haveOwnProperty('a') - }) - }) - - it('should hide mode switch if only one mode is enabled', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-edit > .v-btn').should('not.exist') - }) - - it('should hide alpha slider if mode does not include alpha', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-preview__alpha').should('not.exist') - }) - - it('should emit value when changing hue slider', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-preview__hue') - .then(slider => { - const width = slider.width() ?? 0 - const height = slider.height() ?? 0 - - cy.wrap(slider).click(width / 2, height / 2) - }) - cy.emitted(VColorPicker, 'update:modelValue') - .then(emits => expect(emits[0][0]).to.not.equal('#0000ff')) - }) - - it('should emit value when changing alpha slider', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-preview__alpha') - .then(slider => { - const width = slider.width() ?? 0 - const height = slider.height() ?? 0 - - cy.wrap(slider).click(width / 2, height / 2) - }) - cy.emitted(VColorPicker, 'update:modelValue') - .then(emits => expect(emits[0][0]).to.not.equal('#0000ff')) - }) - - it('should emit value when clicking on swatch', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-swatches__swatch').eq(4) - .find('.v-color-picker-swatches__color').eq(0).as('color') - .click() - cy.get('@color').find('.v-icon').should('exist') - cy.emitted(VColorPicker, 'update:modelValue') - .should('have.length', 1) - }) - - it('should not use global defaults for slider color', () => { - cy.mount(() => ( - - - - ), null, { - defaults: { - VSlider: { - color: 'primary', - trackColor: 'primary', - trackFillColor: 'primary', - }, - }, - }) - - cy.get('.bg-primary').should('not.exist') - cy.get('.text-primary').should('not.exist') - }) - - it('should not show dot or input values if no color is set', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-canvas__dot').should('not.exist') - cy.get('.v-color-picker-edit__input input').should('have.value', '') - cy.get('.v-color-picker-canvas canvas').then(canvas => { - const width = canvas.width() ?? 0 - const height = canvas.height() ?? 0 - - cy.wrap(canvas).click(width / 2, height / 2) - }) - cy.get('.v-color-picker-canvas__dot').should('exist') - cy.get('.v-color-picker-edit__input input').invoke('val').should('not.be.empty') - }) - - it('should emit correct color when typing in hex field', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-color-picker-edit__input input').as('input') - .type('FF00CC') - cy.get('@input').blur() - cy.emitted(VColorPicker, 'update:modelValue') - .should('deep.equal', [['#FF00CC']]) - }) -}) diff --git a/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts b/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts index e45f3ef7758..6608efde02c 100644 --- a/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts +++ b/packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts @@ -1,5 +1,4 @@ // Utilities -import { expect, it } from 'vitest' import { extractColor } from '../' const red = { h: 0, s: 1, v: 1, a: 1 } diff --git a/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.browser.tsx b/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.browser.tsx new file mode 100644 index 00000000000..1d88d22cbb5 --- /dev/null +++ b/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.browser.tsx @@ -0,0 +1,741 @@ +// Components +import { VCombobox } from '../VCombobox' +import { VForm } from '@/components/VForm' + +// Utilities +import { generate, render, screen, userEvent, waitAnimationFrame, waitIdle } from '@test' +import { cloneVNode, ref } from 'vue' + +const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const +const densities = ['default', 'comfortable', 'compact'] as const +const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const + +const stories = Object.fromEntries(Object.entries({ + 'Default input': , + Disabled: , + Affixes: , + 'Prepend/append': , + 'Prepend/append inner': , + Placeholder: , +}).map(([k, v]) => [k, ( +
+ { variants.map(variant => ( + densities.map(density => ( +
+ { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } + { cloneVNode(v, { variant, density, label: `with value`, modelValue: ['California'] }) } + { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: ['California'] }) } + {{ + selection: ({ item }) => { + return item.title + }, + }} + +
+ )) + )).flat()} +
+)])) + +describe('VCombobox', () => { + describe('closableChips', () => { + it('should close only first chip', async () => { + const items = [ + 'Item 1', + 'Item 2', + 'Item 3', + 'Item 4', + ] + + const selectedItems = [ + 'Item 1', + 'Item 2', + 'Item 3', + ] + + render(() => ( + + )) + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + await expect.poll(() => screen.getAllByCSS('.v-chip')).toHaveLength(2) + }) + }) + + describe('complex objects', () => { + it('single', async () => { + const items = [ + { title: 'Item 1', value: 'item1' }, + { title: 'Item 2', value: 'item2' }, + { title: 'Item 3', value: 'item3' }, + { title: 'Item 4', value: 'item4' }, + ] + const model = ref() + const search = ref() + const updateModel = vi.fn(val => model.value = val) + const updateSearch = vi.fn(val => search.value = val) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.click((await screen.findAllByRole('option'))[0]) + expect(model.value).toStrictEqual(items[0]) + expect(search.value).toBe(items[0].title) + expect(screen.getByRole('textbox')).toHaveValue(items[0].title) + expect(screen.getByCSS('.v-combobox__selection')).toHaveTextContent(items[0].title) + + await userEvent.click(element) + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.keyboard('Item 2') + expect(model.value).toBe('Item 2') + expect(search.value).toBe('Item 2') + expect(screen.getByRole('textbox')).toHaveValue('Item 2') + expect(screen.getByCSS('.v-combobox__selection')).toHaveTextContent('Item 2') + + await userEvent.click(element) + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.keyboard('item3') + expect(model.value).toBe('item3') + expect(search.value).toBe('item3') + expect(screen.getByRole('textbox')).toHaveValue('item3') + expect(screen.getByCSS('.v-combobox__selection')).toHaveTextContent('item3') + }) + + it('multiple', async () => { + const items = [ + { title: 'Item 1', value: 'item1' }, + { title: 'Item 2', value: 'item2' }, + { title: 'Item 3', value: 'item3' }, + { title: 'Item 4', value: 'item4' }, + ] + const model = ref<(string | typeof items[number])[]>([]) + const search = ref() + const updateModel = vi.fn(val => model.value = val) + const updateSearch = vi.fn(val => search.value = val) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.click(screen.getAllByRole('option')[0]) + expect(model.value).toStrictEqual([items[0]]) + expect(search.value).toBeUndefined() + expect(screen.getByRole('textbox')).toHaveValue('') + expect(screen.getByCSS('.v-combobox__selection')).toHaveTextContent(items[0].title) + + await userEvent.click(element) + await userEvent.keyboard('Item 2{tab}') + expect(model.value).toStrictEqual([items[0], 'Item 2']) + expect(search.value).toBe('') + expect(screen.getByRole('textbox')).toHaveValue('') + expect(screen.getAllByCSS('.v-combobox__selection').at(-1)).toHaveTextContent('Item 2') + + await userEvent.click(element) + await userEvent.keyboard('item3{tab}') + expect(model.value).toStrictEqual([items[0], 'Item 2', 'item3']) + expect(search.value).toBe('') + expect(screen.getByRole('textbox')).toHaveValue('') + expect(screen.getAllByCSS('.v-combobox__selection').at(-1)).toHaveTextContent('item3') + }) + }) + + describe('search', () => { + it('should filter items', async () => { + const items = [ + 'Item 1', + 'Item 1a', + 'Item 2', + 'Item 2a', + ] + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.keyboard('Item') + expect(await screen.findAllByRole('option')).toHaveLength(4) + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.keyboard('Item 1') + expect(await screen.findAllByRole('option')).toHaveLength(2) + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.keyboard('Item 3') + expect(screen.queryAllByRole('option')).toHaveLength(0) + }) + + it('should filter items when using multiple', async () => { + const items = [ + 'Item 1', + 'Item 1a', + 'Item 2', + 'Item 2a', + ] + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.keyboard('Item') + expect(await screen.findAllByRole('option')).toHaveLength(4) + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.keyboard('Item 1') + expect(await screen.findAllByRole('option')).toHaveLength(2) + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.keyboard('Item 3') + expect(screen.queryAllByRole('option')).toHaveLength(0) + }) + + it('should filter with custom item shape', async () => { + const items = [ + { + id: 1, + name: 'Test1', + }, + { + id: 2, + name: 'Antonsen PK', + }, + ] + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.keyboard('test') + expect(await screen.findByRole('option')).toHaveTextContent('Test1') + + await userEvent.keyboard('{Control>}a{/Ctrl}{Backspace}') + await userEvent.keyboard('antonsen') + expect(await screen.findByRole('option')).toHaveTextContent('Antonsen PK') + }) + }) + + describe('prefilled data', () => { + it('should work with array of strings when using multiple', async () => { + const items = ref(['California', 'Colorado', 'Florida']) + + const selectedItems = ref(['California', 'Colorado']) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + expect(await screen.findAllByRole('option', { selected: true })).toHaveLength(2) + expect(screen.getAllByCSS('.v-chip')).toHaveLength(2) + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + expect(await screen.findByRole('textbox')).toBeInTheDocument() + expect(screen.getAllByCSS('.v-chip')).toHaveLength(1) + expect(selectedItems.value).toStrictEqual(['Colorado']) + }) + + it('should work with objects when using multiple', async () => { + const items = ref([ + { + title: 'Item 1', + value: 'item1', + }, + { + title: 'Item 2', + value: 'item2', + }, + { + title: 'Item 3', + value: 'item3', + }, + ]) + + const selectedItems = ref( + [ + { + title: 'Item 1', + value: 'item1', + }, + { + title: 'Item 2', + value: 'item2', + }, + ] + ) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + expect(await screen.findAllByRole('option', { selected: true })).toHaveLength(2) + expect(screen.getAllByCSS('.v-chip')).toHaveLength(2) + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + expect(await screen.findByRole('textbox')).toBeInTheDocument() + expect(screen.getAllByCSS('.v-chip')).toHaveLength(1) + expect(selectedItems.value).toStrictEqual([{ + title: 'Item 2', + value: 'item2', + }]) + }) + + it('should work with objects when using multiple and item-value', async () => { + const items = ref([ + { + text: 'Item 1', + id: 'item1', + }, + { + text: 'Item 2', + id: 'item2', + }, + { + text: 'Item 3', + id: 'item3', + }, + ]) + + const selectedItems = ref( + [ + { + text: 'Item 1', + id: 'item1', + }, + { + text: 'Item 2', + id: 'item2', + }, + ] + ) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + const options = await screen.findAllByRole('option', { selected: true }) + expect(options).toHaveLength(2) + const input = await screen.findByRole('combobox') + expect(input).toHaveTextContent('Item 1') + expect(input).toHaveTextContent('Item 2') + + await userEvent.click(options[0]) + + expect(selectedItems.value).toStrictEqual([{ + text: 'Item 2', + id: 'item2', + }]) + }) + }) + + describe('readonly', () => { + it('should not be clickable when in readonly', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = 'Item 1' + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + + await userEvent.keyboard('{ArrowDown}') + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + }) + + it('should not be clickable when in readonly form', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = 'Item 1' + + const { element } = render(() => ( + + + + )) + + await userEvent.click(element) + + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + + await userEvent.keyboard('{ArrowDown}') + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + }) + }) + + describe('hide-selected', () => { + it('should hide selected item(s)', async () => { + const items = [ + 'Item 1', + 'Item 2', + 'Item 3', + 'Item 4', + ] + + const selectedItems = [ + 'Item 1', + 'Item 2', + ] + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + const listItems = await screen.findAllByRole('option') + expect(listItems).toHaveLength(2) + expect(listItems[0]).toHaveTextContent('Item 3') + expect(listItems[1]).toHaveTextContent('Item 4') + }) + }) + + // https://github.com/vuetifyjs/vuetify/issues/17120 + it('should display 0 when selected', async () => { + const items = [0, 1, 2, 3, 4] + + const selectedItems = ref(undefined) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + await userEvent.click(screen.getAllByRole('option')[0]) + + expect(screen.getByRole('textbox')).toHaveValue('0') + }) + + it('should conditionally show placeholder', async () => { + const { rerender } = render(VCombobox, { + props: { placeholder: 'Placeholder' }, + }) + + const input = screen.getByRole('textbox') + await expect.poll(() => input).toHaveAttribute('placeholder', 'Placeholder') + + await rerender({ label: 'Label' }) + await expect.poll(() => input).not.toBeVisible() + + await userEvent.click(input) + await expect.poll(() => input).toHaveAttribute('placeholder', 'Placeholder') + expect(input).toBeVisible() + + await userEvent.tab() + await rerender({ persistentPlaceholder: true }) + await expect.poll(() => input).toHaveAttribute('placeholder', 'Placeholder') + expect(input).toBeVisible() + + await rerender({ modelValue: 'Foobar' }) + await expect.poll(() => input).not.toHaveAttribute('placeholder') + + await rerender({ multiple: true, modelValue: ['Foobar'] }) + await expect.poll(() => input).not.toHaveAttribute('placeholder') + }) + + it('should keep TextField focused while selecting items from open menu', async () => { + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + await userEvent.keyboard('{ArrowDown}') + await userEvent.keyboard('{ArrowDown}') + await userEvent.keyboard('{ArrowDown}') + + expect(screen.getByCSS('.v-field')).toHaveClass('v-field--focused') + }) + + it('should not open menu when closing a chip', async () => { + const { element } = render(() => ( + + )) + + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + + await userEvent.click(screen.getAllByTestId('close-chip')[1]) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + + await userEvent.click(screen.getByTestId('close-chip')) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + + await userEvent.click(element) + expect(screen.queryAllByRole('listbox')).toHaveLength(1) + await userEvent.keyboard('{Escape}') + await expect.poll(() => screen.queryAllByRole('listbox')).toHaveLength(0) + }) + + describe('auto-select-first', () => { + it('should auto-select-first item when pressing enter', async () => { + const selectedItems = ref([]) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + expect(screen.getAllByRole('option')).toHaveLength(6) + + await userEvent.keyboard('Cal') + expect(await screen.findByRole('option')).toHaveClass('v-list-item--active') + await userEvent.keyboard('{Enter}') + await expect.poll(() => screen.queryAllByRole('option')).toHaveLength(6) + expect(selectedItems.value).toStrictEqual(['California']) + }) + + it('should auto-select-first item when pressing tab', async () => { + const selectedItems = ref([]) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + expect(screen.getAllByRole('option')).toHaveLength(6) + + await userEvent.keyboard('Cal') + expect(await screen.findByRole('option')).toHaveClass('v-list-item--active') + await userEvent.keyboard('{Tab}') + await expect.poll(() => screen.queryAllByRole('option')).toHaveLength(0) + expect(selectedItems.value).toStrictEqual(['California']) + }) + + it('should not auto-select-first item when blur', async () => { + const selectedItems = ref([]) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + expect(screen.getAllByRole('option')).toHaveLength(6) + + await userEvent.keyboard('Cal') + expect(await screen.findByRole('option')).toHaveClass('v-list-item--active') + await userEvent.click(document.body) + await expect.poll(() => screen.queryAllByRole('option')).toHaveLength(0) + expect(selectedItems.value).toStrictEqual(['Cal']) + }) + }) + + it(`doesn't add duplicate values`, async () => { + const selection = ref([]) + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.keyboard('foo{Enter}') + await userEvent.keyboard('bar{Enter}') + expect(selection.value).toHaveLength(2) + + await userEvent.keyboard('foo{Enter}') + expect(selection.value).toHaveLength(2) + }) + + // https://github.com/vuetifyjs/vuetify/issues/18796 + it('should allow deleting selection via closable-chips', async () => { + const selectedItem = ref('California') + + render(() => ( + + )) + + await userEvent.click(screen.getByTestId('close-chip')) + expect(selectedItem.value).toBeNull() + }) + + // https://github.com/vuetifyjs/vuetify/issues/18556 + it('should show menu if focused and items are added', async () => { + const { rerender } = render(VCombobox) + + await userEvent.keyboard('{Tab}') + await waitAnimationFrame() + expect(screen.queryByRole('listbox')).toBeNull() + + await rerender({ items: ['Foo', 'Bar'] }) + expect(await screen.findByRole('listbox')).toBeInTheDocument() + }) + + // https://github.com/vuetifyjs/vuetify/issues/19346 + it('should not show menu when focused and existing non-empty items are changed', async () => { + const { element, rerender } = render(VCombobox, { + props: { items: ['Foo', 'Bar'] }, + }) + + await userEvent.click(element) + expect(await screen.findByRole('listbox')).toBeInTheDocument() + + await userEvent.click(screen.getAllByRole('option')[0]) + await rerender({ items: ['Foo', 'Bar', 'test'] }) + await waitIdle() + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + }) + + // https://github.com/vuetifyjs/vuetify/issues/17573 + // When using selection slot or chips, input displayed next to chip/selection slot should be always empty + it('should always have empty input value when it is unfocused and when using selection slot or chips', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + const selectedItem = ref('Item 1') + + const { element, getByCSS } = render(() => ( + + )) + + await userEvent.click(element) + const input = getByCSS('input') + expect(input).toHaveValue('') + + // Blur input with a custom search input value + await userEvent.keyboard('test') + input.blur() + await expect.poll(() => selectedItem.value).toBe('test') + expect(input).toHaveValue('') + + // Press enter key with a custom search input value + await userEvent.click(element) + await userEvent.keyboard('test 2{Enter}') + await expect.poll(() => selectedItem.value).toBe('test 2') + expect(input).toHaveValue('') + + // Search existing item and click to select + await userEvent.click(element) + expect(input).toHaveValue('') + await userEvent.keyboard('Item 1') + await userEvent.click(await screen.findByRole('option')) + await expect.poll(() => selectedItem.value).toBe('Item 1') + }) + + // https://github.com/vuetifyjs/vuetify/issues/19319 + it('should respect return-object when blurring', async () => { + const items = [ + { title: 'Item 1', value: 'item1' }, + { title: 'Item 2', value: 'item2' }, + { title: 'Item 3', value: 'item3' }, + { title: 'Item 4', value: 'item4' }, + ] + const model = ref() + const search = ref() + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.click(screen.getAllByRole('option')[0]) + expect(model.value).toStrictEqual({ title: 'Item 1', value: 'item1' }) + + await userEvent.click(document.body) + expect(model.value).toStrictEqual({ title: 'Item 1', value: 'item1' }) + }) + + describe('Showcase', () => { + generate({ stories }) + }) +}) diff --git a/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx b/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx deleted file mode 100644 index 616753caf0c..00000000000 --- a/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx +++ /dev/null @@ -1,816 +0,0 @@ -/// - -// Components -import { VCombobox } from '../VCombobox' -import { VForm } from '@/components/VForm' - -// Utilities -import { cloneVNode, ref } from 'vue' -import { generate } from '../../../../cypress/templates' -import { keyValues } from '@/util' - -const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const -const densities = ['default', 'comfortable', 'compact'] as const -const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const - -const stories = Object.fromEntries(Object.entries({ - 'Default input': , - Disabled: , - Affixes: , - 'Prepend/append': , - 'Prepend/append inner': , - Placeholder: , -}).map(([k, v]) => [k, ( -
- { variants.map(variant => ( - densities.map(density => ( -
- { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } - { cloneVNode(v, { variant, density, label: `with value`, modelValue: ['California'] }) } - { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: ['California'] }) } - {{ - selection: ({ item }) => { - return item.title - }, - }} - -
- )) - )).flat()} -
-)])) - -describe('VCombobox', () => { - describe('closableChips', () => { - it('should close only first chip', () => { - const items = [ - 'Item 1', - 'Item 2', - 'Item 3', - 'Item 4', - ] - - const selectedItems = [ - 'Item 1', - 'Item 2', - 'Item 3', - ] - - cy.mount(() => ( - - )) - .get('.v-chip__close').eq(0) - .click() - cy.get('input').should('exist') - cy.get('.v-chip') - .should('have.length', 2) - }) - }) - - describe('complex objects', () => { - it('single', () => { - const items = [ - { title: 'Item 1', value: 'item1' }, - { title: 'Item 2', value: 'item2' }, - { title: 'Item 3', value: 'item3' }, - { title: 'Item 4', value: 'item4' }, - ] - const model = ref() - const search = ref() - const updateModel = cy.stub().as('model').callsFake(val => model.value = val) - const updateSearch = cy.stub().as('search').callsFake(val => search.value = val) - - cy.mount(() => ( - - )) - .get('input') - .click() - cy.get('.v-list-item').eq(0) - .click({ waitForAnimations: false }) - cy.should(() => { - expect(model.value).to.deep.equal(items[0]) - expect(search.value).to.deep.equal(items[0].title) - }) - cy.get('input') - .should('have.value', items[0].title) - .blur() - cy.get('.v-combobox__selection') - .should('contain', items[0].title) - - cy.get('input').click() - cy.get('input').clear() - cy.get('input').type('Item 2') - cy.should(() => { - expect(model.value).to.equal('Item 2') - expect(search.value).to.equal('Item 2') - }) - cy.get('input') - .should('have.value', 'Item 2') - .blur() - cy.get('.v-combobox__selection') - .should('contain', 'Item 2') - - cy.get('input').click() - cy.get('input').clear() - cy.get('input').type('item3') - cy.should(() => { - expect(model.value).to.equal('item3') - expect(search.value).to.equal('item3') - }) - cy.get('input') - .should('have.value', 'item3') - .blur() - cy.get('.v-combobox__selection') - .should('contain', 'item3') - }) - - it('multiple', () => { - const items = [ - { title: 'Item 1', value: 'item1' }, - { title: 'Item 2', value: 'item2' }, - { title: 'Item 3', value: 'item3' }, - { title: 'Item 4', value: 'item4' }, - ] - const model = ref<(string | typeof items[number])[]>([]) - const search = ref() - const updateModel = cy.stub().as('model').callsFake(val => model.value = val) - const updateSearch = cy.stub().as('search').callsFake(val => search.value = val) - - cy.mount(() => ( - - )) - .get('.v-field input') - .click() - cy.get('.v-list-item').eq(0) - .click({ waitForAnimations: false }) - cy.then(() => { - expect(model.value).to.deep.equal([items[0]]) - expect(search.value).to.be.undefined - }) - cy.get('.v-field input').as('input') - .should('have.value', '') - cy.get('.v-combobox__selection') - .should('contain', items[0].title) - - cy.get('@input').click() - cy.get('@input').type('Item 2') - cy.get('@input').blur() - cy.should(() => { - expect(model.value).to.deep.equal([items[0], 'Item 2']) - expect(search.value).to.equal('') - }) - cy.get('@input').should('have.value', '') - cy.get('.v-combobox__selection') - .should('contain', 'Item 2') - - cy.get('@input').click() - cy.get('@input').type('item3') - cy.get('@input').blur() - cy.should(() => { - expect(model.value).to.deep.equal([items[0], 'Item 2', 'item3']) - expect(search.value).to.equal('') - }) - cy.get('@input').should('have.value', '') - cy.get('.v-combobox__selection') - .should('contain', 'item3') - }) - }) - - describe('search', () => { - it('should filter items', () => { - const items = [ - 'Item 1', - 'Item 1a', - 'Item 2', - 'Item 2a', - ] - - cy.mount(() => ( - - )) - .get('input') - .type('Item') - cy.get('.v-list-item') - .should('have.length', 4) - cy.get('input').clear() - cy.get('input').type('Item 1') - cy.get('.v-list-item') - .should('have.length', 2) - cy.get('input').clear() - cy.get('input').type('Item 3') - cy.get('.v-list-item').should('have.length', 0) - }) - - it('should filter items when using multiple', () => { - const items = [ - 'Item 1', - 'Item 1a', - 'Item 2', - 'Item 2a', - ] - - cy.mount(() => ( - - )) - .get('input') - .type('Item') - cy.get('.v-list-item') - .should('have.length', 4) - cy.get('input:first-child').as('input') - .clear() - cy.get('@input').type('Item 1') - cy.get('.v-list-item') - .should('have.length', 2) - cy.get('@input').clear() - cy.get('@input').type('Item 3') - cy.get('.v-list-item') - .should('have.length', 0) - }) - - it('should filter with custom item shape', () => { - const items = [ - { - id: 1, - name: 'Test1', - }, - { - id: 2, - name: 'Antonsen PK', - }, - ] - - cy.mount(() => ( - - )) - .get('input') - .type('test') - cy.get('.v-list-item') - .should('have.length', 1) - .eq(0) - .should('have.text', 'Test1') - cy.get('input').clear() - cy.get('input').type('antonsen') - cy.get('.v-list-item') - .should('have.length', 1) - .eq(0) - .should('have.text', 'Antonsen PK') - }) - }) - - describe('prefilled data', () => { - it('should work with array of strings when using multiple', () => { - const items = ref(['California', 'Colorado', 'Florida']) - - const selectedItems = ref(['California', 'Colorado']) - - cy.mount(() => ( - - )) - - cy.get('.v-combobox input').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('input').get('.v-chip').should('have.length', 2) - - cy.get('.v-chip__close') - .eq(0) - .click() - cy.get('input').should('exist') - cy.get('.v-chip') - .should('have.length', 1) - cy.should(() => expect(selectedItems.value).to.deep.equal(['Colorado'])) - }) - - it('should work with objects when using multiple', () => { - const items = ref([ - { - title: 'Item 1', - value: 'item1', - }, - { - title: 'Item 2', - value: 'item2', - }, - { - title: 'Item 3', - value: 'item3', - }, - ]) - - const selectedItems = ref( - [ - { - title: 'Item 1', - value: 'item1', - }, - { - title: 'Item 2', - value: 'item2', - }, - ] - ) - - cy.mount(() => ( - - )) - - cy.get('.v-combobox input').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('input').get('.v-chip').should('have.length', 2) - - cy.get('.v-chip__close') - .eq(0) - .click() - cy.get('input').should('exist') - cy.get('.v-chip') - .should('have.length', 1) - cy.should(() => expect(selectedItems.value).to.deep.equal([{ - title: 'Item 2', - value: 'item2', - }])) - }) - - it('should work with objects when using multiple and item-value', () => { - const items = ref([ - { - text: 'Item 1', - id: 'item1', - }, - { - text: 'Item 2', - id: 'item2', - }, - { - text: 'Item 3', - id: 'item3', - }, - ]) - - const selectedItems = ref( - [ - { - text: 'Item 1', - id: 'item1', - }, - { - text: 'Item 2', - id: 'item2', - }, - ] - ) - - cy.mount(() => ( - - )) - - cy.get('.v-combobox input').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('.v-field__input').should('include.text', 'Item 1') - cy.get('.v-field__input').should('include.text', 'Item 2') - - cy.get('.v-list-item--active input') - .eq(0) - .click() - .get('.v-field__input') - .should(() => expect(selectedItems.value).to.deep.equal([{ - text: 'Item 2', - id: 'item2', - }])) - }) - }) - - describe('readonly', () => { - it('should not be clickable when in readonly', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = 'Item 1' - - cy.mount(() => ( - - )) - - cy.get('.v-combobox') - .click() - cy.get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - - cy.get('.v-combobox input').as('input') - .focus() - cy.get('@input').type('{downarrow}', { force: true }) - cy.get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - }) - - it('should not be clickable when in readonly form', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = 'Item 1' - - cy.mount(() => ( - - - - )) - - cy.get('.v-combobox') - .click() - cy.get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - - cy.get('.v-combobox input').as('input') - .focus() - cy.get('@input').type('{downarrow}', { force: true }) - cy.get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - }) - }) - - describe('hide-selected', () => { - it('should hide selected item(s)', () => { - const items = [ - 'Item 1', - 'Item 2', - 'Item 3', - 'Item 4', - ] - - const selectedItems = [ - 'Item 1', - 'Item 2', - ] - - cy.mount(() => ( - - )) - - cy.get('.v-combobox input').click() - - cy.get('.v-overlay__content .v-list-item').should('have.length', 2) - cy.get('.v-overlay__content .v-list-item .v-list-item-title').eq(0).should('have.text', 'Item 3') - cy.get('.v-overlay__content .v-list-item .v-list-item-title').eq(1).should('have.text', 'Item 4') - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/17120 - it('should display 0 when selected', () => { - const items = [0, 1, 2, 3, 4] - - const selectedItems = ref(undefined) - - cy.mount(() => ( - - )) - .get('.v-field input') - .click() - - cy.get('.v-list-item').eq(0) - .click({ waitForAnimations: false }) - - cy.get('.v-combobox input') - .should('have.value', '0') - }) - - it('should conditionally show placeholder', () => { - cy.mount(props => ( - - )) - .get('.v-combobox input') - .should('have.attr', 'placeholder', 'Placeholder') - .setProps({ label: 'Label' }) - .get('.v-combobox input') - .should('not.be.visible') - .get('.v-combobox input') - .focus() - .should('have.attr', 'placeholder', 'Placeholder') - .should('be.visible') - .blur() - .setProps({ persistentPlaceholder: true }) - .get('.v-combobox input') - .should('have.attr', 'placeholder', 'Placeholder') - .should('be.visible') - .setProps({ modelValue: 'Foobar' }) - .get('.v-combobox input') - .should('not.have.attr', 'placeholder') - .setProps({ multiple: true, modelValue: ['Foobar'] }) - .get('.v-combobox input') - .should('not.have.attr', 'placeholder') - }) - - it('should keep TextField focused while selecting items from open menu', () => { - cy.mount(() => ( - - )) - - cy.get('.v-combobox') - .click() - - cy.get('.v-list') - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - - cy.get('.v-field').should('have.class', 'v-field--focused') - }) - - it('should not open menu when closing a chip', () => { - cy - .mount(() => ( - - )) - .get('.v-combobox') - .should('not.have.class', 'v-combobox--active-menu') - .get('.v-chip__close').eq(1) - .click() - .get('.v-combobox') - .should('not.have.class', 'v-combobox--active-menu') - .get('.v-chip__close') - .click() - .get('.v-combobox') - .should('not.have.class', 'v-combobox--active-menu') - .click() - .should('have.class', 'v-combobox--active-menu') - .trigger('keydown', { key: keyValues.esc }) - .should('not.have.class', 'v-combobox--active-menu') - }) - - describe('auto-select-first', () => { - it('should auto-select-first item when pressing enter', () => { - cy - .mount(() => ( - - )) - .get('.v-combobox') - .click() - .get('.v-list-item') - .should('have.length', 6) - .get('.v-combobox input') - .type('Cal') - .get('.v-list-item').eq(0) - .should('have.class', 'v-list-item--active') - .get('.v-combobox input') - .trigger('keydown', { key: keyValues.enter, waitForAnimations: false }) - .get('.v-list-item') - .should('have.length', 6) - }) - - it('should auto-select-first item when pressing tab', () => { - const selectedItems = ref([]) - - cy - .mount(() => ( - - )) - .get('.v-combobox') - .click() - .get('.v-list-item') - .should('have.length', 6) - .get('.v-combobox input') - .type('Cal') - .get('.v-list-item').eq(0) - .should('have.class', 'v-list-item--active') - .realPress('Tab') - .get('.v-list-item') - .should('have.length', 0) - .then(_ => { - expect(selectedItems.value).to.deep.equal(['California']) - }) - }) - - it('should not auto-select-first item when blur', () => { - const selectedItems = ref(undefined) - - cy - .mount(() => ( - - )) - .get('.v-combobox') - .click() - .get('.v-list-item') - .should('have.length', 6) - .get('.v-combobox input') - .type('Cal') - .get('.v-list-item').eq(0) - .should('have.class', 'v-list-item--active') - .get('.v-combobox input') - .blur() - .get('.v-list-item') - .should('have.length', 0) - .should(_ => { - expect(selectedItems.value).to.deep.equal(['Cal']) - }) - }) - }) - - it(`doesn't add duplicate values`, () => { - cy - .mount(() => ( - - )) - .get('.v-combobox input') - .click() - .type('foo{enter}') - .type('bar{enter}') - .get('.v-combobox__selection') - .should('have.length', 2) - .get('.v-combobox input') - .type('foo{enter}') - .get('.v-combobox__selection') - .should('have.length', 2) - }) - - // https://github.com/vuetifyjs/vuetify/issues/18796 - it('should allow deleting selection via closable-chips', () => { - const selectedItem = ref('California') - - cy.mount(() => ( - - )) - .get('.v-chip__close') - .click() - .then(_ => { - expect(selectedItem.value).to.equal(null) - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/18556 - it('should show menu if focused and items are added', () => { - cy - .mount(props => ()) - .get('.v-combobox input') - .focus() - .get('.v-overlay') - .should('not.exist') - .setProps({ items: ['Foo', 'Bar'] }) - .get('.v-overlay') - .should('exist') - }) - - // https://github.com/vuetifyjs/vuetify/issues/19346 - it('should not show menu when focused and existing non-empty items are changed', () => { - cy - .mount((props: any) => ()) - .setProps({ items: ['Foo', 'Bar'] }) - .get('.v-combobox') - .click() - .get('.v-overlay') - .should('exist') - .get('.v-list-item').eq(0).click({ waitForAnimations: false }) - .setProps({ items: ['Foo', 'Bar', 'test'] }) - .get('.v-overlay') - .should('not.exist') - }) - - // https://github.com/vuetifyjs/vuetify/issues/17573 - // When using selection slot or chips, input displayed next to chip/selection slot should be always empty - it('should always have empty input value when it is unfocused and when using selection slot or chips', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - const selectedItem = ref('Item 1') - - cy - .mount(() => ( - - )) - .get('.v-combobox').click() - .get('.v-combobox input').should('have.value', '') - // Blur input with a custom search input value - .type('test') - .blur() - .should('have.value', '') - .should(() => { - expect(selectedItem.value).to.equal('test') - }) - // Press enter key with a custom search input value - .get('.v-combobox').click() - .get('.v-combobox input').should('have.value', '') - .type('test 2') - .trigger('keydown', { key: keyValues.enter, waitForAnimations: false }) - .should('have.value', '') - .should(() => { - expect(selectedItem.value).to.equal('test 2') - }) - // Search existing item and click to select - .get('.v-combobox').click() - .get('.v-combobox input').type('Item 1') - .get('.v-list-item').eq(0).click({ waitForAnimations: false }) - .get('.v-combobox input').should('have.value', '') - .should(() => { - expect(selectedItem.value).to.equal('Item 1') - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/19319 - it('should respect return-object when blurring', () => { - const items = [ - { title: 'Item 1', value: 'item1' }, - { title: 'Item 2', value: 'item2' }, - { title: 'Item 3', value: 'item3' }, - { title: 'Item 4', value: 'item4' }, - ] - const model = ref() - const search = ref() - - cy.mount(() => ( - - )) - .get('.v-combobox').click() - .get('.v-list-item').eq(0).click({ waitForAnimations: false }) - .should(() => { - expect(model.value).to.deep.equal({ title: 'Item 1', value: 'item1' }) - }) - .get('.v-combobox input').blur() - .should(() => { - expect(model.value).to.deep.equal({ title: 'Item 1', value: 'item1' }) - }) - }) - - describe('Showcase', () => { - generate({ stories }) - }) -}) diff --git a/packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.browser.tsx b/packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.browser.tsx new file mode 100644 index 00000000000..0e6a7b53889 --- /dev/null +++ b/packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.browser.tsx @@ -0,0 +1,88 @@ +// Components +import { VConfirmEdit } from '../' + +// Utilities +import { render, screen, userEvent } from '@test' +import { nextTick, shallowRef } from 'vue' + +describe('VConfirmEdit', () => { + it('mirrors external updates', async () => { + const externalModel = shallowRef('foo') + + render(() => ( + + { ({ model }) => ( +

{ model.value }

+ )} +
+ )) + + expect(screen.getByText('foo')).toBeInTheDocument() + + externalModel.value = 'bar' + await nextTick() + expect(screen.getByText('bar')).toBeInTheDocument() + }) + + it("doesn't mutate the original value", async () => { + const externalModel = shallowRef(['foo']) + + render(() => ( + + { ({ model }) => ( + <> +

{ model.value.join(',') }

+ + + )} +
+ )) + + expect(screen.getByText('foo')).toBeInTheDocument() + + await userEvent.click(screen.getByTestId('push')) + expect(screen.getByText('foo,bar')).toBeInTheDocument() + expect(externalModel.value).toEqual(['foo']) + + await userEvent.click(screen.getByText('OK')) + expect(externalModel.value).toEqual(['foo', 'bar']) + }) + + describe('hides actions if used from the slot', () => { + it('nothing', () => { + render(() => ) + expect(screen.getAllByCSS('button')).toHaveLength(2) + }) + + it('consume model', () => { + render(() => ( + + { ({ model }) => { + void model + }} + + )) + expect(screen.getAllByCSS('button')).toHaveLength(2) + }) + + it('consume actions', () => { + render(() => ( + + { ({ actions }) => { + void actions + }} + + )) + expect(screen.queryAllByCSS('button')).toHaveLength(0) + }) + + it('render actions', () => { + render(() => ( + + { ({ actions }) => actions } + + )) + expect(screen.getAllByCSS('button')).toHaveLength(2) + }) + }) +}) diff --git a/packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.cy.tsx b/packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.cy.tsx deleted file mode 100644 index 340f862759b..00000000000 --- a/packages/vuetify/src/components/VConfirmEdit/__test__/VConfirmEdit.spec.cy.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/// - -import { VConfirmEdit } from '..' - -// Utilities -import { ref } from 'vue' - -// Tests -describe('VConfirmEdit', () => { - it('mirrors external updates', () => { - const externalModel = ref('foo') - - cy.mount(() => ( - - { ({ model }) => ( -

{ model.value }

- )} -
- )).get('p') - .should('have.text', 'foo') - .then(() => { - externalModel.value = 'bar' - }) - .get('p') - .should('have.text', 'bar') - }) - - it(`doesn't mutate the original value`, () => { - const externalModel = ref(['foo']) - - cy.mount( - - { ({ model }) => ( - <> -

{ model.value.join(',') }

- - - )} -
- ).get('p') - .should('have.text', 'foo') - .get('[data-test="push"]').click() - .get('p') - .should('have.text', 'foo,bar') - .then(() => { - expect(externalModel.value).to.deep.equal(['foo']) - }) - cy.contains('.v-btn', 'OK').click() - cy.get('p') - .should('have.text', 'foo,bar') - .then(() => { - expect(externalModel.value).to.deep.equal(['foo', 'bar']) - }) - }) - - it('hides actions if used from the slot', () => { - cy.mount( - - ).get('.v-btn').should('have.length', 2) - - cy.mount( - - { ({ model }) => { - void model - }} - - ).get('.v-btn').should('have.length', 2) - - cy.mount( - - { ({ actions }) => { - void actions - }} - - ).get('.v-btn').should('have.length', 0) - - cy.mount( - - { ({ actions }) => actions } - - ).get('.v-btn').should('have.length', 2) - }) -}) diff --git a/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts b/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts index ba5dc1899d1..c85fa867f92 100644 --- a/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts +++ b/packages/vuetify/src/components/VDataTable/__tests__/headers.spec.ts @@ -1,5 +1,4 @@ // Utilities -import { expect, it } from 'vitest' import { createHeaders } from '../composables/headers' describe('VDataTable headers', () => { diff --git a/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts b/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts index 477aa4e8dc7..59723ba1152 100644 --- a/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts +++ b/packages/vuetify/src/components/VDataTable/__tests__/sort.spec.ts @@ -5,7 +5,6 @@ import { sortItems as _sortItems } from '../composables/sort' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' // Types import type { SortItem } from '../composables/sort' diff --git a/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.browser.tsx b/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.browser.tsx new file mode 100644 index 00000000000..c82604ac601 --- /dev/null +++ b/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.browser.tsx @@ -0,0 +1,191 @@ +// Components +import { VFileInput } from '../VFileInput' + +// Utilities +import { CenteredGrid, generate, render, screen, userEvent } from '@test' +import { cloneVNode, defineComponent, ref } from 'vue' + +const oneMBFile = new File([new ArrayBuffer(1021576)], '1MB file') +const twoMBFile = new File([new ArrayBuffer(2021152)], '2MB file') + +const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const +const densities = ['default', 'comfortable', 'compact'] as const +const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const + +const stories = Object.fromEntries(Object.entries({ + 'Default input': , + Disabled: , + 'Prepend/append': , + 'Prepend/append inner': , + Placeholder: , +}).map(([k, v]) => [k, ( +
+ { variants.map(variant => ( + densities.map(density => ( +
+ { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } + { cloneVNode(v, { variant, density, label: `with value`, modelValue: [oneMBFile, twoMBFile] }) } + { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: [oneMBFile, twoMBFile] }) } + {{ + selection: ({ fileNames }) => { + return fileNames.map(f => f) + }, + }} + +
+ )) + )).flat()} +
+)])) + +describe('VFileInput', () => { + it('should add file', async () => { + const model = ref() + const { element } = render(() => ( + + )) + + const input = screen.getByCSS('input') + + await userEvent.upload(input, 'text.txt') + expect(element).toHaveTextContent('text.txt') + expect(model.value).toEqual(expect.objectContaining({ name: 'text.txt' })) + }) + + it('should show number of files', async () => { + const { element } = render(() => ( + + )) + + expect(element).toHaveTextContent('2 files') + }) + + it('should show size of files', async () => { + const { element } = render(() => ( + + )) + + expect(element).toHaveTextContent('1MB file (1.0 MB), 2MB file (2.0 MB)') + }) + + it('should show total size of files in counter', async () => { + const { element } = render(() => ( + + )) + + expect(element).toHaveTextContent('2 files (3.0 MB in total)') + }) + + it('should clear input', async () => { + const model = ref([oneMBFile, twoMBFile]) + const { element } = render(() => ( + + )) + + await userEvent.click(screen.getByLabelText(/clear/i)) + + expect(element).not.toHaveTextContent('1MB file, 2MB file') + expect(model.value).toHaveLength(0) + expect(screen.getByCSS('input')).toHaveValue('') + }) + + it('should support removing clearable icon', async () => { + render(() => ( + + )) + + expect(screen.queryAllByLabelText(/clear/i)).toHaveLength(0) + }) + + it('should be disabled', async () => { + render(() => ( + + )) + expect(screen.getByCSS('input')).toBeDisabled() + }) + + it('should support no prepend icon', async () => { + render(() => ( + + )) + expect(screen.queryAllByCSS('.v-file-input .v-input__prepend')).toHaveLength(0) + }) + + it('should support chips', () => { + render(() => ( + + )) + expect(screen.getAllByCSS('.v-file-input .v-chip')).toHaveLength(2) + }) + + // https://github.com/vuetifyjs/vuetify/issues/8167 + it('should not emit change event when input is blurred', async () => { + const change = vi.fn() + const update = vi.fn() + render(() => ( + + )) + + const input = screen.getByCSS('input') + input.focus() + await userEvent.upload(input, 'text.txt') + await userEvent.tab() + + expect(change).toHaveBeenCalledTimes(1) + expect(update).toHaveBeenCalledTimes(1) + }) + + it('should put extra attributes on input', () => { + render(() => ( + + )) + expect(screen.getByCSS('input')).toHaveAttribute('accept', 'image/*') + }) + + // https://github.com/vuetifyjs/vuetify/issues/16486 + it('should reset the underlying HTMLInput when model is controlled input', async () => { + render(defineComponent({ + setup () { + const files = ref([]) + const onReset = () => { + files.value = [] + } + return () => ( + + + + + ) + }, + })) + + const input = screen.getByCSS('input') as HTMLInputElement + expect(input.files).toHaveLength(0) + + // add file + await userEvent.upload(input, 'text.txt') + expect(input.files).toHaveLength(1) + + // reset input from wrapper/parent component + await userEvent.click(screen.getByText(/reset/i)) + expect(input.files).toHaveLength(0) + + // add same file again + await userEvent.upload(input, 'text.txt') + expect(input.files).toHaveLength(1) + + // reset input from wrapper/parent component + await userEvent.click(screen.getByText(/reset/i)) + expect(input.files).toHaveLength(0) + }) + + describe('Showcase', () => { + generate({ stories }) + }) +}) diff --git a/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.cy.tsx b/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.cy.tsx deleted file mode 100644 index fcfa4889a0c..00000000000 --- a/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.cy.tsx +++ /dev/null @@ -1,237 +0,0 @@ -/// - -import { CenteredGrid, generate } from '@/../cypress/templates' - -// Components -import { VFileInput } from '../VFileInput' - -// Utilities -import { cloneVNode, ref } from 'vue' - -const oneMBFile = new File([new ArrayBuffer(1021576)], '1MB file') -const twoMBFile = new File([new ArrayBuffer(2021152)], '2MB file') - -const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const -const densities = ['default', 'comfortable', 'compact'] as const -const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const - -const stories = Object.fromEntries(Object.entries({ - 'Default input': , - Disabled: , - Affixes: , - 'Prepend/append': , - 'Prepend/append inner': , - Placeholder: , -}).map(([k, v]) => [k, ( -
- { variants.map(variant => ( - densities.map(density => ( -
- { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } - { cloneVNode(v, { variant, density, label: `with value`, modelValue: [oneMBFile, twoMBFile] }) } - { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: [oneMBFile, twoMBFile] }) } - {{ - selection: ({ fileNames }) => { - return fileNames.map(f => f) - }, - }} - -
- )) - )).flat()} -
-)])) - -describe('VFileInput', () => { - it('should add file', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input input') - .attachFile('text.txt') - .get('.v-file-input .v-field__input') - .should('have.text', 'text.txt') - }) - - it('should show number of files', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input .v-input__details') - .should('have.text', '2 files') - }) - - it('should show size of files', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input .v-field__input') - .should('have.text', '1MB file (1.0 MB), 2MB file (2.0 MB)') - }) - - it('should show total size of files in counter', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input .v-input__details') - .should('have.text', '2 files (3.0 MB in total)') - }) - - it('should clear input', () => { - const model = ref([oneMBFile, twoMBFile]) - cy.mount(() => ( - - - - )) - .get('.v-field__clearable > .v-icon') - .click() - cy.get('.v-input input') - .should('have.value', '') - }) - - it('should support removing clearable icon', () => { - cy.mount(() => ( - - - - )) - .get('.v-field__append-inner > .v-btn') - .should('not.exist') - }) - - it('should be disabled', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input') - .should('have.class', 'v-input--disabled') - .get('.v-file-input input') - .should('have.attr', 'disabled') - }) - - it('should support no prepend icon', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input .v-input__prepend') - .should('not.exist') - }) - - it('should support chips', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input .v-chip') - .should('have.length', 2) - }) - - // https://github.com/vuetifyjs/vuetify/issues/8167 - it('should not emit change event when input is blurred', () => { - const change = cy.spy().as('change') - const update = cy.spy().as('update') - cy.mount(() => ( - - ), { - props: { - onChange: change, - 'onUpdate:modelValue': update, - }, - }) - .get('.v-file-input input').as('input') - .focus() - cy.get('@input').attachFile('text.txt') - cy.get('@input').blur() - cy.then(() => { - expect(change).to.be.calledOnce - expect(update).to.be.calledOnce - }) - }) - - it('should put extra attributes on input', () => { - cy.mount(() => ( - - - - )) - .get('.v-file-input input') - .should('have.attr', 'accept', 'image/*') - }) - - /** - * https://github.com/vuetifyjs/vuetify/issues/16486 - */ - it('should reset the underlying HTMLInput when model is controlled input', () => { - function TestWrapper () { - const files = ref([]) - const onReset = () => { - files.value = [] - } - return ( - - - - - ) - } - - cy.mount(() => ( - - )) - .get('.v-file-input input').as('input') - .should($res => { - const input = $res[0] as HTMLInputElement - expect(input.files).to.have.length(0) - }) - // add file - cy.get('@input').attachFile('text.txt') - .should($res => { - const input = $res[0] as HTMLInputElement - expect(input.files).to.have.length(1) - }) - // reset input from wrapper/parent component - cy.get('button').click() - cy.get('@input') - .should($res => { - const input = $res[0] as HTMLInputElement - expect(input.files).to.have.length(0) - }) - // add same file again - .attachFile('text.txt') - .should($res => { - const input = $res[0] as HTMLInputElement - expect(input.files).to.have.length(1) - }) - // reset input from wrapper/parent component - cy.get('button').click() - cy.get('@input') - .should($res => { - const input = $res[0] as HTMLInputElement - expect(input.files).to.have.length(0) - }) - }) - - describe('Showcase', () => { - generate({ stories }) - }) -}) diff --git a/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx b/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx index 0b129da50d4..4b03dfe2a15 100644 --- a/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx +++ b/packages/vuetify/src/components/VFileInput/__tests__/VFileInput.spec.tsx @@ -2,7 +2,6 @@ import { VFileInput } from '../VFileInput' // Utilities import { mount } from '@vue/test-utils' -import { describe, expect, it, vi } from 'vitest' import { createVuetify } from '@/framework' describe('VFileInput', () => { diff --git a/packages/vuetify/src/components/VFileInput/__tests__/text.txt b/packages/vuetify/src/components/VFileInput/__tests__/text.txt new file mode 100644 index 00000000000..8e27be7d615 --- /dev/null +++ b/packages/vuetify/src/components/VFileInput/__tests__/text.txt @@ -0,0 +1 @@ +text diff --git a/packages/vuetify/src/components/VGrid/__tests__/VCol.spec.ts b/packages/vuetify/src/components/VGrid/__tests__/VCol.spec.ts index fc94f974bec..01dcf307c72 100644 --- a/packages/vuetify/src/components/VGrid/__tests__/VCol.spec.ts +++ b/packages/vuetify/src/components/VGrid/__tests__/VCol.spec.ts @@ -1,6 +1,5 @@ // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { VCol } from '../VCol' import { createVuetify } from '@/framework' diff --git a/packages/vuetify/src/components/VInput/__tests__/VInput.spec.cy.tsx b/packages/vuetify/src/components/VInput/__tests__/VInput.spec.browser.tsx similarity index 83% rename from packages/vuetify/src/components/VInput/__tests__/VInput.spec.cy.tsx rename to packages/vuetify/src/components/VInput/__tests__/VInput.spec.browser.tsx index 6a437a0ffb3..ba96423bdf4 100644 --- a/packages/vuetify/src/components/VInput/__tests__/VInput.spec.cy.tsx +++ b/packages/vuetify/src/components/VInput/__tests__/VInput.spec.browser.tsx @@ -1,18 +1,15 @@ -/// - // Components import { VInput } from '../VInput' // Utilities +import { generate } from '@test' import { cloneVNode } from 'vue' -import { generate } from '../../../../cypress/templates' const densities = ['default', 'comfortable', 'compact'] const stories = Object.fromEntries(Object.entries({ Default: , Disabled: , - Affixes: , PrependAppend: , Hint: , Messages: , diff --git a/packages/vuetify/src/components/VItemGroup/__tests__/VItemGroup.spec.ts b/packages/vuetify/src/components/VItemGroup/__tests__/VItemGroup.spec.ts index 82910d5afb2..e43637d739c 100644 --- a/packages/vuetify/src/components/VItemGroup/__tests__/VItemGroup.spec.ts +++ b/packages/vuetify/src/components/VItemGroup/__tests__/VItemGroup.spec.ts @@ -4,7 +4,6 @@ import { VItemGroup } from '../VItemGroup' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { h } from 'vue' import { createVuetify } from '@/framework' diff --git a/packages/vuetify/src/components/VList/VListItem.tsx b/packages/vuetify/src/components/VList/VListItem.tsx index fae894279cd..dcd422e06ba 100644 --- a/packages/vuetify/src/components/VList/VListItem.tsx +++ b/packages/vuetify/src/components/VList/VListItem.tsx @@ -244,6 +244,7 @@ export const VListItem = genericComponent()({ props.style, ]} tabindex={ isClickable.value ? (list ? -2 : 0) : undefined } + aria-selected={ root.activatable.value ? isActivated.value : isSelected.value } onClick={ onClick } onKeydown={ isClickable.value && !isLink.value && onKeyDown } v-ripple={ isClickable.value && props.ripple } diff --git a/packages/vuetify/src/components/VList/__tests__/VList.spec.ts b/packages/vuetify/src/components/VList/__tests__/VList.spec.ts index 58a6a31d5d2..59eebb5816d 100644 --- a/packages/vuetify/src/components/VList/__tests__/VList.spec.ts +++ b/packages/vuetify/src/components/VList/__tests__/VList.spec.ts @@ -3,7 +3,6 @@ import { VList } from '..' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { createVuetify } from '@/framework' describe('VList', () => { diff --git a/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts b/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts index bd799bd8200..a73cab175d4 100644 --- a/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts +++ b/packages/vuetify/src/components/VList/__tests__/VListItemMedia.spec.ts @@ -3,7 +3,6 @@ import { VListItemMedia } from '..' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { createVuetify } from '@/framework' describe('VListItemMedia', () => { diff --git a/packages/vuetify/src/components/VMain/__tests__/VMain.spec.cy.tsx b/packages/vuetify/src/components/VMain/__tests__/VMain.spec.cy.tsx deleted file mode 100644 index baa5cac03e6..00000000000 --- a/packages/vuetify/src/components/VMain/__tests__/VMain.spec.cy.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/// - -// Components -import { VMain } from '..' -import { VApp } from '@/components/VApp' - -describe('VAppBar', () => { - it('should allow custom height', () => { - cy.mount(() => ( - - - - )) - - cy.get('.v-main').should('have.prop', 'tagName').should('eq', 'DIV') - }) -}) diff --git a/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts b/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts index 5257be49b7b..b681e41c146 100644 --- a/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts +++ b/packages/vuetify/src/components/VResponsive/__tests__/VResponsive.spec.ts @@ -3,7 +3,6 @@ import { VResponsive } from '..' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { h } from 'vue' import { createVuetify } from '@/framework' diff --git a/packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.browser.tsx b/packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.browser.tsx new file mode 100644 index 00000000000..166ca6bcacb --- /dev/null +++ b/packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.browser.tsx @@ -0,0 +1,596 @@ +// Components +import { VSelect } from '../VSelect' +import { VForm } from '@/components/VForm' +import { VListItem } from '@/components/VList' + +// Utilities +import { generate, render, screen, userEvent } from '@test' +import { commands } from '@vitest/browser/context' +import { cloneVNode, ref } from 'vue' + +const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const +const densities = ['default', 'comfortable', 'compact'] as const +const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const + +const stories = Object.fromEntries(Object.entries({ + 'Default input': , + Disabled: , + Affixes: , + 'Prepend/append': , + 'Prepend/append inner': , + Placeholder: , +}).map(([k, v]) => [k, ( +
+ { variants.map(variant => ( + densities.map(density => ( +
+ { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } + { cloneVNode(v, { variant, density, label: `with value`, modelValue: ['California'] }) } + { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: ['California'] }) } + {{ + selection: ({ item }) => { + return item.title + }, + }} + +
+ )) + )).flat()} +
+)])) + +describe('VSelect', () => { + it('should render selection slot', () => { + const items = [ + { title: 'a' }, + { title: 'b' }, + { title: 'c' }, + ] + let model: { title: string }[] = [{ title: 'b' }] + + render(() => ( + model = val } + > + {{ + selection: ({ item, index }) => { + return item.raw.title.toUpperCase() + }, + }} + + )) + + expect(screen.getByCSS('.v-select__selection')).toHaveTextContent('B') + }) + + it('should render prepend-item slot', () => { + render(() => ( + + {{ + 'prepend-item': () => ( + + ), + }} + + )) + + expect(screen.getAllByCSS('.v-list-item')[0]).toHaveTextContent('Foo') + }) + + it('should render append-item slot', () => { + render(() => ( + + {{ + 'append-item': () => ( + + ), + }} + + )) + expect(screen.getAllByCSS('.v-list-item').at(-1)).toHaveTextContent('Foo') + }) + + it('should close only first chip', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = ['Item 1', 'Item 2', 'Item 3'] + + render(() => ( + + )) + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + await expect.poll(() => screen.getAllByCSS('.v-chip')).toHaveLength(2) + }) + + describe('prefilled data', () => { + it('should work with array of strings when using multiple', async () => { + const items = ['California', 'Colorado', 'Florida'] + + const selectedItems = ref(['California', 'Colorado']) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + expect(await screen.findAllByRole('option', { selected: true })).toHaveLength(2) + + const option = screen.getAllByRole('option')[2] + await commands.waitStable('.v-list') + await userEvent.click(option) + expect(selectedItems.value).toStrictEqual(['California', 'Colorado', 'Florida']) + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + expect(screen.getAllByCSS('.v-chip')).toHaveLength(2) + expect(selectedItems.value).toStrictEqual(['Colorado', 'Florida']) + }) + + it('should work with objects when using multiple', async () => { + const items = [ + { + title: 'Item 1', + value: 'item1', + }, + { + title: 'Item 2', + value: 'item2', + }, + { + title: 'Item 3', + value: 'item3', + }, + ] + + const selectedItems = ref( + [ + { + title: 'Item 1', + value: 'item1', + }, + { + title: 'Item 2', + value: 'item2', + }, + ] + ) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + expect(await screen.findAllByRole('option', { selected: true })).toHaveLength(2) + await commands.waitStable('.v-list') + await userEvent.click(screen.getAllByRole('option')[2]) + expect(selectedItems.value).toStrictEqual([ + { + title: 'Item 1', + value: 'item1', + }, + { + title: 'Item 2', + value: 'item2', + }, + { + title: 'Item 3', + value: 'item3', + }, + ]) + + await userEvent.click(screen.getAllByTestId('close-chip')[0]) + expect(screen.getAllByCSS('.v-chip')).toHaveLength(2) + expect(selectedItems.value).toStrictEqual([ + { + title: 'Item 2', + value: 'item2', + }, + { + title: 'Item 3', + value: 'item3', + }, + ]) + }) + + it('should work with objects when using multiple and item-value', async () => { + const items = [ + { + text: 'Item 1', + id: 'item1', + }, + { + text: 'Item 2', + id: 'item2', + }, + { + text: 'Item 3', + id: 'item3', + }, + ] + + const selectedItems = ref([ + { + text: 'Item 1', + id: 'item1', + }, + { + text: 'Item 2', + id: 'item2', + }, + ]) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await commands.waitStable('.v-list') + const options = screen.getAllByRole('option', { selected: true }) + expect(options).toHaveLength(2) + expect(element).toHaveTextContent('Item 1') + expect(element).toHaveTextContent('Item 2') + + await userEvent.click(options[0]) + expect(selectedItems.value).toStrictEqual([{ + text: 'Item 2', + id: 'item2', + }]) + }) + }) + + it('should not be clickable when in readonly', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = 'Item 1' + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + + await userEvent.keyboard('{ArrowDown}') + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + }) + + it('should not be clickable when in readonly form', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = 'Item 1' + + const { element } = render(() => ( + + + + )) + + await userEvent.click(element) + + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + + await userEvent.keyboard('{ArrowDown}') + expect(screen.queryAllByRole('option')).toHaveLength(0) + expect(screen.queryAllByRole('listbox')).toHaveLength(0) + }) + + // https://github.com/vuetifyjs/vuetify/issues/16442 + describe('null value', () => { + it('should allow null as legit itemValue', async () => { + const items = [ + { name: 'Default Language', code: null }, + { code: 'en-US', name: 'English' }, + { code: 'de-DE', name: 'German' }, + ] + + const selectedItems = null + + const { element } = render(() => ( + + )) + expect(element).toHaveTextContent('Default Language') + }) + it('should mark input as "not dirty" when the v-model is null, but null is not present in the items', async () => { + const items = [ + { code: 'en-US', name: 'English' }, + { code: 'de-DE', name: 'German' }, + ] + + render(() => ( + + )) + expect(screen.queryAllByCSS('.v-field--dirty')).toHaveLength(0) + }) + }) + + it('should conditionally show placeholder', async () => { + const { rerender } = render(VSelect, { + props: { placeholder: 'Placeholder' }, + }) + + const input = screen.getByCSS('input') + await expect.element(input).toHaveAttribute('placeholder', 'Placeholder') + + await rerender({ label: 'Label' }) + await expect.element(input).not.toHaveAttribute('placeholder') + input.focus() + await expect.element(input).toHaveAttribute('placeholder', 'Placeholder') + input.blur() + await expect.element(input).not.toHaveAttribute('placeholder') + + await rerender({ persistentPlaceholder: true }) + await expect.element(input).toHaveAttribute('placeholder', 'Placeholder') + + await rerender({ modelValue: 'Foobar' }) + await expect.element(input).not.toHaveAttribute('placeholder') + + await rerender({ multiple: true, modelValue: ['Foobar'] }) + await expect.element(input).not.toHaveAttribute('placeholder') + }) + + // https://github.com/vuetifyjs/vuetify/issues/16210 + it('should return item object as the argument of item-title function', async () => { + const items = [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + ] + + const selectedItems = ref(null) + + const itemTitleFunc = vi.fn((item: any) => ( + 'Item: ' + JSON.stringify(item) + )) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await commands.waitStable('.v-list') + await userEvent.click(screen.getAllByRole('option')[0]) + expect(selectedItems.value).toBe(1) + expect(itemTitleFunc).toHaveBeenCalledWith({ id: 1, name: 'a' }, expect.anything()) + expect(element).toHaveTextContent(`Item: {"id":1,"name":"a"}`) + }) + + describe('hide-selected', () => { + it('should hide selected item(s)', async () => { + const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] + + const selectedItems = ref(['Item 1', 'Item 2']) + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await commands.waitStable('.v-list') + const options = screen.getAllByRole('option') + expect(options).toHaveLength(2) + expect(options[0]).toHaveTextContent('Item 3') + expect(options[1]).toHaveTextContent('Item 4') + }) + + // https://github.com/vuetifyjs/vuetify/issues/19806 + it('should hide selected item(s) with return-object', async () => { + const selectedItem = ref({ text: 'Item 1', id: 'item1' }) + const items = [ + { + text: 'Item 1', + id: 'item1', + }, + { + text: 'Item 2', + id: 'item2', + }, + { + text: 'Item 3', + id: 'item3', + }, + ] + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await commands.waitStable('.v-list') + expect(screen.queryAllByRole('option', { selected: true })).toHaveLength(0) + let options = screen.getAllByRole('option') + expect(options).toHaveLength(2) + expect(options[0]).toHaveTextContent('Item 2') + + await userEvent.click(options[0]) + expect(selectedItem.value).toStrictEqual({ text: 'Item 2', id: 'item2' }) + expect(screen.queryAllByRole('option', { selected: true })).toHaveLength(0) + options = screen.getAllByRole('option') + expect(options).toHaveLength(2) + expect(options[0]).toHaveTextContent('Item 1') + }) + }) + + // https://github.com/vuetifyjs/vuetify/issues/16055 + it('should select item after typing its first few letters', async () => { + const items = ['aaa', 'foo', 'faa'] + const selectedItems = ref() + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await userEvent.keyboard('f') + expect(screen.getAllByRole('option')).toHaveLength(3) + expect(selectedItems.value).toBe('foo') + }) + + it('should keep TextField focused while selecting items from open menu', async () => { + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await commands.waitStable('.v-list') + await userEvent.keyboard('{ArrowDown}') + await userEvent.keyboard('{ArrowDown}') + await userEvent.keyboard('{ArrowDown}') + expect(screen.getByCSS('.v-field')).toHaveClass('v-field--focused') + }) + + it('should not open menu when closing a chip', async () => { + const { element } = render(() => ( + + )) + + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + await userEvent.click(screen.getAllByTestId('close-chip')[1]) + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + await userEvent.click(screen.getByTestId('close-chip')) + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + await userEvent.click(element) + await expect.poll(() => screen.queryByRole('listbox')).toBeInTheDocument() + await userEvent.keyboard('{Escape}') + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + }) + + // https://github.com/vuetifyjs/vuetify/issues/19235 + it('should update v-model when click closable chip', async () => { + const selectedItem = ref('abc') + + render(() => ( + + )) + + await userEvent.click(screen.getByTestId('close-chip')) + expect(selectedItem.value).toBeNull() + }) + + // https://github.com/vuetifyjs/vuetify/issues/19261 + it('should not toggle v-model to null when clicking already selected item in single selection mode', async () => { + const selectedItem = ref('abc') + + const { element } = render(() => ( + + )) + + await userEvent.click(element) + await commands.waitStable('.v-list') + const options = screen.getAllByRole('option') + expect(options).toHaveLength(2) + await userEvent.click(options[0]) + expect(selectedItem.value).toBe('abc') + }) + + // https://github.com/vuetifyjs/vuetify/issues/18556 + it('should show menu if focused and items are added', async () => { + const { rerender } = render(VSelect) + + await userEvent.keyboard('{Tab}') + expect(screen.queryByRole('listbox')).toBeNull() + + await rerender({ items: ['Foo', 'Bar'] }) + await expect.poll(() => screen.queryByRole('listbox')).toBeInTheDocument() + }) + + // https://github.com/vuetifyjs/vuetify/issues/19346 + it('should not show menu when focused and existing non-empty items are changed', async () => { + const { element, rerender } = render(VSelect, { + props: { items: ['Foo', 'Bar'] }, + }) + + await userEvent.click(element) + await expect.poll(() => screen.queryByRole('listbox')).toBeInTheDocument() + await userEvent.click(screen.getAllByRole('option')[0]) + + await rerender({ items: ['Foo', 'Bar', 'test', 'test 2'] }) + await expect.poll(() => screen.queryByRole('listbox')).toBeNull() + }) + + describe('Showcase', () => { + generate({ stories }) + }) +}) diff --git a/packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.cy.tsx b/packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.cy.tsx deleted file mode 100644 index fd60cd9c537..00000000000 --- a/packages/vuetify/src/components/VSelect/__tests__/VSelect.spec.cy.tsx +++ /dev/null @@ -1,643 +0,0 @@ -/// - -// Components -import { VSelect } from '../VSelect' -import { VForm } from '@/components/VForm' -import { VListItem } from '@/components/VList' - -// Utilities -import { cloneVNode, ref } from 'vue' -import { generate } from '../../../../cypress/templates' -import { keyValues } from '@/util' - -const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const -const densities = ['default', 'comfortable', 'compact'] as const -const items = ['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming'] as const - -const stories = Object.fromEntries(Object.entries({ - 'Default input': , - Disabled: , - Affixes: , - 'Prepend/append': , - 'Prepend/append inner': , - Placeholder: , -}).map(([k, v]) => [k, ( -
- { variants.map(variant => ( - densities.map(density => ( -
- { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } - { cloneVNode(v, { variant, density, label: `with value`, modelValue: ['California'] }) } - { cloneVNode(v, { variant, density, label: `chips`, chips: true, modelValue: ['California'] }) } - {{ - selection: ({ item }) => { - return item.title - }, - }} - -
- )) - )).flat()} -
-)])) - -describe('VSelect', () => { - it('should render selection slot', () => { - const items = [ - { title: 'a' }, - { title: 'b' }, - { title: 'c' }, - ] - let model: { title: string }[] = [{ title: 'b' }] - - cy.mount(() => ( - model = val } - > - {{ - selection: ({ item, index }) => { - return item.raw.title.toUpperCase() - }, - }} - - )) - .get('.v-select__selection').eq(0).invoke('text').should('equal', 'B') - }) - - it('should render prepend-item slot', () => { - cy.mount(() => ( - - {{ - 'prepend-item': () => ( - - ), - }} - - )) - .get('.v-list-item').eq(0).invoke('text').should('equal', 'Foo') - }) - - it('should render append-item slot', () => { - cy.mount(() => ( - - {{ - 'append-item': () => ( - - ), - }} - - )) - .get('.v-list-item').last().invoke('text').should('equal', 'Foo') - }) - - it('should close only first chip', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = ['Item 1', 'Item 2', 'Item 3'] - - cy.mount(() => ( - - )) - .get('.v-chip__close') - .eq(0) - .click() - .get('input') - .get('.v-chip') - .should('have.length', 2) - }) - - describe('prefilled data', () => { - it('should work with array of strings when using multiple', () => { - const items = ref(['California', 'Colorado', 'Florida']) - - const selectedItems = ref(['California', 'Colorado']) - - cy.mount(() => ( - - )) - - cy.get('.v-select').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('.v-list-item input').eq(2).click().should(() => { - expect(selectedItems.value).to.deep.equal(['California', 'Colorado', 'Florida']) - }) - - cy - .get('.v-chip__close') - .eq(0) - .click() - .get('.v-chip') - .should('have.length', 2) - .should(() => expect(selectedItems.value).to.deep.equal(['Colorado', 'Florida'])) - }) - - it('should work with objects when using multiple', () => { - const items = ref([ - { - title: 'Item 1', - value: 'item1', - }, - { - title: 'Item 2', - value: 'item2', - }, - { - title: 'Item 3', - value: 'item3', - }, - ]) - - const selectedItems = ref( - [ - { - title: 'Item 1', - value: 'item1', - }, - { - title: 'Item 2', - value: 'item2', - }, - ] - ) - - cy.mount(() => ( - - )) - - cy.get('.v-select').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('.v-list-item input').eq(2).click().should(() => { - expect(selectedItems.value).to.deep.equal([ - { - title: 'Item 1', - value: 'item1', - }, - { - title: 'Item 2', - value: 'item2', - }, - { - title: 'Item 3', - value: 'item3', - }, - ]) - }) - - cy - .get('.v-chip__close') - .eq(0) - .click() - .get('.v-chip') - .should('have.length', 2) - .should(() => expect(selectedItems.value).to.deep.equal([ - { - title: 'Item 2', - value: 'item2', - }, - { - title: 'Item 3', - value: 'item3', - }, - ])) - }) - - it('should work with objects when using multiple and item-value', () => { - const items = ref([ - { - text: 'Item 1', - id: 'item1', - }, - { - text: 'Item 2', - id: 'item2', - }, - { - text: 'Item 3', - id: 'item3', - }, - ]) - - const selectedItems = ref([ - { - text: 'Item 1', - id: 'item1', - }, - { - text: 'Item 2', - id: 'item2', - }, - ]) - - cy.mount(() => ( - - )) - - cy.get('.v-select').click() - - cy.get('.v-list-item--active').should('have.length', 2) - cy.get('.v-field__input').should('include.text', 'Item 1') - cy.get('.v-field__input').should('include.text', 'Item 2') - - cy.get('.v-list-item--active input') - .eq(0) - .click() - .get('.v-field__input') - .should(() => expect(selectedItems.value).to.deep.equal([{ - text: 'Item 2', - id: 'item2', - }])) - }) - }) - - it('should not be clickable when in readonly', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = 'Item 1' - - cy.mount(() => ( - - )) - - cy.get('.v-select') - .click() - .get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - - cy - .get('.v-select input') - .focus() - .type('{downarrow}', { force: true }) - .get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - }) - - it('should not be clickable when in readonly form', () => { - const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'] - - const selectedItems = 'Item 1' - - cy.mount(() => ( - - - - )) - - cy.get('.v-select') - .click() - .get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - - cy - .get('.v-select input') - .focus() - .type('{downarrow}', { force: true }) - .get('.v-list-item').should('have.length', 0) - .get('.v-select--active-menu').should('have.length', 0) - }) - - // https://github.com/vuetifyjs/vuetify/issues/16442 - describe('null value', () => { - it('should allow null as legit itemValue', () => { - const items = [ - { name: 'Default Language', code: null }, - { code: 'en-US', name: 'English' }, - { code: 'de-DE', name: 'German' }, - ] - - const selectedItems = null - - cy.mount(() => ( - - )) - - cy.get('.v-select__selection').eq(0).invoke('text').should('equal', 'Default Language') - }) - it('should mark input as "not dirty" when the v-model is null, but null is not present in the items', () => { - const items = [ - { code: 'en-US', name: 'English' }, - { code: 'de-DE', name: 'German' }, - ] - - cy.mount(() => ( - - )) - - cy.get('.v-field').should('not.have.class', 'v-field--dirty') - }) - }) - - it('should conditionally show placeholder', () => { - cy.mount(props => ( - - )) - .get('.v-select input') - .should('have.attr', 'placeholder', 'Placeholder') - .setProps({ label: 'Label' }) - .get('.v-select input') - .should('not.have.attr', 'placeholder') - .get('.v-select input') - .focus() - .should('have.attr', 'placeholder', 'Placeholder') - .blur() - .setProps({ persistentPlaceholder: true }) - .get('.v-select input') - .should('have.attr', 'placeholder', 'Placeholder') - .setProps({ modelValue: 'Foobar' }) - .get('.v-select input') - .should('not.have.attr', 'placeholder') - .setProps({ multiple: true, modelValue: ['Foobar'] }) - .get('.v-select input') - .should('not.have.attr', 'placeholder') - }) - - // https://github.com/vuetifyjs/vuetify/issues/16210 - it('should return item object as the argument of item-title function', () => { - const items = [ - { id: 1, name: 'a' }, - { id: 2, name: 'b' }, - ] - - const selectedItems = ref(null) - - function itemTitleFunc (item: any) { - return 'Item: ' + JSON.stringify(item) - } - - const itemTitleFuncSpy = cy.spy(itemTitleFunc).as('itemTitleFunc') - - cy.mount(() => ( - - )) - - cy.get('.v-select').click() - - cy.get('.v-list-item').eq(0).click({ waitForAnimations: false }).should(() => { - expect(selectedItems.value).to.deep.equal(1) - }) - - cy.get('@itemTitleFunc') - .should('have.been.calledWith', { id: 1, name: 'a' }) - - cy.get('.v-select__selection-text').should('have.text', `Item: {"id":1,"name":"a"}`) - }) - - describe('hide-selected', () => { - it('should hide selected item(s)', () => { - const items = ref(['Item 1', - 'Item 2', - 'Item 3', - 'Item 4', - ]) - - const selectedItems = ref([ - 'Item 1', - 'Item 2', - ]) - - cy.mount(() => ( - - )) - - cy.get('.v-select').click() - - cy.get('.v-overlay__content .v-list-item').should('have.length', 2) - cy.get('.v-overlay__content .v-list-item .v-list-item-title').eq(0).should('have.text', 'Item 3') - cy.get('.v-overlay__content .v-list-item .v-list-item-title').eq(1).should('have.text', 'Item 4') - }) - - // https://github.com/vuetifyjs/vuetify/issues/19806 - it('should hide selected item(s) with return-object', () => { - const selectedItem = ref({ text: 'Item 1', id: 'item1' }) - const items = ref([ - { - text: 'Item 1', - id: 'item1', - }, - { - text: 'Item 2', - id: 'item2', - }, - { - text: 'Item 3', - id: 'item3', - }, - ]) - cy.mount((props: any) => ( - - )).get('.v-select').click() - .get('.v-list-item--active').should('have.length', 0) - .get('.v-overlay__content .v-list-item').should('have.length', 2) - .get('.v-overlay__content .v-list-item .v-list-item-title').eq(0).should('have.text', 'Item 2') - .get('.v-overlay__content .v-list-item').eq(0).click({ waitForAnimations: false }).should(() => { - expect(selectedItem.value).to.deep.equal({ text: 'Item 2', id: 'item2' }) - }) - .get('.v-list-item--active').should('have.length', 0) - .get('.v-overlay__content .v-list-item').should('have.length', 2) - .get('.v-overlay__content .v-list-item .v-list-item-title').eq(0).should('have.text', 'Item 1') - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/16055 - it('should select item after typing its first few letters', () => { - const items = ref(['aaa', 'foo', 'faa']) - - const selectedItems = ref(undefined) - - cy.mount(() => ( - - )) - - cy.get('.v-select') - .click() - .get('.v-select input') - .focus() - .type('f', { force: true }) - .get('.v-list-item').should('have.length', 3) - .then(_ => { - expect(selectedItems.value).equal('foo') - }) - }) - - it('should keep TextField focused while selecting items from open menu', () => { - cy.mount(() => ( - - )) - - cy.get('.v-select') - .click() - - cy.get('.v-list') - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - .trigger('keydown', { key: keyValues.down, waitForAnimations: false }) - - cy.get('.v-field').should('have.class', 'v-field--focused') - }) - - it('should not open menu when closing a chip', () => { - cy - .mount(() => ( - - )) - .get('.v-select') - .should('not.have.class', 'v-select--active-menu') - .get('.v-chip__close').eq(1) - .click() - .get('.v-select') - .should('not.have.class', 'v-select--active-menu') - .get('.v-chip__close') - .click() - .get('.v-select') - .should('not.have.class', 'v-select--active-menu') - .click() - .should('have.class', 'v-select--active-menu') - .trigger('keydown', { key: keyValues.esc }) - .should('not.have.class', 'v-select--active-menu') - }) - - // https://github.com/vuetifyjs/vuetify/issues/19235 - it('should update v-model when click closable chip', () => { - const selectedItem = ref('abc') - - cy.mount(() => ( - - )) - - cy.get('.v-chip__close') - .click() - .then(_ => { - expect(selectedItem.value).equal(null) - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/19261 - it('should not toggle v-model to null when clicking already selected item in single selection mode', () => { - const selectedItem = ref('abc') - - cy.mount(() => ( - - )) - - cy.get('.v-select').click() - - cy.get('.v-list-item').should('have.length', 2) - cy.get('.v-list-item').eq(0).click({ waitForAnimations: false }).should(() => { - expect(selectedItem.value).equal('abc') - }) - }) - - // https://github.com/vuetifyjs/vuetify/issues/18556 - it('should show menu if focused and items are added', () => { - cy - .mount(props => ()) - .get('.v-select input') - .focus() - .get('.v-overlay') - .should('not.exist') - .setProps({ items: ['Foo', 'Bar'] }) - .get('.v-overlay') - .should('exist') - }) - - // https://github.com/vuetifyjs/vuetify/issues/19346 - it('should not show menu when focused and existing non-empty items are changed', () => { - cy - .mount((props: any) => ()) - .setProps({ items: ['Foo', 'Bar'] }) - .get('.v-select') - .click() - .get('.v-overlay') - .should('exist') - .get('.v-list-item').eq(1).click({ waitForAnimations: false }) - .setProps({ items: ['Foo', 'Bar', 'test', 'test 2'] }) - .get('.v-overlay') - .should('not.exist') - }) - - describe('Showcase', () => { - generate({ stories }) - }) -}) diff --git a/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.cy.tsx b/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.cy.tsx deleted file mode 100644 index 953e9015133..00000000000 --- a/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.cy.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/// - -import { VSelectionControl } from '../VSelectionControl' - -const colors = ['success', 'info', 'warning', 'error', 'invalid'] - -// Actual tests -describe('VSelectionControl', () => { - describe('color', () => { - it('supports default color props', () => { - cy.mount(() => ( - <> - { colors.map(color => ( - - ))} - - )) - .get('div.v-selection-control') - .should('have.length', colors.length) - .then(subjects => { - Array.from(subjects).forEach((subject, i) => { - expect(subject).to.contain(colors[i]) - }) - }) - }) - }) -}) diff --git a/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx b/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx index c42bd239f69..f77d0a70946 100644 --- a/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx +++ b/packages/vuetify/src/components/VSelectionControl/__tests__/VSelectionControl.spec.tsx @@ -3,7 +3,6 @@ import { makeVSelectionControlProps, useSelectionControl } from '../VSelectionCo // Utilities import { mount } from '@vue/test-utils' -import { describe, expect, it, vi } from 'vitest' import { defineComponent, nextTick } from 'vue' import { createVuetify } from '@/framework' diff --git a/packages/vuetify/src/components/VSwitch/__tests__/VSwitch.spec.cy.tsx b/packages/vuetify/src/components/VSwitch/__tests__/VSwitch.spec.browser.tsx similarity index 78% rename from packages/vuetify/src/components/VSwitch/__tests__/VSwitch.spec.cy.tsx rename to packages/vuetify/src/components/VSwitch/__tests__/VSwitch.spec.browser.tsx index 5b9afbf0de8..841559dd246 100644 --- a/packages/vuetify/src/components/VSwitch/__tests__/VSwitch.spec.cy.tsx +++ b/packages/vuetify/src/components/VSwitch/__tests__/VSwitch.spec.browser.tsx @@ -1,7 +1,7 @@ -/// - import { VSwitch } from '../VSwitch' -import { generate, gridOn } from '@/../cypress/templates' + +// Utilities +import { generate, gridOn } from '@test' const contextColor = 'rgb(0, 0, 255)' const color = 'rgb(255, 0, 0)' @@ -20,9 +20,14 @@ const stories = { )), } +const props = { + loading: [true], + inset: [true], + indeterminate: [true], +} describe('VSwitch', () => { describe('Showcase', () => { - generate({ stories, props: {}, component: VSwitch }) + generate({ stories, props, component: VSwitch }) }) }) diff --git a/packages/vuetify/src/components/VSystemBar/__tests__/VSystemBar.spec.cy.tsx b/packages/vuetify/src/components/VSystemBar/__tests__/VSystemBar.spec.cy.tsx deleted file mode 100644 index ae8be15e8dc..00000000000 --- a/packages/vuetify/src/components/VSystemBar/__tests__/VSystemBar.spec.cy.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/// - -// Components -import { VSystemBar } from '..' -import { VLayout } from '@/components/VLayout' - -// Tests -describe('VSystemBar', () => { - it('supports default themes', () => { - cy.mount((props: any) => ( - - Content - - )) - .get('.v-system-bar') - .should('have.class', 'v-theme--light') - .setProps({ theme: 'dark' }) - .get('.v-system-bar') - .should('have.class', 'v-theme--dark') - }) -}) diff --git a/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.browser.tsx b/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.browser.tsx new file mode 100644 index 00000000000..74115bd51c2 --- /dev/null +++ b/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.browser.tsx @@ -0,0 +1,96 @@ +import { VTextField } from '../VTextField' + +// Utilities +import { generate, render, userEvent } from '@test' +import { cloneVNode } from 'vue' + +const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const +const densities = ['default', 'comfortable', 'compact'] as const + +const stories = Object.fromEntries(Object.entries({ + 'Default input': , + Disabled: , + Affixes: , + 'Prepend/append': , + 'Prepend/append inner': , + Placeholder: , +}).map(([k, v]) => [k, ( +
+ { variants.map(variant => ( + densities.map(density => ( +
+ { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } + { cloneVNode(v, { variant, density, label: `with value`, modelValue: 'Value' }) } +
+ )) + )).flat()} +
+)])) + +describe('VTextField', () => { + it('validates input on mount', async () => { + const rule = vi.fn(v => v?.length > 4 || 'Error!') + + const { element } = render(() => ( + + )) + + expect(element).not.toHaveClass('v-input--error') + expect(rule).toHaveBeenCalledOnce() + expect(rule).toHaveBeenCalledWith(undefined) + await userEvent.click(element) + await userEvent.keyboard('Hello') + expect(rule).toHaveBeenCalledTimes(6) + expect(element).not.toHaveClass('v-input--error') + }) + + it('does not validate on mount when using validate-on lazy', async () => { + const rule = vi.fn(v => v?.length > 5 || 'Error!') + + const { element } = render(() => ( + + )) + + expect(element).not.toHaveClass('v-input--error') + expect(rule).not.toHaveBeenCalled() + await userEvent.click(element) + await userEvent.keyboard('Hello') + expect(rule).toHaveBeenCalledTimes(5) + expect(element).toHaveClass('v-input--error') + expect(element).toHaveTextContent('Error!') + }) + + it('handles multiple options in validate-on prop', async () => { + const rule = vi.fn(v => v?.length > 5 || 'Error!') + + const { element } = render(() => ( + + )) + + expect(element).not.toHaveClass('v-input--error') + expect(rule).not.toHaveBeenCalled() + + await userEvent.click(element) + await userEvent.keyboard('Hello') + expect(element).not.toHaveClass('v-input--error') + expect(rule).not.toHaveBeenCalled() + + await userEvent.click(document.body) + expect(rule).toHaveBeenCalledOnce() + expect(element).toHaveClass('v-input--error') + expect(element).toHaveTextContent('Error!') + }) + + // https://github.com/vuetifyjs/vuetify/issues/15231 + it('renders details if using hide-details="auto" and counter prop', async () => { + const { element } = render(() => ( + + )) + await userEvent.click(element) + expect(element).toHaveTextContent('0') + }) + + describe('Showcase', () => { + generate({ stories }) + }) +}) diff --git a/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.cy.tsx b/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.cy.tsx deleted file mode 100644 index 0921161c883..00000000000 --- a/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.cy.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/// - -import { VTextField } from '../VTextField' - -// Utilities -import { cloneVNode } from 'vue' -import { generate } from '../../../../cypress/templates' - -const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const -const densities = ['default', 'comfortable', 'compact'] as const - -const stories = Object.fromEntries(Object.entries({ - 'Default input': , - Disabled: , - Affixes: , - 'Prepend/append': , - 'Prepend/append inner': , - Placeholder: , -}).map(([k, v]) => [k, ( -
- { variants.map(variant => ( - densities.map(density => ( -
- { cloneVNode(v, { variant, density, label: `${variant} ${density}` }) } - { cloneVNode(v, { variant, density, label: `with value`, modelValue: 'Value' }) } -
- )) - )).flat()} -
-)])) - -describe('VTextField', () => { - it('validates input on mount', () => { - const rule = cy.spy(v => v?.length > 4 || 'Error!').as('rule') - - cy.mount(() => ( - - )) - - cy.get('.v-text-field').should('not.have.class', 'v-input--error') - cy.get('@rule').should('have.been.calledOnceWith', undefined) - cy.get('.v-text-field input').type('Hello') - cy.get('@rule').should('to.be.callCount', 6) - cy.get('.v-text-field').should('not.have.class', 'v-input--error') - }) - - it('does not validate on mount when using validate-on lazy', () => { - const rule = cy.spy(v => v?.length > 5 || 'Error!').as('rule') - - cy.mount(() => ( - - )) - - cy.get('.v-text-field').should('not.have.class', 'v-input--error') - cy.get('@rule').should('not.have.been.called') - cy.get('.v-text-field input').type('Hello') - cy.get('@rule').should('to.be.callCount', 5) - cy.get('.v-text-field').should('have.class', 'v-input--error') - cy.get('.v-messages').should('exist').invoke('text').should('equal', 'Error!') - }) - - it('handles multiple options in validate-on prop', () => { - const rule = cy.spy(v => v?.length > 5 || 'Error!').as('rule') - - cy.mount(() => ( - - )) - - cy.get('.v-text-field').should('not.have.class', 'v-input--error') - cy.get('@rule').should('not.have.been.called') - - cy.get('.v-text-field input').type('Hello') - - cy.get('.v-text-field').should('not.have.class', 'v-input--error') - cy.get('@rule').should('not.have.been.called') - - cy.get('.v-text-field input').blur() - - cy.get('@rule').should('have.been.calledOnce') - cy.get('.v-text-field').should('have.class', 'v-input--error') - cy.get('.v-messages').should('exist').invoke('text').should('equal', 'Error!') - }) - - // https://github.com/vuetifyjs/vuetify/issues/15231 - it('renders details if using hide-details="auto" and counter prop', () => { - cy.mount(() => ( - - )) - .get('.v-input__details').should('be.visible') - }) - - describe('Showcase', () => { - generate({ stories }) - }) -}) diff --git a/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx b/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx index 2532399c57e..1eb24c6de53 100644 --- a/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx +++ b/packages/vuetify/src/components/VTextField/__tests__/VTextField.spec.tsx @@ -2,7 +2,6 @@ import { VTextField } from '../VTextField' // Utilities import { mount } from '@vue/test-utils' -import { describe, expect, it, vi } from 'vitest' import { createVuetify } from '@/framework' describe('VTextField', () => { diff --git a/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.tsx b/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.tsx index 4aad3d728e1..e05bde32a5e 100644 --- a/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.tsx +++ b/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.tsx @@ -2,7 +2,6 @@ import { VTextarea } from '../VTextarea' // Utilities import { mount } from '@vue/test-utils' -import { describe, expect, it, vi } from 'vitest' import { createVuetify } from '@/framework' describe('VTextarea', () => { diff --git a/packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.browser.tsx b/packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.browser.tsx new file mode 100644 index 00000000000..f99d914ad36 --- /dev/null +++ b/packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.browser.tsx @@ -0,0 +1,51 @@ +// Components +import { VVirtualScroll } from '../VVirtualScroll' + +// Utilities +import { render, scroll, waitIdle } from '@test' +import { createRange } from '@/util' + +describe('VVirtualScroll', () => { + it('only renders visible items', async () => { + const items = createRange(1000) + + const { container } = render(() => ( + + {{ + default: ({ index }) => ( +
{ index }
+ ), + }} +
+ )) + + const elements = container.querySelectorAll('.v-virtual-scroll__item') + expect(elements.length).toBeGreaterThan(10) + expect(elements.length).toBeLessThan(50) + }) + + it('reuses the same elements', async () => { + const items = createRange(1000) + + const result = render(() => ( + + {{ + default: ({ item, index }) => ( +
{ index }
+ ), + }} +
+ )) + + const root = result.container.querySelector('.v-virtual-scroll')! + + await waitIdle() + const el = await result.findByText(16) + await scroll({ top: 400, behavior: 'smooth' }, root) + expect(await result.findByText(16)).toBe(el) + + await scroll({ top: 800, behavior: 'smooth' }, root) + await scroll({ top: 200, behavior: 'smooth' }, root) + expect(await result.findByText(16)).not.toBe(el) + }) +}) diff --git a/packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.cy.tsx b/packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.cy.tsx deleted file mode 100644 index 4813a8d00b7..00000000000 --- a/packages/vuetify/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.cy.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/// - -// Components -import { VVirtualScroll } from '../VVirtualScroll' - -// Utilities -import { createRange } from '@/util' - -describe('VVirtualScroll', () => { - it('only renders visible items', () => { - const items = createRange(1000) - - cy.mount(() => ( - - {{ - default: ({ item, index }) => ( -
{ index }
- ), - }} -
- )) - - cy.get('.v-virtual-scroll__item').should('have.length.above', 10).should('have.length.below', 50) - }) - - it('reuses the same elements', () => { - const items = createRange(1000) - - cy.mount(() => ( - - {{ - default: ({ item, index }) => ( -
{ index }
- ), - }} -
- )) - - cy.get('.v-virtual-scroll__item').contains('15') - .then($el => { - cy.get('.v-virtual-scroll').scrollTo(0, 320, { duration: 50 }) - cy.get('.v-virtual-scroll__item').contains('15').then($el2 => { - expect($el2[0]).to.equal($el[0]) - }) - }) - }) -}) diff --git a/packages/vuetify/src/composables/__tests__/border.spec.ts b/packages/vuetify/src/composables/__tests__/border.spec.ts index 3886aedc549..abb1c1054bf 100644 --- a/packages/vuetify/src/composables/__tests__/border.spec.ts +++ b/packages/vuetify/src/composables/__tests__/border.spec.ts @@ -3,7 +3,6 @@ import { makeBorderProps, useBorder } from '../border' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' // Types import type { BorderProps } from '../border' diff --git a/packages/vuetify/src/composables/__tests__/calendar.spec.cy.tsx b/packages/vuetify/src/composables/__tests__/calendar.spec.cy.tsx deleted file mode 100644 index 7f3aeb68ff5..00000000000 --- a/packages/vuetify/src/composables/__tests__/calendar.spec.cy.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/// - -// Composables -import { makeCalendarProps, useCalendar } from '@/composables/calendar' -import { useDate } from '@/composables/date' - -// Utilities -import { defineComponent } from 'vue' - -const Component = defineComponent({ - props: makeCalendarProps(), - setup (props) { - const { daysInMonth, displayValue } = useCalendar(props as any) - const date = useDate() - - return () => ( -
-
- { date.format(displayValue.value, 'monthAndYear') } -
- -
- { daysInMonth.value.map((day: any) => ( -
{ day.isoDate }
- ))} -
-
- ) - }, -}) - -describe('calendar.ts', () => { - it('render days based upon displayValue', () => { - cy - .mount(() => ()) - .percySnapshot() - }) -}) diff --git a/packages/vuetify/src/composables/__tests__/calendar.spec.ts b/packages/vuetify/src/composables/__tests__/calendar.spec.ts new file mode 100644 index 00000000000..27c120dbe97 --- /dev/null +++ b/packages/vuetify/src/composables/__tests__/calendar.spec.ts @@ -0,0 +1,73 @@ +// Composables +import { makeCalendarProps, useCalendar } from '@/composables/calendar' +import { useDate } from '@/composables/date' + +// Utilities +import { mount } from '@vue/test-utils' +import { defineComponent } from 'vue' +import { createVuetify } from '@/framework' + +describe('calendar', () => { + it('renders days based upon displayValue', () => { + expect.assertions(2) + mount(defineComponent({ + props: makeCalendarProps(), + setup (props) { + const calendar = useCalendar({ ...props, displayValue: '2021-10-10' } as any) + const date = useDate() + + expect(date.format(calendar.displayValue.value, 'monthAndYear')).toMatchInlineSnapshot(`"October 2021"`) + expect(calendar.daysInMonth.value.map(day => day.isoDate)).toMatchInlineSnapshot(` + [ + "2021-09-26", + "2021-09-27", + "2021-09-28", + "2021-09-29", + "2021-09-30", + "2021-10-01", + "2021-10-02", + "2021-10-03", + "2021-10-04", + "2021-10-05", + "2021-10-06", + "2021-10-07", + "2021-10-08", + "2021-10-09", + "2021-10-10", + "2021-10-11", + "2021-10-12", + "2021-10-13", + "2021-10-14", + "2021-10-15", + "2021-10-16", + "2021-10-17", + "2021-10-18", + "2021-10-19", + "2021-10-20", + "2021-10-21", + "2021-10-22", + "2021-10-23", + "2021-10-24", + "2021-10-25", + "2021-10-26", + "2021-10-27", + "2021-10-28", + "2021-10-29", + "2021-10-30", + "2021-10-31", + "2021-11-01", + "2021-11-02", + "2021-11-03", + "2021-11-04", + "2021-11-05", + "2021-11-06", + ] + `) + + return () => {} + }, + }), { + global: { plugins: [createVuetify()] }, + }) + }) +}) diff --git a/packages/vuetify/src/composables/__tests__/color.spec.ts b/packages/vuetify/src/composables/__tests__/color.spec.ts index a3c8f716e80..cb96018f377 100644 --- a/packages/vuetify/src/composables/__tests__/color.spec.ts +++ b/packages/vuetify/src/composables/__tests__/color.spec.ts @@ -2,7 +2,6 @@ import { useBackgroundColor, useColor, useTextColor } from '../color' // Utilities -import { expect, it } from 'vitest' import { reactive, toRef } from 'vue' describe('color.ts', () => { diff --git a/packages/vuetify/src/composables/__tests__/defaults.spec.ts b/packages/vuetify/src/composables/__tests__/defaults.spec.ts index 6e6dd589a95..4fd099a08a4 100644 --- a/packages/vuetify/src/composables/__tests__/defaults.spec.ts +++ b/packages/vuetify/src/composables/__tests__/defaults.spec.ts @@ -3,7 +3,6 @@ import { VBtn } from '@/components/VBtn' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { createVuetify } from '@/framework' describe('defaults', () => { diff --git a/packages/vuetify/src/composables/__tests__/delay.spec.ts b/packages/vuetify/src/composables/__tests__/delay.spec.ts index 3c4345d58aa..adcd8787ff1 100644 --- a/packages/vuetify/src/composables/__tests__/delay.spec.ts +++ b/packages/vuetify/src/composables/__tests__/delay.spec.ts @@ -3,7 +3,6 @@ import { makeDelayProps, useDelay } from '../delay' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { wait } from '@/../test' describe('delayProps', () => { diff --git a/packages/vuetify/src/composables/__tests__/dimensions.spec.ts b/packages/vuetify/src/composables/__tests__/dimensions.spec.ts index 0ae905575aa..60cbd5a6c45 100644 --- a/packages/vuetify/src/composables/__tests__/dimensions.spec.ts +++ b/packages/vuetify/src/composables/__tests__/dimensions.spec.ts @@ -1,5 +1,4 @@ // Utilities -import { expect, it } from 'vitest' import { useDimension } from '../dimensions' // Types diff --git a/packages/vuetify/src/composables/__tests__/display-components.spec.browser.tsx b/packages/vuetify/src/composables/__tests__/display-components.spec.browser.tsx new file mode 100644 index 00000000000..cea846c10f9 --- /dev/null +++ b/packages/vuetify/src/composables/__tests__/display-components.spec.browser.tsx @@ -0,0 +1,49 @@ +/* eslint-disable max-len */ + +// Components +import { VBanner } from '@/components/VBanner/VBanner' +import { VLayout } from '@/components/VLayout/VLayout' +import { VMain } from '@/components/VMain' +import { VNavigationDrawer } from '@/components/VNavigationDrawer/VNavigationDrawer' +import { VSlideGroup } from '@/components/VSlideGroup/VSlideGroup' + +// Utilities +import { render } from '@test' +import { page } from '@vitest/browser/context' +import { ref } from 'vue' + +// Types +import type { DisplayBreakpoint } from '@/composables' + +describe('display-components', () => { + it('should render items', async () => { + await page.viewport(960, 800) + + const mobileBreakpoint = ref('lg') + const { container } = render(() => ( + + + + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta quaerat fugit ratione totam magnam, beatae consequuntur qui quam enim et sapiente autem accusantium id nesciunt maiores obcaecati minus molestiae! Ipsa. + + + + + )) + + const navigationDrawer = container.querySelector('.v-navigation-drawer') + const banner = container.querySelector('.v-banner') + const slideGroup = container.querySelector('.v-slide-group') + + expect(navigationDrawer).toHaveClass('v-navigation-drawer--mobile') + expect(banner).toHaveClass('v-banner--mobile') + expect(slideGroup).toHaveClass('v-slide-group--mobile') + + mobileBreakpoint.value = 959 + + await expect.poll(() => navigationDrawer).not.toHaveClass('v-navigation-drawer--mobile') + await expect.poll(() => banner).not.toHaveClass('v-banner--mobile') + await expect.poll(() => slideGroup).not.toHaveClass('v-slide-group--mobile') + }) +}) diff --git a/packages/vuetify/src/composables/__tests__/display.spec.ts b/packages/vuetify/src/composables/__tests__/display.spec.browser.ts similarity index 91% rename from packages/vuetify/src/composables/__tests__/display.spec.ts rename to packages/vuetify/src/composables/__tests__/display.spec.browser.ts index 0074283bafd..5dbc704668e 100644 --- a/packages/vuetify/src/composables/__tests__/display.spec.ts +++ b/packages/vuetify/src/composables/__tests__/display.spec.browser.ts @@ -2,8 +2,7 @@ import { createDisplay } from '../display' // Utilities -import { expect, it } from 'vitest' -import { resizeWindow } from '@/../test' +import { page } from '@vitest/browser/context' const breakpoints = [ 'xs', @@ -261,7 +260,7 @@ describe('display', () => { ], ], ])('should calculate breakpoint for $description', async (options, expected) => { - await resizeWindow(options.width, options.height) + await page.viewport(options.width, options.height) const display = createDisplay() @@ -278,20 +277,20 @@ describe('display', () => { thresholds: { sm: 400 }, }) - await resizeWindow(400) - expect(name.value).toBe('sm') + await page.viewport(400, 900) + await expect.poll(() => name.value).toBe('sm') - await resizeWindow(399) - expect(name.value).toBe('xs') + await page.viewport(399, 900) + await expect.poll(() => name.value).toBe('xs') }) it('should allow breakpoint strings for mobileBreakpoint', async () => { const { mobile } = createDisplay({ mobileBreakpoint: 'lg' }) - await resizeWindow(1920) - expect(mobile.value).toBe(false) + await page.viewport(1920, 900) + await expect.poll(() => mobile.value).toBe(false) - await resizeWindow(600) - expect(mobile.value).toBe(true) + await page.viewport(600, 900) + await expect.poll(() => mobile.value).toBe(true) }) }) diff --git a/packages/vuetify/src/composables/__tests__/display.spec.cy.tsx b/packages/vuetify/src/composables/__tests__/display.spec.cy.tsx deleted file mode 100644 index 09fd49ff1dd..00000000000 --- a/packages/vuetify/src/composables/__tests__/display.spec.cy.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* eslint-disable max-len */ -/// - -// Components -import { VBanner } from '@/components/VBanner/VBanner' -import { VLayout } from '@/components/VLayout/VLayout' -import { VMain } from '@/components/VMain' -import { VNavigationDrawer } from '@/components/VNavigationDrawer/VNavigationDrawer' -import { VSlideGroup } from '@/components/VSlideGroup/VSlideGroup' - -describe('VWindow', () => { - it('should render items', () => { - cy.viewport(960, 800) - .mount(({ mobileBreakpoint }: any) => ( - - - - - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta quaerat fugit ratione totam magnam, beatae consequuntur qui quam enim et sapiente autem accusantium id nesciunt maiores obcaecati minus molestiae! Ipsa. - - - - - - )) - - cy - .setProps({ mobileBreakpoint: 'lg' }) - .get('.v-navigation-drawer').should('have.class', 'v-navigation-drawer--mobile') - .get('.v-banner').should('have.class', 'v-banner--mobile') - .get('.v-slide-group').should('have.class', 'v-slide-group--mobile') - .setProps({ mobileBreakpoint: 959 }) - .get('.v-navigation-drawer').should('not.have.class', 'v-navigation-drawer--mobile') - .get('.v-banner').should('not.have.class', 'v-banner--mobile') - .get('.v-slide-group').should('not.have.class', 'v-slide-group--mobile') - }) -}) diff --git a/packages/vuetify/src/composables/__tests__/elevation.spec.ts b/packages/vuetify/src/composables/__tests__/elevation.spec.ts index d88dd91f796..a92b4f1bcbc 100644 --- a/packages/vuetify/src/composables/__tests__/elevation.spec.ts +++ b/packages/vuetify/src/composables/__tests__/elevation.spec.ts @@ -2,7 +2,6 @@ import { makeElevationProps, useElevation } from '../elevation' // Utilities -import { expect, it } from 'vitest' // Utilities diff --git a/packages/vuetify/src/composables/__tests__/filter.spec.ts b/packages/vuetify/src/composables/__tests__/filter.spec.ts index 2c6d1bdc8fd..751fd2e52b7 100644 --- a/packages/vuetify/src/composables/__tests__/filter.spec.ts +++ b/packages/vuetify/src/composables/__tests__/filter.spec.ts @@ -3,7 +3,6 @@ import { defaultFilter, filterItems, useFilter } from '../filter' import { transformItem, transformItems } from '../list-items' // Utilities -import { expect, it } from 'vitest' import { nextTick, ref } from 'vue' import { deepEqual } from '@/util' diff --git a/packages/vuetify/src/composables/__tests__/forwardRefs.spec.tsx b/packages/vuetify/src/composables/__tests__/forwardRefs.spec.tsx index d35dfb04fd8..ed6f24b853b 100644 --- a/packages/vuetify/src/composables/__tests__/forwardRefs.spec.tsx +++ b/packages/vuetify/src/composables/__tests__/forwardRefs.spec.tsx @@ -3,7 +3,6 @@ import { forwardRefs } from '@/composables/forwardRefs' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { defineComponent, ref } from 'vue' import { useRender } from '@/util' diff --git a/packages/vuetify/src/composables/__tests__/goto.spec.browser.tsx b/packages/vuetify/src/composables/__tests__/goto.spec.browser.tsx new file mode 100644 index 00000000000..9d18526a152 --- /dev/null +++ b/packages/vuetify/src/composables/__tests__/goto.spec.browser.tsx @@ -0,0 +1,82 @@ +// Utilities +import { render } from '@test' +import { userEvent } from '@testing-library/user-event' +import { defineComponent } from 'vue' +import { useGoTo } from '../goto' + +const ComponentA = defineComponent({ + props: { + target: String, + }, + + setup (props) { + const goTo = useGoTo() + + function onClick () { + return goTo(props.target!) + } + + return () => ( + + ) + }, +}) + +const ComponentB = defineComponent({ + props: { + target: String, + container: String, + }, + + setup (props) { + const goTo = useGoTo() + + function onClick () { + return goTo.horizontal(props.target!, { container: props.container }) + } + + return () => ( + + ) + }, +}) + +describe('goto', () => { + it('scrolls vertically', async () => { + const { container } = render(() => ( +
+ +
+ +
+ )) + + const top = container.querySelector('#top')! + const bottom = container.querySelector('#bottom')! + + await userEvent.click(top) + await expect.poll(() => window.scrollY).toBeCloseTo(1250, -1) + + await userEvent.click(bottom) + await expect.poll(() => window.scrollY).toBe(0) + }) + + it('scrolls horizontally', async () => { + const { container } = render(() => ( +
+ + + +
+ )) + + const start = container.querySelector('#start')! + const end = container.querySelector('#end')! + + await userEvent.click(start) + await expect.poll(() => window.scrollX).toBeCloseTo(755, -1) + + await userEvent.click(end) + await expect.poll(() => window.scrollX).toBe(0) + }) +}) diff --git a/packages/vuetify/src/composables/__tests__/goto.spec.cy.tsx b/packages/vuetify/src/composables/__tests__/goto.spec.cy.tsx deleted file mode 100644 index fa9acc19be3..00000000000 --- a/packages/vuetify/src/composables/__tests__/goto.spec.cy.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* eslint-disable cypress/no-unnecessary-waiting */ -/// - -// Utilities -import { defineComponent } from 'vue' -import { useGoTo } from '../goto' -import { useRender } from '@/util' - -const ComponentA = defineComponent({ - props: { - id: String, - target: String, - }, - - setup (props) { - const goTo = useGoTo() - - function onClick () { - return goTo(props.target!) - } - - useRender(() => ( - - )) - - return {} - }, -}) - -const ComponentB = defineComponent({ - props: { - id: String, - target: String, - container: String, - }, - - setup (props) { - const goTo = useGoTo() - - function onClick () { - return goTo.horizontal(props.target!, { container: props.container }) - } - - useRender(() => ( - - )) - - return {} - }, -}) - -describe('goto', () => { - it('scrolls vertically', () => { - cy - .mount(() => ( -
- - -
- - -
- )) - .get('#top').click() - .window().should(win => { - expect(Math.ceil(win.scrollY)).to.equal(1223) - }) - .get('#bottom').click() - .window().should(win => { - expect(win.scrollY).to.equal(0) - }) - }) - - it('scrolls horizontally', () => { - cy.viewport(1075, 825) - cy - .mount(() => ( -
- - - -
- )) - .get('#start').click().wait(500) - .get('#end').should('be.visible') - .get('#end').click().wait(500) - .get('#start').should('be.visible') - }) -}) diff --git a/packages/vuetify/src/composables/__tests__/group.spec.ts b/packages/vuetify/src/composables/__tests__/group.spec.ts index d29f00f3440..2bcd25c2f86 100644 --- a/packages/vuetify/src/composables/__tests__/group.spec.ts +++ b/packages/vuetify/src/composables/__tests__/group.spec.ts @@ -1,6 +1,5 @@ // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { defineComponent, h, nextTick, reactive, useSlots } from 'vue' import { makeGroupProps, useGroup, useGroupItem } from '../group' diff --git a/packages/vuetify/src/composables/__tests__/icons.spec.ts b/packages/vuetify/src/composables/__tests__/icons.spec.ts index 83782a8e3a0..ab3f6e31dfd 100644 --- a/packages/vuetify/src/composables/__tests__/icons.spec.ts +++ b/packages/vuetify/src/composables/__tests__/icons.spec.ts @@ -3,7 +3,6 @@ import { useIcon } from '../icons' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { defineComponent, toRef } from 'vue' import { createVuetify } from '@/framework' diff --git a/packages/vuetify/src/composables/__tests__/items.spec.ts b/packages/vuetify/src/composables/__tests__/items.spec.ts index c40310ac970..574aa7036f5 100644 --- a/packages/vuetify/src/composables/__tests__/items.spec.ts +++ b/packages/vuetify/src/composables/__tests__/items.spec.ts @@ -2,7 +2,6 @@ import { useItems } from '../list-items' // Utilities -import { expect, it } from 'vitest' import { deepEqual } from '@/util' describe('items', () => { diff --git a/packages/vuetify/src/composables/__tests__/loader.spec.ts b/packages/vuetify/src/composables/__tests__/loader.spec.ts index 12979360c32..e767400fcd0 100644 --- a/packages/vuetify/src/composables/__tests__/loader.spec.ts +++ b/packages/vuetify/src/composables/__tests__/loader.spec.ts @@ -1,5 +1,4 @@ // Utilities -import { expect, it } from 'vitest' import { useLoader } from '../loader' describe('size', () => { diff --git a/packages/vuetify/src/composables/__tests__/location.spec.ts b/packages/vuetify/src/composables/__tests__/location.spec.ts index 76d2cc37542..da71cdf95c1 100644 --- a/packages/vuetify/src/composables/__tests__/location.spec.ts +++ b/packages/vuetify/src/composables/__tests__/location.spec.ts @@ -3,7 +3,6 @@ import { useLocation } from '../location' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' // Types import { createVuetify } from '@/framework' diff --git a/packages/vuetify/src/composables/__tests__/mutationObserver.spec.ts b/packages/vuetify/src/composables/__tests__/mutationObserver.spec.ts index 047db35937d..61ea8eef1d2 100644 --- a/packages/vuetify/src/composables/__tests__/mutationObserver.spec.ts +++ b/packages/vuetify/src/composables/__tests__/mutationObserver.spec.ts @@ -3,7 +3,6 @@ import { useMutationObserver } from '../mutationObserver' // Utilities import { mount } from '@vue/test-utils' -import { expect } from 'vitest' import { h } from 'vue' describe('mutationObserver', () => { diff --git a/packages/vuetify/src/composables/__tests__/position.spec.ts b/packages/vuetify/src/composables/__tests__/position.spec.ts index 172c4eaf428..1fa276ee307 100644 --- a/packages/vuetify/src/composables/__tests__/position.spec.ts +++ b/packages/vuetify/src/composables/__tests__/position.spec.ts @@ -2,7 +2,6 @@ import { usePosition } from '../position' // Utilities -import { expect, it } from 'vitest' // Types import type { PositionProps } from '../position' diff --git a/packages/vuetify/src/composables/__tests__/proxiedModel.spec.ts b/packages/vuetify/src/composables/__tests__/proxiedModel.spec.ts index 5e81fefb28a..d1c4f73b9dc 100644 --- a/packages/vuetify/src/composables/__tests__/proxiedModel.spec.ts +++ b/packages/vuetify/src/composables/__tests__/proxiedModel.spec.ts @@ -3,7 +3,6 @@ import { useProxiedModel } from '../proxiedModel' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { defineComponent, h } from 'vue' const TestComponent = defineComponent({ diff --git a/packages/vuetify/src/composables/__tests__/resizeObserver.spec.browser.tsx b/packages/vuetify/src/composables/__tests__/resizeObserver.spec.browser.tsx new file mode 100644 index 00000000000..0f04bdc6949 --- /dev/null +++ b/packages/vuetify/src/composables/__tests__/resizeObserver.spec.browser.tsx @@ -0,0 +1,25 @@ +// Composables +import { useResizeObserver } from '../resizeObserver' + +// Utilities +import { waitIdle } from '@test' +import { render, screen } from '@testing-library/vue' + +describe('resizeObserver', () => { + it('calls the callback after mount', async () => { + const callback = vi.fn() + render({ + setup () { + const { resizeRef } = useResizeObserver(callback) + + return () =>
foo
+ }, + }) + + expect(screen.getByText('foo')).toBeInTheDocument() + + await waitIdle() + + expect(callback).toHaveBeenCalledTimes(1) + }) +}) diff --git a/packages/vuetify/src/composables/__tests__/resizeObserver.spec.ts b/packages/vuetify/src/composables/__tests__/resizeObserver.spec.ts deleted file mode 100644 index f9a34a7fc0f..00000000000 --- a/packages/vuetify/src/composables/__tests__/resizeObserver.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Composables -import { useResizeObserver } from '../resizeObserver' - -// Utilities -import { mount } from '@vue/test-utils' -import { expect } from 'vitest' -import { h, nextTick } from 'vue' - -describe('resizeObserver', () => { - it('should make sure mock exists', async () => { - const callback = vi.fn() - mount({ - setup () { - const { resizeRef } = useResizeObserver(callback) - - return () => h('div', { ref: resizeRef }, ['foo']) - }, - }) - - await nextTick() - - expect(callback).toHaveBeenCalled() - }) -}) diff --git a/packages/vuetify/src/composables/__tests__/rounded.spec.ts b/packages/vuetify/src/composables/__tests__/rounded.spec.ts index 1c907ebc0ad..ff5514456e7 100644 --- a/packages/vuetify/src/composables/__tests__/rounded.spec.ts +++ b/packages/vuetify/src/composables/__tests__/rounded.spec.ts @@ -3,7 +3,6 @@ import { makeRoundedProps, useRounded } from '../rounded' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' // Types import type { RoundedProps } from '../rounded' diff --git a/packages/vuetify/src/composables/__tests__/scroll.spec.browser.tsx b/packages/vuetify/src/composables/__tests__/scroll.spec.browser.tsx new file mode 100644 index 00000000000..8dc55e36ffc --- /dev/null +++ b/packages/vuetify/src/composables/__tests__/scroll.spec.browser.tsx @@ -0,0 +1,98 @@ +// Composables +import { makeScrollProps, useScroll } from '../scroll' + +// Utilities +import { render, scroll, wait } from '@test' +import { defineComponent, reactive } from 'vue' + +// Types +import type { UnwrapNestedRefs } from 'vue' +import type { ScrollProps } from '../scroll' + +describe('useScroll', () => { + function setup (props?: Partial) { + let data!: UnwrapNestedRefs> + render(defineComponent({ + props: makeScrollProps(), + setup (props) { + data = reactive(useScroll(props)) + return () =>
+ }, + }), { props }) + return { data } + } + + it('should set isScrollingUp', async () => { + const { data } = setup() + + await scroll({ top: 1000 }) + expect(data.isScrollingUp).toBe(false) + + await scroll({ top: 0 }) + expect(data.isScrollingUp).toBe(true) + }) + + // it.skip('should use a custom target', async () => { + // const thresholdMetCallback = vi.fn() + // mountFunction({}, { + // props: { scrollTarget: 'body', scrollThreshold: 300 }, + // }) + // + // await wait() + // expect(thresholdMetCallback).not.toHaveBeenCalled() + // + // await scroll({ top: 1000 }, document.body) + // await expect.poll(() => thresholdMetCallback).toHaveBeenCalled() + // }) + // + // it.skip('should do nothing if !canScroll', async () => { + // const thresholdMetCallback = vi.fn() + // mountFunction({ + // canScroll: ref(false), + // }, { + // props: { scrollTarget: 'body', scrollThreshold: 300 }, + // }) + // + // await wait() + // expect(thresholdMetCallback).not.toHaveBeenCalled() + // + // await scroll({ top: 1000 }, document.body) + // await expect.poll(() => thresholdMetCallback).not.toHaveBeenCalled() + // }) + // + // it.skip('should do something if canScroll', async () => { + // const thresholdMetCallback = vi.fn() + // mountFunction({ + // canScroll: ref(true), + // }, { + // props: { scrollTarget: 'body', scrollThreshold: 300 }, + // }) + // + // await wait() + // expect(thresholdMetCallback).not.toHaveBeenCalled() + // + // await scroll({ top: 1000 }, document.body) + // await expect.poll(() => thresholdMetCallback).toHaveBeenCalled() + // }) + + it('should reset savedScroll when isActive state changes', async () => { + const { data } = setup() + + await scroll({ top: 1000 }) + expect(data.savedScroll).toBe(0) + + await scroll({ top: 900 }) + expect(data.savedScroll).toBe(900) + + data.isScrollActive = true + await wait() + expect(data.savedScroll).toBe(0) + }) + + it(`should warn if target isn't present`, async () => { + setup({ scrollTarget: '#test' }) + + await wait() + expect('Unable to locate element with identifier #test').toHaveBeenTipped() + }) +}) diff --git a/packages/vuetify/src/composables/__tests__/scroll.spec.ts b/packages/vuetify/src/composables/__tests__/scroll.spec.ts deleted file mode 100644 index f35ced8eff6..00000000000 --- a/packages/vuetify/src/composables/__tests__/scroll.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -// Composables -import { makeScrollProps, useScroll } from '../scroll' - -// Utilities -import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' -import { defineComponent, ref } from 'vue' - -// Types -import type { ScrollArguments } from '../scroll' - -// Utils -import { - scrollElement, - scrollWindow, - wait, -} from '@/../test' - -describe('scrollProps', () => { - it('should allow setting default values', () => { - const wrapper = mount({ - template: '
', - props: makeScrollProps({ - scrollTarget: 'foo', - scrollThreshold: 500, - }), - }) - - expect(wrapper.props()).toStrictEqual({ - scrollTarget: 'foo', - scrollThreshold: 500, - }) - }) -}) - -describe('useScroll', () => { - function mountFunction (args?: ScrollArguments, options?: any) { - return mount(defineComponent({ - props: makeScrollProps(), - setup (props) { - return useScroll(props, args) - }, - template: '
', - }), options) - } - - beforeEach(() => { - (window as any).pageYOffset = 0 - document.body.scrollTop = 0 - }) - - it('should set isScrollingUp', async () => { - const { vm } = mountFunction() - - await scrollWindow(1000) - expect(vm.isScrollingUp).toBe(false) - - await scrollWindow(0) - expect(vm.isScrollingUp).toBe(true) - }) - - it.skip('should use a custom target', async () => { - const thresholdMetCallback = vi.fn() - mountFunction({}, { - props: { scrollTarget: 'body', scrollThreshold: 300 }, - }) - - await wait() - expect(thresholdMetCallback).not.toHaveBeenCalled() - - await scrollElement(document.body, 1000) - expect(thresholdMetCallback).toHaveBeenCalled() - }) - - it.skip('should do nothing if !canScroll', async () => { - const thresholdMetCallback = vi.fn() - mountFunction({ - canScroll: ref(false), - }, { - props: { scrollTarget: 'body', scrollThreshold: 300 }, - }) - - await wait() - expect(thresholdMetCallback).not.toHaveBeenCalled() - - await scrollElement(document.body, 1000) - expect(thresholdMetCallback).not.toHaveBeenCalled() - }) - - it.skip('should do something if canScroll', async () => { - const thresholdMetCallback = vi.fn() - mountFunction({ - canScroll: ref(true), - }, { - props: { scrollTarget: 'body', scrollThreshold: 300 }, - }) - - await wait() - expect(thresholdMetCallback).not.toHaveBeenCalled() - - await scrollElement(document.body, 1000) - expect(thresholdMetCallback).toHaveBeenCalled() - }) - - it('should reset savedScroll when isActive state changes', async () => { - const { vm } = mountFunction() - - await scrollWindow(1000) - expect(vm.savedScroll).toBe(0) - - await scrollWindow(900) - expect(vm.savedScroll).toBe(900) - - vm.isScrollActive = true - await wait() - expect(vm.savedScroll).toBe(0) - }) - - it(`should warn if target isn't present`, async () => { - mountFunction(undefined, { props: { scrollTarget: '#test' } }) - - await wait() - expect('Unable to locate element with identifier #test').toHaveBeenTipped() - }) -}) diff --git a/packages/vuetify/src/composables/__tests__/size.spec.ts b/packages/vuetify/src/composables/__tests__/size.spec.ts index 4bcf5d32165..ca3416967f6 100644 --- a/packages/vuetify/src/composables/__tests__/size.spec.ts +++ b/packages/vuetify/src/composables/__tests__/size.spec.ts @@ -2,7 +2,6 @@ import { useSize } from '../size' // Utilities -import { expect, it } from 'vitest' // Utilities diff --git a/packages/vuetify/src/composables/__tests__/tag.spec.ts b/packages/vuetify/src/composables/__tests__/tag.spec.ts index 0ff5218e438..428d2d5b8cb 100644 --- a/packages/vuetify/src/composables/__tests__/tag.spec.ts +++ b/packages/vuetify/src/composables/__tests__/tag.spec.ts @@ -3,7 +3,6 @@ import { makeTagProps } from '../tag' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { h } from 'vue' // Types diff --git a/packages/vuetify/src/composables/__tests__/theme.spec.ts b/packages/vuetify/src/composables/__tests__/theme.spec.ts index f7b220b02e9..e959e1c6369 100644 --- a/packages/vuetify/src/composables/__tests__/theme.spec.ts +++ b/packages/vuetify/src/composables/__tests__/theme.spec.ts @@ -1,10 +1,9 @@ -/* eslint-disable jest/no-commented-out-tests */ +/* eslint-disable vitest/no-commented-out-tests */ // Composables import { createTheme } from '../theme' // Utilities -import { expect, it } from 'vitest' import { createApp } from 'vue' // Types diff --git a/packages/vuetify/src/composables/__tests__/validation.spec.ts b/packages/vuetify/src/composables/__tests__/validation.spec.ts index c8511c6d6ab..82838f56c56 100644 --- a/packages/vuetify/src/composables/__tests__/validation.spec.ts +++ b/packages/vuetify/src/composables/__tests__/validation.spec.ts @@ -3,7 +3,6 @@ import { makeValidationProps, useValidation } from '../validation' // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { defineComponent, nextTick } from 'vue' // Types diff --git a/packages/vuetify/src/composables/__tests__/variant.spec.ts b/packages/vuetify/src/composables/__tests__/variant.spec.ts index 3041c388328..e17dca8f0f0 100644 --- a/packages/vuetify/src/composables/__tests__/variant.spec.ts +++ b/packages/vuetify/src/composables/__tests__/variant.spec.ts @@ -2,7 +2,6 @@ import { allowedVariants, makeVariantProps, useVariant } from '../variant' // Utilities -import { expect, it } from 'vitest' // Utilities diff --git a/packages/vuetify/src/composables/date/__tests__/date.spec.ts b/packages/vuetify/src/composables/date/__tests__/date.spec.ts index e2cafa2daf8..510c96147b4 100644 --- a/packages/vuetify/src/composables/date/__tests__/date.spec.ts +++ b/packages/vuetify/src/composables/date/__tests__/date.spec.ts @@ -2,7 +2,6 @@ import { getWeek } from '../date' // Utilities -import { expect, it } from 'vitest' import { VuetifyDateAdapter } from '../adapters/vuetify' // Types diff --git a/packages/vuetify/src/composables/date/adapters/__tests__/vuetify.spec.ts b/packages/vuetify/src/composables/date/adapters/__tests__/vuetify.spec.ts index 632ac4fcab0..d13e74852c2 100644 --- a/packages/vuetify/src/composables/date/adapters/__tests__/vuetify.spec.ts +++ b/packages/vuetify/src/composables/date/adapters/__tests__/vuetify.spec.ts @@ -1,6 +1,5 @@ // Utilities import timezoneMock from 'timezone-mock' -import { expect, it } from 'vitest' import { VuetifyDateAdapter } from '../vuetify' // Types diff --git a/packages/vuetify/src/composables/nested/__tests__/selectStrategies.spec.ts b/packages/vuetify/src/composables/nested/__tests__/selectStrategies.spec.ts index 307a5560bef..8328f6b95af 100644 --- a/packages/vuetify/src/composables/nested/__tests__/selectStrategies.spec.ts +++ b/packages/vuetify/src/composables/nested/__tests__/selectStrategies.spec.ts @@ -1,7 +1,6 @@ /* eslint-disable max-len */ /* eslint-disable sonarjs/no-identical-functions */ // Utilities -import { expect, it } from 'vitest' import { classicSelectStrategy, independentSelectStrategy, independentSingleSelectStrategy, leafSelectStrategy, leafSingleSelectStrategy } from '../selectStrategies' describe('selectStrategies', () => { diff --git a/packages/vuetify/src/directives/click-outside/__tests__/click-outside-shadow-dom.spec.ts b/packages/vuetify/src/directives/click-outside/__tests__/click-outside-shadow-dom.spec.ts index 1c7192f1bce..26f6a796843 100644 --- a/packages/vuetify/src/directives/click-outside/__tests__/click-outside-shadow-dom.spec.ts +++ b/packages/vuetify/src/directives/click-outside/__tests__/click-outside-shadow-dom.spec.ts @@ -2,7 +2,6 @@ import ClickOutside from '../' // Utilities -import { describe, expect, it, vi } from 'vitest' import { wait } from '@/../test' function bootstrap (args?: object) { diff --git a/packages/vuetify/src/directives/click-outside/__tests__/click-outside.spec.ts b/packages/vuetify/src/directives/click-outside/__tests__/click-outside.spec.ts index b9e47168890..f86e4fdea3b 100644 --- a/packages/vuetify/src/directives/click-outside/__tests__/click-outside.spec.ts +++ b/packages/vuetify/src/directives/click-outside/__tests__/click-outside.spec.ts @@ -2,7 +2,6 @@ import ClickOutside from '../' // Utilities -import { expect } from 'vitest' import { wait } from '@/../test' function bootstrap (args?: object) { diff --git a/packages/vuetify/src/directives/intersect/__tests__/intersect.spec.browser.tsx b/packages/vuetify/src/directives/intersect/__tests__/intersect.spec.browser.tsx new file mode 100644 index 00000000000..d3997460d04 --- /dev/null +++ b/packages/vuetify/src/directives/intersect/__tests__/intersect.spec.browser.tsx @@ -0,0 +1,92 @@ +// Directives +import Intersect from '../' + +// Utilities +import { scroll, waitIdle } from '@test' +import { render, screen } from '@testing-library/vue' + +describe('v-intersect', () => { + it('binds event on mounted', async () => { + const callback = vi.fn() + + render({ + directives: { Intersect }, + setup () { + return () =>
+ }, + }) + + await waitIdle() + + expect(callback).toHaveBeenCalled() + }) + + // TODO: flaky, sometimes triggers with isIntersecting=false + it.skip('does not callback on mount when quiet', async () => { + const callback = vi.fn() + + render({ + directives: { Intersect }, + setup () { + return () =>
+ }, + }) + + await waitIdle() + + expect(callback).not.toHaveBeenCalled() + }) + + describe('once', () => { + async function setup (height: string, quiet: boolean) { + const callback = vi.fn() + + render({ + directives: { Intersect }, + setup () { + return () => ( + <> +
+ { quiet // directive modifiers are static + ?
el
+ :
el
+ } +
+ + ) + }, + }) + + const el = screen.getByText('el') + expect(Object.keys(el._observe!)).toHaveLength(1) + + await waitIdle() + return { callback, el } + } + + it.each([ + ['initially in', '100px', false, 1, 0, 1], + ['initially out', '120vh', false, 0, 1, 1], + // ['initially in - quiet', '100px', true, 0, 1, 1], // TODO: flaky + // ['initially out - quiet', '120vh', true, 0, 1, 1], + ])('%s', async (name, height, quiet, ...v) => { + const { callback, el } = await setup(height, quiet) + + expect(callback).toHaveBeenCalledTimes(v[0]) + expect(Object.keys(el._observe!)).toHaveLength(v[1]) + + el.scrollIntoView() + await waitIdle() + expect(callback).toHaveBeenCalledTimes(v[2]) + expect(Object.keys(el._observe!)).toHaveLength(0) + callback.mockClear() + + await scroll({ top: 1000 }) + expect(callback).not.toHaveBeenCalled() + + el.scrollIntoView() + await waitIdle() + expect(callback).not.toHaveBeenCalled() + }) + }) +}) diff --git a/packages/vuetify/src/directives/intersect/__tests__/intersect.spec.ts b/packages/vuetify/src/directives/intersect/__tests__/intersect.spec.ts deleted file mode 100644 index b7bbd0cd1de..00000000000 --- a/packages/vuetify/src/directives/intersect/__tests__/intersect.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Directives -import Intersect from '../' - -// Utilities -import { expect } from 'vitest' - -describe('v-intersect', () => { - it('should bind event on mounted', () => { - const callback = vi.fn() - const el = document.createElement('div') - document.body.appendChild(el) - - Intersect.mounted(el, { - value: callback, - modifiers: { quiet: true }, - instance: { - $: { uid: 1 }, - }, - } as any) - - expect((el as any)._observe).toBeTruthy() - expect(callback).not.toHaveBeenCalled() - - document.body.removeChild(el) - - Intersect.unmounted(el, { - instance: { - $: { uid: 1 }, - }, - } as any) - - expect((el as any)._observe[1]).toBeUndefined() - }) - - it('should invoke callback once and unmount', () => { - const el = document.createElement('div') - document.body.appendChild(el) - - const callback = vi.fn() - - Intersect.mounted(el, { - value: callback, - modifiers: { once: true }, - instance: { - $: { uid: 1 }, - }, - } as any) - - expect(callback).toHaveBeenCalledTimes(0) - expect((el as any)._observe[1]).toBeTruthy() - - ;(el as any)._observe[1].observer.callback([{ isIntersecting: false }]) - - expect(callback).toHaveBeenCalledTimes(1) - expect((el as any)._observe[1]).toBeTruthy() - - ;(el as any)._observe[1].observer.callback([{ isIntersecting: true }]) - - expect(callback).toHaveBeenCalledTimes(2) - expect((el as any)._observe[1]).toBeUndefined() - }) -}) diff --git a/packages/vuetify/src/directives/mutate/__tests__/mutate.spec.ts b/packages/vuetify/src/directives/mutate/__tests__/mutate.spec.ts index b95b9c4e4ad..e6bad869796 100644 --- a/packages/vuetify/src/directives/mutate/__tests__/mutate.spec.ts +++ b/packages/vuetify/src/directives/mutate/__tests__/mutate.spec.ts @@ -2,7 +2,6 @@ import Mutate from '..' // Utilities -import { expect, it } from 'vitest' // Utilities diff --git a/packages/vuetify/src/directives/resize/__tests__/resize.spec.ts b/packages/vuetify/src/directives/resize/__tests__/resize.spec.ts index 2b0b9845611..f085bbcedb1 100644 --- a/packages/vuetify/src/directives/resize/__tests__/resize.spec.ts +++ b/packages/vuetify/src/directives/resize/__tests__/resize.spec.ts @@ -2,7 +2,6 @@ import Resize from '../' // Utilities -import { expect, it } from 'vitest' // Types import type { Mock } from 'vitest' diff --git a/packages/vuetify/src/directives/ripple/__tests__/ripple.spec.ts b/packages/vuetify/src/directives/ripple/__tests__/ripple.spec.ts index 090bec38857..44aca60550b 100644 --- a/packages/vuetify/src/directives/ripple/__tests__/ripple.spec.ts +++ b/packages/vuetify/src/directives/ripple/__tests__/ripple.spec.ts @@ -3,7 +3,6 @@ import Ripple from '../' // Utilities import { mount } from '@vue/test-utils' -import { describe, expect, it, vi } from 'vitest' import { defineComponent } from 'vue' import { keyCodes } from '@/util' diff --git a/packages/vuetify/src/directives/ripple/index.ts b/packages/vuetify/src/directives/ripple/index.ts index 2f4a83a7b67..bd3b51db1e2 100644 --- a/packages/vuetify/src/directives/ripple/index.ts +++ b/packages/vuetify/src/directives/ripple/index.ts @@ -5,9 +5,7 @@ import './VRipple.sass' import { isObject, keyCodes } from '@/util' // Types -import type { - DirectiveBinding, -} from 'vue' +import type { DirectiveBinding } from 'vue' const stopSymbol = Symbol('rippleStop') diff --git a/packages/vuetify/src/directives/scroll/__tests__/scroll.spec.browser.tsx b/packages/vuetify/src/directives/scroll/__tests__/scroll.spec.browser.tsx new file mode 100644 index 00000000000..7730239d1e4 --- /dev/null +++ b/packages/vuetify/src/directives/scroll/__tests__/scroll.spec.browser.tsx @@ -0,0 +1,49 @@ +// Directives +import Scroll from '../' + +// Utilities +import { render, scroll } from '@test' +import { defineComponent } from 'vue' + +describe('v-scroll', () => { + function setup (selector = '') { + const callback = vi.fn() + const result = render(defineComponent({ + directives: { Scroll }, + setup () { + return () => ( +
+
el
+
+ ) + }, + })) + + const el = result.getByText('el') + const root = result.getByTestId('root') + + return { callback, result, el, root } + } + + it('listens to scroll on window', async () => { + const { callback, root } = setup() + + await scroll({ top: 100 }) + expect(callback).toHaveBeenCalled() + + callback.mockClear() + await scroll({ top: 100 }, root) + expect(callback).not.toHaveBeenCalled() + }) + + it('listens to scroll on selector', async () => { + const { callback, root } = setup('[data-testid="root"]') + + await scroll({ top: 100 }, root) + expect(callback).toHaveBeenCalled() + + callback.mockClear() + await scroll({ top: 100 }) + expect(callback).not.toHaveBeenCalled() + }) +}) diff --git a/packages/vuetify/src/directives/scroll/__tests__/scroll.spec.ts b/packages/vuetify/src/directives/scroll/__tests__/scroll.spec.ts deleted file mode 100644 index 15830249f3a..00000000000 --- a/packages/vuetify/src/directives/scroll/__tests__/scroll.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -/// - -// Directives -import Scroll from '../' - -// Utilities -import { expect } from 'vitest' -import { - createApp, - defineComponent, - h, - withDirectives, -} from 'vue' -import { scrollWindow } from '@/../test' - -describe('v-scroll', () => { - const instance = { - $: { uid: 1 }, - } - const el = document.createElement('div') - const mountFunction = (value: EventListenerOrEventListenerObject, selector = ''): HTMLElement => { - const Test = defineComponent(() => () => withDirectives(h('div', { class: 'test' }), [[Scroll, value, selector]])) - - createApp(Test).mount(el) - return el.querySelector('.test')! - } - - it('shoud bind event on inserted (selector)', () => { - const value = () => {} - const targetElement = { addEventListener: vi.fn(), removeEventListener: vi.fn() } as any as Element - const el = {} as HTMLElement - const querySelector = vi.spyOn(window.document, 'querySelector').mockImplementation( - selector => selector === '.selector' ? targetElement : null - ) - - Scroll.mounted(el, { value, arg: '.selector', instance } as any) - expect(targetElement.addEventListener).toHaveBeenCalledWith('scroll', value, { passive: true }) - Scroll.unmounted(el, { instance } as any) - expect(targetElement.removeEventListener).toHaveBeenCalledWith('scroll', value, { passive: true }) - - Scroll.mounted(el, { value, arg: '.selector', instance } as any) - expect(targetElement.addEventListener).toHaveBeenCalledWith('scroll', value, { passive: true }) - Scroll.unmounted(el, { instance } as any) - expect(targetElement.removeEventListener).toHaveBeenCalledWith('scroll', value, { passive: true }) - - querySelector.mockRestore() - }) - - it('shoud bind event on inserted (window)', () => { - const value = () => {} - const addListener = vi.spyOn(window, 'addEventListener') - const removeListener = vi.spyOn(window, 'removeEventListener') - const el = {} - - Scroll.mounted(el as HTMLElement, { value, instance } as any) - expect(addListener).toHaveBeenCalledWith('scroll', value, { passive: true }) - Scroll.unmounted(el as HTMLElement, { instance } as any) - expect(removeListener).toHaveBeenCalledWith('scroll', value, { passive: true }) - - addListener.mockRestore() - removeListener.mockRestore() - }) - - it('shoud rebind event on updated', () => { - const value1 = () => {} - const value2 = () => {} - const addListener = vi.spyOn(window, 'addEventListener') - const removeListener = vi.spyOn(window, 'removeEventListener') - const el = {} - - Scroll.mounted(el as HTMLElement, { value: value1, instance } as any) - expect(addListener).toHaveBeenCalledTimes(1) - expect(addListener).toHaveBeenCalledWith('scroll', value1, { passive: true }) - - Scroll.updated(el as HTMLElement, { value: value2, oldValue: value1, instance } as any) - expect(removeListener).toHaveBeenCalledTimes(1) - expect(removeListener).toHaveBeenCalledWith('scroll', value1, { passive: true }) - expect(addListener).toHaveBeenCalledTimes(2) - expect(addListener).toHaveBeenCalledWith('scroll', value2, { passive: true }) - - addListener.mockRestore() - removeListener.mockRestore() - }) - - it('should not fail when unbinding element without _onScroll', () => { - expect(() => { - Scroll.unmounted({} as HTMLElement, { instance } as any) - }).not.toThrow() - }) - - it('should call the callback on scroll', async () => { - const callback = vi.fn() - - mountFunction(event => callback(event.target)) - - expect(callback).not.toHaveBeenCalled() - - await scrollWindow(400) - - expect(callback).toHaveBeenCalledWith(jsdom.window) - }) -}) diff --git a/packages/vuetify/src/directives/touch/__tests__/touch.spec.browser.tsx b/packages/vuetify/src/directives/touch/__tests__/touch.spec.browser.tsx new file mode 100644 index 00000000000..70b8637870d --- /dev/null +++ b/packages/vuetify/src/directives/touch/__tests__/touch.spec.browser.tsx @@ -0,0 +1,96 @@ +// Directives +import Touch from '../' + +// Utilities +import { render } from '@testing-library/vue' +import { commands } from '@vitest/browser/context' +import { defineComponent } from 'vue' + +// Types +import type { PropType } from 'vue' +import type { TouchValue } from '../' + +const TestComponent = defineComponent({ + directives: { Touch }, + props: { + value: Object as PropType, + }, + setup (props) { + return () => ( +
+ ) + }, +}) + +describe('v-touch', () => { + describe('calls directive handler', () => { + it.each([ + ['down', [100, 140]], + ['up', [100, 60]], + ['left', [60, 100]], + ['right', [140, 100]], + ])('%s', async (name, to) => { + const fn = vi.fn() + const start = vi.fn() + const move = vi.fn() + const end = vi.fn() + + render() + + await commands.drag([100, 100], to) + + expect(fn).toHaveBeenCalled() + expect(start).toHaveBeenCalled() + expect(move).toHaveBeenCalled() + expect(end).toHaveBeenCalled() + }) + }) + + describe('calls directive handler if not straight', () => { + it.each([ + ['down', 'right', [115, 140]], + ['up', 'left', [85, 60]], + ['left', 'down', [60, 115]], + ['right', 'up', [140, 85]], + ])('%s', async (name, not, to) => { + const fn = vi.fn() + const nope = vi.fn() + const start = vi.fn() + const move = vi.fn() + const end = vi.fn() + + render() + + await commands.drag([100, 100], to) + + expect(fn).toHaveBeenCalled() + expect(nope).not.toHaveBeenCalled() + expect(start).toHaveBeenCalled() + expect(move).toHaveBeenCalled() + expect(end).toHaveBeenCalled() + }) + }) + + describe('does not call directive handlers if distance is too small', () => { + it.each([ + ['down', [100, 115]], + ['up', [100, 85]], + ['left', [85, 100]], + ['right', [115, 100]], + ])('%s', async (name, to) => { + const fn = vi.fn() + const start = vi.fn() + const move = vi.fn() + const end = vi.fn() + + render() + + await commands.drag([100, 100], to) + + expect(fn).not.toHaveBeenCalled() + expect(start).toHaveBeenCalled() + expect(move).not.toHaveBeenCalled() + expect(end).toHaveBeenCalled() + }) + }) +}) diff --git a/packages/vuetify/src/directives/touch/__tests__/touch.spec.ts b/packages/vuetify/src/directives/touch/__tests__/touch.spec.ts deleted file mode 100644 index c840b27da1e..00000000000 --- a/packages/vuetify/src/directives/touch/__tests__/touch.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Directives -import Touch from '../' - -// Utilities -import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' -import { nextTick } from 'vue' -import { touch } from '@/../test' - -// Types -import type { TouchValue } from '../' - -describe('v-touch', () => { - const mountFunction = (value: TouchValue): Element => { - const wrapper = mount({ - directives: { Touch }, - props: { - value: Object, - }, - template: '
', - }, { props: { value } }) - - return wrapper.element - } - - it('should call directive handlers', () => { - const down = vi.fn() - touch(mountFunction({ down })).start(0, 0).end(0, 20) - expect(down).toHaveBeenCalled() - - const up = vi.fn() - touch(mountFunction({ up })).start(0, 0).end(0, -20) - expect(up).toHaveBeenCalled() - - const left = vi.fn() - touch(mountFunction({ left })).start(0, 0).end(-20, 0) - expect(left).toHaveBeenCalled() - - const right = vi.fn() - touch(mountFunction({ right })).start(0, 0).end(20, 0) - expect(right).toHaveBeenCalled() - - const start = vi.fn() - touch(mountFunction({ start })).start(0, 0) - expect(start).toHaveBeenCalled() - - const move = vi.fn() - touch(mountFunction({ move })).move(0, 0) - expect(move).toHaveBeenCalled() - - const end = vi.fn() - touch(mountFunction({ end })).end(0, 0) - expect(end).toHaveBeenCalled() - }) - - it('should call directive handlers if not straight down/up/right/left', async () => { - const nope = vi.fn() - const down = vi.fn() - touch(mountFunction({ down, right: nope })).start(0, 0).end(5, 20) - expect(nope).not.toHaveBeenCalled() - expect(down).toHaveBeenCalled() - }) - - it('should not call directive handlers if distance is too small', async () => { - const down = vi.fn() - touch(mountFunction({ down })).start(0, 0).end(0, 10) - expect(down).not.toHaveBeenCalled() - - const up = vi.fn() - touch(mountFunction({ up })).start(0, 0).end(0, -10) - expect(up).not.toHaveBeenCalled() - - const left = vi.fn() - touch(mountFunction({ left })).start(0, 0).end(-10, 0) - expect(left).not.toHaveBeenCalled() - - const right = vi.fn() - touch(mountFunction({ right })).start(0, 0).end(10, 0) - expect(right).not.toHaveBeenCalled() - }) - - it('should unmount', async () => { - const start = vi.fn() - const wrapper = mount({ - directives: { Touch }, - props: { - value: Object, - bound: Boolean, - }, - template: '
', - }, { - props: { - value: { start }, - bound: true, - }, - }) - const el = wrapper.element - - await nextTick() - await wrapper.setProps({ bound: false }) - - touch(el).start(0, 0) - expect(start.mock.calls).toHaveLength(0) - }) -}) diff --git a/packages/vuetify/src/globals.d.ts b/packages/vuetify/src/globals.d.ts index 0dcfacb906e..8888011e7ab 100644 --- a/packages/vuetify/src/globals.d.ts +++ b/packages/vuetify/src/globals.d.ts @@ -169,13 +169,3 @@ declare module 'vue' { export interface CSSProperties extends CustomProperties {} } - -interface CustomMatchers { - toHaveBeenTipped: () => R - toHaveBeenWarned: () => R -} - -declare module 'vitest' { - interface Assertion extends CustomMatchers {} - interface AsymmetricMatchersContaining extends CustomMatchers {} -} diff --git a/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.browser.tsx b/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.browser.tsx new file mode 100644 index 00000000000..0e9ef6b7ec1 --- /dev/null +++ b/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.browser.tsx @@ -0,0 +1,654 @@ +// Components +import { VTreeview } from '../VTreeview' + +// Utilities +import { render, screen, userEvent } from '@test' +import { nextTick, reactive, ref, shallowRef } from 'vue' + +const items = [ + { + id: 1, + title: 'Vuetify Human Resources', + children: [ + { + id: 2, + title: 'Core team', + children: [ + { + id: 201, + title: 'John', + }, + { + id: 202, + title: 'Kael', + }, + { + id: 203, + title: 'Nekosaur', + }, + { + id: 204, + title: 'Jacek', + }, + { + id: 205, + title: 'Andrew', + }, + ], + }, + { + id: 3, + title: 'Administrators', + children: [ + { + id: 301, + title: 'Mike', + }, + { + id: 302, + title: 'Hunt', + }, + ], + }, + { + id: 4, + title: 'Other contributors', + }, + ], + }, +] + +describe.each([ + // ['plain', items], // TODO: broken + ['reactive', reactive(items)], +])('VTreeview with %s items', (_, items) => { + describe('activate', () => { + it('single-leaf strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([203]) + }) + + it('leaf strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([201, 202, 203]) + }) + + it('independent strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([1]) + + await userEvent.click(screen.getByText(/Core team/)) + expect(activated.value).toStrictEqual([1, 2]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([1, 2, 201, 202, 203]) + }) + + it('single-independent strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([1]) + + await userEvent.click(screen.getByText(/Core team/)) + expect(activated.value).toStrictEqual([2]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([203]) + }) + }) + + describe('select', () => { + it('single-leaf strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(8) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([302]) + await userEvent.click(screen.getByText(/contributors/)) + expect(selected.value).toStrictEqual([4]) + }) + + it('leaf strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(8) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([301, 302]) + await userEvent.click(screen.getByText(/contributors/)) + expect(selected.value).toStrictEqual([301, 302, 4]) + }) + + it('independent strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(11) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([301, 302]) + await userEvent.click(screen.getByText(/contributors/)) + expect(selected.value).toStrictEqual([301, 302, 4]) + await userEvent.click(screen.getByText(/Core/).parentElement!.previousElementSibling!) + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([301, 302, 4, 2, 1]) + }) + + it('single-independent strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(11) + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + expect(selected.value).toStrictEqual([202]) + await userEvent.click(screen.getByText(/Core/).parentElement!.previousElementSibling!) + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([1]) + }) + + it('classic strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(11) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([301, 302]) + await userEvent.click(screen.getByText(/Administrators/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([]) + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([4, 201, 202, 203, 204, 205, 301, 302]) + }) + }) + + describe('return-object', () => { + describe('open', () => { + it('open and collapse should both work', async () => { + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect.element(screen.getByText(/Core/)).toBeVisible() + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect.element(screen.getByText(/Core/)).not.toBeVisible() + }) + + it('open-all should work', async () => { + render(() => ( + + )) + + const itemEl = screen.getAllByCSS('.v-treeview-item') + expect(itemEl).toHaveLength(11) + itemEl.forEach(el => { + expect(el).toBeVisible() + }) + }) + + it('should return opened object to v-model:opened', async () => { + const opened = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect(opened.value).toEqual([ + expect.objectContaining({ id: 1 }), + ]) + + await userEvent.click(screen.getByText(/Core/).parentElement!.previousElementSibling!) + expect(opened.value).toEqual([ + expect.objectContaining({ id: 1 }), + expect.objectContaining({ id: 2 }), + ]) + }) + }) + + describe('activate', () => { + it('single-leaf strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 203 }), + ]) + }) + + it('leaf strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 201 }), + expect.objectContaining({ id: 202 }), + expect.objectContaining({ id: 203 })] + ) + }) + + it('independent strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 1 }), + ]) + + await userEvent.click(screen.getByText(/Core team/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 1 }), + expect.objectContaining({ id: 2 }), + ]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 1 }), + expect.objectContaining({ id: 2 }), + expect.objectContaining({ id: 201 }), + expect.objectContaining({ id: 202 }), + expect.objectContaining({ id: 203 }), + ]) + }) + + it('single-independent strategy', async () => { + const activated = ref([]) + render(() => ( + + )) + + await userEvent.click(screen.getByText(/Human Resources/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 1 }), + ]) + + await userEvent.click(screen.getByText(/Core team/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 2 }), + ]) + + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + await userEvent.click(screen.getByText(/Nekosaur/)) + expect(activated.value).toStrictEqual([ + expect.objectContaining({ id: 203 }), + ]) + }) + }) + + describe('select', () => { + it('single-leaf strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(8) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 302 }), + ]) + await userEvent.click(screen.getByText(/contributors/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 4 }), + ]) + }) + + it('leaf strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(8) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 301 }), + expect.objectContaining({ id: 302 }), + ]) + await userEvent.click(screen.getByText(/contributors/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 301 }), + expect.objectContaining({ id: 302 }), + expect.objectContaining({ id: 4 }), + ]) + }) + + it('independent strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(11) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 301 }), + expect.objectContaining({ id: 302 }), + ]) + await userEvent.click(screen.getByText(/contributors/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 301 }), + expect.objectContaining({ id: 302 }), + expect.objectContaining({ id: 4 }), + ]) + await userEvent.click(screen.getByText(/Core/).parentElement!.previousElementSibling!) + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 301 }), + expect.objectContaining({ id: 302 }), + expect.objectContaining({ id: 4 }), + expect.objectContaining({ id: 2 }), + expect.objectContaining({ id: 1 }), + ]) + }) + + it('single-independent strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(11) + await userEvent.click(screen.getByText(/John/)) + await userEvent.click(screen.getByText(/Kael/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 202 }), + ]) + await userEvent.click(screen.getByText(/Core/).parentElement!.previousElementSibling!) + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 1 }), + ]) + }) + + it('classic strategy', async () => { + const selected = ref([]) + render(() => ( + + )) + + expect(screen.getAllByCSS('.v-checkbox-btn')).toHaveLength(11) + await userEvent.click(screen.getByText(/Mike/)) + await userEvent.click(screen.getByText(/Hunt/)) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 301 }), + expect.objectContaining({ id: 302 }), + ]) + await userEvent.click(screen.getByText(/Administrators/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([]) + await userEvent.click(screen.getByText(/Vuetify/).parentElement!.previousElementSibling!) + expect(selected.value).toStrictEqual([ + expect.objectContaining({ id: 4 }), + expect.objectContaining({ id: 201 }), + expect.objectContaining({ id: 202 }), + expect.objectContaining({ id: 203 }), + expect.objectContaining({ id: 204 }), + expect.objectContaining({ id: 205 }), + expect.objectContaining({ id: 301 }), + expect.objectContaining({ id: 302 }), + ]) + }) + }) + + describe('search', () => { + // https://github.com/vuetifyjs/vuetify/issues/20488 + it('should filter items based on the search text and return the correct result', async () => { + const search = shallowRef('') + render(() => ( + + )) + + search.value = 'j' + await nextTick() + expect(screen.getByText(/Vuetify/)).toBeVisible() + expect(screen.getByText(/Core/)).toBeVisible() + expect(screen.getByText(/John/)).toBeVisible() + expect(screen.getByText(/Jacek/)).toBeVisible() + expect(screen.getByText(/Andrew/)).not.toBeVisible() + expect(screen.getByText(/Administrators/)).not.toBeVisible() + }) + }) + }) + + it('should have all items visible when open-all is applied', async () => { + render(() => ( + + )) + + const itemEl = screen.getAllByCSS('.v-treeview-item') + expect(itemEl).toHaveLength(11) + itemEl.forEach(el => { + expect(el).toBeVisible() + }) + }) +}) diff --git a/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx b/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx deleted file mode 100644 index a3e5aebf144..00000000000 --- a/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx +++ /dev/null @@ -1,970 +0,0 @@ -/// - -// Components -import { VTreeview } from '../VTreeview' -import { VTextField } from '@/components/VTextField' - -// Utilities -import { ref, shallowRef } from 'vue' - -function compareItemObject (a: any, b: any) { - return a.id - b.id -} - -const items = ref([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, -]) - -describe('VTreeview', () => { - describe('activate', () => { - it('single-leaf strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([]) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value).to.deep.equal([5]) - }) - }) - it('leaf strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([]) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value.sort()).to.deep.equal([3, 4, 5].sort()) - }) - }) - it('independent strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([1]) - }) - .get('.v-treeview-item').eq(1).click() - .then(_ => { - expect(activated.value).to.deep.equal([1, 2]) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value.sort()).to.deep.equal([1, 2, 3, 4, 5].sort()) - }) - }) - it('single-independent strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([1]) - }) - .get('.v-treeview-item').eq(1).click() - .then(_ => { - expect(activated.value).to.deep.equal([2]) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value).to.deep.equal([5]) - }) - }) - }) - describe('select', () => { - it('single-leaf strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 5) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([4]) - }) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([6]) - }) - }) - it('leaf strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 5) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .then(_ => { - expect(selected.value.sort()).to.deep.equal([3, 4].sort()) - }) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value.sort()).to.deep.equal([3, 4, 6].sort()) - }) - }) - it('independent strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 7) - .get('.v-checkbox-btn').eq(2).click(20, 20) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value.sort()).to.deep.equal([3, 4].sort()) - }) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .then(_ => { - expect(selected.value.sort()).to.deep.equal([1, 2, 3, 4].sort()) - }) - }) - it('single-independent strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 7) - .get('.v-checkbox-btn').eq(2).click(20, 20) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value.sort()).to.deep.equal([4].sort()) - }) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .then(_ => { - expect(selected.value.sort()).to.deep.equal([1].sort()) - }) - }) - - it('classic strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').eq(2).click(20, 20) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .get('.v-checkbox-btn').eq(4).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([3, 4, 5]) - }) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([]) - }) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .then(_ => { - expect(selected.value.sort()).to.deep.equal([3, 4, 5, 6, 7].sort()) - }) - }) - }) - - describe('return-object', () => { - describe('open', () => { - it('open and collapse should both work', () => { - cy.mount(() => ( - <> - - - )) - .get('.v-list-item-action .v-btn').eq(0).click() - .get('.v-list-group__items').eq(0).should('be.visible') - .get('.v-list-item-action .v-btn').eq(0).click() - .get('.v-list-group__items').eq(0).should('not.be.visible') - }) - it('opan-all should work', () => { - cy.mount(() => ( - <> - - - )) - .get('.v-treeview-item').eq(1).should('be.visible') - .get('.v-treeview-item').eq(2).should('be.visible') - .get('.v-treeview-item').eq(3).should('be.visible') - .get('.v-treeview-item').eq(4).should('be.visible') - .get('.v-treeview-item').eq(5).should('be.visible') - .get('.v-treeview-item').eq(6).should('be.visible') - }) - it('should return opened object to v-model:opened', () => { - const opened = ref([]) - cy.mount(() => ( - <> - - - )) - .get('.v-list-item-action .v-btn').eq(0).click() - .then(_ => { - expect(opened.value).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }]) - }) - .get('.v-list-item-action .v-btn').eq(1).click() - .then(_ => { - expect(opened.value.sort(compareItemObject)).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - ].sort(compareItemObject)) - }) - }) - }) - describe('activate', () => { - it('single-leaf strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([]) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value).to.deep.equal([{ id: 5, title: 'All about app : dir' }]) - }) - }) - it('leaf strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([]) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value.sort(compareItemObject)).to.deep.equal([ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ].sort(compareItemObject)) - }) - }) - it('independent strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, - ]) - }) - .get('.v-treeview-item').eq(1).click() - .then(_ => { - expect(activated.value.sort(compareItemObject)).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - ].sort(compareItemObject)) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value.sort(compareItemObject)).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ].sort(compareItemObject)) - }) - }) - it('single-independent strategy', () => { - const activated = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-treeview-item').should('have.length', 7) - .get('.v-treeview-item').eq(0).click() - .then(_ => { - expect(activated.value).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, - ]) - }) - .get('.v-treeview-item').eq(1).click() - .then(_ => { - expect(activated.value).to.deep.equal([ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - ]) - }) - .get('.v-treeview-item').eq(2).click() - .get('.v-treeview-item').eq(3).click() - .get('.v-treeview-item').eq(4).click() - .then(_ => { - expect(activated.value).to.deep.equal([{ id: 5, title: 'All about app : dir' }]) - }) - }) - }) - describe('select', () => { - it('single-leaf strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 5) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([{ id: 4, title: 'Advanced techniques : mp4' }]) - }) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([{ id: 6, title: 'Intro : mov' }]) - }) - }) - it('leaf strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 5) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .then(_ => { - expect(selected.value.sort(compareItemObject)).to.deep.equal([ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - ].sort(compareItemObject)) - }) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value.sort(compareItemObject)).to.deep.equal([ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 6, title: 'Intro : mov' }, - ].sort(compareItemObject)) - }) - }) - it('independent strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 7) - .get('.v-checkbox-btn').eq(2).click(20, 20) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value.sort(compareItemObject)).to.deep.equal([ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - ].sort(compareItemObject)) - }) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .then(_ => { - expect(selected.value.sort(compareItemObject)).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - ].sort(compareItemObject)) - }) - }) - it('single-independent strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').should('have.length', 7) - .get('.v-checkbox-btn').eq(2).click(20, 20) - .get('.v-checkbox-btn').eq(3).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([{ id: 4, title: 'Advanced techniques : mp4' }]) - }) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([ - { - id: 1, - title: 'Videos :', - children: [ - { - id: 2, - title: 'Tutorials :', - children: [ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ], - }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ], - }, - ]) - }) - }) - - it('classic strategy', () => { - const selected = ref([]) - cy.mount(() => ( - <> - - - )) - - cy.get('.v-checkbox-btn').eq(0).click(20, 20) - .then(_ => { - expect(selected.value.sort(compareItemObject)).to.deep.equal([ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - { id: 6, title: 'Intro : mov' }, - { id: 7, title: 'Conference introduction : avi' }, - ].sort(compareItemObject)) - }) - .get('.v-checkbox-btn').eq(0).click(20, 20) - .then(_ => { - expect(selected.value).to.deep.equal([]) - }) - .get('.v-checkbox-btn').eq(1).click(20, 20) - .then(_ => { - expect(selected.value.sort(compareItemObject)).to.deep.equal([ - { id: 3, title: 'Basic layouts : mp4' }, - { id: 4, title: 'Advanced techniques : mp4' }, - { id: 5, title: 'All about app : dir' }, - ].sort(compareItemObject)) - }) - }) - }) - describe('search', () => { - // https://github.com/vuetifyjs/vuetify/issues/20488 - it('should filter items based on the search text and return the correct result', () => { - const items = ref([ - { - id: 1, - title: 'Vuetify Human Resources', - children: [ - { - id: 2, - title: 'Core team', - children: [ - { - id: 201, - title: 'John', - }, - { - id: 202, - title: 'Kael', - }, - { - id: 203, - title: 'Nekosaur', - }, - { - id: 204, - title: 'Jacek', - }, - { - id: 205, - title: 'Andrew', - }, - ], - }, - { - id: 3, - title: 'Administrators', - children: [ - { - id: 301, - title: 'Mike', - }, - { - id: 302, - title: 'Hunt', - }, - ], - }, - { - id: 4, - title: 'Contributors', - children: [ - { - id: 401, - title: 'Phlow', - }, - { - id: 402, - title: 'Brandon', - }, - { - id: 403, - title: 'Sean', - }, - ], - }, - ], - }, - ]) - const search = shallowRef('') - - function filterFn (value: string, search: string) { - return value.toLowerCase().includes(search.toLowerCase()) - } - cy.mount(() => ( - <> - - - - )) - .get('.v-text-field input') - .type('j') - .get('.v-treeview-item').eq(0).should('be.visible') // { id: 1, title: 'Vuetify Human Resources' } - .get('.v-treeview-item').eq(1).should('be.visible') // { id: 2, title: 'Core team' } - .get('.v-treeview-item').eq(2).should('be.visible') // { id: 201, title: 'John' } - .get('.v-treeview-item').eq(3).should('not.be.visible') - .get('.v-treeview-item').eq(4).should('not.be.visible') - .get('.v-treeview-item').eq(5).should('be.visible') // { id: 204, title: 'Jacek' } - .get('.v-treeview-item').eq(9).should('not.be.visible') - .get('.v-treeview-item').eq(13).should('not.be.visible') - }) - }) - }) - - it('should have all items visible when open-all is applied', () => { - cy.mount(() => ( - <> - - - )) - .get('.v-treeview-item') - .filter(':visible') - .should('have.length', 7) - }) -}) diff --git a/packages/vuetify/src/locale/__tests__/index.spec.ts b/packages/vuetify/src/locale/__tests__/index.spec.ts index 2854a4194c9..beb59bf6bff 100755 --- a/packages/vuetify/src/locale/__tests__/index.spec.ts +++ b/packages/vuetify/src/locale/__tests__/index.spec.ts @@ -1,7 +1,6 @@ // Utilities import fs from 'fs' import path from 'path' -import { expect, it } from 'vitest' import * as locales from '../' describe('locales', () => { diff --git a/packages/vuetify/src/util/__tests__/colorUtils.spec.ts b/packages/vuetify/src/util/__tests__/colorUtils.spec.ts index 13517150611..7b0e3794bcd 100644 --- a/packages/vuetify/src/util/__tests__/colorUtils.spec.ts +++ b/packages/vuetify/src/util/__tests__/colorUtils.spec.ts @@ -1,5 +1,4 @@ // Utilities -import { expect, it } from 'vitest' import { APCAcontrast } from '../color/APCA' import * as transformCIELAB from '../color/transformCIELAB' import * as transformSRGB from '../color/transformSRGB' diff --git a/packages/vuetify/src/util/__tests__/dom.spec.ts b/packages/vuetify/src/util/__tests__/dom.spec.ts index 19e58b96052..eda6f581f6a 100644 --- a/packages/vuetify/src/util/__tests__/dom.spec.ts +++ b/packages/vuetify/src/util/__tests__/dom.spec.ts @@ -1,6 +1,5 @@ // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { defineComponent, h } from 'vue' import { attachedRoot, diff --git a/packages/vuetify/src/util/__tests__/getCurrentInstance.spec.tsx b/packages/vuetify/src/util/__tests__/getCurrentInstance.spec.tsx index 03e7f65e0ad..1f8600d764c 100644 --- a/packages/vuetify/src/util/__tests__/getCurrentInstance.spec.tsx +++ b/packages/vuetify/src/util/__tests__/getCurrentInstance.spec.tsx @@ -1,6 +1,5 @@ // Utilities import { mount } from '@vue/test-utils' -import { expect, it } from 'vitest' import { getCurrentInstance } from '../getCurrentInstance' describe('getCurrentInstance.ts', () => { diff --git a/packages/vuetify/src/util/__tests__/helpers.spec.ts b/packages/vuetify/src/util/__tests__/helpers.spec.ts index 85c4b49172a..dce2b5e81aa 100644 --- a/packages/vuetify/src/util/__tests__/helpers.spec.ts +++ b/packages/vuetify/src/util/__tests__/helpers.spec.ts @@ -1,5 +1,4 @@ // Utilities -import { describe, expect, it, vi } from 'vitest' import { isProxy, isRef, ref } from 'vue' import { arrayDiff, diff --git a/packages/vuetify/src/util/__tests__/propsFactory.spec.ts b/packages/vuetify/src/util/__tests__/propsFactory.spec.ts index 8c6022419bb..5961ac1725a 100644 --- a/packages/vuetify/src/util/__tests__/propsFactory.spec.ts +++ b/packages/vuetify/src/util/__tests__/propsFactory.spec.ts @@ -1,5 +1,4 @@ // Utilities -import { expect, it } from 'vitest' import { propsFactory } from '../propsFactory' describe('propsFactory', () => { diff --git a/packages/vuetify/test/globals.d.ts b/packages/vuetify/test/globals.d.ts new file mode 100644 index 00000000000..17b4cf6e93c --- /dev/null +++ b/packages/vuetify/test/globals.d.ts @@ -0,0 +1,15 @@ +import type { CustomCommands } from './setup/browser-commands.ts' + +interface CustomMatchers { + toHaveBeenTipped: () => R + toHaveBeenWarned: () => R +} + +declare module 'vitest' { + interface Assertion extends CustomMatchers {} + interface AsymmetricMatchersContaining extends CustomMatchers {} +} + +declare module '@vitest/browser/context' { + interface BrowserCommands extends CustomCommands {} +} diff --git a/packages/vuetify/test/index.ts b/packages/vuetify/test/index.ts index 72a8928e6e5..6718d8ccbea 100644 --- a/packages/vuetify/test/index.ts +++ b/packages/vuetify/test/index.ts @@ -1,20 +1,16 @@ -// Setup -// import type { ComponentOptions } from 'vue' - // Utilities -import toHaveBeenWarnedInit from './util/to-have-been-warned' +import './globals.d' +import { render as _render } from '@testing-library/vue' +import { createVuetify } from '../src/framework' +import { mergeDeep } from '../src/util' +import { aliases } from '../src/iconsets/mdi-svg' + +import type { RenderOptions, RenderResult } from '@testing-library/vue' +import type { VuetifyOptions } from '../src/framework' -// export function functionalContext (context: ComponentOptions = {}, children = []) { -// if (!Array.isArray(children)) children = [children] -// return { -// context: { -// data: {}, -// props: {}, -// ...context, -// }, -// children, -// } -// } +export { userEvent } from '@vitest/browser/context' +export { screen } from '@testing-library/vue' +export * from './templates' export function touch (element: Element) { const createTrigger = (eventName: string) => (clientX: number, clientY: number) => { @@ -39,73 +35,42 @@ export const wait = (timeout?: number) => { return new Promise(resolve => setTimeout(resolve, timeout)) } -export const waitAnimationFrame = (timeout?: number) => { +export const waitAnimationFrame = () => { return new Promise(resolve => requestAnimationFrame(resolve)) } -export const resizeWindow = (width = window.innerWidth, height = window.innerHeight) => { - (window as any).innerWidth = width - ;(window as any).innerHeight = height - window.dispatchEvent(new Event('resize')) - - return wait(200) -} - -export const scrollWindow = (y: number) => { - (window as any).pageYOffset = y - window.dispatchEvent(new Event('scroll')) - - return wait(200) +export const waitIdle = () => { + return new Promise(resolve => requestIdleCallback(resolve, { timeout: 500 })) } -export const scrollElement = (element: Element, y: number) => { - element.scrollTop = y - element.dispatchEvent(new Event('scroll')) - - return wait(200) +export const scroll = (options: ScrollToOptions, el: Element | Window = window) => { + return Promise.race([ + wait(500), + new Promise(resolve => { + el.addEventListener('scrollend', resolve, { once: true }) + el.scroll(options) + }).then(waitIdle), + ]) } -// Add a global mockup for IntersectionObserver -class IntersectionObserver { - callback?: (entries: any, observer: any) => {} - - constructor (callback: any) { - this.callback = callback +export function render ( + component: C, + options?: RenderOptions | null, + vuetifyOptions?: VuetifyOptions +): RenderResult { + const vuetify = createVuetify(mergeDeep({ icons: { aliases } }, vuetifyOptions)) + + const defaultOptions = { + global: { + stubs: { + transition: false, + 'transition-group': false, + }, + plugins: [vuetify], + }, } - observe () { - this.callback?.([], this) - return null - } + const mountOptions = mergeDeep(defaultOptions, options!, (a, b) => a.concat(b)) - unobserve () { - this.callback = undefined - return null - } + return _render(component, mountOptions) } - -(global as any).IntersectionObserver = IntersectionObserver - -class ResizeObserver { - callback?: ResizeObserverCallback - - constructor (callback: ResizeObserverCallback) { - this.callback = callback - } - - observe () { - this.callback?.([], this) - } - - unobserve () { - this.callback = undefined - } - - disconnect () { - this.callback = undefined - } -} - -(global as any).ResizeObserver = ResizeObserver - -toHaveBeenWarnedInit() diff --git a/packages/vuetify/test/setup/browser-commands.ts b/packages/vuetify/test/setup/browser-commands.ts new file mode 100644 index 00000000000..06f862f28bb --- /dev/null +++ b/packages/vuetify/test/setup/browser-commands.ts @@ -0,0 +1,73 @@ +/// +/// + +import type { BrowserCommandContext } from 'vitest/node' +import percy from '@percy/sdk-utils' +import type { PercyOptions } from '@percy/sdk-utils' +import { createRequire } from 'node:module' +import { readFileSync } from 'node:fs' +import path from 'upath' + +const require = createRequire(import.meta.url) + +const pkg = JSON.parse(readFileSync('../../package.json', 'utf8')) +const wdioPkg = JSON.parse(readFileSync(path.resolve(require.resolve('webdriverio'), '../../../package.json'), 'utf8')) +const CLIENT_INFO = `${pkg.name}/${pkg.version}` +const ENV_INFO = `${wdioPkg.name}/${wdioPkg.version}` + +function drag (ctx: BrowserCommandContext, start: [number, number], ...moves: number[][]) { + const action = ctx.browser.action('pointer', { + parameters: { pointerType: 'touch' }, + }) + action.move({ x: start[0], y: start[1] }) + action.down() + for (const move of moves) { + action.move({ x: move[0], y: move[1], duration: 10 }) + } + action.up() + return action.perform() +} + +function scroll (ctx: BrowserCommandContext, x: number, y: number) { + return ctx.browser.scroll(x, y) +} + +export function isDisplayedInViewport (ctx: BrowserCommandContext, el: any) { + return ctx.browser.$(el).isDisplayedInViewport() +} + +export async function percySnapshot (ctx: BrowserCommandContext, name: string, options?: PercyOptions) { + if (!(await percy.isPercyEnabled())) return + + try { + const dom = await percy.fetchPercyDOM() + await ctx.browser.executeScript(dom, []) + + const domSnapshot = await ctx.browser.executeScript('return PercyDOM.serialize(arguments[0])', [options]) + + await percy.postSnapshot({ + ...options, + environmentInfo: ENV_INFO, + clientInfo: CLIENT_INFO, + url: await ctx.browser.getUrl(), + domSnapshot, + name, + }) + } catch (err) { + const log = percy.logger('webdriverio') + log.error(`Could not take DOM snapshot "${name}"`) + log.error(err) + } +} + +export async function waitStable (ctx: BrowserCommandContext, el: any) { + return ctx.browser.$(el).waitForStable() +} + +export const commands = { drag, scroll, isDisplayedInViewport, percySnapshot, waitStable } + +export type CustomCommands = { + [k in keyof typeof commands]: typeof commands[k] extends (ctx: any, ...args: infer A) => any + ? (...args: A) => any + : 'never' +} diff --git a/packages/vuetify/test/setup/browser-setup.ts b/packages/vuetify/test/setup/browser-setup.ts new file mode 100644 index 00000000000..ea3504db1b5 --- /dev/null +++ b/packages/vuetify/test/setup/browser-setup.ts @@ -0,0 +1,12 @@ +import 'roboto-fontface' +import '@/styles/main.sass' +import { beforeEach } from 'vitest' +import { cleanup } from '@testing-library/vue' +import { page } from '@vitest/browser/context' + +beforeEach(async () => { + // Cleanup before not after, so if the test + // fails we can inspect what has happened + cleanup() + await page.viewport(1280, 800) +}) diff --git a/packages/vuetify/test/setup/percy.d.ts b/packages/vuetify/test/setup/percy.d.ts new file mode 100644 index 00000000000..23212247eb4 --- /dev/null +++ b/packages/vuetify/test/setup/percy.d.ts @@ -0,0 +1,13 @@ +declare module '@percy/sdk-utils' { + const utils: { + logger: any + fetchPercyDOM: () => Promise + isPercyEnabled: () => Promise + postSnapshot: (...args: any[]) => Promise + } + export default utils + + export interface PercyOptions { + // + } +} diff --git a/packages/vuetify/test/setup/to-have-been-warned.ts b/packages/vuetify/test/setup/to-have-been-warned.ts new file mode 100644 index 00000000000..1afbe1ef747 --- /dev/null +++ b/packages/vuetify/test/setup/to-have-been-warned.ts @@ -0,0 +1,68 @@ +import type { Mock } from 'vitest' +import { afterEach, beforeAll, beforeEach, expect, vi } from 'vitest' + +function noop () {} +if (typeof console === 'undefined') { + (window as any).console = { + warn: noop, + error: noop, + } +} + +// avoid info messages during test +// eslint-disable-next-line no-console +console.info = noop + +let warn: Mock +let error: Mock +beforeAll(() => { + warn = vi.spyOn(console, 'warn').mockImplementation(noop) as any + error = vi.spyOn(console, 'error').mockImplementation(noop) as any + expect.extend({ + toHaveBeenWarned: createCompareFn(error), + toHaveBeenTipped: createCompareFn(warn), + }) +}) + +const asserted: string[] = [] + +beforeEach(() => { + asserted.length = 0 + warn.mockClear() + error.mockClear() +}) + +afterEach(() => { + for (const type of ['error', 'warn']) { + const warned = (msg: string) => asserted.some(assertedMsg => msg.toString().includes(assertedMsg)) + for (const args of (console as any)[type].mock.calls) { + if (!warned(args[0])) { + throw new Error(`Unexpected console.${type} message: ${args[0]}`) + } + } + } +}) + +function createCompareFn (spy: Mock) { + const hasWarned = (msg: string) => { + for (const args of spy.mock.calls) { + if (args.some((arg: any) => ( + arg.toString().includes(msg) + ))) return true + } + return false + } + + return (msg: string) => { + asserted.push(msg) + const warned = Array.isArray(msg) + ? msg.some(hasWarned) + : hasWarned(msg) + return { + pass: warned, + message: warned + ? () => (`Expected message "${msg}" not to have been warned`) + : () => (`Expected message "${msg}" to have been warned`), + } + } +} diff --git a/packages/vuetify/test/setup/unit-setup.ts b/packages/vuetify/test/setup/unit-setup.ts new file mode 100644 index 00000000000..14ac37ab1d4 --- /dev/null +++ b/packages/vuetify/test/setup/unit-setup.ts @@ -0,0 +1,6 @@ +import { afterEach } from 'vitest' +import { cleanup } from '@testing-library/vue' + +afterEach(() => { + cleanup() +}) diff --git a/packages/vuetify/cypress/templates/Application.tsx b/packages/vuetify/test/templates/Application.tsx similarity index 100% rename from packages/vuetify/cypress/templates/Application.tsx rename to packages/vuetify/test/templates/Application.tsx diff --git a/packages/vuetify/cypress/templates/CenteredGrid.tsx b/packages/vuetify/test/templates/CenteredGrid.tsx similarity index 100% rename from packages/vuetify/cypress/templates/CenteredGrid.tsx rename to packages/vuetify/test/templates/CenteredGrid.tsx diff --git a/packages/vuetify/cypress/templates/generateStories.tsx b/packages/vuetify/test/templates/generateStories.tsx similarity index 66% rename from packages/vuetify/cypress/templates/generateStories.tsx rename to packages/vuetify/test/templates/generateStories.tsx index fdf32e476ca..18f9b210117 100644 --- a/packages/vuetify/cypress/templates/generateStories.tsx +++ b/packages/vuetify/test/templates/generateStories.tsx @@ -2,13 +2,14 @@ * Utilities for generating formatted mount functions * Some utility functions for mounting these generated examples inside of tests */ -import { FunctionalComponent } from 'vue' -import { JSXComponent } from '@/composables' - -const _ = Cypress._ +import type { FunctionalComponent } from 'vue' +import type { JSXComponent } from '@/composables' +import { it } from 'vitest' +import { commands, page } from '@vitest/browser/context' +import { render } from '@test' type Stories = Record -type Props = Record +type Props = Record type GenerateConfiguration = { props: Props component: JSXComponent @@ -20,8 +21,8 @@ type GenerateConfiguration = { } type Example = { - name: string, - mount: JSX.Element + name: string + mount: () => JSX.Element } /** Utility components */ @@ -42,16 +43,17 @@ const Wrapper: FunctionalComponent = (_, { slots }) =>
{ slots }) */ export const makeExamplesFromStories = (stories: Stories): Example[] => { - return Object.entries(stories).reduce((acc: Example[], [key, value]) => { - acc.push({ + return Object.entries(stories).map(([key, value]) => { + return { name: key, - mount: - { title(key) } - { grid(value) } - , - }) - return acc - }, []) + mount: () => ( + + { title(key) } + { grid(value) } + + ), + } + }) } /** @@ -65,30 +67,31 @@ export const makeExamplesFromStories = (stories: Stories): Example[] => { }, VBtn) */ export const makeExamplesFromProps = (props: Props, Component: JSXComponent): Example[] => { - return Object.entries(props).reduce((acc: Example[], [key, value]) => { + return Object.entries(props).map(([key, value]) => { // Collect an array of examples by prop. const variants: JSX.Element[] = [] // Props with boolean values should be rendered with both their true/false states - if (_.isBoolean(value)) { + if (typeof value === 'boolean') { variants.push(Is { key }) variants.push(Is not { key }) - } else if (_.isArray(value)) { + } else if (Array.isArray(value)) { // Props with array values should be iterated over - value.forEach((v) => { + value.forEach(v => { variants.push({ v }) }) } - acc.push({ + return { name: key, - mount: - { title(key) } - { grid(variants) } - - }) - return acc - }, []) + mount: () => ( + + { title(key) } + { grid(variants) } + + ), + } + }) } /** @@ -108,17 +111,35 @@ export const generate = ({ props, stories, component }: GenerateConfiguration) = exampleProps = makeExamplesFromProps(props, component) } - return it('renders everything', () => { - cy.mount(() => <> - { exampleStories && <> -

Stories

- { exampleStories.map(s => s.mount) } - } - { exampleProps && <> -

Props

- { exampleProps.map(s => s.mount) } - } - ).percySnapshot() + return it('renders everything', async () => { + await page.viewport(1280, 825) + + render(() => ( + <> + { exampleStories && ( + <> +

Stories

+ { exampleStories.map(s => s.mount()) } + + )} + { exampleProps && ( + <> +

Props

+ { exampleProps.map(s => s.mount()) } + + )} + + )) + + let suite = (globalThis as any).__vitest_worker__.current + let name = '' + while (suite) { + name = suite.name + ' ' + name + suite = suite.suite + } + + await commands.percySnapshot(name.trim()) + await page.screenshot() }) } @@ -129,7 +150,9 @@ export const generate = ({ props, stories, component }: GenerateConfiguration) = */ export const generateByExample = (stories: Stories) => { return makeExamplesFromStories(stories).map(({ name, mount }) => { - return it(name, () => { cy.mount(() => <>{ mount }) }) + return it(name, () => { + render(mount) + }) }) } @@ -141,6 +164,8 @@ export const generateByExample = (stories: Stories) => { */ export const generateByProps = (props: Props, component: JSXComponent) => { return makeExamplesFromProps(props, component).map(({ mount, name }) => { - return it(name, () => { cy.mount(() => <>{ mount }) }) + return it(name, () => { + render(mount) + }) }) } diff --git a/packages/vuetify/cypress/templates/gridOn.tsx b/packages/vuetify/test/templates/gridOn.tsx similarity index 100% rename from packages/vuetify/cypress/templates/gridOn.tsx rename to packages/vuetify/test/templates/gridOn.tsx diff --git a/packages/vuetify/cypress/templates/index.ts b/packages/vuetify/test/templates/index.ts similarity index 100% rename from packages/vuetify/cypress/templates/index.ts rename to packages/vuetify/test/templates/index.ts diff --git a/packages/vuetify/test/util/to-have-been-warned.ts b/packages/vuetify/test/util/to-have-been-warned.ts deleted file mode 100644 index 3b80582fe66..00000000000 --- a/packages/vuetify/test/util/to-have-been-warned.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { Mock } from 'vitest' -import { beforeAll, expect, vi } from 'vitest' - -// From Vue, slightly modified -function noop () { } - -if (typeof console === 'undefined') { - (window as any).console = { - warn: noop, - error: noop, - } -} - -// avoid info messages during test -// eslint-disable-next-line no-console -console.info = noop - -const asserted: string[] = [] - -function createCompareFn (spy: Mock) { - const hasWarned = (msg: string) => { - for (const args of spy.mock.calls) { - if (args.some((arg: any) => ( - arg.toString().includes(msg) - ))) return true - } - return false - } - - return (msg: string) => { - asserted.push(msg) - const warned = Array.isArray(msg) - ? msg.some(hasWarned) - : hasWarned(msg) - return { - pass: warned, - message: warned - ? () => (`Expected message "${msg}" not to have been warned`) - : () => (`Expected message "${msg}" to have been warned`), - } - } -} - -function toHaveBeenWarnedInit () { - let warn: Mock - let error: Mock - beforeAll(() => { - warn = vi.spyOn(console, 'warn').mockImplementation(noop) as any - error = vi.spyOn(console, 'error').mockImplementation(noop) as any - expect.extend({ - toHaveBeenWarned: createCompareFn(error), - toHaveBeenTipped: createCompareFn(warn), - }) - }) - - beforeEach(() => { - asserted.length = 0 - warn.mockClear() - error.mockClear() - }) - - afterEach(() => { - for (const type of ['error', 'warn']) { - const warned = (msg: string) => asserted.some(assertedMsg => msg.toString().includes(assertedMsg)) - for (const args of (console as any)[type].mock.calls) { - if (!warned(args[0])) { - throw new Error(`Unexpected console.${type} message: ${args[0]}`) - } - } - } - }) -} - -export default toHaveBeenWarnedInit diff --git a/packages/vuetify/tsconfig.dev.json b/packages/vuetify/tsconfig.dev.json index cd9f5ea4d76..55131eda055 100644 --- a/packages/vuetify/tsconfig.dev.json +++ b/packages/vuetify/tsconfig.dev.json @@ -3,13 +3,18 @@ "include": [ "src", "dev", + "test", "cypress", "cypress.config.ts", "vite.config.mts", - "vitest.config.mts" + "vitest.config.mts", + "vitest.workspace.mts" ], "compilerOptions": { - "allowJs": true + "allowJs": true, + "types": [ + "@vitest/browser/providers/webdriverio" + ] }, "vueCompilerOptions": { "strictTemplates": true diff --git a/packages/vuetify/tsconfig.dist.json b/packages/vuetify/tsconfig.dist.json index d3ed99e75ef..0eccfe9e486 100644 --- a/packages/vuetify/tsconfig.dist.json +++ b/packages/vuetify/tsconfig.dist.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "exclude": ["dev", "**/*.spec.*", "cypress"] + "exclude": ["dev", "**/*.spec.*", "test"] } diff --git a/packages/vuetify/tsconfig.json b/packages/vuetify/tsconfig.json index f6190fddd56..71a3cb7a635 100644 --- a/packages/vuetify/tsconfig.json +++ b/packages/vuetify/tsconfig.json @@ -2,23 +2,21 @@ "extends": "../../tsconfig.json", "include": [ "src", - "dev" + "dev", ], - "exclude": ["types-temp"], + "exclude": ["types-temp", "**/*.spec.cy.ts", "**/*.spec.cy.tsx"], "compilerOptions": { "baseUrl": ".", "outDir": "./types-temp", "paths": { - "@/*": [ - "src/*" - ], - "types": [ - "jest", - "node", - "vue-router" - ] + "@/*": ["src/*"], + "@test": ["test/index.ts"] }, + "types": [ + "node", + "vue-router" + ], "stripInternal": true, - "skipLibCheck": false, + "skipLibCheck": false } } diff --git a/packages/vuetify/types/cypress.d.ts b/packages/vuetify/types/cypress.d.ts deleted file mode 100644 index c578b2b0af8..00000000000 --- a/packages/vuetify/types/cypress.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -import 'cypress-file-upload' -import 'cypress-real-events' -import type { mount as cyMount } from 'cypress/vue' -import type { SnapshotOptions } from '@percy/core' -import type { MountingOptions, VueWrapper } from '@vue/test-utils' -import type { AllowedComponentProps, ComponentPublicInstance, DefineSetupFnComponent, FunctionalComponent, VNodeProps } from 'vue' -import type { VuetifyOptions } from '@/framework' - -type Swipe = number[] | string - -type StripProps = keyof VNodeProps | keyof AllowedComponentProps | 'v-slots' | '$children' | `v-slot:${string}` -type Events = T extends { $props: infer P extends object } - ? { - [K in Exclude as K extends `on${infer N}` - ? Uncapitalize - : never - ]: P[K] extends (((...args: any[]) => any) | undefined) - ? Parameters>[] - : never - } - : never - -declare global { - namespace Cypress { - export interface Chainable { - mount: typeof cyMount & ( - (component: FunctionalComponent, options?: MountingOptions | null, vuetifyOptions?: VuetifyOptions) => Chainable - ) & ( - (component: JSX.Element, options?: MountingOptions | null, vuetifyOptions?: VuetifyOptions) => Chainable - ) - setProps (props: Record): Chainable> - getBySel (dataTestAttribute: string, args?: any): Chainable - percySnapshot ( - name?: string, - options?: SnapshotOptions - ): Chainable - vue (): Chainable> - swipe (...path: Swipe[]): Chainable - emitted any, E extends Events>, K extends keyof E> ( - selector: T, - event?: K - ): Chainable - } - } -} - -declare module 'cypress/vue' { - export function mount (component: JSX.Element, options?: MountingOptions | null): Cypress.Chainable -} diff --git a/packages/vuetify/vite.config.mts b/packages/vuetify/vite.config.mts index 87f760be536..06ba4e9b222 100644 --- a/packages/vuetify/vite.config.mts +++ b/packages/vuetify/vite.config.mts @@ -7,7 +7,6 @@ import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' import vueJsx from '@vitejs/plugin-vue-jsx' -import viteSSR from 'vite-ssr/plugin.js' import Components from 'unplugin-vue-components/vite' import { warmup } from 'vite-plugin-warmup' @@ -26,6 +25,8 @@ const map = new Map(components.flatMap(file => { return Array.from(matches, m => [m[1] || m[2], file.replace('src/', '@/').replace('.ts', '')]) })) +const viteSSR = process.env.TEST ? () => null : (await import('vite-ssr/plugin.js').then(m => m.default)) + export default defineConfig(({ mode }) => { Object.assign(process.env, loadEnv(mode, process.cwd(), '')) @@ -33,8 +34,8 @@ export default defineConfig(({ mode }) => { root: resolve('dev'), server: { host: process.env.HOST, - port: process.env.CYPRESS ? undefined : +(process.env.PORT ?? 8090), - strictPort: !!process.env.PORT && !process.env.CYPRESS, + port: process.env.TEST ? undefined : +(process.env.PORT ?? 8090), + strictPort: !!process.env.PORT && !process.env.TEST, }, preview: { host: process.env.HOST, @@ -53,7 +54,7 @@ export default defineConfig(({ mode }) => { vueJsx({ optimize: false, enableObjectSlots: false }), viteSSR(), Components({ - dts: !process.env.CYPRESS, + dts: !process.env.TEST, resolvers: [ name => { if (map.has(name)) { @@ -64,12 +65,7 @@ export default defineConfig(({ mode }) => { ], }), warmup({ - clientFiles: process.env.CYPRESS ? [ - './src/**/*.spec.cy.{js,jsx,ts,tsx}', - './cypress/support/index.ts', - ] : [ - './dev/index.html', - ], + clientFiles: process.env.TEST ? [] : ['./dev/index.html'], }), ], define: { diff --git a/packages/vuetify/vitest.config.mts b/packages/vuetify/vitest.config.mts index 3ad0356b2a6..18aac633fc7 100644 --- a/packages/vuetify/vitest.config.mts +++ b/packages/vuetify/vitest.config.mts @@ -1,39 +1,58 @@ import { defineConfig, mergeConfig } from 'vitest/config' import viteConfig from './vite.config.mjs' import AutoImport from 'unplugin-auto-import/vite' +import { fileURLToPath } from 'url' -export default defineConfig(configEnv => mergeConfig( - viteConfig(configEnv), - defineConfig({ - root: './src', - plugins: [ - AutoImport({ - imports: { - vitest: [ - 'describe', - 'it', - 'expect', - 'assert', - 'vi', - 'beforeAll', - 'afterAll', - 'beforeEach', - 'afterEach', - ], +const IS_RUN = process.argv.slice(2).some(v => v === 'run') + +export default defineConfig(configEnv => { + return mergeConfig( + viteConfig(configEnv), + defineConfig({ + root: './src', + resolve: { + alias: { + vue: 'vue/dist/vue.esm-bundler.js', + '@test': fileURLToPath(new URL('test/index.ts', import.meta.url)), + }, + }, + optimizeDeps: { + exclude: ['@vue/test-utils'], + }, + plugins: [ + AutoImport({ + include: '**/*.spec.?(browser.)@(ts|tsx)', + imports: { + vitest: [ + 'describe', + 'it', + 'expect', + 'assert', + 'vi', + 'beforeAll', + 'afterAll', + 'beforeEach', + 'afterEach', + ], + }, + dts: true, + }), + ], + server: { + hmr: false, + preTransformRequests: false, + }, + clearScreen: !IS_RUN, + test: { + watch: false, + setupFiles: ['../test/setup/to-have-been-warned.ts'], + reporters: process.env.GITHUB_ACTIONS ? ['basic', 'github-actions'] : [IS_RUN ? 'dot' : 'basic'], + coverage: { + provider: 'v8', + reporter: ['html'], + clean: true, }, - dts: true, - }), - ], - test: { - watch: false, - environment: 'jsdom', - setupFiles: ['../test/index.ts'], - reporters: process.env.GITHUB_ACTIONS ? ['dot', 'github-actions'] : ['dot'], - coverage: { - provider: 'v8', - reporter: ['html'], - clean: true, }, - }, - }) -)) + }) + ) +}) diff --git a/packages/vuetify/vitest.workspace.mts b/packages/vuetify/vitest.workspace.mts new file mode 100644 index 00000000000..70feb820b16 --- /dev/null +++ b/packages/vuetify/vitest.workspace.mts @@ -0,0 +1,43 @@ +import { defineWorkspace } from 'vitest/config' +import { commands } from './test/setup/browser-commands.ts' + +export default defineWorkspace([ + { + extends: './vitest.config.mts', + test: { + name: 'unit', + include: ['**/*.spec.{ts,tsx}'], + setupFiles: ['../test/setup/unit-setup.ts'], + environment: 'jsdom', + }, + }, + { + extends: './vitest.config.mts', + test: { + name: 'browser', + include: ['**/*.spec.browser.{ts,tsx}'], + setupFiles: ['../test/setup/browser-setup.ts'], + bail: process.env.TEST_BAIL ? 1 : undefined, + browser: { + enabled: true, + provider: 'webdriverio', + name: 'chrome', + ui: false, + headless: !process.env.TEST_BAIL, + commands, + viewport: { + width: 1280, + height: 800, + }, + providerOptions: { + capabilities: { + 'goog:chromeOptions': { + // @ts-ignore + args: ['--start-maximized', process.env.BAIL && '--auto-open-devtools-for-tabs'].filter(v => !!v), + }, + }, + }, + }, + }, + }, +]) diff --git a/patches/@testing-library__vue.patch b/patches/@testing-library__vue.patch new file mode 100644 index 00000000000..1d6195da5eb --- /dev/null +++ b/patches/@testing-library__vue.patch @@ -0,0 +1,39 @@ +diff --git a/dist/render.js b/dist/render.js +index 948b5b112ddb6a86516955d45d70791960e22676..47c757c2af9eab0cf9b66f96a7d5038751065551 100644 +--- a/dist/render.js ++++ b/dist/render.js +@@ -43,6 +43,9 @@ function render(Component) { + return _objectSpread({ + container, + baseElement, ++ wrapper, ++ element: wrapper.element, ++ vm: wrapper.vm, + debug: function debug() { + var el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : baseElement; + var maxLength = arguments.length > 1 ? arguments[1] : undefined; +diff --git a/types/index.d.ts b/types/index.d.ts +index d4edc3bfe9aa77e5ffb39c20d172d0d56aa625b6..9e749cfc116ee78bc8250f28988027921e968f79 100644 +--- a/types/index.d.ts ++++ b/types/index.d.ts +@@ -1,8 +1,8 @@ + // Minimum TypeScript Version: 4.0 + /* eslint-disable @typescript-eslint/no-explicit-any */ + +-import {VNodeChild} from 'vue' +-import {MountingOptions} from '@vue/test-utils' ++import {ComponentPublicInstance, VNodeChild} from 'vue' ++import {MountingOptions, VueWrapper} from '@vue/test-utils' + import {queries, EventType, BoundFunctions} from '@testing-library/dom' + // eslint-disable-next-line import/no-extraneous-dependencies + import {OptionsReceived as PrettyFormatOptions} from 'pretty-format' +@@ -23,6 +23,9 @@ type Debug = ( + export interface RenderResult extends BoundFunctions { + container: Element + baseElement: Element ++ element: Element ++ wrapper: VueWrapper ++ vm: ComponentPublicInstance + debug: Debug + unmount(): void + html(): string diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 294fb4bba99..c01138f480f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,8 @@ settings: excludeLinksFromLockfile: false overrides: + '@testing-library/dom': npm:@vuetify/testing-library-dom@1.0.2 + '@types/node': 22.5.4 tough-cookie: 5.0.0-rc.4 pnpmfileChecksum: hdycaw5dzspbcs5sui7ue3czcu @@ -13,6 +15,9 @@ patchedDependencies: '@mdi/js@7.4.47': hash: wt4lkgr52gphla2wb445bnli3i path: patches/@mdi__js@7.4.47.patch + '@testing-library/vue': + hash: 3limad3b7od6m3nrz2f3jnaixy + path: patches/@testing-library__vue.patch importers: @@ -161,10 +166,10 @@ importers: version: 2.0.1 vite-plugin-inspect: specifier: ^0.8.3 - version: 0.8.3(rollup@4.14.1)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 0.8.3(rollup@4.21.2)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-warmup: specifier: ^0.1.0 - version: 0.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 0.1.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vue: specifier: ^3.4.27 version: 3.4.27(typescript@5.5.4) @@ -295,7 +300,7 @@ importers: version: 4.3.3 '@intlify/unplugin-vue-i18n': specifier: ^4.0.0 - version: 4.0.0(rollup@4.14.1)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4))) + version: 4.0.0(rollup@4.21.2)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4))) '@mdi/js': specifier: 7.4.47 version: 7.4.47(patch_hash=wt4lkgr52gphla2wb445bnli3i) @@ -322,10 +327,10 @@ importers: version: 1.26.3 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 1.1.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) '@vitejs/plugin-vue': specifier: ^5.0.4 - version: 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + version: 5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) '@vue/compiler-sfc': specifier: ^3.4.27 version: 3.4.27 @@ -334,10 +339,10 @@ importers: version: link:../api-generator '@yankeeinlondon/builder-api': specifier: ^1.4.1 - version: 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) ajv: specifier: ^8.12.0 - version: 8.12.0 + version: 8.17.1 algoliasearch-helper: specifier: ^3.22.3 version: 3.22.3(algoliasearch@4.23.3) @@ -355,10 +360,10 @@ importers: version: 4.0.2 jest: specifier: ^28.1.3 - version: 28.1.3(@types/node@20.12.7) + version: 28.1.3(@types/node@22.5.4) jest-runner-eslint: specifier: ^2.2.0 - version: 2.2.0(@jest/test-result@28.1.3)(eslint@8.57.0)(jest-runner@28.1.3)(jest@28.1.3(@types/node@20.12.7)) + version: 2.2.0(@jest/test-result@28.1.3)(eslint@8.57.0)(jest-runner@28.1.3)(jest@28.1.3(@types/node@22.5.4)) jest-silent-reporter: specifier: ^0.5.0 version: 0.5.0 @@ -394,31 +399,31 @@ importers: version: 0.39.0 unplugin-auto-import: specifier: 0.17.5 - version: 0.17.5(rollup@4.14.1) + version: 0.17.5(rollup@4.21.2) unplugin-fonts: specifier: 1.0.3 - version: 1.0.3(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 1.0.3(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) unplugin-vue-components: specifier: ^0.27.4 - version: 0.27.4(@babel/parser@7.25.6)(rollup@4.14.1)(vue@3.4.27(typescript@5.5.4)) + version: 0.27.4(@babel/parser@7.25.6)(rollup@4.21.2)(vue@3.4.27(typescript@5.5.4)) vite: - specifier: ^5.4.0 - version: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + specifier: ^5.4.3 + version: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vite-plugin-md: specifier: ^0.21.5 - version: 0.21.5(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 0.21.5(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-pages: specifier: ^0.32.1 - version: 0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-pwa: specifier: ^0.17.4 - version: 0.17.5(@types/babel__core@7.1.19)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + version: 0.17.5(@types/babel__core@7.1.19)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) vite-plugin-vue-layouts: specifier: ^0.11.0 - version: 0.11.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) + version: 0.11.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) vite-plugin-vuetify: specifier: ^2.0.4 - version: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify) + version: 2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify) vue-tsc: specifier: ^2.0.29 version: 2.0.29(typescript@5.5.4) @@ -433,7 +438,7 @@ importers: version: 3.0.0(date-fns@3.6.0) '@date-io/dayjs': specifier: ^3.0.0 - version: 3.0.0(dayjs@1.10.4) + version: 3.0.0 '@formatjs/intl': specifier: ^2.10.1 version: 2.10.1(typescript@5.5.4) @@ -447,11 +452,11 @@ importers: specifier: ^3.0.6 version: 3.0.6(@fortawesome/fontawesome-svg-core@6.5.2)(vue@3.4.27(typescript@5.5.4)) '@percy/cli': - specifier: ^1.28.2 - version: 1.28.2(typescript@5.5.4) - '@percy/cypress': - specifier: ^3.1.2 - version: 3.1.2(cypress@13.7.2) + specifier: ^1.29.3 + version: 1.29.3(typescript@5.5.4) + '@percy/sdk-utils': + specifier: ^1.29.3 + version: 1.29.3 '@rollup/plugin-alias': specifier: ^5.1.0 version: 5.1.0(rollup@3.29.4) @@ -464,21 +469,36 @@ importers: '@rollup/plugin-typescript': specifier: ^11.1.6 version: 11.1.6(rollup@3.29.4)(tslib@2.6.2)(typescript@5.5.4) + '@testing-library/dom': + specifier: npm:@vuetify/testing-library-dom@1.0.2 + version: '@vuetify/testing-library-dom@1.0.2' + '@testing-library/user-event': + specifier: ^14.5.2 + version: 14.5.2(@vuetify/testing-library-dom@1.0.2) + '@testing-library/vue': + specifier: ^8.1.0 + version: 8.1.0(patch_hash=3limad3b7od6m3nrz2f3jnaixy)(@vue/compiler-sfc@3.4.27)(vue@3.4.27(typescript@5.5.4)) '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: 22.5.4 + version: 22.5.4 '@types/resize-observer-browser': specifier: ^0.1.11 version: 0.1.11 '@vitejs/plugin-vue': specifier: ^5.0.4 - version: 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + version: 5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) '@vitejs/plugin-vue-jsx': specifier: ^3.1.0 - version: 3.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + version: 3.1.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + '@vitest/browser': + specifier: ^2.1.1 + version: 2.1.1(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vitest@2.1.1)(webdriverio@8.40.5(encoding@0.1.13)) '@vitest/coverage-v8': - specifier: ^2.0.5 - version: 2.0.5(vitest@2.0.5(@types/node@20.12.7)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + specifier: ^2.1.1 + version: 2.1.1(@vitest/browser@2.1.1(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vitest@2.1.1)(webdriverio@8.40.5(encoding@0.1.13)))(vitest@2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + '@vitest/ui': + specifier: ^2.1.1 + version: 2.1.1(vitest@2.1.1) '@vue/babel-plugin-jsx': specifier: ^1.2.2 version: 1.2.2(@babel/core@7.25.2) @@ -493,7 +513,7 @@ importers: version: 8.3.2 autoprefixer: specifier: ^10.4.19 - version: 10.4.19(postcss@8.4.40) + version: 10.4.19(postcss@8.4.45) babel-plugin-add-import-extension: specifier: 1.5.1 version: 1.5.1(@babel/core@7.25.2) @@ -511,34 +531,25 @@ importers: version: 8.2.2 cssnano: specifier: ^6.1.2 - version: 6.1.2(postcss@8.4.40) + version: 6.1.2(postcss@8.4.45) csstype: specifier: ^3.1.3 version: 3.1.3 cy-mobile-commands: specifier: ^0.3.0 version: 0.3.0 - cypress: - specifier: ^13.7.2 - version: 13.7.2 - cypress-file-upload: - specifier: ^5.0.8 - version: 5.0.8(cypress@13.7.2) - cypress-real-events: - specifier: ^1.12.0 - version: 1.12.0(cypress@13.7.2) date-fns: specifier: ^3.6.0 version: 3.6.0 dotenv: specifier: ^16.4.5 version: 16.4.5 - eslint-plugin-cypress: - specifier: ^2.15.1 - version: 2.15.1(eslint@8.57.0) eslint-plugin-jest: specifier: ^28.7.0 - version: 28.7.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@28.1.3(@types/node@20.12.7))(typescript@5.5.4) + version: 28.7.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@28.1.3(@types/node@22.5.4))(typescript@5.5.4) + eslint-plugin-vitest: + specifier: 0.4.1 + version: 0.4.1(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)(vitest@2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) expect: specifier: ^28.1.3 version: 28.1.3 @@ -553,10 +564,13 @@ importers: version: 25.0.0 micromatch: specifier: ^4.0.5 - version: 4.0.5 + version: 4.0.8 postcss: specifier: ^8.4.38 - version: 8.4.40 + version: 8.4.45 + roboto-fontface: + specifier: ^0.10.0 + version: 0.10.0 rollup: specifier: ^3.20.7 version: 3.29.4 @@ -568,7 +582,7 @@ importers: version: 1.12.21(rollup@3.29.4) rollup-plugin-sourcemaps: specifier: ^0.6.3 - version: 0.6.3(@types/node@20.12.7)(rollup@3.29.4) + version: 0.6.3(@types/node@22.5.4)(rollup@3.29.4) rollup-plugin-terser: specifier: ^7.0.2 version: 7.0.2(rollup@3.29.4) @@ -585,20 +599,23 @@ importers: specifier: ^2.0.1 version: 2.0.1 vite: - specifier: ^5.4.0 - version: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + specifier: ^5.4.3 + version: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vite-ssr: specifier: ^0.17.1 - version: 0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) + version: 0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)) vitest: - specifier: ^2.0.5 - version: 2.0.5(@types/node@20.12.7)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + specifier: ^2.1.1 + version: 2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue-i18n: specifier: ^9.7.1 version: 9.11.1(vue@3.4.27(typescript@5.5.4)) vue-router: specifier: ^4.3.0 version: 4.3.0(vue@3.4.27(typescript@5.5.4)) + webdriverio: + specifier: ^8.40.5 + version: 8.40.5(encoding@0.1.13) packages: @@ -1288,15 +1305,17 @@ packages: '@bufbuild/protobuf@1.10.0': resolution: {integrity: sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==} - '@cosmicjs/sdk@1.0.11': - resolution: {integrity: sha512-Zm53TsyAGg2ytsJaBf06NcFA5FVG+tc39ZAYQgANi3uLkojnZFWGCIkwHVAn7CYVBac8dPF4tt0U6pYWNAA+Pg==} + '@bundled-es-modules/cookie@2.0.0': + resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==} - '@cypress/request@3.0.1': - resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==} - engines: {node: '>= 6'} + '@bundled-es-modules/statuses@1.0.1': + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} - '@cypress/xvfb@1.2.4': - resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + '@bundled-es-modules/tough-cookie@0.1.6': + resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + + '@cosmicjs/sdk@1.0.11': + resolution: {integrity: sha512-Zm53TsyAGg2ytsJaBf06NcFA5FVG+tc39ZAYQgANi3uLkojnZFWGCIkwHVAn7CYVBac8dPF4tt0U6pYWNAA+Pg==} '@date-io/core@3.0.0': resolution: {integrity: sha512-S3j+IAQVBYNkQzchVVhX40eBkGDreBpScy9RXwTS5j2+k07+62pMVPisQ44Gq76Rqy5AOG/EZXCwBpY/jbemvA==} @@ -1709,6 +1728,22 @@ packages: resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} engines: {node: '>=6.9.0'} + '@inquirer/confirm@3.2.0': + resolution: {integrity: sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==} + engines: {node: '>=18'} + + '@inquirer/core@9.1.0': + resolution: {integrity: sha512-RZVfH//2ytTjmaBIzeKT1zefcQZzuruwkpTwwbe/i2jTl4o9M+iML5ChULzz6iw1Ok8iUBBsRCjY2IEbD8Ft4w==} + engines: {node: '>=18'} + + '@inquirer/figures@1.0.5': + resolution: {integrity: sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==} + engines: {node: '>=18'} + + '@inquirer/type@1.5.3': + resolution: {integrity: sha512-xUQ14WQGR/HK5ei+2CvgcwoH9fQ4PgPGmVFSN0pc1+fVyDL3MREhyAY7nxEErSu6CkllBM3D7e3e+kOvtu+eIg==} + engines: {node: '>=18'} + '@intlify/bundle-utils@8.0.0': resolution: {integrity: sha512-1B++zykRnMwQ+20SpsZI1JCnV/YJt9Oq7AGlEurzkWJOFtFAVqaGc/oV36PBRYeiKnTbY9VYfjBimr2Vt42wLQ==} engines: {node: '>= 14.16'} @@ -1874,6 +1909,10 @@ packages: '@mdi/svg@7.4.47': resolution: {integrity: sha512-WQ2gDll12T9WD34fdRFgQVgO8bag3gavrAgJ0frN4phlwdJARpE6gO1YvLEMJR0KKgoc+/Ea/A0Pp11I00xBvw==} + '@mswjs/interceptors@0.29.1': + resolution: {integrity: sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==} + engines: {node: '>=18'} + '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} @@ -2115,74 +2154,78 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} - '@percy/cli-app@1.28.2': - resolution: {integrity: sha512-UhuxmBRcgeyBnzV7ixiSqUlMdcBg7LyrTtDJWEjQ36SH0jJOAVu020cGcPLNDDTmqXDU7DsDoNifxtPzXT+d5w==} + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + + '@percy/cli-app@1.29.3': + resolution: {integrity: sha512-7yGEDFIRLMsJ6nzl6aMem9nMj5rfkxODEQIciuIcuao5ZD1x23KhuN3u4QLLwQFOFgy7h4WAePnUTCR6ZtpGCQ==} engines: {node: '>=14'} - '@percy/cli-build@1.28.2': - resolution: {integrity: sha512-VWfrgcOaN6rxSCwifQ5aJuGQDU2Nmq3lvvqZsVVSj3lBbE4KsEaxyoH2Hmm2pCOXi1DzOQ0+zHv+Ra+m4CyBvA==} + '@percy/cli-build@1.29.3': + resolution: {integrity: sha512-fvDr4mUFIG/TQmMWnzQqWi2ga57SWPzXwlh65a4/0PPRKo0dKybFhvZvhCFYhcnVWqXEVYRHM21/oUvFhgnsCw==} engines: {node: '>=14'} - '@percy/cli-command@1.28.2': - resolution: {integrity: sha512-UUa+dSpzTcXVjzvElL4wD315QYDuGrbnXObgaztyGWdufEbvLWflU4AiQZrxC5abDXQdNWQUAAizorA5dGhaCg==} + '@percy/cli-command@1.29.3': + resolution: {integrity: sha512-jSltYf97E5u4jjTaW6gLU+5T/sRBwS0RlvraE21gKa0N9SH1l5nWs4YFfsIwamYg3EnCmIrwAf0gupQcQgAuaA==} engines: {node: '>=14'} hasBin: true - '@percy/cli-config@1.28.2': - resolution: {integrity: sha512-O1O2n16jOm6HCzGM207/NbX+IR7ezUaQGnExi4G5SbOYqZeBIrsKpbEi/SERBfg4Kexv16LrF6NLOs75N2oaSw==} + '@percy/cli-config@1.29.3': + resolution: {integrity: sha512-lVrOqeS1ACaQp9tM4LE7joW/cuGaSJcM/182ci5D3Zr9Yz6Ik/oe1MQnIM9dqnsHmnwasuGBsICsflbVqqcXHQ==} engines: {node: '>=14'} - '@percy/cli-exec@1.28.2': - resolution: {integrity: sha512-tRvmoDJMb94XjA60a0lmN2XphzC/r70ruic+VfhFwEqDVoLY/6LxqjSXjehiSD5huXYDyPtaMeJo7oU1FxJyZg==} + '@percy/cli-exec@1.29.3': + resolution: {integrity: sha512-AfZ2hI/snahjgXHuI0bKhRLJoEOfod8Uph6fu1UdjI2r6gacgBurvJmrwZOT5yChp2i8+B99e+qFqWNUi9AI7Q==} engines: {node: '>=14'} - '@percy/cli-snapshot@1.28.2': - resolution: {integrity: sha512-Qda4MKjKxoM/TEBjl54lCXMJAmQB6ZZheE96pJzEJzlPQtlj9r/moM3etCV+res0qaSOgx9BL0DncruvAwM/4g==} + '@percy/cli-snapshot@1.29.3': + resolution: {integrity: sha512-5buoW+tSdfCu0Df7LYzOpjJlb9u+4aCTDrYlmwBcyEVUq01E39LN1kRWCYL6jU/APNB+ybUKtLr9w0RtcPDYTQ==} engines: {node: '>=14'} - '@percy/cli-upload@1.28.2': - resolution: {integrity: sha512-vzH4wRdAFGvktNlh57p4s9Qq+rT0MsiQ/kh7pDvzQ1lJ6glpCBXSiiahMtkR8AP8gMMzxYONAuV/htB/t8sFUw==} + '@percy/cli-upload@1.29.3': + resolution: {integrity: sha512-KYAtcAzE50lbZ8NTqao/GSVurESUi2iQFCJ0zRwEccxViOJy/dfb5j1i10VPlqP5glCZS+eXXY2YYoxjxVCz3w==} engines: {node: '>=14'} - '@percy/cli@1.28.2': - resolution: {integrity: sha512-hwibBu6zsjfWXIe8WFgrKizGjxkTzYcGQ4eOPcMQXfgK3yUZ24N5v8sqCOobRA/SbdD117zp2WUEkBRWCJ85gg==} + '@percy/cli@1.29.3': + resolution: {integrity: sha512-j+LEHQrrtQV0uOe1u38U6RExPl86rwof+qWtkV8cOvPwucAo0DmeVfperLhZFIU/qrZjA9lHkDdYHZyzRndOBw==} engines: {node: '>=14'} hasBin: true - '@percy/client@1.28.2': - resolution: {integrity: sha512-UoQ4WY8zJhwv/7vKJS+1vbeu/T7YckSmOp/moCoAnHY6QOIXYs7EGkNyeEw5iXoQYzMw6KkkLYPC7YC0rt5pSg==} + '@percy/client@1.29.3': + resolution: {integrity: sha512-BTP/wfgs2/Hjj650tGmp+jkATEIOdNNZFZSRWPXGXF+PFG4zK5jTejBEZlBl3NUqhwMqtfLX/uyvsfKFaWfYDA==} engines: {node: '>=14'} - '@percy/config@1.28.2': - resolution: {integrity: sha512-Q9NoenDuhRiY+eBGrw8FJmmU8hErTsjBxccUOvrfn0A4JXRvcFHitvrh85rXG/HhyT4bcoB9O93QhV6F9KTq7A==} + '@percy/config@1.29.3': + resolution: {integrity: sha512-Jk79XGpiCNI7gmdCoWkn5V7HVa6FFfcYvFg3H1OMd2BqZEDKkPq9bbk0e4AZ93xc2BOjmYWHHj69w7VCu1peug==} engines: {node: '>=14'} - '@percy/core@1.28.2': - resolution: {integrity: sha512-7JkZrsLoHDD2bkhN4u5T/+0sC0UT73Lv1qF3lIMLu+Qjt1BhyKdnitbOnjFlrVOwqC5uNgr7/gvcULLVbJga8Q==} + '@percy/core@1.29.3': + resolution: {integrity: sha512-5RwQyezq/i4fqSMeoKJole/kZ7n7lABITS6py2e9een6svNFRKI8VqWBlMuFsL50Z5mUcbSJDhIl8O8NbIpdwQ==} engines: {node: '>=14'} - '@percy/cypress@3.1.2': - resolution: {integrity: sha512-JXrGDZbqwkzQd2h5T5D7PvqoucNaiMh4ChPp8cLQiEtRuLHta9nf1lEuXH+jnatGL2j+3jJFIHJ0L7XrgVnvQA==} - peerDependencies: - cypress: '>=3' - - '@percy/dom@1.28.2': - resolution: {integrity: sha512-bUU38EMowO+y+pnLzl0naikv0pVQvcrkrBm7K7eVGUt6orRTqr5Tr8bMV7Ooac4mlMwaZvCkAH7gPhiDAONUmw==} + '@percy/dom@1.29.3': + resolution: {integrity: sha512-wz5PV5IW/ooYTmeiq4qFDWyZrVoyp4x+cOQ4ndYStDMkiFMnN5zvvqJlSsUOJ9/YKh/BeMn+ed8hlfKOWW3zEQ==} - '@percy/env@1.28.2': - resolution: {integrity: sha512-40UhiL5MylFN39pzzoyDKgult2ZmSbuc3ADrNGBx9zyMdFEoTLZg5BcFZoSUHHjPboe2jYZFYrRqoXxix++OfA==} + '@percy/env@1.29.3': + resolution: {integrity: sha512-DwWsnrGWsBQkIuNvw//CNQpyd5LY2rzc6wqB/2GMpVf4iuzKvm5ND55GX8j0FYhf0kJan0aS/+mDKEgZfea1LA==} engines: {node: '>=14'} - '@percy/logger@1.28.2': - resolution: {integrity: sha512-ZF1iDjY9oBL+4WEqGuJ4JJaUdyUqGhdJtS+qDV8iqrQ6VngWBpO3lg0Uhy8RIkqUSLGKbwVbnxkfvA5kXx+yAw==} + '@percy/logger@1.29.3': + resolution: {integrity: sha512-nNslGmznG5ChKHFtPtRFcjAeuG/Zhr1OgRapLLeikyXyxy8bT929kUgBuGh4ADhp95iovcN7zlHQmpuwbOPQ2Q==} engines: {node: '>=14'} - '@percy/sdk-utils@1.28.2': - resolution: {integrity: sha512-cMFz8AjZ2KunN0dVwzA+Wosk4B+6G9dUkh2YPhYvqs0KLcCyYs3s91IzOQmtBOYwAUVja/W/u6XmBHw0jaxg0A==} + '@percy/sdk-utils@1.29.3': + resolution: {integrity: sha512-ITUZinf+50O/Izs/X3HaRxnZvLv4Fw8lV2mSqVD/500au6bApUNeMHnoaAHOC57FgyUOUaYldiAAXNtE/zANtw==} engines: {node: '>=14'} - '@percy/webdriver-utils@1.28.2': - resolution: {integrity: sha512-bD0UoR1/69xcsL2mhvZ4xQKhWJYbqUJUFMiNr8xqR55Z4dArbeN9S2ZYU6aMVRemuKyn7ki0ttNFHq0z2GFvGg==} + '@percy/webdriver-utils@1.29.3': + resolution: {integrity: sha512-+0qyRGKLfYdtzhc9U1m7RCBk6c3+aGy8DPLM6FdlvCrX5+Z93PLLMpoQcXid9cUFFTGAnxOKtYUWS2kc6Q32mg==} engines: {node: '>=14'} '@pkgjs/parseargs@0.11.0': @@ -2192,6 +2235,14 @@ packages: '@polka/url@1.0.0-next.25': resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + '@promptbook/utils@0.70.0-1': + resolution: {integrity: sha512-qd2lLRRN+sE6UuNMi2tEeUUeb4zmXnxY5EMdfHVXNE+bqBDpUC7/aEfXgA3jnUXEr+xFjQ8PTFQgWvBMaKvw0g==} + + '@puppeteer/browsers@1.9.1': + resolution: {integrity: sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==} + engines: {node: '>=16.3.0'} + hasBin: true + '@rollup/plugin-alias@5.1.0': resolution: {integrity: sha512-lpA3RZ9PdIG7qqhEfv79tBffNaoDuukFDrmhLqg9ifv99u/ehn+lOg30x2zmhf8AQqQUZaMk/B9fZraQ6/acDQ==} engines: {node: '>=14.0.0'} @@ -2278,78 +2329,83 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.14.1': - resolution: {integrity: sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==} + '@rollup/rollup-android-arm-eabi@4.21.2': + resolution: {integrity: sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.14.1': - resolution: {integrity: sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==} + '@rollup/rollup-android-arm64@4.21.2': + resolution: {integrity: sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.14.1': - resolution: {integrity: sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==} + '@rollup/rollup-darwin-arm64@4.21.2': + resolution: {integrity: sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.14.1': - resolution: {integrity: sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==} + '@rollup/rollup-darwin-x64@4.21.2': + resolution: {integrity: sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.14.1': - resolution: {integrity: sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==} + '@rollup/rollup-linux-arm-gnueabihf@4.21.2': + resolution: {integrity: sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.21.2': + resolution: {integrity: sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.14.1': - resolution: {integrity: sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==} + '@rollup/rollup-linux-arm64-gnu@4.21.2': + resolution: {integrity: sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.14.1': - resolution: {integrity: sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==} + '@rollup/rollup-linux-arm64-musl@4.21.2': + resolution: {integrity: sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.14.1': - resolution: {integrity: sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==} - cpu: [ppc64le] + '@rollup/rollup-linux-powerpc64le-gnu@4.21.2': + resolution: {integrity: sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==} + cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.14.1': - resolution: {integrity: sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==} + '@rollup/rollup-linux-riscv64-gnu@4.21.2': + resolution: {integrity: sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.14.1': - resolution: {integrity: sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==} + '@rollup/rollup-linux-s390x-gnu@4.21.2': + resolution: {integrity: sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.14.1': - resolution: {integrity: sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==} + '@rollup/rollup-linux-x64-gnu@4.21.2': + resolution: {integrity: sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.14.1': - resolution: {integrity: sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==} + '@rollup/rollup-linux-x64-musl@4.21.2': + resolution: {integrity: sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.14.1': - resolution: {integrity: sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==} + '@rollup/rollup-win32-arm64-msvc@4.21.2': + resolution: {integrity: sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.14.1': - resolution: {integrity: sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==} + '@rollup/rollup-win32-ia32-msvc@4.21.2': + resolution: {integrity: sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.14.1': - resolution: {integrity: sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==} + '@rollup/rollup-win32-x64-msvc@4.21.2': + resolution: {integrity: sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==} cpu: [x64] os: [win32] @@ -2387,6 +2443,10 @@ packages: resolution: {integrity: sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==} engines: {node: '>=4'} + '@sindresorhus/is@5.6.0': + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + '@sinonjs/commons@1.8.1': resolution: {integrity: sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==} @@ -2396,6 +2456,29 @@ packages: '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} + '@szmarczak/http-timer@5.0.1': + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + + '@testing-library/user-event@14.5.2': + resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': npm:@vuetify/testing-library-dom@1.0.2 + + '@testing-library/vue@8.1.0': + resolution: {integrity: sha512-ls4RiHO1ta4mxqqajWRh8158uFObVrrtAPoxk7cIp4HrnQUj/ScKzqz53HxYpG3X6Zb7H2v+0eTGLSoy8HQ2nA==} + engines: {node: '>=14'} + peerDependencies: + '@vue/compiler-sfc': '>= 3' + vue: '>= 3' + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -2414,6 +2497,9 @@ packages: '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/babel__core@7.1.19': resolution: {integrity: sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==} @@ -2429,6 +2515,9 @@ packages: '@types/color-name@1.1.1': resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -2450,6 +2539,9 @@ packages: '@types/hogan.js@3.0.1': resolution: {integrity: sha512-D03i/2OY7kGyMq9wdQ7oD8roE49z/ZCZThe/nbahtvuqCNZY9T2MfedOWyeBdbEpY2W8Gnh/dyJLdFtUCOkYbg==} + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@types/istanbul-lib-coverage@2.0.3': resolution: {integrity: sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==} @@ -2495,8 +2587,11 @@ packages: '@types/ms@0.7.31': resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} - '@types/node@20.12.7': - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + '@types/mute-stream@0.0.4': + resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} + + '@types/node@22.5.4': + resolution: {integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -2525,21 +2620,30 @@ packages: '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - '@types/sinonjs__fake-timers@8.1.1': - resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} - - '@types/sizzle@2.3.2': - resolution: {integrity: sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==} - '@types/stack-utils@2.0.0': resolution: {integrity: sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==} + '@types/statuses@2.0.5': + resolution: {integrity: sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==} + '@types/stringify-object@4.0.5': resolution: {integrity: sha512-TzX5V+njkbJ8iJ0mrj+Vqveep/1JBH4SSA3J2wYrE1eUrOhdsjTBCb0kao4EquSQ8KgPpqY4zSVP2vCPWKBElg==} + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/trusted-types@2.0.2': resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==} + '@types/which@2.0.2': + resolution: {integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==} + + '@types/wrap-ansi@3.0.0': + resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} + + '@types/ws@8.5.12': + resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} + '@types/yargs-parser@15.0.0': resolution: {integrity: sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==} @@ -2549,8 +2653,8 @@ packages: '@types/yargs@17.0.13': resolution: {integrity: sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==} - '@types/yauzl@2.9.1': - resolution: {integrity: sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} '@typescript-eslint/eslint-plugin@7.18.0': resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} @@ -2683,28 +2787,63 @@ packages: vite: ^5.0.0 vue: ^3.2.25 - '@vitest/coverage-v8@2.0.5': - resolution: {integrity: sha512-qeFcySCg5FLO2bHHSa0tAZAOnAUbp4L6/A5JDuj9+bt53JREl8hpLjLHEWF0e/gWc8INVpJaqA7+Ene2rclpZg==} + '@vitest/browser@2.1.1': + resolution: {integrity: sha512-wLKqohwlZI24xMIEZAPwv9SVliv1avaIBeE0ou471D++BRPhiw2mubKBczFFIDHXuSL7UXb8/JQK9Ui6ttW9bQ==} + peerDependencies: + playwright: '*' + safaridriver: '*' + vitest: 2.1.1 + webdriverio: '*' + peerDependenciesMeta: + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + + '@vitest/coverage-v8@2.1.1': + resolution: {integrity: sha512-md/A7A3c42oTT8JUHSqjP5uKTWJejzUW4jalpvs+rZ27gsURsMU8DEb+8Jf8C6Kj2gwfSHJqobDNBuoqlm0cFw==} + peerDependencies: + '@vitest/browser': 2.1.1 + vitest: 2.1.1 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@2.1.1': + resolution: {integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==} + + '@vitest/mocker@2.1.1': + resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==} peerDependencies: - vitest: 2.0.5 + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true - '@vitest/expect@2.0.5': - resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} + '@vitest/pretty-format@2.1.1': + resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==} - '@vitest/pretty-format@2.0.5': - resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} + '@vitest/runner@2.1.1': + resolution: {integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==} - '@vitest/runner@2.0.5': - resolution: {integrity: sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==} + '@vitest/snapshot@2.1.1': + resolution: {integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==} - '@vitest/snapshot@2.0.5': - resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==} + '@vitest/spy@2.1.1': + resolution: {integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==} - '@vitest/spy@2.0.5': - resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} + '@vitest/ui@2.1.1': + resolution: {integrity: sha512-IIxo2LkQDA+1TZdPLYPclzsXukBWd5dX2CKpGqH8CCt8Wh0ZuDn4+vuQ9qlppEju6/igDGzjWF/zyorfsf+nHg==} + peerDependencies: + vitest: 2.1.1 - '@vitest/utils@2.0.5': - resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} + '@vitest/utils@2.1.1': + resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==} '@volar/language-core@2.4.0-alpha.18': resolution: {integrity: sha512-JAYeJvYQQROmVRtSBIczaPjP3DX4QW1fOqW1Ebs0d3Y3EwSNRglz03dSv0Dm61dzd0Yx3WgTW3hndDnTQqgmyg==} @@ -2834,11 +2973,42 @@ packages: vue: ^3.4.0 vuetify: ^3.6.1 + '@vuetify/testing-library-dom@1.0.2': + resolution: {integrity: sha512-tQo3A63uCq2646IhgYLIFugC8HRVyBssvRidzu+iQLkCWSO8ikz9z6tqDU3NjbAxSXxeAFa5x1Nq7VMDxrQ4Lw==} + engines: {node: '>=18'} + '@vueuse/head@1.3.1': resolution: {integrity: sha512-XCcHGfDzkGlHS7KIPJVYN//L7jpfASLsN7MUE19ndHVQLnPIDxqFLDl7IROsY81PKzawVAUe4OYVWcGixseWxA==} peerDependencies: vue: '>=2.7 || >=3' + '@wdio/config@8.40.3': + resolution: {integrity: sha512-HIi+JnHEDAExhzGRQuZOXw1HWIpe/bsVFHwNISJhY6wS4Nijaigmegs2p14Rv16ydOF19hGrxdKsl8k5STIP2A==} + engines: {node: ^16.13 || >=18} + + '@wdio/logger@8.38.0': + resolution: {integrity: sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==} + engines: {node: ^16.13 || >=18} + + '@wdio/logger@9.0.8': + resolution: {integrity: sha512-uIyYIDBwLczmsp9JE5hN3ME8Xg+9WNBfSNXD69ICHrY9WPTzFf94UeTuavK7kwSKF3ro2eJbmNZItYOfnoovnw==} + engines: {node: '>=18.20.0'} + + '@wdio/protocols@8.40.3': + resolution: {integrity: sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==} + + '@wdio/repl@8.40.3': + resolution: {integrity: sha512-mWEiBbaC7CgxvSd2/ozpbZWebnRIc8KRu/J81Hlw/txUWio27S7IpXBlZGVvhEsNzq0+cuxB/8gDkkXvMPbesw==} + engines: {node: ^16.13 || >=18} + + '@wdio/types@8.40.3': + resolution: {integrity: sha512-zK17uyON3Ise3m+XwiF5VrrdZcXXmvqB8AWXoKe88DiksFUPMVoCOuVL2SSX1KnA2YLlZBA55qcFZT99GORVKQ==} + engines: {node: ^16.13 || >=18} + + '@wdio/utils@8.40.3': + resolution: {integrity: sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==} + engines: {node: ^16.13 || >=18} + '@yankeeinlondon/builder-api@1.4.1': resolution: {integrity: sha512-qc6HyfqtuS06FvA5rK0L62Nmc1LnarVOt8/V/mTX2DBZlpTfIDpudpbE/7/kxjme9pP4PFMCk7cPSrprLEorjw==} @@ -2856,6 +3026,10 @@ packages: resolution: {integrity: sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==} engines: {node: '>=14.15.0'} + '@zip.js/zip.js@2.7.52': + resolution: {integrity: sha512-+5g7FQswvrCHwYKNMd/KFxZSObctLSsQOgqBSi0LzwHo3li9Eh1w5cF5ndjQw9Zbr3ajVnd2+XyiX85gAetx1Q==} + engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} + '@zkochan/js-yaml@0.0.7': resolution: {integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==} hasBin: true @@ -2871,6 +3045,10 @@ packages: resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2904,8 +3082,8 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} algoliasearch-helper@3.19.0: resolution: {integrity: sha512-AaSb5DZDMZmDQyIy6lf4aL0OZGgyIdqvLIIvSuVQOIOqfhrYSY7TvotIFI2x0Q3cP3xUpTd7lI1astUC4aXBJw==} @@ -2971,8 +3149,13 @@ packages: aproba@2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} - arch@2.2.0: - resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -2980,6 +3163,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -3037,20 +3223,13 @@ packages: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} engines: {node: '>=8'} - asn1@0.2.4: - resolution: {integrity: sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==} - - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} async-es@3.2.5: resolution: {integrity: sha512-oXGVkIf1wSg34CtmK7js8brsxUZWwMGjNa63YJFY+fDHb6RQQd7N0d7N2yP53VaqvXh5DTPuOl0hH+vDFKPHuQ==} @@ -3081,15 +3260,12 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - - aws4@1.9.1: - resolution: {integrity: sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==} - axios@1.7.2: resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==} + b4a@1.6.6: + resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==} + babel-eslint@10.1.0: resolution: {integrity: sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==} engines: {node: '>=6'} @@ -3159,11 +3335,27 @@ packages: balanced-match@1.0.0: resolution: {integrity: sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==} + bare-events@2.4.2: + resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==} + + bare-fs@2.3.3: + resolution: {integrity: sha512-7RYKL+vZVCyAsMLi5SPu7QGauGGT8avnP/HO571ndEuV4MYdGXvLhtW67FuLPeEI8EiIY7zbbRR9x7x7HU0kgw==} + + bare-os@2.4.2: + resolution: {integrity: sha512-HZoJwzC+rZ9lqEemTMiO0luOePoGYNBgsLLgegKR/cljiJvcDNhDZQkzC+NC5Oh0aHbdBNSOHpghwMuB5tqhjg==} + + bare-path@2.1.3: + resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} + + bare-stream@2.2.1: + resolution: {integrity: sha512-YTB47kHwBW9zSG8LD77MIBAAQXjU2WjAkMHeeb7hUplVs6+IoM5I7uEVQNPMB7lj9r8I76UMdoMkGnCodHOLqg==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} before-after-hook@2.2.2: resolution: {integrity: sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==} @@ -3179,12 +3371,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - blob-util@2.0.2: - resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} - - bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -3194,8 +3380,8 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} brilliant-errors@0.7.3: @@ -3216,12 +3402,19 @@ packages: buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + buffer-from@1.1.1: resolution: {integrity: sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==} buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -3245,13 +3438,17 @@ packages: resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} engines: {node: ^16.14.0 || >=18.0.0} + cacheable-lookup@7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + + cacheable-request@10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + cacheable-request@2.1.4: resolution: {integrity: sha512-vag0O2LKZ/najSoUwDbVlnlCFvhBE/7mGTY2B5FgCBDcRD+oVV1HYTOwM6JZfMg/hIcM6IwnTZ1uQQL5/X3xIQ==} - cachedir@2.3.0: - resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==} - engines: {node: '>=6'} - call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -3310,9 +3507,6 @@ packages: caniuse-lite@1.0.30001646: resolution: {integrity: sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw==} - caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - chai@5.1.1: resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} engines: {node: '>=12'} @@ -3329,6 +3523,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -3343,10 +3541,6 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} - check-more-types@2.24.0: - resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} - engines: {node: '>= 0.8.0'} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -3355,6 +3549,11 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + chromium-bidi@0.5.8: + resolution: {integrity: sha512-blqh+1cEQbHBKmok3rVJkBlBxt9beKBgOsxbFgs7UJcoVbbeZ+K7+6liAsjgpc8l1Xd55cQUy14fXZdGSb4zIw==} + peerDependencies: + devtools-protocol: '*' + ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} @@ -3389,14 +3588,6 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table3@0.6.1: - resolution: {integrity: sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==} - engines: {node: 10.* || >= 12.*} - - cli-truncate@2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} - cli-width@2.2.0: resolution: {integrity: sha512-EJLbKSuvHTrVRynOXCYFTbQKZOFXWNe3/6DN1yrEH3TuuZT1x4dMQnCHnfCrBUUiGjO63enEIfaB17VaRl2d4A==} @@ -3404,6 +3595,10 @@ packages: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -3456,13 +3651,6 @@ packages: colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - - colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - columnify@1.6.0: resolution: {integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==} engines: {node: '>=8.0.0'} @@ -3490,6 +3678,10 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} @@ -3503,6 +3695,10 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + computeds@0.0.1: resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} @@ -3689,6 +3885,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + core-js-compat@3.37.1: resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} @@ -3716,6 +3916,15 @@ packages: typescript: optional: true + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + create-jest-runner@0.11.2: resolution: {integrity: sha512-6lwspphs4M1PLKV9baBNxHQtWVBPZuDU8kAP4MyrVWa6aEpEcpi2HZeeA6WncwaqgsGNXpP0N2STS7XNM/nHKQ==} hasBin: true @@ -3728,6 +3937,9 @@ packages: jest-runner: optional: true + cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + cross-spawn@6.0.5: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} @@ -3749,6 +3961,9 @@ packages: css-select@5.1.0: resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + css-shorthand-properties@1.1.1: + resolution: {integrity: sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==} + css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -3757,6 +3972,9 @@ packages: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-value@0.0.1: + resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} + css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -3805,22 +4023,6 @@ packages: cy-mobile-commands@0.3.0: resolution: {integrity: sha512-Bj5P2ylw88hPqolLu68xWB6euVH5uNt8zyh+Ju8sBukGv39mWZxpjp6LtnUX/LK/YMthwvILYHhvr9SG1TP+4w==} - cypress-file-upload@5.0.8: - resolution: {integrity: sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==} - engines: {node: '>=8.2.1'} - peerDependencies: - cypress: '>3.0.0' - - cypress-real-events@1.12.0: - resolution: {integrity: sha512-oiy+4kGKkzc2PT36k3GGQqkGxNiVypheWjMtfyi89iIk6bYmTzeqxapaLHS3pnhZOX1IEbTDUVxh8T4Nhs1tyQ==} - peerDependencies: - cypress: ^4.x || ^5.x || ^6.x || ^7.x || ^8.x || ^9.x || ^10.x || ^11.x || ^12.x || ^13.x - - cypress@13.7.2: - resolution: {integrity: sha512-FF5hFI5wlRIHY8urLZjJjj/YvfCBrRpglbZCLr/cYcL9MdDe0+5usa8kTIrDHthlEc9lwihbkb5dmwqBDNS2yw==} - engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} - hasBin: true - dargs@4.1.0: resolution: {integrity: sha512-jyweV/k0rbv2WK4r9KLayuBrSh2Py0tNmV7LBoSMH4hMQyrG8OPyIOWB2VEx4DJKXWmK4lopYMVvORlDt2S8Aw==} engines: {node: '>=0.10.0'} @@ -3829,9 +4031,13 @@ packages: resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} engines: {node: '>=8'} - dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} @@ -3859,9 +4065,6 @@ packages: dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} - dayjs@1.10.4: - resolution: {integrity: sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==} - de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} @@ -3881,8 +4084,17 @@ packages: supports-color: optional: true - debug@4.3.6: - resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -3898,6 +4110,10 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} + decamelize@6.0.0: + resolution: {integrity: sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -3909,6 +4125,10 @@ packages: resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} engines: {node: '>=4'} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} @@ -3935,6 +4155,10 @@ packages: deep-is@0.1.3: resolution: {integrity: sha512-GtxAN4HvBachZzm4OnWqc45ESpUCMwkYcsjnsPs23FwJbsO+k4t0k9bQCgOmzIlpHO28+WPK/KRbRk0DDHuuDw==} + deepmerge-ts@5.1.0: + resolution: {integrity: sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw==} + engines: {node: '>=16.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -3950,6 +4174,10 @@ packages: defaults@1.0.3: resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -3966,6 +4194,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -3973,6 +4205,10 @@ packages: deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-indent@5.0.0: resolution: {integrity: sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==} engines: {node: '>=4'} @@ -3981,6 +4217,12 @@ packages: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} + devtools-protocol@0.0.1232444: + resolution: {integrity: sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==} + + devtools-protocol@0.0.1342118: + resolution: {integrity: sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==} + diff-sequences@28.1.1: resolution: {integrity: sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -4001,6 +4243,9 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -4011,8 +4256,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - domutils@3.0.1: - resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} + domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} dot-prop@3.0.0: resolution: {integrity: sha512-k4ELWeEU3uCcwub7+dWydqQBRjAjkV9L33HjVRG5Xo2QybI6ja/v+4W73SRi8ubCqJz0l9XsTP1NbewfyqaSlw==} @@ -4043,8 +4288,13 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + edge-paths@3.0.5: + resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} + engines: {node: '>=14.0.0'} + + edgedriver@5.6.1: + resolution: {integrity: sha512-3Ve9cd5ziLByUdigw6zovVeWJjVs8QHVmqOB0sJ0WNeVPcwf4p18GnxMmVvlFmYRloUwf5suNuorea4QzwBIOA==} + hasBin: true editorconfig@1.0.4: resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} @@ -4235,11 +4485,6 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-cypress@2.15.1: - resolution: {integrity: sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w==} - peerDependencies: - eslint: '>= 3.2.1' - eslint-plugin-es-x@7.5.0: resolution: {integrity: sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -4296,6 +4541,19 @@ packages: peerDependencies: eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint-plugin-vitest@0.4.1: + resolution: {integrity: sha512-+PnZ2u/BS+f5FiuHXz4zKsHPcMKHie+K+1Uvu/x91ovkCMEOJqEI8E9Tw1Wzx2QRz4MHOBHYf1ypO8N1K0aNAA==} + engines: {node: ^18.0.0 || >= 20.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': '*' + eslint: '>=8.0.0' + vitest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + vitest: + optional: true + eslint-plugin-vue@9.24.1: resolution: {integrity: sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==} engines: {node: ^14.17.0 || >=16.0.0} @@ -4363,20 +4621,21 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - eventemitter2@6.4.7: - resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + execa@1.0.0: resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} engines: {node: '>=6'} - execa@4.1.0: - resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} - engines: {node: '>=10'} - execa@5.0.0: resolution: {integrity: sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==} engines: {node: '>=10'} @@ -4385,14 +4644,6 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - executable@4.1.1: - resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} - engines: {node: '>=4'} - exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} @@ -4408,9 +4659,6 @@ packages: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - external-editor@3.0.3: resolution: {integrity: sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==} engines: {node: '>=4'} @@ -4424,17 +4672,15 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true - extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - - extsprintf@1.4.0: - resolution: {integrity: sha512-6NW8DZ8pWBc5NbGYUiqqccj9dXnuSzilZYqprdKJBZsQodGH9IyUoFOGxIWVDcBzHMb8ET24aqx9p66tZEWZkA==} - engines: {'0': node >=0.6.0} + fast-deep-equal@2.0.1: + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -4445,6 +4691,13 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-uri@3.0.1: + resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==} + + fast-xml-parser@4.5.0: + resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} + hasBin: true + fastq@1.8.0: resolution: {integrity: sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==} @@ -4454,6 +4707,18 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fdir@6.3.0: + resolution: {integrity: sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -4472,8 +4737,8 @@ packages: filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} finalhandler@1.1.2: @@ -4512,8 +4777,8 @@ packages: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true - flatted@3.2.2: - resolution: {integrity: sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==} + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} @@ -4531,17 +4796,18 @@ packages: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - - form-data@2.3.3: - resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} - engines: {node: '>= 0.12'} + form-data-encoder@2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + fp-ts@2.16.9: resolution: {integrity: sha512-+I2+FnVB+tVaxcYyQkHUq7ZdKScaBlX53A41mxQtpIccsfyv8PzdzP7fzp2AY832T4aoK6UZ5WRX/ebGd8uZuQ==} @@ -4594,6 +4860,11 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + geckodriver@4.4.4: + resolution: {integrity: sha512-0zaw19tcmWeluqx7+Y559JGBtidu1D0Lb8ElYKiNEQu8r3sCfrLUf5V10xypl8u29ZLbgRV7WflxCJVTCkCMFA==} + engines: {node: ^16.13 || >=18 || >=20} + hasBin: true + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -4633,6 +4904,10 @@ packages: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} + get-port@7.1.0: + resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + engines: {node: '>=16'} + get-stdin@4.0.1: resolution: {integrity: sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==} engines: {node: '>=0.10.0'} @@ -4665,10 +4940,6 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} @@ -4676,11 +4947,9 @@ packages: get-tsconfig@4.7.2: resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} - getos@3.2.1: - resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} - - getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + get-uri@6.0.3: + resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} + engines: {node: '>= 14'} gh-got@7.1.0: resolution: {integrity: sha512-KeWkkhresa7sbpzQLYzITMgez5rMigUsijhmSAHcLDORIMUbdlkdoZyaN1wQvIjmUZnyb/wkAPaXb4MQKX0mdQ==} @@ -4754,10 +5023,6 @@ packages: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} engines: {node: '>=16 || 14 >=14.17'} - global-dirs@3.0.0: - resolution: {integrity: sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==} - engines: {node: '>=10'} - globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -4777,6 +5042,10 @@ packages: gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + got@12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + got@8.3.2: resolution: {integrity: sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==} engines: {node: '>=4'} @@ -4784,6 +5053,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -4845,6 +5117,9 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + hogan.js@3.0.2: resolution: {integrity: sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==} hasBin: true @@ -4887,26 +5162,18 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-signature@1.3.6: - resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==} - engines: {node: '>=0.10'} + http2-wrapper@2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} https-proxy-agent@7.0.5: resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} - human-signals@1.1.1: - resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} - engines: {node: '>=8.12.0'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - husky@3.1.0: resolution: {integrity: sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ==} engines: {node: '>=8.6.0'} @@ -4938,11 +5205,14 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} - image-size@1.0.0: - resolution: {integrity: sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==} - engines: {node: '>=12.0.0'} + image-size@1.1.1: + resolution: {integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==} + engines: {node: '>=16.x'} hasBin: true + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immutable@4.0.0: resolution: {integrity: sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==} @@ -4959,6 +5229,9 @@ packages: engines: {node: '>=8'} hasBin: true + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -4988,10 +5261,6 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@2.0.0: - resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} - engines: {node: '>=10'} - ini@4.1.3: resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5145,10 +5414,6 @@ packages: engines: {node: '>=14.16'} hasBin: true - is-installed-globally@0.4.0: - resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} - engines: {node: '>=10'} - is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} @@ -5166,6 +5431,9 @@ packages: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number-object@1.0.6: resolution: {integrity: sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==} engines: {node: '>= 0.4'} @@ -5197,6 +5465,10 @@ packages: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} @@ -5242,9 +5514,9 @@ packages: resolution: {integrity: sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==} engines: {node: '>=8'} - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} @@ -5262,9 +5534,6 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} - is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -5309,9 +5578,6 @@ packages: isomorphic-fetch@3.0.0: resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} - isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -5381,7 +5647,7 @@ packages: resolution: {integrity: sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} peerDependencies: - '@types/node': '*' + '@types/node': 22.5.4 ts-node: '>=9.0.0' peerDependenciesMeta: '@types/node': @@ -5530,9 +5796,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} @@ -5557,6 +5820,9 @@ packages: json-buffer@3.0.0: resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} @@ -5621,14 +5887,13 @@ packages: resolution: {integrity: sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg==} engines: {node: '>=0.10.0'} - jsprim@2.0.2: - resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} - engines: {'0': node >=0.6.0} - jsx-ast-utils@3.2.0: resolution: {integrity: sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==} engines: {node: '>=4.0'} + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + just-diff-apply@5.5.0: resolution: {integrity: sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==} @@ -5638,6 +5903,9 @@ packages: keyv@3.0.0: resolution: {integrity: sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==} + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -5646,9 +5914,13 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - lazy-ass@1.6.0: - resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} - engines: {node: '> 0.8'} + ky@0.33.3: + resolution: {integrity: sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==} + engines: {node: '>=14.16'} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} lerna@8.1.7: resolution: {integrity: sha512-v2kkBn8Vqtroo30Pr5/JQ9MygRhnCsoI1jSOf3DxWmcTbkpC5U7c6rGr+7NPK6QrxKbC0/Cj4kuIBMb/7f79sQ==} @@ -5671,6 +5943,9 @@ packages: resolution: {integrity: sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==} engines: {node: ^16.14.0 || >=18.0.0} + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lilconfig@3.1.1: resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} engines: {node: '>=14'} @@ -5688,12 +5963,6 @@ packages: linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - listr2@3.10.0: - resolution: {integrity: sha512-eP40ZHihu70sSmqFNbNy2NL1YwImmlMmPh9WO5sLmPDleurMHt3n+SwEWNu2kzKScexZnkyFtc1VI0z/TGlmpw==} - engines: {node: '>=10.0.0'} - peerDependencies: - enquirer: '>= 2.3.0 < 3' - load-json-file@1.1.0: resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} engines: {node: '>=0.10.0'} @@ -5710,6 +5979,9 @@ packages: resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} engines: {node: '>=14'} + locate-app@2.4.39: + resolution: {integrity: sha512-hl7NwJrpGKLlmVgNrMRxFLRJTjve6IIav08bnv4MQSjahFRUPPVp+R02PSYpll6wY/YZqMrha68uScTmRJeMeA==} + locate-path@2.0.0: resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} @@ -5732,6 +6004,9 @@ packages: lodash._reinterpolate@3.0.0: resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -5744,9 +6019,6 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} @@ -5759,6 +6031,9 @@ packages: lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + lodash.zip@4.2.0: + resolution: {integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -5766,11 +6041,14 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} - log-update@4.0.0: - resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} - engines: {node: '>=10'} + loglevel-plugin-prefix@0.8.4: + resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} - loose-envify@1.4.0: + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -5789,6 +6067,10 @@ packages: resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==} engines: {node: '>=0.10.0'} + lowercase-keys@3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -5803,6 +6085,14 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.25.7: resolution: {integrity: sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==} @@ -5930,8 +6220,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} mime-db@1.52.0: @@ -5950,14 +6240,18 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + mimic-response@4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -6046,6 +6340,12 @@ packages: mitt@2.1.0: resolution: {integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@0.3.0: resolution: {integrity: sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==} deprecated: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.) @@ -6080,6 +6380,22 @@ packages: ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + msw@2.4.2: + resolution: {integrity: sha512-GImSQGhn19czhVpxPdiUDK8CMZ6jbBcvOhzfJd8KFErjEER2wDKWs1UYaetJs2GSNlAqt6heZYm7g3eLatTcog==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + graphql: '>= 16.8.x' + typescript: '>= 4.8.x' + peerDependenciesMeta: + graphql: + optional: true + typescript: + optional: true + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} @@ -6115,6 +6431,10 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + nice-napi@1.0.2: resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==} os: ['!win32'] @@ -6125,6 +6445,10 @@ packages: node-addon-api@3.2.1: resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -6134,6 +6458,19 @@ packages: encoding: optional: true + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-gyp-build@4.5.0: resolution: {integrity: sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==} hasBin: true @@ -6184,6 +6521,10 @@ packages: resolution: {integrity: sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==} engines: {node: '>=4'} + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + npm-bundled@3.0.1: resolution: {integrity: sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -6220,10 +6561,6 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -6299,10 +6636,6 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - open@10.1.0: resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} engines: {node: '>=18'} @@ -6331,13 +6664,17 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} - ospath@1.2.2: - resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} p-cancelable@0.4.1: resolution: {integrity: sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==} engines: {node: '>=4'} + p-cancelable@3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -6414,6 +6751,14 @@ packages: resolution: {integrity: sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==} engines: {node: '>=8'} + pac-proxy-agent@7.0.2: + resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-json-from-dist@1.0.0: resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} @@ -6422,6 +6767,12 @@ packages: engines: {node: ^16.14.0 || >=18.0.0} hasBin: true + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -6489,10 +6840,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -6504,8 +6851,8 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} - path-to-regexp@6.2.0: - resolution: {integrity: sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==} + path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} path-type@1.1.0: resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} @@ -6532,16 +6879,17 @@ packages: perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - - picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -6772,8 +7120,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.40: - resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} + postcss@8.4.45: + resolution: {integrity: sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==} engines: {node: ^10 || ^12 || >=14} preact@10.11.3: @@ -6800,6 +7148,10 @@ packages: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + pretty-format@28.1.3: resolution: {integrity: sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6830,6 +7182,10 @@ packages: resolution: {integrity: sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + promise-all-reject-late@1.0.1: resolution: {integrity: sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==} @@ -6865,8 +7221,9 @@ packages: protocols@2.0.1: resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} - proxy-from-env@1.0.0: - resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + proxy-agent@6.3.1: + resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} + engines: {node: '>= 14'} proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -6891,6 +7248,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + puppeteer-core@21.11.0: + resolution: {integrity: sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q==} + engines: {node: '>=16.13.2'} + q@1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} @@ -6899,18 +7260,20 @@ packages: (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) - qs@6.10.4: - resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} - engines: {node: '>=0.6'} - qs@6.9.7: resolution: {integrity: sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==} engines: {node: '>=0.6'} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + query-string@5.1.1: resolution: {integrity: sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==} engines: {node: '>=0.10.0'} + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + queue@6.0.2: resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} @@ -6922,12 +7285,19 @@ packages: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} @@ -6974,6 +7344,13 @@ packages: resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} engines: {node: '>= 6'} + readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -7036,9 +7413,6 @@ packages: request-light@0.7.0: resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} - request-progress@3.0.0: - resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -7054,6 +7428,9 @@ packages: reselect@4.1.7: resolution: {integrity: sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==} + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -7088,6 +7465,13 @@ packages: responselike@1.0.2: resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} + responselike@3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + + resq@1.11.0: + resolution: {integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==} + restore-cursor@2.0.0: resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} engines: {node: '>=4'} @@ -7104,6 +7488,9 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rgb2hex@0.2.5: + resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -7137,7 +7524,7 @@ packages: resolution: {integrity: sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw==} engines: {node: '>=10.0.0'} peerDependencies: - '@types/node': '>=10.0.0' + '@types/node': 22.5.4 rollup: '>=0.31.2' peerDependenciesMeta: '@types/node': @@ -7159,8 +7546,8 @@ packages: engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true - rollup@4.14.1: - resolution: {integrity: sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==} + rollup@4.21.2: + resolution: {integrity: sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7197,6 +7584,9 @@ packages: rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + safaridriver@0.1.2: + resolution: {integrity: sha512-4R309+gWflJktzPXBQCobbWEHlzC4aK3a+Ov3tz2Ib2aBxiwd11phkdIBH1l0EO22x24CJMUQkpKFumRriCSRg==} + safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} @@ -7372,6 +7762,10 @@ packages: engines: {node: '>=10'} hasBin: true + serialize-error@11.0.3: + resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==} + engines: {node: '>=14.16'} + serialize-javascript@4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} @@ -7386,6 +7780,9 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + shallow-clone@3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} @@ -7451,14 +7848,6 @@ packages: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} - slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} - - slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -7475,8 +7864,8 @@ packages: resolution: {integrity: sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==} engines: {node: '>=4'} - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} source-map-resolve@0.6.0: @@ -7501,6 +7890,9 @@ packages: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead + spacetrim@0.11.39: + resolution: {integrity: sha512-S/baW29azJ7py5ausQRE2S6uEDQnlxgMHOEEq4V770ooBDD1/9kZnxRcco/tjZYuDuqYXblCk/r3N13ZmvHZ2g==} + spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} @@ -7522,6 +7914,10 @@ packages: split2@3.2.2: resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + split@1.0.1: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} @@ -7531,11 +7927,6 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - sshpk@1.17.0: - resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} - engines: {node: '>=0.10.0'} - hasBin: true - ssri@10.0.6: resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -7551,6 +7942,10 @@ packages: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} @@ -7558,6 +7953,12 @@ packages: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} + streamx@2.20.0: + resolution: {integrity: sha512-ZGd1LhDeGFucr1CUCTBOS58ZhEendd0ttpGT3usTvosS4ntIwKN9LJFp+OeCSprsCPL14BXVRZlHGRY1V9PVzQ==} + + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + strict-uri-encode@1.1.0: resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} engines: {node: '>=0.10.0'} @@ -7651,10 +8052,6 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - strip-indent@1.0.1: resolution: {integrity: sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==} engines: {node: '>=0.10.0'} @@ -7675,6 +8072,9 @@ packages: strip-literal@1.3.0: resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} + strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + strong-log-transformer@2.1.0: resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==} engines: {node: '>=4'} @@ -7717,10 +8117,19 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tar-fs@3.0.4: + resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} + + tar-fs@3.0.6: + resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} + tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -7758,6 +8167,9 @@ packages: resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} engines: {node: '>=18'} + text-decoder@1.1.1: + resolution: {integrity: sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==} + text-extensions@1.9.0: resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} engines: {node: '>=0.10'} @@ -7768,9 +8180,6 @@ packages: throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} - throttleit@1.0.0: - resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==} - through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -7793,6 +8202,13 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@0.3.0: + resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + + tinyglobby@0.2.6: + resolution: {integrity: sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g==} + engines: {node: '>=12.0.0'} + tinypool@1.0.1: resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -7801,8 +8217,8 @@ packages: resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} engines: {node: '>=14.0.0'} - tinyspy@3.0.0: - resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==} + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} tldts-core@6.1.41: @@ -7910,12 +8326,6 @@ packages: resolution: {integrity: sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==} engines: {node: ^16.14.0 || >=18.0.0} - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -7956,6 +8366,14 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} + type-fest@2.13.0: + resolution: {integrity: sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==} + engines: {node: '>=12.20'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + type-fest@4.15.0: resolution: {integrity: sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==} engines: {node: '>=16'} @@ -8004,8 +8422,11 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} unhead@1.9.4: resolution: {integrity: sha512-QVU0y3KowRu2cLjXxfemTKNohK4vdEwyahoszlEnRz0E5BTNRZQSs8AnommorGmVM7DvB2t4dwWadB51wDlPzw==} @@ -8094,10 +8515,6 @@ packages: resolution: {integrity: sha512-aXEH9c5qi3uYZHo0niUtxDlT9ylG/luMW/dZslSCkbtC31wCyFkmM0kyoBBh+Grhn7CL+/kvKLfN61/EdxPxMQ==} engines: {node: '>=14.0.0'} - untildify@4.0.0: - resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} - engines: {node: '>=8'} - upath@1.2.0: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} @@ -8123,6 +8540,13 @@ packages: resolution: {integrity: sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==} engines: {node: '>= 4'} + urlpattern-polyfill@10.0.0: + resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} + + userhome@1.0.0: + resolution: {integrity: sha512-ayFKY3H+Pwfy4W98yPdtH1VqH4psDeyW8lYYFzfecR9d6hqLpqhecktvYR3SEEXt7vG0S1JEpciI3g94pMErig==} + engines: {node: '>= 0.8.0'} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -8139,10 +8563,6 @@ packages: deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. hasBin: true - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - v8-to-istanbul@9.0.1: resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} engines: {node: '>=10.12.0'} @@ -8162,12 +8582,8 @@ packages: peerDependencies: vue: ^3.3.11 - verror@1.10.0: - resolution: {integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=} - engines: {'0': node >=0.6.0} - - vite-node@2.0.5: - resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} + vite-node@2.1.1: + resolution: {integrity: sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -8261,12 +8677,12 @@ packages: vue-router: optional: true - vite@5.4.0: - resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==} + vite@5.4.3: + resolution: {integrity: sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 + '@types/node': 22.5.4 less: '*' lightningcss: ^1.21.0 sass: '*' @@ -8292,15 +8708,15 @@ packages: terser: optional: true - vitest@2.0.5: - resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==} + vitest@2.1.1: + resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.0.5 - '@vitest/ui': 2.0.5 + '@types/node': 22.5.4 + '@vitest/browser': 2.1.1 + '@vitest/ui': 2.1.1 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -8512,6 +8928,11 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + wait-port@1.1.0: + resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} + engines: {node: '>=10'} + hasBin: true + walk-up-path@3.0.1: resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} @@ -8521,6 +8942,23 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + webdriver@8.40.3: + resolution: {integrity: sha512-mc/pxLpgAQphnIaWvix/QXzp9CJpEvIA3YeF9t5plPaTbvbEaCAYYWkTP6e3vYPYWvx57krjGaYkNUnDCBNolA==} + engines: {node: ^16.13 || >=18} + + webdriverio@8.40.5: + resolution: {integrity: sha512-fKzaAF8lbgVFWIP8i0eGk22MpjactVVTWP8qtUXDob5Kdo8ffrg1lCKP8mcyrz6fiZM1OY1m6dvkbFelf23Nxw==} + engines: {node: ^16.13 || >=18} + peerDependencies: + devtools: ^8.14.0 + peerDependenciesMeta: + devtools: + optional: true + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -8690,6 +9128,18 @@ packages: resolution: {integrity: sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==} engines: {node: '>=8'} + ws@8.16.0: + resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -8735,8 +9185,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.4.1: - resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + yaml@2.5.1: + resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} engines: {node: '>= 14'} hasBin: true @@ -8767,9 +9217,17 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors-cjs@2.1.2: + resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + engines: {node: '>=18'} + zhead@2.2.4: resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==} + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + snapshots: '@aashutoshrathi/word-wrap@1.2.6': {} @@ -8859,9 +9317,9 @@ snapshots: '@antfu/utils@0.7.10': {} - '@apideck/better-ajv-errors@0.3.1(ajv@8.12.0)': + '@apideck/better-ajv-errors@0.3.1(ajv@8.17.1)': dependencies: - ajv: 8.12.0 + ajv: 8.17.1 json-schema: 0.4.0 jsonpointer: 5.0.0 leven: 3.1.0 @@ -8887,7 +9345,7 @@ snapshots: '@babel/code-frame@7.24.7': dependencies: '@babel/highlight': 7.24.7 - picocolors: 1.0.1 + picocolors: 1.1.0 '@babel/compat-data@7.25.2': {} @@ -8904,7 +9362,7 @@ snapshots: '@babel/traverse': 7.25.3 '@babel/types': 7.25.6 convert-source-map: 2.0.0 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -8962,7 +9420,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-compilation-targets': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -9058,7 +9516,7 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.1 + picocolors: 1.1.0 '@babel/parser@7.25.6': dependencies: @@ -9675,7 +10133,7 @@ snapshots: '@babel/parser': 7.25.6 '@babel/template': 7.25.0 '@babel/types': 7.25.6 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -9690,40 +10148,25 @@ snapshots: '@bufbuild/protobuf@1.10.0': {} - '@cosmicjs/sdk@1.0.11': + '@bundled-es-modules/cookie@2.0.0': dependencies: - axios: 1.7.2 - form-data: 4.0.0 - transitivePeerDependencies: - - debug + cookie: 0.5.0 - '@cypress/request@3.0.1': + '@bundled-es-modules/statuses@1.0.1': dependencies: - aws-sign2: 0.7.0 - aws4: 1.9.1 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.3.3 - http-signature: 1.3.6 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.35 - performance-now: 2.1.0 - qs: 6.10.4 - safe-buffer: 5.2.1 + statuses: 2.0.1 + + '@bundled-es-modules/tough-cookie@0.1.6': + dependencies: + '@types/tough-cookie': 4.0.5 tough-cookie: 5.0.0-rc.4 - tunnel-agent: 0.6.0 - uuid: 8.3.2 - '@cypress/xvfb@1.2.4(supports-color@8.1.1)': + '@cosmicjs/sdk@1.0.11': dependencies: - debug: 3.2.7(supports-color@8.1.1) - lodash.once: 4.1.1 + axios: 1.7.2 + form-data: 4.0.0 transitivePeerDependencies: - - supports-color + - debug '@date-io/core@3.0.0': {} @@ -9733,11 +10176,9 @@ snapshots: optionalDependencies: date-fns: 3.6.0 - '@date-io/dayjs@3.0.0(dayjs@1.10.4)': + '@date-io/dayjs@3.0.0': dependencies: '@date-io/core': 3.0.0 - optionalDependencies: - dayjs: 1.10.4 '@emailjs/browser@4.3.3': {} @@ -9925,7 +10366,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -10004,7 +10445,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -10015,6 +10456,33 @@ snapshots: '@hutson/parse-repository-url@3.0.2': {} + '@inquirer/confirm@3.2.0': + dependencies: + '@inquirer/core': 9.1.0 + '@inquirer/type': 1.5.3 + + '@inquirer/core@9.1.0': + dependencies: + '@inquirer/figures': 1.0.5 + '@inquirer/type': 1.5.3 + '@types/mute-stream': 0.0.4 + '@types/node': 22.5.4 + '@types/wrap-ansi': 3.0.0 + ansi-escapes: 4.3.2 + cli-spinners: 2.9.2 + cli-width: 4.1.0 + mute-stream: 1.0.0 + signal-exit: 4.1.0 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + + '@inquirer/figures@1.0.5': {} + + '@inquirer/type@1.5.3': + dependencies: + mute-stream: 1.0.0 + '@intlify/bundle-utils@8.0.0(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))': dependencies: '@intlify/message-compiler': 9.11.1 @@ -10024,7 +10492,7 @@ snapshots: estree-walker: 2.0.2 jsonc-eslint-parser: 2.4.0 mlly: 1.7.1 - source-map-js: 1.2.0 + source-map-js: 1.2.1 yaml-eslint-parser: 1.2.2 optionalDependencies: vue-i18n: 9.11.1(vue@3.4.27(typescript@5.5.4)) @@ -10037,23 +10505,23 @@ snapshots: '@intlify/message-compiler@9.11.1': dependencies: '@intlify/shared': 9.11.1 - source-map-js: 1.2.0 + source-map-js: 1.2.1 '@intlify/shared@9.11.1': {} - '@intlify/unplugin-vue-i18n@4.0.0(rollup@4.14.1)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))': + '@intlify/unplugin-vue-i18n@4.0.0(rollup@4.21.2)(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4)))': dependencies: '@intlify/bundle-utils': 8.0.0(vue-i18n@9.11.1(vue@3.4.27(typescript@5.5.4))) '@intlify/shared': 9.11.1 - '@rollup/pluginutils': 5.1.0(rollup@4.14.1) + '@rollup/pluginutils': 5.1.0(rollup@4.21.2) '@vue/compiler-sfc': 3.4.27 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 fast-glob: 3.3.2 js-yaml: 4.1.0 json5: 2.2.3 pathe: 1.1.2 - picocolors: 1.0.1 - source-map-js: 1.2.0 + picocolors: 1.1.0 + source-map-js: 1.2.1 unplugin: 1.12.1 optionalDependencies: vue-i18n: 9.11.1(vue@3.4.27(typescript@5.5.4)) @@ -10085,7 +10553,7 @@ snapshots: '@jest/console@28.1.3': dependencies: '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 chalk: 4.1.2 jest-message-util: 28.1.3 jest-util: 28.1.3 @@ -10098,14 +10566,14 @@ snapshots: '@jest/test-result': 28.1.3 '@jest/transform': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 28.1.3 - jest-config: 28.1.3(@types/node@20.12.7) + jest-config: 28.1.3(@types/node@22.5.4) jest-haste-map: 28.1.3 jest-message-util: 28.1.3 jest-regex-util: 28.0.2 @@ -10117,7 +10585,7 @@ snapshots: jest-util: 28.1.3 jest-validate: 28.1.3 jest-watcher: 28.1.3 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 28.1.3 rimraf: 3.0.2 slash: 3.0.0 @@ -10130,7 +10598,7 @@ snapshots: dependencies: '@jest/fake-timers': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 jest-mock: 28.1.3 '@jest/expect-utils@28.1.3': @@ -10148,7 +10616,7 @@ snapshots: dependencies: '@jest/types': 28.1.3 '@sinonjs/fake-timers': 9.1.2 - '@types/node': 20.12.7 + '@types/node': 22.5.4 jest-message-util: 28.1.3 jest-mock: 28.1.3 jest-util: 28.1.3 @@ -10169,7 +10637,7 @@ snapshots: '@jest/transform': 28.1.3 '@jest/types': 28.1.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.12.7 + '@types/node': 22.5.4 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -10232,7 +10700,7 @@ snapshots: jest-haste-map: 28.1.3 jest-regex-util: 28.0.2 jest-util: 28.1.3 - micromatch: 4.0.5 + micromatch: 4.0.8 pirates: 4.0.5 slash: 3.0.0 write-file-atomic: 4.0.2 @@ -10243,7 +10711,7 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.3 '@types/istanbul-reports': 3.0.0 - '@types/node': 20.12.7 + '@types/node': 22.5.4 '@types/yargs': 15.0.9 chalk: 4.1.2 @@ -10252,7 +10720,7 @@ snapshots: '@jest/schemas': 28.1.3 '@types/istanbul-lib-coverage': 2.0.3 '@types/istanbul-reports': 3.0.0 - '@types/node': 20.12.7 + '@types/node': 22.5.4 '@types/yargs': 17.0.13 chalk: 4.1.2 @@ -10369,6 +10837,15 @@ snapshots: '@mdi/svg@7.4.47': {} + '@mswjs/interceptors@0.29.1': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@napi-rs/wasm-runtime@0.2.4': dependencies: '@emnapi/core': 1.2.0 @@ -10668,7 +11145,7 @@ snapshots: '@octokit/request-error': 3.0.3 '@octokit/types': 9.3.2 is-plain-object: 5.0.0 - node-fetch: 2.6.7(encoding@0.1.13) + node-fetch: 2.7.0(encoding@0.1.13) universal-user-agent: 6.0.0 transitivePeerDependencies: - encoding @@ -10705,48 +11182,58 @@ snapshots: '@one-ini/wasm@0.1.1': {} - '@percy/cli-app@1.28.2(typescript@5.5.4)': + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + + '@percy/cli-app@1.29.3(typescript@5.5.4)': dependencies: - '@percy/cli-command': 1.28.2(typescript@5.5.4) - '@percy/cli-exec': 1.28.2(typescript@5.5.4) + '@percy/cli-command': 1.29.3(typescript@5.5.4) + '@percy/cli-exec': 1.29.3(typescript@5.5.4) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/cli-build@1.28.2(typescript@5.5.4)': + '@percy/cli-build@1.29.3(typescript@5.5.4)': dependencies: - '@percy/cli-command': 1.28.2(typescript@5.5.4) + '@percy/cli-command': 1.29.3(typescript@5.5.4) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/cli-command@1.28.2(typescript@5.5.4)': + '@percy/cli-command@1.29.3(typescript@5.5.4)': dependencies: - '@percy/config': 1.28.2(typescript@5.5.4) - '@percy/core': 1.28.2(typescript@5.5.4) - '@percy/logger': 1.28.2 + '@percy/config': 1.29.3(typescript@5.5.4) + '@percy/core': 1.29.3(typescript@5.5.4) + '@percy/logger': 1.29.3 transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/cli-config@1.28.2(typescript@5.5.4)': + '@percy/cli-config@1.29.3(typescript@5.5.4)': dependencies: - '@percy/cli-command': 1.28.2(typescript@5.5.4) + '@percy/cli-command': 1.29.3(typescript@5.5.4) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/cli-exec@1.28.2(typescript@5.5.4)': + '@percy/cli-exec@1.29.3(typescript@5.5.4)': dependencies: - '@percy/cli-command': 1.28.2(typescript@5.5.4) + '@percy/cli-command': 1.29.3(typescript@5.5.4) + '@percy/logger': 1.29.3 cross-spawn: 7.0.3 which: 2.0.2 transitivePeerDependencies: @@ -10755,99 +11242,97 @@ snapshots: - typescript - utf-8-validate - '@percy/cli-snapshot@1.28.2(typescript@5.5.4)': + '@percy/cli-snapshot@1.29.3(typescript@5.5.4)': dependencies: - '@percy/cli-command': 1.28.2(typescript@5.5.4) - yaml: 2.4.1 + '@percy/cli-command': 1.29.3(typescript@5.5.4) + yaml: 2.5.1 transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/cli-upload@1.28.2(typescript@5.5.4)': + '@percy/cli-upload@1.29.3(typescript@5.5.4)': dependencies: - '@percy/cli-command': 1.28.2(typescript@5.5.4) + '@percy/cli-command': 1.29.3(typescript@5.5.4) fast-glob: 3.3.2 - image-size: 1.0.0 + image-size: 1.1.1 transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/cli@1.28.2(typescript@5.5.4)': - dependencies: - '@percy/cli-app': 1.28.2(typescript@5.5.4) - '@percy/cli-build': 1.28.2(typescript@5.5.4) - '@percy/cli-command': 1.28.2(typescript@5.5.4) - '@percy/cli-config': 1.28.2(typescript@5.5.4) - '@percy/cli-exec': 1.28.2(typescript@5.5.4) - '@percy/cli-snapshot': 1.28.2(typescript@5.5.4) - '@percy/cli-upload': 1.28.2(typescript@5.5.4) - '@percy/client': 1.28.2 - '@percy/logger': 1.28.2 + '@percy/cli@1.29.3(typescript@5.5.4)': + dependencies: + '@percy/cli-app': 1.29.3(typescript@5.5.4) + '@percy/cli-build': 1.29.3(typescript@5.5.4) + '@percy/cli-command': 1.29.3(typescript@5.5.4) + '@percy/cli-config': 1.29.3(typescript@5.5.4) + '@percy/cli-exec': 1.29.3(typescript@5.5.4) + '@percy/cli-snapshot': 1.29.3(typescript@5.5.4) + '@percy/cli-upload': 1.29.3(typescript@5.5.4) + '@percy/client': 1.29.3 + '@percy/logger': 1.29.3 transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/client@1.28.2': + '@percy/client@1.29.3': dependencies: - '@percy/env': 1.28.2 - '@percy/logger': 1.28.2 + '@percy/env': 1.29.3 + '@percy/logger': 1.29.3 + pako: 2.1.0 - '@percy/config@1.28.2(typescript@5.5.4)': + '@percy/config@1.29.3(typescript@5.5.4)': dependencies: - '@percy/logger': 1.28.2 - ajv: 8.12.0 + '@percy/logger': 1.29.3 + ajv: 8.17.1 cosmiconfig: 8.3.6(typescript@5.5.4) - yaml: 2.4.1 + yaml: 2.5.1 transitivePeerDependencies: - typescript - '@percy/core@1.28.2(typescript@5.5.4)': + '@percy/core@1.29.3(typescript@5.5.4)': dependencies: - '@percy/client': 1.28.2 - '@percy/config': 1.28.2(typescript@5.5.4) - '@percy/dom': 1.28.2 - '@percy/logger': 1.28.2 - '@percy/webdriver-utils': 1.28.2(typescript@5.5.4) + '@percy/client': 1.29.3 + '@percy/config': 1.29.3(typescript@5.5.4) + '@percy/dom': 1.29.3 + '@percy/logger': 1.29.3 + '@percy/webdriver-utils': 1.29.3(typescript@5.5.4) content-disposition: 0.5.4 cross-spawn: 7.0.3 - extract-zip: 2.0.1(supports-color@8.1.1) + extract-zip: 2.0.1 fast-glob: 3.3.2 - micromatch: 4.0.5 + micromatch: 4.0.8 mime-types: 2.1.35 - path-to-regexp: 6.2.0 + pako: 2.1.0 + path-to-regexp: 6.2.2 rimraf: 3.0.2 ws: 8.18.0 + yaml: 2.5.1 transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@percy/cypress@3.1.2(cypress@13.7.2)': - dependencies: - '@percy/sdk-utils': 1.28.2 - cypress: 13.7.2 - - '@percy/dom@1.28.2': {} + '@percy/dom@1.29.3': {} - '@percy/env@1.28.2': + '@percy/env@1.29.3': dependencies: - '@percy/logger': 1.28.2 + '@percy/logger': 1.29.3 - '@percy/logger@1.28.2': {} + '@percy/logger@1.29.3': {} - '@percy/sdk-utils@1.28.2': {} + '@percy/sdk-utils@1.29.3': {} - '@percy/webdriver-utils@1.28.2(typescript@5.5.4)': + '@percy/webdriver-utils@1.29.3(typescript@5.5.4)': dependencies: - '@percy/config': 1.28.2(typescript@5.5.4) - '@percy/sdk-utils': 1.28.2 + '@percy/config': 1.29.3(typescript@5.5.4) + '@percy/sdk-utils': 1.29.3 transitivePeerDependencies: - typescript @@ -10856,6 +11341,22 @@ snapshots: '@polka/url@1.0.0-next.25': {} + '@promptbook/utils@0.70.0-1': + dependencies: + spacetrim: 0.11.39 + + '@puppeteer/browsers@1.9.1': + dependencies: + debug: 4.3.4 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.3.1 + tar-fs: 3.0.4 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + '@rollup/plugin-alias@5.1.0(rollup@3.29.4)': dependencies: slash: 4.0.0 @@ -10948,57 +11449,60 @@ snapshots: optionalDependencies: rollup: 3.29.4 - '@rollup/pluginutils@5.1.0(rollup@4.14.1)': + '@rollup/pluginutils@5.1.0(rollup@4.21.2)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: - rollup: 4.14.1 + rollup: 4.21.2 + + '@rollup/rollup-android-arm-eabi@4.21.2': + optional: true - '@rollup/rollup-android-arm-eabi@4.14.1': + '@rollup/rollup-android-arm64@4.21.2': optional: true - '@rollup/rollup-android-arm64@4.14.1': + '@rollup/rollup-darwin-arm64@4.21.2': optional: true - '@rollup/rollup-darwin-arm64@4.14.1': + '@rollup/rollup-darwin-x64@4.21.2': optional: true - '@rollup/rollup-darwin-x64@4.14.1': + '@rollup/rollup-linux-arm-gnueabihf@4.21.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.14.1': + '@rollup/rollup-linux-arm-musleabihf@4.21.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.14.1': + '@rollup/rollup-linux-arm64-gnu@4.21.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.14.1': + '@rollup/rollup-linux-arm64-musl@4.21.2': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.14.1': + '@rollup/rollup-linux-powerpc64le-gnu@4.21.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.14.1': + '@rollup/rollup-linux-riscv64-gnu@4.21.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.14.1': + '@rollup/rollup-linux-s390x-gnu@4.21.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.14.1': + '@rollup/rollup-linux-x64-gnu@4.21.2': optional: true - '@rollup/rollup-linux-x64-musl@4.14.1': + '@rollup/rollup-linux-x64-musl@4.21.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.14.1': + '@rollup/rollup-win32-arm64-msvc@4.21.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.14.1': + '@rollup/rollup-win32-ia32-msvc@4.21.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.14.1': + '@rollup/rollup-win32-x64-msvc@4.21.2': optional: true '@sigstore/bundle@2.3.2': @@ -11039,6 +11543,8 @@ snapshots: '@sindresorhus/is@0.7.0': {} + '@sindresorhus/is@5.6.0': {} + '@sinonjs/commons@1.8.1': dependencies: type-detect: 4.0.8 @@ -11054,6 +11560,25 @@ snapshots: magic-string: 0.25.7 string.prototype.matchall: 4.0.11 + '@szmarczak/http-timer@5.0.1': + dependencies: + defer-to-connect: 2.0.1 + + '@testing-library/user-event@14.5.2(@vuetify/testing-library-dom@1.0.2)': + dependencies: + '@testing-library/dom': '@vuetify/testing-library-dom@1.0.2' + + '@testing-library/vue@8.1.0(patch_hash=3limad3b7od6m3nrz2f3jnaixy)(@vue/compiler-sfc@3.4.27)(vue@3.4.27(typescript@5.5.4))': + dependencies: + '@babel/runtime': 7.24.4 + '@testing-library/dom': '@vuetify/testing-library-dom@1.0.2' + '@vue/test-utils': 2.4.6 + vue: 3.4.27(typescript@5.5.4) + optionalDependencies: + '@vue/compiler-sfc': 3.4.27 + + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@trysound/sax@0.2.0': {} '@ts-morph/common@0.23.0': @@ -11074,6 +11599,8 @@ snapshots: dependencies: tslib: 2.6.2 + '@types/aria-query@5.0.4': {} + '@types/babel__core@7.1.19': dependencies: '@babel/parser': 7.25.6 @@ -11097,6 +11624,8 @@ snapshots: '@types/color-name@1.1.1': {} + '@types/cookie@0.6.0': {} + '@types/debug@4.1.12': dependencies: '@types/ms': 0.7.31 @@ -11111,10 +11640,12 @@ snapshots: '@types/graceful-fs@4.1.5': dependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 '@types/hogan.js@3.0.1': {} + '@types/http-cache-semantics@4.0.4': {} + '@types/istanbul-lib-coverage@2.0.3': {} '@types/istanbul-lib-report@3.0.0': @@ -11129,7 +11660,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 '@types/linkify-it@3.0.2': {} @@ -11161,9 +11692,13 @@ snapshots: '@types/ms@0.7.31': {} - '@types/node@20.12.7': + '@types/mute-stream@0.0.4': + dependencies: + '@types/node': 22.5.4 + + '@types/node@22.5.4': dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 '@types/normalize-package-data@2.4.4': {} @@ -11179,24 +11714,32 @@ snapshots: '@types/resolve@1.17.1': dependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 '@types/resolve@1.20.2': {} '@types/responselike@1.0.3': dependencies: - '@types/node': 20.12.7 - - '@types/sinonjs__fake-timers@8.1.1': {} - - '@types/sizzle@2.3.2': {} + '@types/node': 22.5.4 '@types/stack-utils@2.0.0': {} + '@types/statuses@2.0.5': {} + '@types/stringify-object@4.0.5': {} + '@types/tough-cookie@4.0.5': {} + '@types/trusted-types@2.0.2': {} + '@types/which@2.0.2': {} + + '@types/wrap-ansi@3.0.0': {} + + '@types/ws@8.5.12': + dependencies: + '@types/node': 22.5.4 + '@types/yargs-parser@15.0.0': {} '@types/yargs@15.0.9': @@ -11207,9 +11750,9 @@ snapshots: dependencies: '@types/yargs-parser': 15.0.0 - '@types/yauzl@2.9.1': + '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 optional: true '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': @@ -11236,7 +11779,7 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 eslint: 8.57.0 optionalDependencies: typescript: 5.5.4 @@ -11257,7 +11800,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: @@ -11273,7 +11816,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -11288,7 +11831,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.0.1 '@typescript-eslint/visitor-keys': 8.0.1 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -11369,30 +11912,51 @@ snapshots: unhead: 1.9.4 vue: 3.4.27(typescript@5.5.4) - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': dependencies: - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) - '@vitejs/plugin-vue-jsx@3.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': + '@vitejs/plugin-vue-jsx@3.1.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2) '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2) - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': + '@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))': dependencies: - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) - '@vitest/coverage-v8@2.0.5(vitest@2.0.5(@types/node@20.12.7)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': + '@vitest/browser@2.1.1(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vitest@2.1.1)(webdriverio@8.40.5(encoding@0.1.13))': + dependencies: + '@testing-library/dom': '@vuetify/testing-library-dom@1.0.2' + '@testing-library/user-event': 14.5.2(@vuetify/testing-library-dom@1.0.2) + '@vitest/mocker': 2.1.1(msw@2.4.2(typescript@5.5.4))(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + '@vitest/utils': 2.1.1 + magic-string: 0.30.11 + msw: 2.4.2(typescript@5.5.4) + sirv: 2.0.4 + tinyrainbow: 1.2.0 + vitest: 2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + ws: 8.18.0 + optionalDependencies: + webdriverio: 8.40.5(encoding@0.1.13) + transitivePeerDependencies: + - bufferutil + - graphql + - typescript + - utf-8-validate + - vite + + '@vitest/coverage-v8@2.1.1(@vitest/browser@2.1.1(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vitest@2.1.1)(webdriverio@8.40.5(encoding@0.1.13)))(vitest@2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -11402,40 +11966,61 @@ snapshots: std-env: 3.7.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.0.5(@types/node@20.12.7)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vitest: 2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + optionalDependencies: + '@vitest/browser': 2.1.1(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vitest@2.1.1)(webdriverio@8.40.5(encoding@0.1.13)) transitivePeerDependencies: - supports-color - '@vitest/expect@2.0.5': + '@vitest/expect@2.1.1': dependencies: - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 + '@vitest/spy': 2.1.1 + '@vitest/utils': 2.1.1 chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/pretty-format@2.0.5': + '@vitest/mocker@2.1.1(msw@2.4.2(typescript@5.5.4))(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': + dependencies: + '@vitest/spy': 2.1.1 + estree-walker: 3.0.3 + magic-string: 0.30.11 + optionalDependencies: + msw: 2.4.2(typescript@5.5.4) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + + '@vitest/pretty-format@2.1.1': dependencies: tinyrainbow: 1.2.0 - '@vitest/runner@2.0.5': + '@vitest/runner@2.1.1': dependencies: - '@vitest/utils': 2.0.5 + '@vitest/utils': 2.1.1 pathe: 1.1.2 - '@vitest/snapshot@2.0.5': + '@vitest/snapshot@2.1.1': dependencies: - '@vitest/pretty-format': 2.0.5 + '@vitest/pretty-format': 2.1.1 magic-string: 0.30.11 pathe: 1.1.2 - '@vitest/spy@2.0.5': + '@vitest/spy@2.1.1': dependencies: - tinyspy: 3.0.0 + tinyspy: 3.0.2 - '@vitest/utils@2.0.5': + '@vitest/ui@2.1.1(vitest@2.1.1)': dependencies: - '@vitest/pretty-format': 2.0.5 - estree-walker: 3.0.3 + '@vitest/utils': 2.1.1 + fflate: 0.8.2 + flatted: 3.3.1 + pathe: 1.1.2 + sirv: 2.0.4 + tinyglobby: 0.2.6 + tinyrainbow: 1.2.0 + vitest: 2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + + '@vitest/utils@2.1.1': + dependencies: + '@vitest/pretty-format': 2.1.1 loupe: 3.1.1 tinyrainbow: 1.2.0 @@ -11521,7 +12106,7 @@ snapshots: '@vue/shared': 3.4.27 entities: 4.5.0 estree-walker: 2.0.2 - source-map-js: 1.2.0 + source-map-js: 1.2.1 '@vue/compiler-dom@3.4.27': dependencies: @@ -11537,8 +12122,8 @@ snapshots: '@vue/shared': 3.4.27 estree-walker: 2.0.2 magic-string: 0.30.11 - postcss: 8.4.40 - source-map-js: 1.2.0 + postcss: 8.4.45 + source-map-js: 1.2.1 '@vue/compiler-ssr@3.4.27': dependencies: @@ -11668,6 +12253,17 @@ snapshots: vue: 3.4.27(typescript@5.5.4) vuetify: link:packages/vuetify + '@vuetify/testing-library-dom@1.0.2': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/runtime': 7.24.4 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + '@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4))': dependencies: '@unhead/dom': 1.9.4 @@ -11676,16 +12272,70 @@ snapshots: '@unhead/vue': 1.9.4(vue@3.4.27(typescript@5.5.4)) vue: 3.4.27(typescript@5.5.4) - '@yankeeinlondon/builder-api@1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': + '@wdio/config@8.40.3': dependencies: - '@types/markdown-it': 12.2.3 - '@yankeeinlondon/happy-wrapper': 2.10.1(encoding@0.1.13) - fp-ts: 2.16.9 - inferred-types: 0.37.6 - markdown-it: 13.0.2 - vite-plugin-md: 0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + '@wdio/logger': 8.38.0 + '@wdio/types': 8.40.3 + '@wdio/utils': 8.40.3 + decamelize: 6.0.0 + deepmerge-ts: 5.1.0 + glob: 10.4.5 + import-meta-resolve: 4.1.0 transitivePeerDependencies: - - '@vitejs/plugin-vue' + - supports-color + + '@wdio/logger@8.38.0': + dependencies: + chalk: 5.3.0 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/logger@9.0.8': + dependencies: + chalk: 5.3.0 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/protocols@8.40.3': {} + + '@wdio/repl@8.40.3': + dependencies: + '@types/node': 22.5.4 + + '@wdio/types@8.40.3': + dependencies: + '@types/node': 22.5.4 + + '@wdio/utils@8.40.3': + dependencies: + '@puppeteer/browsers': 1.9.1 + '@wdio/logger': 8.38.0 + '@wdio/types': 8.40.3 + decamelize: 6.0.0 + deepmerge-ts: 5.1.0 + edgedriver: 5.6.1 + geckodriver: 4.4.4 + get-port: 7.1.0 + import-meta-resolve: 4.1.0 + locate-app: 2.4.39 + safaridriver: 0.1.2 + split2: 4.2.0 + wait-port: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@yankeeinlondon/builder-api@1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))': + dependencies: + '@types/markdown-it': 12.2.3 + '@yankeeinlondon/happy-wrapper': 2.10.1(encoding@0.1.13) + fp-ts: 2.16.9 + inferred-types: 0.37.6 + markdown-it: 13.0.2 + vite-plugin-md: 0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + transitivePeerDependencies: + - '@vitejs/plugin-vue' - encoding - vite @@ -11712,6 +12362,8 @@ snapshots: js-yaml: 3.14.1 tslib: 2.6.2 + '@zip.js/zip.js@2.7.52': {} + '@zkochan/js-yaml@0.0.7': dependencies: argparse: 2.0.1 @@ -11725,6 +12377,10 @@ snapshots: abbrev@2.0.0: {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: acorn: 8.12.1 @@ -11739,7 +12395,7 @@ snapshots: agent-base@7.1.1: dependencies: - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -11755,12 +12411,12 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.2.2 - ajv@8.12.0: + ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 + fast-uri: 3.0.1 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - uri-js: 4.2.2 algoliasearch-helper@3.19.0(algoliasearch@4.23.3): dependencies: @@ -11826,7 +12482,25 @@ snapshots: aproba@2.0.0: {} - arch@2.2.0: {} + archiver-utils@5.0.2: + dependencies: + glob: 10.4.5 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 4.5.2 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.5 + buffer-crc32: 1.0.0 + readable-stream: 4.5.2 + readdir-glob: 1.1.3 + tar-stream: 3.1.7 + zip-stream: 6.0.1 argparse@1.0.10: dependencies: @@ -11834,6 +12508,10 @@ snapshots: argparse@2.0.1: {} + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -11916,15 +12594,11 @@ snapshots: arrify@2.0.1: {} - asn1@0.2.4: - dependencies: - safer-buffer: 2.1.2 - - assert-plus@1.0.0: {} - assertion-error@2.0.1: {} - astral-regex@2.0.0: {} + ast-types@0.13.4: + dependencies: + tslib: 2.6.2 async-es@3.2.5: {} @@ -11936,24 +12610,20 @@ snapshots: atob@2.1.2: {} - autoprefixer@10.4.19(postcss@8.4.40): + autoprefixer@10.4.19(postcss@8.4.45): dependencies: browserslist: 4.23.3 caniuse-lite: 1.0.30001646 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.0.1 - postcss: 8.4.40 + picocolors: 1.1.0 + postcss: 8.4.45 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 - aws-sign2@0.7.0: {} - - aws4@1.9.1: {} - axios@1.7.2: dependencies: follow-redirects: 1.15.6 @@ -11962,6 +12632,8 @@ snapshots: transitivePeerDependencies: - debug + b4a@1.6.6: {} + babel-eslint@10.1.0(eslint@8.57.0): dependencies: '@babel/code-frame': 7.24.7 @@ -12081,11 +12753,33 @@ snapshots: balanced-match@1.0.0: {} - base64-js@1.5.1: {} + bare-events@2.4.2: + optional: true + + bare-fs@2.3.3: + dependencies: + bare-events: 2.4.2 + bare-path: 2.1.3 + bare-stream: 2.2.1 + optional: true + + bare-os@2.4.2: + optional: true + + bare-path@2.1.3: + dependencies: + bare-os: 2.4.2 + optional: true - bcrypt-pbkdf@1.0.2: + bare-stream@2.2.1: dependencies: - tweetnacl: 0.14.5 + b4a: 1.6.6 + streamx: 2.20.0 + optional: true + + base64-js@1.5.1: {} + + basic-ftp@5.0.5: {} before-after-hook@2.2.2: {} @@ -12104,10 +12798,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.0 - blob-util@2.0.2: {} - - bluebird@3.7.2: {} - boolbase@1.0.0: {} brace-expansion@1.1.11: @@ -12119,9 +12809,9 @@ snapshots: dependencies: balanced-match: 1.0.0 - braces@3.0.2: + braces@3.0.3: dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 brilliant-errors@0.7.3: dependencies: @@ -12143,6 +12833,8 @@ snapshots: buffer-crc32@0.2.13: {} + buffer-crc32@1.0.0: {} + buffer-from@1.1.1: {} buffer@5.7.1: @@ -12150,6 +12842,11 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + builtin-modules@3.3.0: {} builtins@5.0.1: @@ -12179,6 +12876,18 @@ snapshots: tar: 6.2.1 unique-filename: 3.0.0 + cacheable-lookup@7.0.0: {} + + cacheable-request@10.2.14: + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + cacheable-request@2.1.4: dependencies: clone-response: 1.0.2 @@ -12189,8 +12898,6 @@ snapshots: normalize-url: 2.0.1 responselike: 1.0.2 - cachedir@2.3.0: {} - call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -12247,8 +12954,6 @@ snapshots: caniuse-lite@1.0.30001646: {} - caseless@0.12.0: {} - chai@5.1.1: dependencies: assertion-error: 2.0.1 @@ -12273,6 +12978,8 @@ snapshots: ansi-styles: 4.2.1 supports-color: 7.2.0 + chalk@5.3.0: {} + char-regex@1.0.2: {} character-parser@2.2.0: @@ -12283,12 +12990,10 @@ snapshots: check-error@2.1.1: {} - check-more-types@2.24.0: {} - chokidar@3.6.0: dependencies: anymatch: 3.1.2 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -12299,6 +13004,12 @@ snapshots: chownr@2.0.0: {} + chromium-bidi@0.5.8(devtools-protocol@0.0.1232444): + dependencies: + devtools-protocol: 0.0.1232444 + mitt: 3.0.1 + urlpattern-polyfill: 10.0.0 + ci-info@2.0.0: {} ci-info@3.9.0: {} @@ -12321,21 +13032,12 @@ snapshots: cli-spinners@2.9.2: {} - cli-table3@0.6.1: - dependencies: - string-width: 4.2.3 - optionalDependencies: - colors: 1.4.0 - - cli-truncate@2.1.0: - dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 - cli-width@2.2.0: {} cli-width@3.0.0: {} + cli-width@4.1.0: {} + cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -12384,11 +13086,6 @@ snapshots: colord@2.9.3: {} - colorette@1.4.0: {} - - colors@1.4.0: - optional: true - columnify@1.6.0: dependencies: strip-ansi: 6.0.1 @@ -12408,6 +13105,8 @@ snapshots: commander@7.2.0: {} + commander@9.5.0: {} + common-ancestor-path@1.0.1: {} common-tags@1.8.0: {} @@ -12422,6 +13121,14 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.5.2 + computeds@0.0.1: {} concat-map@0.0.1: {} @@ -12675,7 +13382,7 @@ snapshots: dependencies: conventional-changelog: 2.0.3 dateformat: 3.0.3 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 gh-got: 7.1.0 git-semver-tags: 2.0.3 lodash.merge: 4.6.2 @@ -12704,6 +13411,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie@0.5.0: {} + core-js-compat@3.37.1: dependencies: browserslist: 4.23.3 @@ -12736,6 +13445,13 @@ snapshots: optionalDependencies: typescript: 5.5.4 + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.5.2 + create-jest-runner@0.11.2(@jest/test-result@28.1.3)(jest-runner@28.1.3): dependencies: chalk: 4.1.2 @@ -12745,6 +13461,12 @@ snapshots: '@jest/test-result': 28.1.3 jest-runner: 28.1.3 + cross-fetch@4.0.0(encoding@0.1.13): + dependencies: + node-fetch: 2.7.0(encoding@0.1.13) + transitivePeerDependencies: + - encoding + cross-spawn@6.0.5: dependencies: nice-try: 1.0.5 @@ -12761,27 +13483,31 @@ snapshots: crypto-random-string@2.0.0: {} - css-declaration-sorter@7.2.0(postcss@8.4.40): + css-declaration-sorter@7.2.0(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 css-select@5.1.0: dependencies: boolbase: 1.0.0 css-what: 6.1.0 domhandler: 5.0.3 - domutils: 3.0.1 + domutils: 3.1.0 nth-check: 2.1.1 + css-shorthand-properties@1.1.1: {} + css-tree@2.2.1: dependencies: mdn-data: 2.0.28 - source-map-js: 1.2.0 + source-map-js: 1.2.1 css-tree@2.3.1: dependencies: mdn-data: 2.0.30 - source-map-js: 1.2.0 + source-map-js: 1.2.1 + + css-value@0.0.1: {} css-what@6.1.0: {} @@ -12789,49 +13515,49 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-default@6.1.2(postcss@8.4.40): + cssnano-preset-default@6.1.2(postcss@8.4.45): dependencies: browserslist: 4.23.3 - css-declaration-sorter: 7.2.0(postcss@8.4.40) - cssnano-utils: 4.0.2(postcss@8.4.40) - postcss: 8.4.40 - postcss-calc: 9.0.1(postcss@8.4.40) - postcss-colormin: 6.1.0(postcss@8.4.40) - postcss-convert-values: 6.1.0(postcss@8.4.40) - postcss-discard-comments: 6.0.2(postcss@8.4.40) - postcss-discard-duplicates: 6.0.3(postcss@8.4.40) - postcss-discard-empty: 6.0.3(postcss@8.4.40) - postcss-discard-overridden: 6.0.2(postcss@8.4.40) - postcss-merge-longhand: 6.0.5(postcss@8.4.40) - postcss-merge-rules: 6.1.1(postcss@8.4.40) - postcss-minify-font-values: 6.1.0(postcss@8.4.40) - postcss-minify-gradients: 6.0.3(postcss@8.4.40) - postcss-minify-params: 6.1.0(postcss@8.4.40) - postcss-minify-selectors: 6.0.4(postcss@8.4.40) - postcss-normalize-charset: 6.0.2(postcss@8.4.40) - postcss-normalize-display-values: 6.0.2(postcss@8.4.40) - postcss-normalize-positions: 6.0.2(postcss@8.4.40) - postcss-normalize-repeat-style: 6.0.2(postcss@8.4.40) - postcss-normalize-string: 6.0.2(postcss@8.4.40) - postcss-normalize-timing-functions: 6.0.2(postcss@8.4.40) - postcss-normalize-unicode: 6.1.0(postcss@8.4.40) - postcss-normalize-url: 6.0.2(postcss@8.4.40) - postcss-normalize-whitespace: 6.0.2(postcss@8.4.40) - postcss-ordered-values: 6.0.2(postcss@8.4.40) - postcss-reduce-initial: 6.1.0(postcss@8.4.40) - postcss-reduce-transforms: 6.0.2(postcss@8.4.40) - postcss-svgo: 6.0.3(postcss@8.4.40) - postcss-unique-selectors: 6.0.4(postcss@8.4.40) - - cssnano-utils@4.0.2(postcss@8.4.40): - dependencies: - postcss: 8.4.40 - - cssnano@6.1.2(postcss@8.4.40): - dependencies: - cssnano-preset-default: 6.1.2(postcss@8.4.40) + css-declaration-sorter: 7.2.0(postcss@8.4.45) + cssnano-utils: 4.0.2(postcss@8.4.45) + postcss: 8.4.45 + postcss-calc: 9.0.1(postcss@8.4.45) + postcss-colormin: 6.1.0(postcss@8.4.45) + postcss-convert-values: 6.1.0(postcss@8.4.45) + postcss-discard-comments: 6.0.2(postcss@8.4.45) + postcss-discard-duplicates: 6.0.3(postcss@8.4.45) + postcss-discard-empty: 6.0.3(postcss@8.4.45) + postcss-discard-overridden: 6.0.2(postcss@8.4.45) + postcss-merge-longhand: 6.0.5(postcss@8.4.45) + postcss-merge-rules: 6.1.1(postcss@8.4.45) + postcss-minify-font-values: 6.1.0(postcss@8.4.45) + postcss-minify-gradients: 6.0.3(postcss@8.4.45) + postcss-minify-params: 6.1.0(postcss@8.4.45) + postcss-minify-selectors: 6.0.4(postcss@8.4.45) + postcss-normalize-charset: 6.0.2(postcss@8.4.45) + postcss-normalize-display-values: 6.0.2(postcss@8.4.45) + postcss-normalize-positions: 6.0.2(postcss@8.4.45) + postcss-normalize-repeat-style: 6.0.2(postcss@8.4.45) + postcss-normalize-string: 6.0.2(postcss@8.4.45) + postcss-normalize-timing-functions: 6.0.2(postcss@8.4.45) + postcss-normalize-unicode: 6.1.0(postcss@8.4.45) + postcss-normalize-url: 6.0.2(postcss@8.4.45) + postcss-normalize-whitespace: 6.0.2(postcss@8.4.45) + postcss-ordered-values: 6.0.2(postcss@8.4.45) + postcss-reduce-initial: 6.1.0(postcss@8.4.45) + postcss-reduce-transforms: 6.0.2(postcss@8.4.45) + postcss-svgo: 6.0.3(postcss@8.4.45) + postcss-unique-selectors: 6.0.4(postcss@8.4.45) + + cssnano-utils@4.0.2(postcss@8.4.45): + dependencies: + postcss: 8.4.45 + + cssnano@6.1.2(postcss@8.4.45): + dependencies: + cssnano-preset-default: 6.1.2(postcss@8.4.45) lilconfig: 3.1.1 - postcss: 8.4.40 + postcss: 8.4.45 csso@5.0.5: dependencies: @@ -12849,68 +13575,15 @@ snapshots: cy-mobile-commands@0.3.0: {} - cypress-file-upload@5.0.8(cypress@13.7.2): - dependencies: - cypress: 13.7.2 - - cypress-real-events@1.12.0(cypress@13.7.2): - dependencies: - cypress: 13.7.2 - - cypress@13.7.2: - dependencies: - '@cypress/request': 3.0.1 - '@cypress/xvfb': 1.2.4(supports-color@8.1.1) - '@types/sinonjs__fake-timers': 8.1.1 - '@types/sizzle': 2.3.2 - arch: 2.2.0 - blob-util: 2.0.2 - bluebird: 3.7.2 - buffer: 5.7.1 - cachedir: 2.3.0 - chalk: 4.1.2 - check-more-types: 2.24.0 - cli-cursor: 3.1.0 - cli-table3: 0.6.1 - commander: 6.2.1 - common-tags: 1.8.0 - dayjs: 1.10.4 - debug: 4.3.6(supports-color@8.1.1) - enquirer: 2.3.6 - eventemitter2: 6.4.7 - execa: 4.1.0 - executable: 4.1.1 - extract-zip: 2.0.1(supports-color@8.1.1) - figures: 3.2.0 - fs-extra: 9.1.0 - getos: 3.2.1 - is-ci: 3.0.1 - is-installed-globally: 0.4.0 - lazy-ass: 1.6.0 - listr2: 3.10.0(enquirer@2.3.6) - lodash: 4.17.21 - log-symbols: 4.1.0 - minimist: 1.2.8 - ospath: 1.2.2 - pretty-bytes: 5.6.0 - process: 0.11.10 - proxy-from-env: 1.0.0 - request-progress: 3.0.0 - semver: 7.6.3 - supports-color: 8.1.1 - tmp: 0.2.1 - untildify: 4.0.0 - yauzl: 2.10.0 - dargs@4.1.0: dependencies: number-is-nan: 1.0.1 dargs@7.0.0: {} - dashdash@1.14.1: - dependencies: - assert-plus: 1.0.0 + data-uri-to-buffer@4.0.1: {} + + data-uri-to-buffer@6.0.2: {} data-urls@5.0.0: dependencies: @@ -12943,25 +13616,23 @@ snapshots: dateformat@3.0.3: {} - dayjs@1.10.4: {} - de-indent@1.0.2: {} debug@2.6.9: dependencies: ms: 2.0.0 - debug@3.2.7(supports-color@8.1.1): + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.4: dependencies: ms: 2.1.2 - optionalDependencies: - supports-color: 8.1.1 - debug@4.3.6(supports-color@8.1.1): + debug@4.3.7: dependencies: - ms: 2.1.2 - optionalDependencies: - supports-color: 8.1.1 + ms: 2.1.3 decamelize-keys@1.1.0: dependencies: @@ -12970,6 +13641,8 @@ snapshots: decamelize@1.2.0: {} + decamelize@6.0.0: {} + decimal.js@10.4.3: {} decode-uri-component@0.2.0: {} @@ -12978,6 +13651,10 @@ snapshots: dependencies: mimic-response: 1.0.1 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + dedent@0.7.0: {} dedent@1.5.3: {} @@ -13009,6 +13686,8 @@ snapshots: deep-is@0.1.3: {} + deepmerge-ts@5.1.0: {} + deepmerge@4.3.1: {} default-browser-id@5.0.0: {} @@ -13022,6 +13701,8 @@ snapshots: dependencies: clone: 1.0.4 + defer-to-connect@2.0.1: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 @@ -13038,14 +13719,26 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + delayed-stream@1.0.0: {} deprecation@2.3.1: {} + dequal@2.0.3: {} + detect-indent@5.0.0: {} detect-newline@3.1.0: {} + devtools-protocol@0.0.1232444: {} + + devtools-protocol@0.0.1342118: {} + diff-sequences@28.1.1: {} diff-sequences@29.6.3: {} @@ -13062,6 +13755,8 @@ snapshots: dependencies: esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -13074,7 +13769,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - domutils@3.0.1: + domutils@3.1.0: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 @@ -13104,10 +13799,20 @@ snapshots: eastasianwidth@0.2.0: {} - ecc-jsbn@0.1.2: + edge-paths@3.0.5: dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 + '@types/which': 2.0.2 + which: 2.0.2 + + edgedriver@5.6.1: + dependencies: + '@wdio/logger': 8.38.0 + '@zip.js/zip.js': 2.7.52 + decamelize: 6.0.0 + edge-paths: 3.0.5 + fast-xml-parser: 4.5.0 + node-fetch: 3.3.2 + which: 4.0.0 editorconfig@1.0.4: dependencies: @@ -13362,7 +14067,7 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 is-core-module: 2.13.1 resolve: 1.22.8 transitivePeerDependencies: @@ -13370,7 +14075,7 @@ snapshots: eslint-module-utils@2.8.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 @@ -13378,11 +14083,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-cypress@2.15.1(eslint@8.57.0): - dependencies: - eslint: 8.57.0 - globals: 13.24.0 - eslint-plugin-es-x@7.5.0(eslint@8.57.0): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) @@ -13396,7 +14096,7 @@ snapshots: array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 @@ -13417,13 +14117,13 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@28.7.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@28.1.3(@types/node@20.12.7))(typescript@5.5.4): + eslint-plugin-jest@28.7.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@28.1.3(@types/node@22.5.4))(typescript@5.5.4): dependencies: '@typescript-eslint/utils': 8.0.1(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - jest: 28.1.3(@types/node@20.12.7) + jest: 28.1.3(@types/node@22.5.4) transitivePeerDependencies: - supports-color - typescript @@ -13475,6 +14175,17 @@ snapshots: dependencies: eslint: 8.57.0 + eslint-plugin-vitest@0.4.1(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)(vitest@2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + dependencies: + '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + eslint: 8.57.0 + optionalDependencies: + '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) + vitest: 2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-vue@9.24.1(eslint@8.57.0): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) @@ -13520,7 +14231,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -13582,10 +14293,12 @@ snapshots: esutils@2.0.3: {} - eventemitter2@6.4.7: {} + event-target-shim@5.0.1: {} eventemitter3@4.0.7: {} + events@3.3.0: {} + execa@1.0.0: dependencies: cross-spawn: 6.0.5 @@ -13596,24 +14309,12 @@ snapshots: signal-exit: 3.0.7 strip-eof: 1.0.0 - execa@4.1.0: - dependencies: - cross-spawn: 7.0.3 - get-stream: 5.2.0 - human-signals: 1.1.1 - is-stream: 2.0.0 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - execa@5.0.0: dependencies: cross-spawn: 7.0.3 get-stream: 6.0.1 human-signals: 2.1.0 - is-stream: 2.0.0 + is-stream: 2.0.1 merge-stream: 2.0.0 npm-run-path: 4.0.1 onetime: 5.1.2 @@ -13625,29 +14326,13 @@ snapshots: cross-spawn: 7.0.3 get-stream: 6.0.1 human-signals: 2.1.0 - is-stream: 2.0.0 + is-stream: 2.0.1 merge-stream: 2.0.0 npm-run-path: 4.0.1 onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - execa@8.0.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - executable@4.1.1: - dependencies: - pify: 2.3.0 - exit@0.1.2: {} expect@28.1.3: @@ -13664,8 +14349,6 @@ snapshots: dependencies: is-extendable: 0.1.1 - extend@3.0.2: {} - external-editor@3.0.3: dependencies: chardet: 0.7.0 @@ -13677,34 +14360,40 @@ snapshots: esprima-extract-comments: 1.1.0 parse-code-context: 1.0.0 - extract-zip@2.0.1(supports-color@8.1.1): + extract-zip@2.0.1: dependencies: - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: - '@types/yauzl': 2.9.1 + '@types/yauzl': 2.10.3 transitivePeerDependencies: - supports-color - extsprintf@1.3.0: {} - - extsprintf@1.4.0: {} + fast-deep-equal@2.0.1: {} fast-deep-equal@3.1.3: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} + fast-uri@3.0.1: {} + + fast-xml-parser@4.5.0: + dependencies: + strnum: 1.0.5 + fastq@1.8.0: dependencies: reusify: 1.0.4 @@ -13717,6 +14406,15 @@ snapshots: dependencies: pend: 1.2.0 + fdir@6.3.0(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + fflate@0.8.2: {} figures@2.0.0: @@ -13735,7 +14433,7 @@ snapshots: dependencies: minimatch: 5.1.6 - fill-range@7.0.1: + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -13781,12 +14479,12 @@ snapshots: flat-cache@3.0.4: dependencies: - flatted: 3.2.2 + flatted: 3.3.1 rimraf: 3.0.2 flat@5.0.2: {} - flatted@3.2.2: {} + flatted@3.3.1: {} follow-redirects@1.15.6: {} @@ -13799,19 +14497,17 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - forever-agent@0.6.1: {} + form-data-encoder@2.1.4: {} - form-data@2.3.3: + form-data@4.0.0: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@4.0.0: + formdata-polyfill@4.0.10: dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 + fetch-blob: 3.2.0 fp-ts@2.16.9: {} @@ -13867,6 +14563,19 @@ snapshots: functions-have-names@1.2.3: {} + geckodriver@4.4.4: + dependencies: + '@wdio/logger': 9.0.8 + '@zip.js/zip.js': 2.7.52 + decamelize: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + node-fetch: 3.3.2 + tar-fs: 3.0.6 + which: 4.0.0 + transitivePeerDependencies: + - supports-color + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -13904,6 +14613,8 @@ snapshots: get-port@5.1.1: {} + get-port@7.1.0: {} + get-stdin@4.0.1: {} get-stdin@7.0.0: {} @@ -13924,8 +14635,6 @@ snapshots: get-stream@6.0.1: {} - get-stream@8.0.1: {} - get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 @@ -13936,13 +14645,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - getos@3.2.1: + get-uri@6.0.3: dependencies: - async: 3.2.5 - - getpass@0.1.7: - dependencies: - assert-plus: 1.0.0 + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.3.7 + fs-extra: 11.2.0 + transitivePeerDependencies: + - supports-color gh-got@7.1.0: dependencies: @@ -14049,10 +14759,6 @@ snapshots: minipass: 4.2.8 path-scurry: 1.11.1 - global-dirs@3.0.0: - dependencies: - ini: 2.0.0 - globals@11.12.0: {} globals@13.24.0: @@ -14076,6 +14782,20 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + got@12.6.1: + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + got@8.3.2: dependencies: '@sindresorhus/is': 0.7.0 @@ -14100,6 +14820,8 @@ snapshots: graceful-fs@4.2.11: {} + grapheme-splitter@1.0.4: {} + graphemer@1.4.0: {} handlebars@4.7.8: @@ -14116,7 +14838,7 @@ snapshots: css.escape: 1.5.1 he: 1.2.0 iconv-lite: 0.6.3 - node-fetch: 2.6.7(encoding@0.1.13) + node-fetch: 2.7.0(encoding@0.1.13) webidl-conversions: 7.0.0 whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 @@ -14159,6 +14881,8 @@ snapshots: he@1.2.0: {} + headers-polyfill@4.0.3: {} + hogan.js@3.0.2: dependencies: mkdirp: 0.3.0 @@ -14193,29 +14917,24 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color - http-signature@1.3.6: + http2-wrapper@2.2.1: dependencies: - assert-plus: 1.0.0 - jsprim: 2.0.2 - sshpk: 1.17.0 + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.1 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color - human-signals@1.1.1: {} - human-signals@2.1.0: {} - human-signals@5.0.0: {} - husky@3.1.0: dependencies: chalk: 2.4.2 @@ -14252,10 +14971,12 @@ snapshots: ignore@5.3.1: {} - image-size@1.0.0: + image-size@1.1.1: dependencies: queue: 6.0.2 + immediate@3.0.6: {} + immutable@4.0.0: {} import-fresh@2.0.0: @@ -14273,6 +14994,8 @@ snapshots: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + import-meta-resolve@4.1.0: {} + imurmurhash@0.1.4: {} indent-string@2.1.0: @@ -14296,8 +15019,6 @@ snapshots: ini@1.3.8: {} - ini@2.0.0: {} - ini@4.1.3: {} init-package-json@6.0.3: @@ -14487,11 +15208,6 @@ snapshots: dependencies: is-docker: 3.0.0 - is-installed-globally@0.4.0: - dependencies: - global-dirs: 3.0.0 - is-path-inside: 3.0.3 - is-interactive@1.0.0: {} is-lambda@1.0.1: {} @@ -14502,6 +15218,8 @@ snapshots: is-negative-zero@2.0.3: {} + is-node-process@1.2.0: {} + is-number-object@1.0.6: dependencies: has-tostringtag: 1.0.2 @@ -14520,6 +15238,8 @@ snapshots: is-plain-obj@1.1.0: {} + is-plain-obj@4.1.0: {} + is-plain-object@2.0.4: dependencies: isobject: 3.0.1 @@ -14553,7 +15273,7 @@ snapshots: is-stream@2.0.0: {} - is-stream@3.0.0: {} + is-stream@2.0.1: {} is-string@1.0.7: dependencies: @@ -14571,8 +15291,6 @@ snapshots: dependencies: which-typed-array: 1.1.15 - is-typedarray@1.0.0: {} - is-unicode-supported@0.1.0: {} is-utf8@0.2.1: {} @@ -14605,13 +15323,11 @@ snapshots: isomorphic-fetch@3.0.0(encoding@0.1.13): dependencies: - node-fetch: 2.6.7(encoding@0.1.13) + node-fetch: 2.7.0(encoding@0.1.13) whatwg-fetch: 3.6.2 transitivePeerDependencies: - encoding - isstream@0.1.2: {} - istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: @@ -14632,7 +15348,7 @@ snapshots: istanbul-lib-source-maps@4.0.0: dependencies: - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -14641,7 +15357,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -14700,7 +15416,7 @@ snapshots: '@jest/expect': 28.1.3 '@jest/test-result': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -14718,7 +15434,7 @@ snapshots: transitivePeerDependencies: - supports-color - jest-cli@28.1.3(@types/node@20.12.7): + jest-cli@28.1.3(@types/node@22.5.4): dependencies: '@jest/core': 28.1.3 '@jest/test-result': 28.1.3 @@ -14727,7 +15443,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 28.1.3(@types/node@20.12.7) + jest-config: 28.1.3(@types/node@22.5.4) jest-util: 28.1.3 jest-validate: 28.1.3 prompts: 2.4.2 @@ -14737,7 +15453,7 @@ snapshots: - supports-color - ts-node - jest-config@28.1.3(@types/node@20.12.7): + jest-config@28.1.3(@types/node@22.5.4): dependencies: '@babel/core': 7.25.2 '@jest/test-sequencer': 28.1.3 @@ -14756,13 +15472,13 @@ snapshots: jest-runner: 28.1.3 jest-util: 28.1.3 jest-validate: 28.1.3 - micromatch: 4.0.5 + micromatch: 4.0.8 parse-json: 5.2.0 pretty-format: 28.1.3 slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 transitivePeerDependencies: - supports-color @@ -14797,7 +15513,7 @@ snapshots: '@jest/environment': 28.1.3 '@jest/fake-timers': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 jest-mock: 28.1.3 jest-util: 28.1.3 @@ -14809,14 +15525,14 @@ snapshots: dependencies: '@jest/types': 28.1.3 '@types/graceful-fs': 4.1.5 - '@types/node': 20.12.7 + '@types/node': 22.5.4 anymatch: 3.1.2 fb-watchman: 2.0.0 graceful-fs: 4.2.11 jest-regex-util: 28.0.2 jest-util: 28.1.3 jest-worker: 28.1.3 - micromatch: 4.0.5 + micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 @@ -14840,7 +15556,7 @@ snapshots: '@types/stack-utils': 2.0.0 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 28.1.3 slash: 3.0.0 stack-utils: 2.0.5 @@ -14848,7 +15564,7 @@ snapshots: jest-mock@28.1.3: dependencies: '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 jest-pnp-resolver@1.2.2(jest-resolve@28.1.3): optionalDependencies: @@ -14875,14 +15591,14 @@ snapshots: resolve.exports: 1.1.0 slash: 3.0.0 - jest-runner-eslint@2.2.0(@jest/test-result@28.1.3)(eslint@8.57.0)(jest-runner@28.1.3)(jest@28.1.3(@types/node@20.12.7)): + jest-runner-eslint@2.2.0(@jest/test-result@28.1.3)(eslint@8.57.0)(jest-runner@28.1.3)(jest@28.1.3(@types/node@22.5.4)): dependencies: chalk: 4.1.2 cosmiconfig: 7.1.0 create-jest-runner: 0.11.2(@jest/test-result@28.1.3)(jest-runner@28.1.3) dot-prop: 6.0.1 eslint: 8.57.0 - jest: 28.1.3(@types/node@20.12.7) + jest: 28.1.3(@types/node@22.5.4) transitivePeerDependencies: - '@jest/test-result' - jest-runner @@ -14894,7 +15610,7 @@ snapshots: '@jest/test-result': 28.1.3 '@jest/transform': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 chalk: 4.1.2 emittery: 0.10.2 graceful-fs: 4.2.11 @@ -14976,16 +15692,16 @@ snapshots: jest-util@26.6.2: dependencies: '@jest/types': 26.6.2 - '@types/node': 20.12.7 + '@types/node': 22.5.4 chalk: 4.1.2 graceful-fs: 4.2.11 is-ci: 2.0.0 - micromatch: 4.0.5 + micromatch: 4.0.8 jest-util@28.1.3: dependencies: '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -15004,7 +15720,7 @@ snapshots: dependencies: '@jest/test-result': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 20.12.7 + '@types/node': 22.5.4 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.10.2 @@ -15013,22 +15729,22 @@ snapshots: jest-worker@26.6.2: dependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 merge-stream: 2.0.0 supports-color: 7.2.0 jest-worker@28.1.3: dependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@28.1.3(@types/node@20.12.7): + jest@28.1.3(@types/node@22.5.4): dependencies: '@jest/core': 28.1.3 '@jest/types': 28.1.3 import-local: 3.1.0 - jest-cli: 28.1.3(@types/node@20.12.7) + jest-cli: 28.1.3(@types/node@22.5.4) transitivePeerDependencies: - '@types/node' - supports-color @@ -15052,8 +15768,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@0.1.1: {} - jsbn@1.1.0: {} jsdom@25.0.0: @@ -15090,6 +15804,8 @@ snapshots: json-buffer@3.0.0: {} + json-buffer@3.0.1: {} + json-parse-better-errors@1.0.2: {} json-parse-even-better-errors@2.3.1: {} @@ -15139,18 +15855,18 @@ snapshots: jsonpointer@5.0.0: {} - jsprim@2.0.2: - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - jsx-ast-utils@3.2.0: dependencies: array-includes: 3.1.7 object.assign: 4.1.5 + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.7 + setimmediate: 1.0.5 + just-diff-apply@5.5.0: {} just-diff@6.0.2: {} @@ -15159,11 +15875,19 @@ snapshots: dependencies: json-buffer: 3.0.0 + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + kind-of@6.0.3: {} kleur@3.0.3: {} - lazy-ass@1.6.0: {} + ky@0.33.3: {} + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.7 lerna@8.1.7(encoding@0.1.13): dependencies: @@ -15284,6 +16008,10 @@ snapshots: transitivePeerDependencies: - supports-color + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lilconfig@3.1.1: {} lines-and-columns@1.1.6: {} @@ -15298,17 +16026,6 @@ snapshots: dependencies: uc.micro: 2.1.0 - listr2@3.10.0(enquirer@2.3.6): - dependencies: - cli-truncate: 2.1.0 - colorette: 1.4.0 - enquirer: 2.3.6 - log-update: 4.0.0 - p-map: 4.0.0 - rxjs: 6.6.7 - through: 2.3.8 - wrap-ansi: 7.0.0 - load-json-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -15336,6 +16053,12 @@ snapshots: mlly: 1.7.1 pkg-types: 1.1.3 + locate-app@2.4.39: + dependencies: + '@promptbook/utils': 0.70.0-1 + type-fest: 2.13.0 + userhome: 1.0.0 + locate-path@2.0.0: dependencies: p-locate: 2.0.0 @@ -15358,6 +16081,8 @@ snapshots: lodash._reinterpolate@3.0.0: {} + lodash.clonedeep@4.5.0: {} + lodash.debounce@4.0.8: {} lodash.ismatch@4.4.0: {} @@ -15366,8 +16091,6 @@ snapshots: lodash.merge@4.6.2: {} - lodash.once@4.1.1: {} - lodash.sortby@4.7.0: {} lodash.template@4.5.0: @@ -15381,6 +16104,8 @@ snapshots: lodash.uniq@4.5.0: {} + lodash.zip@4.2.0: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -15388,12 +16113,9 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 - log-update@4.0.0: - dependencies: - ansi-escapes: 4.3.2 - cli-cursor: 3.1.0 - slice-ansi: 4.0.0 - wrap-ansi: 6.2.0 + loglevel-plugin-prefix@0.8.4: {} + + loglevel@1.9.2: {} loose-envify@1.4.0: dependencies: @@ -15412,6 +16134,8 @@ snapshots: lowercase-keys@1.0.1: {} + lowercase-keys@3.0.0: {} + lru-cache@10.4.3: {} lru-cache@11.0.0: {} @@ -15424,6 +16148,10 @@ snapshots: dependencies: yallist: 4.0.0 + lru-cache@7.18.3: {} + + lz-string@1.5.0: {} + magic-string@0.25.7: dependencies: sourcemap-codec: 1.4.8 @@ -15436,7 +16164,7 @@ snapshots: dependencies: '@babel/parser': 7.25.6 '@babel/types': 7.25.6 - source-map-js: 1.2.0 + source-map-js: 1.2.1 make-dir@2.1.0: dependencies: @@ -15609,9 +16337,9 @@ snapshots: merge2@1.4.1: {} - micromatch@4.0.5: + micromatch@4.0.8: dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 mime-db@1.52.0: {} @@ -15624,10 +16352,12 @@ snapshots: mimic-fn@2.1.0: {} - mimic-fn@4.0.0: {} - mimic-response@1.0.1: {} + mimic-response@3.1.0: {} + + mimic-response@4.0.0: {} + min-indent@1.0.1: {} minimatch@10.0.1: @@ -15716,6 +16446,10 @@ snapshots: mitt@2.1.0: {} + mitt@3.0.1: {} + + mkdirp-classic@0.5.3: {} + mkdirp@0.3.0: {} mkdirp@1.0.4: {} @@ -15739,6 +16473,29 @@ snapshots: ms@2.1.2: {} + ms@2.1.3: {} + + msw@2.4.2(typescript@5.5.4): + dependencies: + '@bundled-es-modules/cookie': 2.0.0 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 3.2.0 + '@mswjs/interceptors': 0.29.1 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.5 + chalk: 4.1.2 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.2.2 + strict-event-emitter: 0.5.1 + type-fest: 4.15.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.5.4 + muggle-string@0.4.1: {} multimatch@5.0.0: @@ -15768,6 +16525,8 @@ snapshots: neo-async@2.6.2: {} + netmask@2.0.2: {} + nice-napi@1.0.2: dependencies: node-addon-api: 3.2.1 @@ -15779,12 +16538,26 @@ snapshots: node-addon-api@3.2.1: optional: true + node-domexception@1.0.0: {} + node-fetch@2.6.7(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 optionalDependencies: encoding: 0.1.13 + node-fetch@2.7.0(encoding@0.1.13): + dependencies: + whatwg-url: 5.0.0 + optionalDependencies: + encoding: 0.1.13 + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-gyp-build@4.5.0: optional: true @@ -15847,6 +16620,8 @@ snapshots: query-string: 5.1.1 sort-keys: 2.0.0 + normalize-url@8.0.1: {} + npm-bundled@3.0.1: dependencies: npm-normalize-package-bin: 3.0.1 @@ -15896,10 +16671,6 @@ snapshots: dependencies: path-key: 3.1.1 - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - nth-check@2.1.1: dependencies: boolbase: 1.0.0 @@ -16024,10 +16795,6 @@ snapshots: dependencies: mimic-fn: 2.1.0 - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - open@10.1.0: dependencies: default-browser: 5.2.1 @@ -16077,10 +16844,12 @@ snapshots: os-tmpdir@1.0.2: {} - ospath@1.2.2: {} + outvariant@1.4.3: {} p-cancelable@0.4.1: {} + p-cancelable@3.0.0: {} + p-finally@1.0.0: {} p-is-promise@1.1.0: {} @@ -16144,6 +16913,24 @@ snapshots: dependencies: p-reduce: 2.1.0 + pac-proxy-agent@7.0.2: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.1 + debug: 4.3.7 + get-uri: 6.0.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + package-json-from-dist@1.0.0: {} pacote@18.0.6: @@ -16169,6 +16956,10 @@ snapshots: - bluebird - supports-color + pako@1.0.11: {} + + pako@2.1.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -16229,8 +17020,6 @@ snapshots: path-key@3.1.1: {} - path-key@4.0.0: {} - path-parse@1.0.7: {} path-scurry@1.11.1: @@ -16243,7 +17032,7 @@ snapshots: lru-cache: 11.0.0 minipass: 7.1.2 - path-to-regexp@6.2.0: {} + path-to-regexp@6.2.2: {} path-type@1.1.0: dependencies: @@ -16265,12 +17054,12 @@ snapshots: perfect-debounce@1.0.0: {} - performance-now@2.1.0: {} - - picocolors@1.0.1: {} + picocolors@1.1.0: {} picomatch@2.3.1: {} + picomatch@4.0.2: {} + pify@2.3.0: {} pify@3.0.0: {} @@ -16319,140 +17108,140 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-calc@9.0.1(postcss@8.4.40): + postcss-calc@9.0.1(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-selector-parser: 6.0.16 postcss-value-parser: 4.2.0 - postcss-colormin@6.1.0(postcss@8.4.40): + postcss-colormin@6.1.0(postcss@8.4.45): dependencies: browserslist: 4.23.3 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-convert-values@6.1.0(postcss@8.4.40): + postcss-convert-values@6.1.0(postcss@8.4.45): dependencies: browserslist: 4.23.3 - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-discard-comments@6.0.2(postcss@8.4.40): + postcss-discard-comments@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 - postcss-discard-duplicates@6.0.3(postcss@8.4.40): + postcss-discard-duplicates@6.0.3(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 - postcss-discard-empty@6.0.3(postcss@8.4.40): + postcss-discard-empty@6.0.3(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 - postcss-discard-overridden@6.0.2(postcss@8.4.40): + postcss-discard-overridden@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 - postcss-merge-longhand@6.0.5(postcss@8.4.40): + postcss-merge-longhand@6.0.5(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - stylehacks: 6.1.1(postcss@8.4.40) + stylehacks: 6.1.1(postcss@8.4.45) - postcss-merge-rules@6.1.1(postcss@8.4.40): + postcss-merge-rules@6.1.1(postcss@8.4.45): dependencies: browserslist: 4.23.3 caniuse-api: 3.0.0 - cssnano-utils: 4.0.2(postcss@8.4.40) - postcss: 8.4.40 + cssnano-utils: 4.0.2(postcss@8.4.45) + postcss: 8.4.45 postcss-selector-parser: 6.0.16 - postcss-minify-font-values@6.1.0(postcss@8.4.40): + postcss-minify-font-values@6.1.0(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-minify-gradients@6.0.3(postcss@8.4.40): + postcss-minify-gradients@6.0.3(postcss@8.4.45): dependencies: colord: 2.9.3 - cssnano-utils: 4.0.2(postcss@8.4.40) - postcss: 8.4.40 + cssnano-utils: 4.0.2(postcss@8.4.45) + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-minify-params@6.1.0(postcss@8.4.40): + postcss-minify-params@6.1.0(postcss@8.4.45): dependencies: browserslist: 4.23.3 - cssnano-utils: 4.0.2(postcss@8.4.40) - postcss: 8.4.40 + cssnano-utils: 4.0.2(postcss@8.4.45) + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-minify-selectors@6.0.4(postcss@8.4.40): + postcss-minify-selectors@6.0.4(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-selector-parser: 6.0.16 - postcss-normalize-charset@6.0.2(postcss@8.4.40): + postcss-normalize-charset@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 - postcss-normalize-display-values@6.0.2(postcss@8.4.40): + postcss-normalize-display-values@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-normalize-positions@6.0.2(postcss@8.4.40): + postcss-normalize-positions@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@6.0.2(postcss@8.4.40): + postcss-normalize-repeat-style@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-normalize-string@6.0.2(postcss@8.4.40): + postcss-normalize-string@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@6.0.2(postcss@8.4.40): + postcss-normalize-timing-functions@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@6.1.0(postcss@8.4.40): + postcss-normalize-unicode@6.1.0(postcss@8.4.45): dependencies: browserslist: 4.23.3 - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-normalize-url@6.0.2(postcss@8.4.40): + postcss-normalize-url@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@6.0.2(postcss@8.4.40): + postcss-normalize-whitespace@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-ordered-values@6.0.2(postcss@8.4.40): + postcss-ordered-values@6.0.2(postcss@8.4.45): dependencies: - cssnano-utils: 4.0.2(postcss@8.4.40) - postcss: 8.4.40 + cssnano-utils: 4.0.2(postcss@8.4.45) + postcss: 8.4.45 postcss-value-parser: 4.2.0 - postcss-reduce-initial@6.1.0(postcss@8.4.40): + postcss-reduce-initial@6.1.0(postcss@8.4.45): dependencies: browserslist: 4.23.3 caniuse-api: 3.0.0 - postcss: 8.4.40 + postcss: 8.4.45 - postcss-reduce-transforms@6.0.2(postcss@8.4.40): + postcss-reduce-transforms@6.0.2(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 postcss-selector-parser@6.0.16: @@ -16460,24 +17249,24 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@6.0.3(postcss@8.4.40): + postcss-svgo@6.0.3(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-value-parser: 4.2.0 svgo: 3.2.0 - postcss-unique-selectors@6.0.4(postcss@8.4.40): + postcss-unique-selectors@6.0.4(postcss@8.4.45): dependencies: - postcss: 8.4.40 + postcss: 8.4.45 postcss-selector-parser: 6.0.16 postcss-value-parser@4.2.0: {} - postcss@8.4.40: + postcss@8.4.45: dependencies: nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 + picocolors: 1.1.0 + source-map-js: 1.2.1 preact@10.11.3: {} @@ -16491,6 +17280,12 @@ snapshots: pretty-bytes@6.1.1: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + pretty-format@28.1.3: dependencies: '@jest/schemas': 28.1.3 @@ -16516,6 +17311,8 @@ snapshots: proggy@2.0.0: {} + progress@2.0.3: {} + promise-all-reject-late@1.0.1: {} promise-call-limit@3.0.1: {} @@ -16546,7 +17343,18 @@ snapshots: protocols@2.0.1: {} - proxy-from-env@1.0.0: {} + proxy-agent@6.3.1: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.2 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color proxy-from-env@1.1.0: {} @@ -16572,20 +17380,34 @@ snapshots: punycode@2.3.1: {} - q@1.5.1: {} - - qs@6.10.4: + puppeteer-core@21.11.0(encoding@0.1.13): dependencies: - side-channel: 1.0.6 + '@puppeteer/browsers': 1.9.1 + chromium-bidi: 0.5.8(devtools-protocol@0.0.1232444) + cross-fetch: 4.0.0(encoding@0.1.13) + debug: 4.3.4 + devtools-protocol: 0.0.1232444 + ws: 8.16.0 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + q@1.5.1: {} qs@6.9.7: {} + query-selector-shadow-dom@1.0.1: {} + query-string@5.1.1: dependencies: decode-uri-component: 0.2.0 object-assign: 4.1.1 strict-uri-encode: 1.1.0 + queue-tick@1.0.1: {} + queue@6.0.2: dependencies: inherits: 2.0.4 @@ -16594,12 +17416,16 @@ snapshots: quick-lru@4.0.1: {} + quick-lru@5.1.1: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 react-is@16.13.1: {} + react-is@17.0.2: {} + react-is@18.2.0: {} read-cmd-shim@4.0.0: {} @@ -16664,6 +17490,18 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readable-stream@4.5.2: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -16738,10 +17576,6 @@ snapshots: request-light@0.7.0: {} - request-progress@3.0.0: - dependencies: - throttleit: 1.0.0 - require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -16750,6 +17584,8 @@ snapshots: reselect@4.1.7: {} + resolve-alpn@1.2.1: {} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -16780,6 +17616,14 @@ snapshots: dependencies: lowercase-keys: 1.0.1 + responselike@3.0.0: + dependencies: + lowercase-keys: 3.0.0 + + resq@1.11.0: + dependencies: + fast-deep-equal: 2.0.1 + restore-cursor@2.0.0: dependencies: onetime: 2.0.1 @@ -16794,6 +17638,8 @@ snapshots: reusify@1.0.4: {} + rgb2hex@0.2.5: {} + rimraf@3.0.2: dependencies: glob: 7.2.3 @@ -16824,13 +17670,13 @@ snapshots: transitivePeerDependencies: - rollup - rollup-plugin-sourcemaps@0.6.3(@types/node@20.12.7)(rollup@3.29.4): + rollup-plugin-sourcemaps@0.6.3(@types/node@22.5.4)(rollup@3.29.4): dependencies: '@rollup/pluginutils': 3.1.0(rollup@3.29.4) rollup: 3.29.4 source-map-resolve: 0.6.0 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 rollup-plugin-terser@7.0.2(rollup@2.79.1): dependencies: @@ -16856,25 +17702,26 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - rollup@4.14.1: + rollup@4.21.2: dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.14.1 - '@rollup/rollup-android-arm64': 4.14.1 - '@rollup/rollup-darwin-arm64': 4.14.1 - '@rollup/rollup-darwin-x64': 4.14.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.14.1 - '@rollup/rollup-linux-arm64-gnu': 4.14.1 - '@rollup/rollup-linux-arm64-musl': 4.14.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.14.1 - '@rollup/rollup-linux-riscv64-gnu': 4.14.1 - '@rollup/rollup-linux-s390x-gnu': 4.14.1 - '@rollup/rollup-linux-x64-gnu': 4.14.1 - '@rollup/rollup-linux-x64-musl': 4.14.1 - '@rollup/rollup-win32-arm64-msvc': 4.14.1 - '@rollup/rollup-win32-ia32-msvc': 4.14.1 - '@rollup/rollup-win32-x64-msvc': 4.14.1 + '@rollup/rollup-android-arm-eabi': 4.21.2 + '@rollup/rollup-android-arm64': 4.21.2 + '@rollup/rollup-darwin-arm64': 4.21.2 + '@rollup/rollup-darwin-x64': 4.21.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.21.2 + '@rollup/rollup-linux-arm-musleabihf': 4.21.2 + '@rollup/rollup-linux-arm64-gnu': 4.21.2 + '@rollup/rollup-linux-arm64-musl': 4.21.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.21.2 + '@rollup/rollup-linux-riscv64-gnu': 4.21.2 + '@rollup/rollup-linux-s390x-gnu': 4.21.2 + '@rollup/rollup-linux-x64-gnu': 4.21.2 + '@rollup/rollup-linux-x64-musl': 4.21.2 + '@rollup/rollup-win32-arm64-msvc': 4.21.2 + '@rollup/rollup-win32-ia32-msvc': 4.21.2 + '@rollup/rollup-win32-x64-msvc': 4.21.2 fsevents: 2.3.3 rrweb-cssom@0.6.0: {} @@ -16904,6 +17751,8 @@ snapshots: dependencies: tslib: 2.6.2 + safaridriver@0.1.2: {} + safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 @@ -17005,7 +17854,7 @@ snapshots: dependencies: chokidar: 3.6.0 immutable: 4.0.0 - source-map-js: 1.2.0 + source-map-js: 1.2.1 saxes@6.0.0: dependencies: @@ -17030,6 +17879,10 @@ snapshots: semver@7.6.3: {} + serialize-error@11.0.3: + dependencies: + type-fest: 2.19.0 + serialize-javascript@4.0.0: dependencies: randombytes: 2.1.0 @@ -17052,6 +17905,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + setimmediate@1.0.5: {} + shallow-clone@3.0.1: dependencies: kind-of: 6.0.3 @@ -17114,24 +17969,12 @@ snapshots: slash@4.0.0: {} - slice-ansi@3.0.0: - dependencies: - ansi-styles: 4.2.1 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - - slice-ansi@4.0.0: - dependencies: - ansi-styles: 4.2.1 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - smart-buffer@4.2.0: {} socks-proxy-agent@8.0.4: dependencies: agent-base: 7.1.1 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -17145,7 +17988,7 @@ snapshots: dependencies: is-plain-obj: 1.1.0 - source-map-js@1.2.0: {} + source-map-js@1.2.1: {} source-map-resolve@0.6.0: dependencies: @@ -17170,6 +18013,8 @@ snapshots: sourcemap-codec@1.4.8: {} + spacetrim@0.11.39: {} + spawn-command@0.0.2: {} spdx-correct@3.1.0: @@ -17194,6 +18039,8 @@ snapshots: dependencies: readable-stream: 3.6.0 + split2@4.2.0: {} + split@1.0.1: dependencies: through: 2.3.8 @@ -17202,18 +18049,6 @@ snapshots: sprintf-js@1.1.3: {} - sshpk@1.17.0: - dependencies: - asn1: 0.2.4 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 - ssri@10.0.6: dependencies: minipass: 7.1.2 @@ -17226,12 +18061,24 @@ snapshots: statuses@1.5.0: {} + statuses@2.0.1: {} + std-env@3.7.0: {} stop-iteration-iterator@1.0.0: dependencies: internal-slot: 1.0.7 + streamx@2.20.0: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.1.1 + optionalDependencies: + bare-events: 2.4.2 + + strict-event-emitter@0.5.1: {} + strict-uri-encode@1.1.0: {} string-length@4.0.1: @@ -17342,8 +18189,6 @@ snapshots: strip-final-newline@2.0.0: {} - strip-final-newline@3.0.0: {} - strip-indent@1.0.1: dependencies: get-stdin: 4.0.1 @@ -17360,16 +18205,18 @@ snapshots: dependencies: acorn: 8.12.1 + strnum@1.0.5: {} + strong-log-transformer@2.1.0: dependencies: duplexer: 0.1.1 minimist: 1.2.8 through: 2.3.8 - stylehacks@6.1.1(postcss@8.4.40): + stylehacks@6.1.1(postcss@8.4.45): dependencies: browserslist: 4.23.3 - postcss: 8.4.40 + postcss: 8.4.45 postcss-selector-parser: 6.0.16 supports-color@5.5.0: @@ -17401,10 +18248,24 @@ snapshots: css-tree: 2.3.1 css-what: 6.1.0 csso: 5.0.5 - picocolors: 1.0.1 + picocolors: 1.1.0 symbol-tree@3.2.4: {} + tar-fs@3.0.4: + dependencies: + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 3.1.7 + + tar-fs@3.0.6: + dependencies: + pump: 3.0.0 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.3.3 + bare-path: 2.1.3 + tar-stream@2.2.0: dependencies: bl: 4.1.0 @@ -17413,6 +18274,12 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.0 + tar-stream@3.1.7: + dependencies: + b4a: 1.6.6 + fast-fifo: 1.3.2 + streamx: 2.20.0 + tar@6.2.1: dependencies: chownr: 2.0.0 @@ -17433,7 +18300,7 @@ snapshots: tempy@0.6.0: dependencies: - is-stream: 2.0.0 + is-stream: 2.0.1 temp-dir: 2.0.0 type-fest: 0.16.0 unique-string: 2.0.0 @@ -17462,14 +18329,16 @@ snapshots: glob: 10.4.5 minimatch: 9.0.5 + text-decoder@1.1.1: + dependencies: + b4a: 1.6.6 + text-extensions@1.9.0: {} text-table@0.2.0: {} throat@6.0.2: {} - throttleit@1.0.0: {} - through2@2.0.5: dependencies: readable-stream: 2.3.7 @@ -17491,11 +18360,18 @@ snapshots: tinybench@2.9.0: {} + tinyexec@0.3.0: {} + + tinyglobby@0.2.6: + dependencies: + fdir: 6.3.0(picomatch@4.0.2) + picomatch: 4.0.2 + tinypool@1.0.1: {} tinyrainbow@1.2.0: {} - tinyspy@3.0.0: {} + tinyspy@3.0.2: {} tldts-core@6.1.41: {} @@ -17587,17 +18463,11 @@ snapshots: tuf-js@2.2.1: dependencies: '@tufjs/models': 2.0.1 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 make-fetch-happen: 13.0.1 transitivePeerDependencies: - supports-color - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - - tweetnacl@0.14.5: {} - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -17620,6 +18490,10 @@ snapshots: type-fest@0.8.1: {} + type-fest@2.13.0: {} + + type-fest@2.19.0: {} + type-fest@4.15.0: {} typed-array-buffer@1.0.2: @@ -17678,7 +18552,12 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - undici-types@5.26.5: {} + unbzip2-stream@1.4.3: + dependencies: + buffer: 5.7.1 + through: 2.3.8 + + undici-types@6.19.8: {} unhead@1.9.4: dependencies: @@ -17716,9 +18595,9 @@ snapshots: transitivePeerDependencies: - rollup - unimport@3.7.1(rollup@4.14.1): + unimport@3.7.1(rollup@4.21.2): dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.14.1) + '@rollup/pluginutils': 5.1.0(rollup@4.21.2) acorn: 8.12.1 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 @@ -17767,31 +18646,31 @@ snapshots: transitivePeerDependencies: - rollup - unplugin-auto-import@0.17.5(rollup@4.14.1): + unplugin-auto-import@0.17.5(rollup@4.21.2): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.0(rollup@4.14.1) + '@rollup/pluginutils': 5.1.0(rollup@4.21.2) fast-glob: 3.3.2 local-pkg: 0.5.0 magic-string: 0.30.11 minimatch: 9.0.5 - unimport: 3.7.1(rollup@4.14.1) + unimport: 3.7.1(rollup@4.21.2) unplugin: 1.12.1 transitivePeerDependencies: - rollup - unplugin-fonts@1.0.3(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + unplugin-fonts@1.0.3(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: fast-glob: 3.3.2 unplugin: 1.12.1 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) unplugin-vue-components@0.27.4(@babel/parser@7.25.6)(rollup@3.29.4)(vue@3.4.27(typescript@5.5.4)): dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.1.0(rollup@3.29.4) chokidar: 3.6.0 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 fast-glob: 3.3.2 local-pkg: 0.5.0 magic-string: 0.30.11 @@ -17805,12 +18684,12 @@ snapshots: - rollup - supports-color - unplugin-vue-components@0.27.4(@babel/parser@7.25.6)(rollup@4.14.1)(vue@3.4.27(typescript@5.5.4)): + unplugin-vue-components@0.27.4(@babel/parser@7.25.6)(rollup@4.21.2)(vue@3.4.27(typescript@5.5.4)): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.0(rollup@4.14.1) + '@rollup/pluginutils': 5.1.0(rollup@4.21.2) chokidar: 3.6.0 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 fast-glob: 3.3.2 local-pkg: 0.5.0 magic-string: 0.30.11 @@ -17831,8 +18710,6 @@ snapshots: webpack-sources: 3.2.3 webpack-virtual-modules: 0.6.2 - untildify@4.0.0: {} - upath@1.2.0: {} upath@2.0.1: {} @@ -17841,7 +18718,7 @@ snapshots: dependencies: browserslist: 4.23.3 escalade: 3.1.2 - picocolors: 1.0.1 + picocolors: 1.1.0 uri-js@4.2.2: dependencies: @@ -17853,6 +18730,10 @@ snapshots: url-to-options@1.0.1: {} + urlpattern-polyfill@10.0.0: {} + + userhome@1.0.0: {} + util-deprecate@1.0.2: {} utils-merge@1.0.1: {} @@ -17861,8 +18742,6 @@ snapshots: uuid@3.4.0: {} - uuid@8.3.2: {} - v8-to-istanbul@9.0.1: dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -17884,19 +18763,12 @@ snapshots: type-fest: 4.15.0 vue: 3.4.27(typescript@5.5.4) - verror@1.10.0: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.4.0 - - vite-node@2.0.5(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3): + vite-node@2.1.1(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3): dependencies: cac: 6.7.14 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 pathe: 1.1.2 - tinyrainbow: 1.2.0 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) transitivePeerDependencies: - '@types/node' - less @@ -17908,122 +18780,122 @@ snapshots: - supports-color - terser - vite-plugin-inspect@0.8.3(rollup@4.14.1)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-inspect@0.8.3(rollup@4.21.2)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.0(rollup@4.14.1) - debug: 4.3.6(supports-color@8.1.1) + '@rollup/pluginutils': 5.1.0(rollup@4.21.2) + debug: 4.3.7 error-stack-parser-es: 0.1.1 fs-extra: 11.2.0 open: 10.1.0 perfect-debounce: 1.0.0 - picocolors: 1.0.1 + picocolors: 1.1.0 sirv: 2.0.4 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) transitivePeerDependencies: - rollup - supports-color - vite-plugin-md@0.21.5(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-md@0.21.5(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: - '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) '@yankeeinlondon/gray-matter': 6.2.1 '@yankeeinlondon/happy-wrapper': 2.10.1(encoding@0.1.13) markdown-it: 13.0.2 - source-map-js: 1.2.0 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + source-map-js: 1.2.1 + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) transitivePeerDependencies: - encoding - vite-plugin-md@0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-md@0.22.5(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: - '@vitejs/plugin-vue': 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) - '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + '@vitejs/plugin-vue': 5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + '@yankeeinlondon/builder-api': 1.4.1(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) '@yankeeinlondon/gray-matter': 6.2.1 '@yankeeinlondon/happy-wrapper': 2.10.1(encoding@0.1.13) markdown-it: 13.0.2 - source-map-js: 1.2.0 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + source-map-js: 1.2.1 + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) transitivePeerDependencies: - encoding - vite-plugin-pages@0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-pages@0.32.1(@vue/compiler-sfc@3.4.27)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: '@types/debug': 4.1.12 - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 deep-equal: 2.2.3 extract-comments: 1.1.0 fast-glob: 3.3.2 json5: 2.2.3 local-pkg: 0.5.0 - picocolors: 1.0.1 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) - yaml: 2.4.1 + picocolors: 1.1.0 + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + yaml: 2.5.1 optionalDependencies: '@vue/compiler-sfc': 3.4.27 transitivePeerDependencies: - supports-color - vite-plugin-pwa@0.17.5(@types/babel__core@7.1.19)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-pwa@0.17.5(@types/babel__core@7.1.19)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) workbox-build: 7.0.0(@types/babel__core@7.1.19) workbox-window: 7.0.0 transitivePeerDependencies: - '@types/babel__core' - supports-color - vite-plugin-vue-layouts@0.11.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): + vite-plugin-vue-layouts@0.11.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): dependencies: - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 fast-glob: 3.3.2 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) vue-router: 4.3.0(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color - vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.1): + vite-plugin-vuetify@2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.1): dependencies: '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.1(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4))) - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 upath: 2.0.1 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) vuetify: 3.7.1(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color optional: true - vite-plugin-vuetify@2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify): + vite-plugin-vuetify@2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify): dependencies: '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify) - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 upath: 2.0.1 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) vuetify: link:packages/vuetify transitivePeerDependencies: - supports-color - vite-plugin-warmup@0.1.0(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): + vite-plugin-warmup@0.1.0(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)): dependencies: fast-glob: 3.3.2 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) - vite-ssr@0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): + vite-ssr@0.17.1(@vitejs/plugin-vue@5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)))(@vueuse/head@1.3.1(vue@3.4.27(typescript@5.5.4)))(encoding@0.1.13)(rollup@3.29.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue-router@4.3.0(vue@3.4.27(typescript@5.5.4)))(vue@3.4.27(typescript@5.5.4)): dependencies: '@rollup/plugin-replace': 3.0.0(rollup@3.29.4) '@vue/server-renderer': 3.4.27(vue@3.4.27(typescript@5.5.4)) chalk: 4.1.2 connect: 3.7.0 - node-fetch: 2.6.7(encoding@0.1.13) - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + node-fetch: 2.7.0(encoding@0.1.13) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) optionalDependencies: - '@vitejs/plugin-vue': 5.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) + '@vitejs/plugin-vue': 5.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4)) '@vueuse/head': 1.3.1(vue@3.4.27(typescript@5.5.4)) vue: 3.4.27(typescript@5.5.4) vue-router: 4.3.0(vue@3.4.27(typescript@5.5.4)) @@ -18032,46 +18904,49 @@ snapshots: - rollup - supports-color - vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3): + vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3): dependencies: esbuild: 0.21.5 - postcss: 8.4.40 - rollup: 4.14.1 + postcss: 8.4.45 + rollup: 4.21.2 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 fsevents: 2.3.3 sass: 1.77.8 sass-embedded: 1.77.8 terser: 5.31.3 - vitest@2.0.5(@types/node@20.12.7)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3): + vitest@2.1.1(@types/node@22.5.4)(@vitest/browser@2.1.1)(@vitest/ui@2.1.1)(happy-dom@8.9.0(encoding@0.1.13))(jsdom@25.0.0)(msw@2.4.2(typescript@5.5.4))(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3): dependencies: - '@ampproject/remapping': 2.3.0 - '@vitest/expect': 2.0.5 - '@vitest/pretty-format': 2.0.5 - '@vitest/runner': 2.0.5 - '@vitest/snapshot': 2.0.5 - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 + '@vitest/expect': 2.1.1 + '@vitest/mocker': 2.1.1(msw@2.4.2(typescript@5.5.4))(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3)) + '@vitest/pretty-format': 2.1.1 + '@vitest/runner': 2.1.1 + '@vitest/snapshot': 2.1.1 + '@vitest/spy': 2.1.1 + '@vitest/utils': 2.1.1 chai: 5.1.1 - debug: 4.3.6(supports-color@8.1.1) - execa: 8.0.1 + debug: 4.3.7 magic-string: 0.30.11 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.9.0 + tinyexec: 0.3.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) - vite-node: 2.0.5(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) + vite-node: 2.1.1(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 22.5.4 + '@vitest/browser': 2.1.1(typescript@5.5.4)(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vitest@2.1.1)(webdriverio@8.40.5(encoding@0.1.13)) + '@vitest/ui': 2.1.1(vitest@2.1.1) happy-dom: 8.9.0(encoding@0.1.13) jsdom: 25.0.0 transitivePeerDependencies: - less - lightningcss + - msw - sass - sass-embedded - stylus @@ -18201,7 +19076,7 @@ snapshots: vue-eslint-parser@9.4.2(eslint@8.57.0): dependencies: - debug: 4.3.6(supports-color@8.1.1) + debug: 4.3.7 eslint: 8.57.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 @@ -18262,12 +19137,20 @@ snapshots: vue: 3.4.27(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 - vite-plugin-vuetify: 2.0.4(vite@5.4.0(@types/node@20.12.7)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.1) + vite-plugin-vuetify: 2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.77.8)(sass@1.77.8)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.1) w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 + wait-port@1.1.0: + dependencies: + chalk: 4.1.2 + commander: 9.5.0 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + walk-up-path@3.0.1: {} walker@1.0.8: @@ -18278,6 +19161,59 @@ snapshots: dependencies: defaults: 1.0.3 + web-streams-polyfill@3.3.3: {} + + webdriver@8.40.3: + dependencies: + '@types/node': 22.5.4 + '@types/ws': 8.5.12 + '@wdio/config': 8.40.3 + '@wdio/logger': 8.38.0 + '@wdio/protocols': 8.40.3 + '@wdio/types': 8.40.3 + '@wdio/utils': 8.40.3 + deepmerge-ts: 5.1.0 + got: 12.6.1 + ky: 0.33.3 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + webdriverio@8.40.5(encoding@0.1.13): + dependencies: + '@types/node': 22.5.4 + '@wdio/config': 8.40.3 + '@wdio/logger': 8.38.0 + '@wdio/protocols': 8.40.3 + '@wdio/repl': 8.40.3 + '@wdio/types': 8.40.3 + '@wdio/utils': 8.40.3 + archiver: 7.0.1 + aria-query: 5.3.0 + css-shorthand-properties: 1.1.1 + css-value: 0.0.1 + devtools-protocol: 0.0.1342118 + grapheme-splitter: 1.0.4 + import-meta-resolve: 4.1.0 + is-plain-obj: 4.1.0 + jszip: 3.10.1 + lodash.clonedeep: 4.5.0 + lodash.zip: 4.2.0 + minimatch: 9.0.5 + puppeteer-core: 21.11.0(encoding@0.1.13) + query-selector-shadow-dom: 1.0.1 + resq: 1.11.0 + rgb2hex: 0.2.5 + serialize-error: 11.0.3 + webdriver: 8.40.3 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + webidl-conversions@3.0.1: {} webidl-conversions@4.0.2: {} @@ -18390,7 +19326,7 @@ snapshots: workbox-build@7.0.0(@types/babel__core@7.1.19): dependencies: - '@apideck/better-ajv-errors': 0.3.1(ajv@8.12.0) + '@apideck/better-ajv-errors': 0.3.1(ajv@8.17.1) '@babel/core': 7.25.2 '@babel/preset-env': 7.25.3(@babel/core@7.25.2) '@babel/runtime': 7.24.4 @@ -18398,7 +19334,7 @@ snapshots: '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1) '@rollup/plugin-replace': 2.4.2(rollup@2.79.1) '@surma/rollup-plugin-off-main-thread': 2.2.3 - ajv: 8.12.0 + ajv: 8.17.1 common-tags: 1.8.0 fast-json-stable-stringify: 2.1.0 fs-extra: 9.1.0 @@ -18543,6 +19479,8 @@ snapshots: type-fest: 0.4.1 write-json-file: 3.2.0 + ws@8.16.0: {} + ws@8.18.0: {} xml-name-validator@4.0.0: {} @@ -18563,11 +19501,11 @@ snapshots: dependencies: eslint-visitor-keys: 3.4.3 lodash: 4.17.21 - yaml: 2.4.1 + yaml: 2.5.1 yaml@1.10.2: {} - yaml@2.4.1: {} + yaml@2.5.1: {} yargs-parser@18.1.3: dependencies: @@ -18605,4 +19543,12 @@ snapshots: yocto-queue@0.1.0: {} + yoctocolors-cjs@2.1.2: {} + zhead@2.2.4: {} + + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.5.2 diff --git a/scripts/rules/cypress-types-reference.js b/scripts/rules/cypress-types-reference.js deleted file mode 100644 index fb19ce3c829..00000000000 --- a/scripts/rules/cypress-types-reference.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('upath') - -module.exports = { - meta: { - fixable: 'code', - }, - create (context) { - return { - Program (node) { - const referencePath = path.relative( - path.dirname(context.getFilename()), - path.resolve(__dirname, '../../packages/vuetify/types/cypress') - ) - const cypressTypesReference = node.comments.find(comment => ( - comment.type === 'Line' && - comment.value.trim() === `/ ` - )) - if (!cypressTypesReference) { - context.report({ - loc: { - start: { line: 0, column: 0 }, - end: { line: 0, column: 0 }, - }, - message: 'Missing Cypress types reference', - fix (fixer) { - return fixer.insertTextAfterRange([0, 0], `/// \n`) - }, - }) - } - }, - } - }, -} diff --git a/scripts/rules/sort-imports.js b/scripts/rules/sort-imports.js index a303c3ef917..4aec82f6c37 100644 --- a/scripts/rules/sort-imports.js +++ b/scripts/rules/sort-imports.js @@ -17,7 +17,7 @@ const groups = [ }, { label: 'Utilities', - match: /^@\/util|^vue$|^vue-|^@vue\/|^@jest|^vitest/, + match: /^@\/util|^vue$|^vue-|^@vue\/|^@jest|^@?vitest|^@test$|^@testing-library\//, }, { label: 'Types', diff --git a/scripts/rules/vitest-global-imports.js b/scripts/rules/vitest-global-imports.js index c6175c89f14..fa9d73d49b7 100644 --- a/scripts/rules/vitest-global-imports.js +++ b/scripts/rules/vitest-global-imports.js @@ -12,18 +12,32 @@ module.exports = { node.source.value === 'vitest' )) - if (!vitestGlobalsImport) { + if (!vitestGlobalsImport) return + + const badNodes = vitestGlobalsImport.specifiers.filter(node => ( + ['afterAll', 'afterEach', 'assert', 'beforeAll', 'beforeEach', 'describe', 'expect', 'it', 'vi'] + .includes(node.imported.name) + )) + + if (badNodes.length === vitestGlobalsImport.specifiers.length) { context.report({ - loc: { - start: { line: 0, column: 0 }, - end: { line: 0, column: 0 }, - }, - message: 'Missing vitest import', + node: vitestGlobalsImport, + message: 'Extraneous vitest imports', fix (fixer) { - const firstImport = node.body.find(node => node.type === 'ImportDeclaration') - return fixer.insertTextBefore(firstImport || node, `import { expect, it } from 'vitest'\n`) + const range = vitestGlobalsImport.range + return fixer.removeRange([range[0], range[1] + 1]) }, }) + } else { + for (const node of badNodes) { + context.report({ + node, + message: 'Extraneous vitest import', + fix (fixer) { + return fixer.remove(node) + }, + }) + } } }, } diff --git a/tsconfig.json b/tsconfig.json index b47e090c342..feefcfe3ca8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -51,6 +51,7 @@ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + "allowImportingTsExtensions": true, /* Source Map Options */ // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ From c8ed4bbca55240d5cb538ae35f88241ffdda6563 Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 26 Sep 2024 19:31:15 +1000 Subject: [PATCH 098/190] chore: fix TEST_BAIL env variable name --- packages/vuetify/vitest.workspace.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/vitest.workspace.mts b/packages/vuetify/vitest.workspace.mts index 70feb820b16..d2a5abc7394 100644 --- a/packages/vuetify/vitest.workspace.mts +++ b/packages/vuetify/vitest.workspace.mts @@ -33,7 +33,7 @@ export default defineWorkspace([ capabilities: { 'goog:chromeOptions': { // @ts-ignore - args: ['--start-maximized', process.env.BAIL && '--auto-open-devtools-for-tabs'].filter(v => !!v), + args: ['--start-maximized', process.env.TEST_BAIL && '--auto-open-devtools-for-tabs'].filter(v => !!v), }, }, }, From 87a0cdc5c86f8e18dcf5621bc28e33ae5eaf4b2f Mon Sep 17 00:00:00 2001 From: Pavel Mironov Date: Thu, 26 Sep 2024 21:51:54 +0200 Subject: [PATCH 099/190] docs(enterprise-support): consulting services section (#20513) --- packages/docs/components.d.ts | 2 +- .../introduction/ConsultingServices.vue | 81 +++++++++++++++++++ .../en/introduction/enterprise-support.md | 8 ++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 packages/docs/src/components/introduction/ConsultingServices.vue diff --git a/packages/docs/components.d.ts b/packages/docs/components.d.ts index 9c832b073b8..3d6c948e850 100644 --- a/packages/docs/components.d.ts +++ b/packages/docs/components.d.ts @@ -41,7 +41,6 @@ declare module 'vue' { AppBarStoreLink: typeof import('./src/components/app/bar/StoreLink.vue')['default'] AppBarSupportMenu: typeof import('./src/components/app/bar/SupportMenu.vue')['default'] AppBarTeamLink: typeof import('./src/components/app/bar/TeamLink.vue')['default'] - 'AppBarTeamLink.1': typeof import('./src/components/app/bar/TeamLink.1.vue')['default'] AppBarThemeToggle: typeof import('./src/components/app/bar/ThemeToggle.vue')['default'] AppBtn: typeof import('./src/components/app/Btn.vue')['default'] AppCaption: typeof import('./src/components/app/Caption.vue')['default'] @@ -131,6 +130,7 @@ declare module 'vue' { HomeSponsors: typeof import('./src/components/home/Sponsors.vue')['default'] IconsChevronDown: typeof import('./src/components/icons/ChevronDown.vue')['default'] IntroductionComparison: typeof import('./src/components/introduction/Comparison.vue')['default'] + IntroductionConsultingServices: typeof import('./src/components/introduction/ConsultingServices.vue')['default'] IntroductionDirectSupport: typeof import('./src/components/introduction/DirectSupport.vue')['default'] IntroductionDiscordDeck: typeof import('./src/components/introduction/DiscordDeck.vue')['default'] IntroductionEnterpriseDeck: typeof import('./src/components/introduction/EnterpriseDeck.vue')['default'] diff --git a/packages/docs/src/components/introduction/ConsultingServices.vue b/packages/docs/src/components/introduction/ConsultingServices.vue new file mode 100644 index 00000000000..2b1b05d914e --- /dev/null +++ b/packages/docs/src/components/introduction/ConsultingServices.vue @@ -0,0 +1,81 @@ + + + diff --git a/packages/docs/src/pages/en/introduction/enterprise-support.md b/packages/docs/src/pages/en/introduction/enterprise-support.md index 21f29a78faa..9dbfe1fb551 100644 --- a/packages/docs/src/pages/en/introduction/enterprise-support.md +++ b/packages/docs/src/pages/en/introduction/enterprise-support.md @@ -30,3 +30,11 @@ Vuetify offers a variety of support options to meet any need. Get direct access to the Vuetify team through our private [Discord server](https://community.vuetifyjs.com/). Ask questions, get help, and chat with the team. + +
+ +## Consulting Services + +Take your software projects to the next level with the expert consulting services of our trusted partner, [Epicmax](https://www.epicmax.co/?ref=vuetify). With extensive experience in delivering Vuetify-based projects, Epicmax provides specialized guidance to ensure your project is efficient, innovative, and tailored to your unique requirements. + + From 88b408a7fd56fb005440f37cccaccde16ca44fe8 Mon Sep 17 00:00:00 2001 From: Andrew Henry Date: Thu, 3 Oct 2024 08:23:22 -0400 Subject: [PATCH 100/190] docs(defaults-btn-group): use v-btn-group in example --- .../src/examples/v-btn/defaults-btn-group.vue | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/docs/src/examples/v-btn/defaults-btn-group.vue b/packages/docs/src/examples/v-btn/defaults-btn-group.vue index d6d632abda1..6dd22e0db95 100644 --- a/packages/docs/src/examples/v-btn/defaults-btn-group.vue +++ b/packages/docs/src/examples/v-btn/defaults-btn-group.vue @@ -1,7 +1,6 @@ - - - - From abbf2e160a5f11ce4d452499feae7607f134e544 Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 4 Oct 2024 00:22:51 +1000 Subject: [PATCH 101/190] chore: force cloudflare to revalidate assets --- vercel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vercel.json b/vercel.json index 7ecf12bef45..b4e2d8de1e0 100644 --- a/vercel.json +++ b/vercel.json @@ -27,7 +27,7 @@ "headers": [ { "key" : "Cache-Control", - "value" : "public, immutable, max-age=31536000, stale-if-error=604800" + "value" : "public, immutable, max-age=31536000, stale-if-error=604800, s-maxage=300" } ] }, From 6173caba27f03e325cc8c48c59603339de8c9b46 Mon Sep 17 00:00:00 2001 From: Kael Date: Sat, 5 Oct 2024 16:34:06 +1000 Subject: [PATCH 102/190] docs: add umami analytics --- packages/docs/src/components/app/Toc.vue | 3 +++ .../src/components/app/bar/EnterpriseLink.vue | 3 +++ .../src/components/app/bar/SettingsToggle.vue | 2 ++ .../docs/src/components/app/bar/ThemeToggle.vue | 2 ++ packages/docs/vite.config.mts | 17 +++++++++++++++++ 5 files changed, 27 insertions(+) diff --git a/packages/docs/src/components/app/Toc.vue b/packages/docs/src/components/app/Toc.vue index b15dc95df0a..b21e3eb43b0 100644 --- a/packages/docs/src/components/app/Toc.vue +++ b/packages/docs/src/components/app/Toc.vue @@ -106,7 +106,10 @@ cols="12" > diff --git a/packages/docs/src/components/app/bar/ThemeToggle.vue b/packages/docs/src/components/app/bar/ThemeToggle.vue index 1786d87c08e..5aa1b3ca53b 100644 --- a/packages/docs/src/components/app/bar/ThemeToggle.vue +++ b/packages/docs/src/components/app/bar/ThemeToggle.vue @@ -3,6 +3,8 @@ v-if="!hasToggle" :icon="icon" color="medium-emphasis" + data-umami-event="app-bar" + data-umami-event-type="theme-toggle" path="theme" @click="onClick" /> diff --git a/packages/docs/vite.config.mts b/packages/docs/vite.config.mts index adbba51ff9c..bc25377ed9d 100644 --- a/packages/docs/vite.config.mts +++ b/packages/docs/vite.config.mts @@ -349,6 +349,23 @@ export default defineConfig(({ command, mode, isSsrBuild }) => { }, }, + { + name: 'inject-umami', + transformIndexHtml (html, ctx) { + if (mode !== 'production') return + + return [{ + tag: 'script', + attrs: { + defer: true, + src: 'https://umami.vuetifyjs.com/script.js', + 'data-website-id': 'c635330a-f1a7-49cf-8894-3ff2cfa0331e', + }, + injectTo: 'head', + }] + }, + }, + Inspect(), process.env.HTTPS === 'true' ? basicSsl() : undefined, From 764adc84a024e166277a38f0489712093e78a43d Mon Sep 17 00:00:00 2001 From: Kael Date: Mon, 7 Oct 2024 04:04:10 +1100 Subject: [PATCH 103/190] chore: publish docs to coolify --- .github/workflows/ci.yml | 33 +++++++++++++++++++++++++++- Dockerfile | 4 ++++ packages/docs/build/nginx.conf | 40 ++++++++++++++++++++++++++++++++++ scripts/deploy-and-alias.js | 4 +--- 4 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 Dockerfile create mode 100644 packages/docs/build/nginx.conf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f00c0a5f41c..7f910f9508f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,7 +139,7 @@ jobs: name: docs-dist path: packages/docs/dist - publish-docs: + publish-docs-vercel: needs: [lint, test-unit, build-docs] runs-on: ubuntu-latest if: github.event_name == 'push' && github.repository_owner == 'vuetifyjs' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/next') @@ -153,3 +153,34 @@ jobs: - run: node scripts/deploy-and-alias.js ${{ github.ref }} env: NOW_TOKEN: ${{ secrets.NOW_TOKEN }} + + publish-docs-coolify: + needs: [lint, test-unit, build-docs] + runs-on: ubuntu-latest + environment: Production + if: github.event_name == 'push' && github.repository_owner == 'vuetifyjs' && github.ref == 'refs/heads/master' + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/download-artifact + with: + name: docs-dist + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/vuetifyjs/docs + - uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile + platforms: linux/amd64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + - name: Deploy to Coolify + run: | + curl --request GET '${{ secrets.COOLIFY_WEBHOOK }}' --header 'Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}' diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..d149e10e681 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:alpine +EXPOSE 80 +COPY ./packages/docs/dist /usr/share/nginx/html +COPY ./packages/docs/build/nginx.conf /etc/nginx/nginx.conf diff --git a/packages/docs/build/nginx.conf b/packages/docs/build/nginx.conf new file mode 100644 index 00000000000..ca0860572dc --- /dev/null +++ b/packages/docs/build/nginx.conf @@ -0,0 +1,40 @@ +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + root /usr/share/nginx/html; + + sendfile on; + tcp_nopush on; + + keepalive_timeout 65; + + server { + listen 80; + server_name localhost; + + charset utf-8; + + location / { + index index.html; + try_files $uri $uri/ /_fallback.html; + add_header Cache-Control 'public, max-age=3600, s-maxage=60'; + } + + location /assets/ { + add_header Cache-Control 'public, immutable, max-age=31536000, stale-if-error=604800'; + } + + location = /service-worker.js { + add_header Cache-Control 'public, max-age=0, s-maxage=60, must-revalidate'; + } + + #error_page 404 /404.html; + #error_page 500 502 503 504 /50x.html; + } +} diff --git a/scripts/deploy-and-alias.js b/scripts/deploy-and-alias.js index a949de7fd44..6e2fcebc8c0 100644 --- a/scripts/deploy-and-alias.js +++ b/scripts/deploy-and-alias.js @@ -25,6 +25,4 @@ if (child.code !== 0) { } const instanceUrl = child.stdout -setTimeout(() => { - shell.exec(`vercel alias set ${instanceUrl} ${alias} --scope=vuetifyjs --token=$NOW_TOKEN`, options) -}, 15_000) +shell.exec(`vercel alias set ${instanceUrl} ${alias} --scope=vuetifyjs --token=$NOW_TOKEN`, options) From 1dc48ff0022d2bc449e4b98dd68183f2a9c9ad58 Mon Sep 17 00:00:00 2001 From: Kael Date: Wed, 9 Oct 2024 01:10:11 +1100 Subject: [PATCH 104/190] docs: gracefully handle precache failure --- packages/docs/src/service-worker.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/docs/src/service-worker.js b/packages/docs/src/service-worker.js index d9d681536d6..6c3fd0eb60f 100644 --- a/packages/docs/src/service-worker.js +++ b/packages/docs/src/service-worker.js @@ -233,7 +233,13 @@ async function cacheManifestEntries (manifest) { } const cache = await openCache('precache') await eachLimit(urlsToCacheKeys, 10, async ([url, cacheKey]) => { - const response = ensureCacheableResponse(await fetch(url)) + let response + try { + response = ensureCacheableResponse(await fetch(url)) + } catch (err) { + console.warn(`[SW] Failed to cache ${url}`, err.message) + return + } if (response.status === 200) { await cache.put(cacheKey, response) } else { From 281bd16a36246353e421afb2f1720d38d12a5d91 Mon Sep 17 00:00:00 2001 From: MajesticPotatoe Date: Tue, 8 Oct 2024 20:04:30 -0400 Subject: [PATCH 105/190] docs: add missing locale for blog button --- packages/docs/src/i18n/messages/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/docs/src/i18n/messages/en.json b/packages/docs/src/i18n/messages/en.json index f5de14a3293..f495f07113e 100644 --- a/packages/docs/src/i18n/messages/en.json +++ b/packages/docs/src/i18n/messages/en.json @@ -29,6 +29,7 @@ "bars": "Bars", "become-a-sponsor": "Become a sponsor", "blackguard": "Blackguard", + "blog": "Blog", "brand-kit": "Brand Kit", "breakpoints-table": { "caption": "Material Design Breakpoints", From d795591bd6d9f6720a13cdf9a304ee020fa880bd Mon Sep 17 00:00:00 2001 From: MajesticPotatoe Date: Tue, 8 Oct 2024 20:06:18 -0400 Subject: [PATCH 106/190] docs: add additional links to-from data-table and api --- packages/docs/src/data/page-to-api.json | 6 ++++++ .../docs/src/pages/en/components/data-tables/basics.md | 10 ++++++++++ .../en/components/data-tables/server-side-tables.md | 8 ++++++++ .../pages/en/components/data-tables/virtual-tables.md | 8 ++++++++ 4 files changed, 32 insertions(+) diff --git a/packages/docs/src/data/page-to-api.json b/packages/docs/src/data/page-to-api.json index 49014d5d39a..f4b5b5230b9 100644 --- a/packages/docs/src/data/page-to-api.json +++ b/packages/docs/src/data/page-to-api.json @@ -69,6 +69,12 @@ "VDataTableServer", "VDataTableVirtual" ], + "components/data-tables/server-side-tables": [ + "VDataTableServer" + ], + "components/data-tables/virtual-tables": [ + "VDataTableVirtual" + ], "components/date-inputs": ["VDateInput", "VDatePicker"], "components/date-pickers-month": ["VDatePicker"], "components/date-pickers": ["VDatePicker", "VDateInput"], diff --git a/packages/docs/src/pages/en/components/data-tables/basics.md b/packages/docs/src/pages/en/components/data-tables/basics.md index b7d4cc19a87..5cb61c53a74 100644 --- a/packages/docs/src/pages/en/components/data-tables/basics.md +++ b/packages/docs/src/pages/en/components/data-tables/basics.md @@ -36,6 +36,8 @@ The standard data table presumes that the entire data set is available locally. | [v-data-table](/api/v-data-table/) | Primary Component | | [v-data-table-headers](/api/v-data-table-headers/) | Functional Component used to display Data-table headers | | [v-data-table-footer](/api/v-data-table-footer/) | Functional Component used to display Data-table footers | +| [v-data-table-row](/api/v-data-table-row/) | Functional Component used to display a single row of a data-table | +| [v-data-table-rows](/api/v-data-table-rows/) | Functional Component used to display all of the rows in a data-table | | [v-checkbox-btn](/api/v-checkbox-btn/) | Reusable lightweight [v-checkbox](/components/checkboxes) | @@ -44,6 +46,10 @@ The standard data table presumes that the entire data set is available locally. This variant of the data table is meant to be used for very large datasets, where it would be inefficient to load all the data into the client. It supports sorting, filtering, pagination, and selection like a standard data table, but all the logic must be handled externally by your backend or database. +| Component | Description | +| - | - | +| [v-data-table-server](/api/v-data-table-server/) | Primary Component | + Find more information and examples on the [Server side tables](/components/data-tables/server-side-tables) page. @@ -52,6 +58,10 @@ Find more information and examples on the [Server side tables](/components/data- The virtual variant of the data table relies, like the standard variant, on all data being available locally. But unlike the standard variant it uses virtualization to only render a small portion of the rows. This makes it well suited for displaying large data sets. It supports client-side sorting and filtering, but not pagination. +| Component | Description | +| - | - | +| [v-data-table-virtual](/api/v-data-table-virtual/) | Primary Component | + Find more information and examples on the [Virtual tables](/components/data-tables/virtual-tables) page. diff --git a/packages/docs/src/pages/en/components/data-tables/server-side-tables.md b/packages/docs/src/pages/en/components/data-tables/server-side-tables.md index 0e93bb75b9f..a5c0e35ecbf 100644 --- a/packages/docs/src/pages/en/components/data-tables/server-side-tables.md +++ b/packages/docs/src/pages/en/components/data-tables/server-side-tables.md @@ -16,6 +16,14 @@ Server-side Data tables are used for showing data coming from an API. +## API + +| Component | Description | +| - | - | +| [v-data-table-server](/api/v-data-table-server/) | Primary Component | + + + ## Examples ### Server-side paginate and sort diff --git a/packages/docs/src/pages/en/components/data-tables/virtual-tables.md b/packages/docs/src/pages/en/components/data-tables/virtual-tables.md index e52d9ee9957..798b17af0f3 100644 --- a/packages/docs/src/pages/en/components/data-tables/virtual-tables.md +++ b/packages/docs/src/pages/en/components/data-tables/virtual-tables.md @@ -16,6 +16,14 @@ The v-data-table-virtual component relies on all data being available locally. B +## API + +| Component | Description | +| - | - | +| [v-data-table-virtual](/api/v-data-table-virtual/) | Primary Component | + + + ## Examples ### Basic example From ef13e28ba3e18c7194f5ddde9d159200d2cb77a9 Mon Sep 17 00:00:00 2001 From: Ryan Grunest <37844814+ryangrunest@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:28:56 -0700 Subject: [PATCH 107/190] docs: fix grammatical error (#20464) --- .../src/pages/en/components/data-tables/data-and-display.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/pages/en/components/data-tables/data-and-display.md b/packages/docs/src/pages/en/components/data-tables/data-and-display.md index 4f024946ad1..b0226fe94a4 100644 --- a/packages/docs/src/pages/en/components/data-tables/data-and-display.md +++ b/packages/docs/src/pages/en/components/data-tables/data-and-display.md @@ -12,7 +12,7 @@ related: # Data and Display -Data table filtering is key feature that allows users to quickly find the data they are looking for. +Data table filtering is a key feature that allows users to quickly find the data they are looking for. From 6e9f2a1a0a55360118626fc397c6d0dc4498382b Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 11 Oct 2024 17:09:19 +1100 Subject: [PATCH 108/190] fix(v-tooltip): match provides from new vnode fixes #20564 --- packages/vuetify/src/composables/directiveComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/src/composables/directiveComponent.ts b/packages/vuetify/src/composables/directiveComponent.ts index 342efa046b1..1db5d36b254 100644 --- a/packages/vuetify/src/composables/directiveComponent.ts +++ b/packages/vuetify/src/composables/directiveComponent.ts @@ -96,7 +96,7 @@ function findComponentParent (vnode: VNode, root: ComponentInternalInstance): Co for (const child of children) { if (!child) continue - if (child === vnode) { + if (child === vnode || (child.el && vnode.el && child.el === vnode.el)) { return true } From ae33530ac17226ca942849bea364ee441ae1dd9f Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 11 Oct 2024 17:09:43 +1100 Subject: [PATCH 109/190] fix(v-tooltip): log error instead of throwing fixes #20564 --- packages/vuetify/src/composables/directiveComponent.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/vuetify/src/composables/directiveComponent.ts b/packages/vuetify/src/composables/directiveComponent.ts index 1db5d36b254..d8d95cbfb09 100644 --- a/packages/vuetify/src/composables/directiveComponent.ts +++ b/packages/vuetify/src/composables/directiveComponent.ts @@ -1,6 +1,6 @@ // Utilities import { h, mergeProps, render, resolveComponent } from 'vue' -import { isObject } from '@/util' +import { consoleError, isObject } from '@/util' // Types import type { @@ -118,7 +118,8 @@ function findComponentParent (vnode: VNode, root: ComponentInternalInstance): Co return false } if (!walk([root.subTree])) { - throw new Error('Could not find original vnode') + consoleError('Could not find original vnode, component will not inherit provides') + return root } // Return the first component parent From 499f632c44ba1e10b0d26e146ed6e63f04fbde3d Mon Sep 17 00:00:00 2001 From: Kael Date: Mon, 14 Oct 2024 23:05:26 +1100 Subject: [PATCH 110/190] docs: make the service worker optional, improve precache logic (#20425) --- docker-compose.yml | 8 + packages/docs/auto-imports.d.ts | 22 ++ packages/docs/components.d.ts | 1 + .../src/components/app/bar/SettingsToggle.vue | 17 ++ .../components/app/settings/DeveloperMode.vue | 36 ++- .../src/components/app/settings/Drawer.vue | 7 +- .../src/components/app/settings/Options.vue | 14 +- .../app/settings/SettingsHeader.vue | 11 +- .../app/settings/options/AdOption.vue | 29 ++- .../app/settings/options/ApiOption.vue | 29 ++- .../app/settings/options/CodeOption.vue | 29 ++- .../app/settings/options/OfflineOption.vue | 67 ++++++ .../app/settings/options/PinOption.vue | 44 ++-- .../settings/options/SlashSearchOption.vue | 23 +- packages/docs/src/i18n/messages/en.json | 14 +- packages/docs/src/plugins/pwa.ts | 25 +- packages/docs/src/plugins/vuetify.ts | 1 + packages/docs/src/service-worker.js | 220 +++--------------- packages/docs/src/shims.d.ts | 2 + packages/docs/src/stores/pwa.ts | 61 +++++ packages/docs/src/utils/pwa.ts | 97 ++++++++ packages/docs/tsconfig.json | 1 + packages/docs/vite.config.mts | 7 +- 23 files changed, 445 insertions(+), 320 deletions(-) create mode 100644 docker-compose.yml create mode 100644 packages/docs/src/components/app/settings/options/OfflineOption.vue create mode 100644 packages/docs/src/stores/pwa.ts create mode 100644 packages/docs/src/utils/pwa.ts diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000000..3aa0fd8b8b7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +services: + docs: + image: nginx:alpine + ports: + - ${PORT:-8095}:80 + volumes: + - ./packages/docs/dist:/usr/share/nginx/html + - ./packages/docs/build/nginx.conf:/etc/nginx/nginx.conf diff --git a/packages/docs/auto-imports.d.ts b/packages/docs/auto-imports.d.ts index b41ec364536..e6b6cfa4212 100644 --- a/packages/docs/auto-imports.d.ts +++ b/packages/docs/auto-imports.d.ts @@ -14,13 +14,16 @@ declare global { const PropType: typeof import('vue')['PropType'] const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] const anyLanguagePattern: typeof import('./src/utils/routes')['anyLanguagePattern'] + const cacheManifestEntries: typeof import('./src/utils/pwa')['cacheManifestEntries'] const camelCase: typeof import('lodash-es')['camelCase'] const camelize: typeof import('vue')['camelize'] + const cleanCache: typeof import('./src/utils/pwa')['cleanCache'] const computed: typeof import('vue')['computed'] const configureMarkdown: typeof import('./src/utils/markdown-it')['configureMarkdown'] const copyElementContent: typeof import('./src/utils/helpers')['copyElementContent'] const createAdProps: typeof import('./src/composables/ad')['createAdProps'] const createApp: typeof import('vue')['createApp'] + const createCacheKey: typeof import('./src/utils/pwa')['createCacheKey'] const createOne: typeof import('@vuetify/one')['createOne'] const createPinia: typeof import('pinia')['createPinia'] const customRef: typeof import('vue')['customRef'] @@ -29,12 +32,14 @@ declare global { const defineStore: typeof import('pinia')['defineStore'] const disabledLanguagePattern: typeof import('./src/utils/routes')['disabledLanguagePattern'] const effectScope: typeof import('vue')['effectScope'] + const ensureCacheableResponse: typeof import('./src/utils/pwa')['ensureCacheableResponse'] const eventName: typeof import('./src/utils/helpers')['eventName'] const genAppMetaInfo: typeof import('./src/utils/metadata')['genAppMetaInfo'] const genMetaInfo: typeof import('./src/utils/metadata')['genMetaInfo'] const generatedRoutes: typeof import('./src/utils/routes')['generatedRoutes'] const getActivePinia: typeof import('pinia')['getActivePinia'] const getBranch: typeof import('./src/utils/helpers')['getBranch'] + const getCacheKeyForUrl: typeof import('./src/utils/pwa')['getCacheKeyForUrl'] const getCurrentInstance: typeof import('vue')['getCurrentInstance'] const getCurrentScope: typeof import('vue')['getCurrentScope'] const getDistance: typeof import('./src/utils/helpers')['getDistance'] @@ -58,7 +63,9 @@ declare global { const mapWritableState: typeof import('pinia')['mapWritableState'] const markRaw: typeof import('vue')['markRaw'] const markdownItRules: typeof import('./src/utils/markdown-it-rules')['default'] + const matchPrecache: typeof import('./src/utils/pwa')['matchPrecache'] const mergeProps: typeof import('vue')['mergeProps'] + const messageSW: typeof import('./src/utils/pwa')['messageSW'] const nextTick: typeof import('vue')['nextTick'] const onActivated: typeof import('vue')['onActivated'] const onBeforeMount: typeof import('vue')['onBeforeMount'] @@ -76,9 +83,11 @@ declare global { const onServerPrefetch: typeof import('vue')['onServerPrefetch'] const onUnmounted: typeof import('vue')['onUnmounted'] const onUpdated: typeof import('vue')['onUpdated'] + const openCache: typeof import('./src/utils/pwa')['openCache'] const preferredLocale: typeof import('./src/utils/routes')['preferredLocale'] const propsToString: typeof import('./src/utils/helpers')['propsToString'] const provide: typeof import('vue')['provide'] + const pwaStore: typeof import('./src/stores/pwa')['pwaStore'] const reactive: typeof import('vue')['reactive'] const readonly: typeof import('vue')['readonly'] const redirectRoutes: typeof import('./src/utils/routes')['redirectRoutes'] @@ -125,6 +134,7 @@ declare global { const usePlayground: typeof import('./src/composables/playground')['usePlayground'] const useProductsStore: typeof import('@vuetify/one')['useProductsStore'] const usePromotionsStore: typeof import('./src/stores/promotions')['usePromotionsStore'] + const usePwaStore: typeof import('./src/stores/pwa')['usePwaStore'] const useQueueStore: typeof import('@vuetify/one')['useQueueStore'] const useReleasesStore: typeof import('./src/stores/releases')['useReleasesStore'] const useRoute: typeof import('vue-router')['useRoute'] @@ -164,8 +174,10 @@ declare module 'vue' { readonly IS_SERVER: UnwrapRef readonly acceptHMRUpdate: UnwrapRef readonly anyLanguagePattern: UnwrapRef + readonly cacheManifestEntries: UnwrapRef readonly camelCase: UnwrapRef readonly camelize: UnwrapRef + readonly cleanCache: UnwrapRef readonly computed: UnwrapRef readonly configureMarkdown: UnwrapRef readonly copyElementContent: UnwrapRef @@ -179,6 +191,7 @@ declare module 'vue' { readonly defineStore: UnwrapRef readonly disabledLanguagePattern: UnwrapRef readonly effectScope: UnwrapRef + readonly ensureCacheableResponse: UnwrapRef readonly eventName: UnwrapRef readonly genAppMetaInfo: UnwrapRef readonly genMetaInfo: UnwrapRef @@ -209,6 +222,7 @@ declare module 'vue' { readonly markRaw: UnwrapRef readonly markdownItRules: UnwrapRef readonly mergeProps: UnwrapRef + readonly messageSW: UnwrapRef readonly nextTick: UnwrapRef readonly onActivated: UnwrapRef readonly onBeforeMount: UnwrapRef @@ -225,6 +239,7 @@ declare module 'vue' { readonly onServerPrefetch: UnwrapRef readonly onUnmounted: UnwrapRef readonly onUpdated: UnwrapRef + readonly openCache: UnwrapRef readonly preferredLocale: UnwrapRef readonly propsToString: UnwrapRef readonly provide: UnwrapRef @@ -274,6 +289,7 @@ declare module 'vue' { readonly usePlayground: UnwrapRef readonly useProductsStore: UnwrapRef readonly usePromotionsStore: UnwrapRef + readonly usePwaStore: UnwrapRef readonly useQueueStore: UnwrapRef readonly useReleasesStore: UnwrapRef readonly useRoute: UnwrapRef @@ -306,8 +322,10 @@ declare module '@vue/runtime-core' { readonly IS_SERVER: UnwrapRef readonly acceptHMRUpdate: UnwrapRef readonly anyLanguagePattern: UnwrapRef + readonly cacheManifestEntries: UnwrapRef readonly camelCase: UnwrapRef readonly camelize: UnwrapRef + readonly cleanCache: UnwrapRef readonly computed: UnwrapRef readonly configureMarkdown: UnwrapRef readonly copyElementContent: UnwrapRef @@ -321,6 +339,7 @@ declare module '@vue/runtime-core' { readonly defineStore: UnwrapRef readonly disabledLanguagePattern: UnwrapRef readonly effectScope: UnwrapRef + readonly ensureCacheableResponse: UnwrapRef readonly eventName: UnwrapRef readonly genAppMetaInfo: UnwrapRef readonly genMetaInfo: UnwrapRef @@ -351,6 +370,7 @@ declare module '@vue/runtime-core' { readonly markRaw: UnwrapRef readonly markdownItRules: UnwrapRef readonly mergeProps: UnwrapRef + readonly messageSW: UnwrapRef readonly nextTick: UnwrapRef readonly onActivated: UnwrapRef readonly onBeforeMount: UnwrapRef @@ -367,6 +387,7 @@ declare module '@vue/runtime-core' { readonly onServerPrefetch: UnwrapRef readonly onUnmounted: UnwrapRef readonly onUpdated: UnwrapRef + readonly openCache: UnwrapRef readonly preferredLocale: UnwrapRef readonly propsToString: UnwrapRef readonly provide: UnwrapRef @@ -416,6 +437,7 @@ declare module '@vue/runtime-core' { readonly usePlayground: UnwrapRef readonly useProductsStore: UnwrapRef readonly usePromotionsStore: UnwrapRef + readonly usePwaStore: UnwrapRef readonly useQueueStore: UnwrapRef readonly useReleasesStore: UnwrapRef readonly useRoute: UnwrapRef diff --git a/packages/docs/components.d.ts b/packages/docs/components.d.ts index 3d6c948e850..421ea1bea37 100644 --- a/packages/docs/components.d.ts +++ b/packages/docs/components.d.ts @@ -76,6 +76,7 @@ declare module 'vue' { AppSettingsOptionsBannerOption: typeof import('./src/components/app/settings/options/BannerOption.vue')['default'] AppSettingsOptionsCodeOption: typeof import('./src/components/app/settings/options/CodeOption.vue')['default'] AppSettingsOptionsNotificationsOption: typeof import('./src/components/app/settings/options/NotificationsOption.vue')['default'] + AppSettingsOptionsOfflineOption: typeof import('./src/components/app/settings/options/OfflineOption.vue')['default'] AppSettingsOptionsPinOption: typeof import('./src/components/app/settings/options/PinOption.vue')['default'] AppSettingsOptionsQuickbarOption: typeof import('./src/components/app/settings/options/QuickbarOption.vue')['default'] AppSettingsOptionsRailDrawerOption: typeof import('./src/components/app/settings/options/RailDrawerOption.vue')['default'] diff --git a/packages/docs/src/components/app/bar/SettingsToggle.vue b/packages/docs/src/components/app/bar/SettingsToggle.vue index a181f2a0ea7..f5a4f486a78 100644 --- a/packages/docs/src/components/app/bar/SettingsToggle.vue +++ b/packages/docs/src/components/app/bar/SettingsToggle.vue @@ -1,5 +1,21 @@ diff --git a/packages/docs/src/components/app/bar/ThemeToggle.vue b/packages/docs/src/components/app/bar/ThemeToggle.vue index 5aa1b3ca53b..1786d87c08e 100644 --- a/packages/docs/src/components/app/bar/ThemeToggle.vue +++ b/packages/docs/src/components/app/bar/ThemeToggle.vue @@ -3,8 +3,6 @@ v-if="!hasToggle" :icon="icon" color="medium-emphasis" - data-umami-event="app-bar" - data-umami-event-type="theme-toggle" path="theme" @click="onClick" /> diff --git a/packages/docs/src/main.ts b/packages/docs/src/main.ts index f328c802bfe..fae1579c859 100644 --- a/packages/docs/src/main.ts +++ b/packages/docs/src/main.ts @@ -1,7 +1,8 @@ // Styles import 'prism-theme-vars/base.css' -// Plugins +// Pluginse +import * as Swetrix from 'swetrix' import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import { createHead } from '@unhead/vue' @@ -50,6 +51,11 @@ if (IN_BROWSER) { userStore.$subscribe(() => { userStore.save() }) + Swetrix.init('ycvR7fW63FFz', { + apiURL: 'https://swetrix-api.vuetifyjs.com/log', + }) + Swetrix.trackViews() + Swetrix.trackErrors() } const app = createApp(App) @@ -115,6 +121,13 @@ app.use(router) app.config.errorHandler = (err, vm, info) => { console.error(err, vm, info) + Swetrix.trackError({ + name: (err as any).name, + message: (err as any).message, + lineno: null, + colno: null, + filename: null, + }) } app.config.warnHandler = (err, vm, info) => { console.warn(err, vm, info) @@ -139,9 +152,23 @@ router.onError((err, to) => { location.assign(to.fullPath) } else { console.error('Dynamic import error, reloading page did not fix it', err) + Swetrix.trackError({ + name: err.name, + message: err.message, + lineno: null, + colno: null, + filename: null, + }) } } else { console.error(err) + Swetrix.trackError({ + name: err?.name, + message: err?.message, + lineno: null, + colno: null, + filename: null, + }) } }) diff --git a/packages/docs/src/utils/analytics.ts b/packages/docs/src/utils/analytics.ts index 12f284906a7..92f9a091663 100644 --- a/packages/docs/src/utils/analytics.ts +++ b/packages/docs/src/utils/analytics.ts @@ -1,4 +1,5 @@ /* eslint-disable camelcase */ +import { track } from 'swetrix' export function gtagClick ( event_category: string, @@ -8,4 +9,12 @@ export function gtagClick ( const { event } = useGtag() event('click', { event_category, event_label, value }) + track({ + ev: 'click', + meta: { + category: event_category, + label: event_label, + value, + }, + }) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3db693197da..b0feee60e70 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -118,7 +118,7 @@ importers: version: 9.24.1(eslint@8.57.0) eslint-plugin-vuetify: specifier: ^2.3.0 - version: 2.3.0(eslint@8.57.0)(vuetify@3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4))) + version: 2.3.0(eslint@8.57.0)(vuetify@3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4))) glob: specifier: ^11.0.0 version: 11.0.0 @@ -267,6 +267,9 @@ importers: roboto-fontface: specifier: ^0.10.0 version: 0.10.0 + swetrix: + specifier: ^3.5.0 + version: 3.5.0 vee-validate: specifier: ^4.12.6 version: 4.12.6(vue@3.4.27(typescript@5.5.4)) @@ -8216,6 +8219,9 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + swetrix@3.5.0: + resolution: {integrity: sha512-oL0d259iP8Mz6qeEj2KU6LAU0uvJzdgTXDP3wUX6V+LpzLNDMytOCRp1Cf+/IlOvV3w/jOOe3w6ZpHzjDRz6QQ==} + symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -9010,8 +9016,8 @@ packages: typescript: optional: true - vuetify@3.7.2: - resolution: {integrity: sha512-q0WTcRG977+a9Dqhb8TOaPm+Xmvj0oVhnBJhAdHWFSov3HhHTTxlH2nXP/GBTXZuuMHDbBeIWFuUR2/1Fx0PPw==} + vuetify@3.7.3: + resolution: {integrity: sha512-bpuvBpZl1/+nLlXDgdVXekvMNR6W/ciaoa8CYlpeAzAARbY8zUFSoBq05JlLhkIHI58AnzKVy4c09d0OtfYAPg==} engines: {node: ^12.20 || >=14.13} peerDependencies: typescript: '>=4.7' @@ -12391,11 +12397,11 @@ snapshots: vue: 3.4.27(typescript@5.5.4) vue-demi: 0.13.11(vue@3.4.27(typescript@5.5.4)) - '@vuetify/loader-shared@2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)))': + '@vuetify/loader-shared@2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)))': dependencies: upath: 2.0.1 vue: 3.4.27(typescript@5.5.4) - vuetify: 3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)) + vuetify: 3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)) optional: true '@vuetify/loader-shared@2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@packages+vuetify)': @@ -14366,12 +14372,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-vuetify@2.3.0(eslint@8.57.0)(vuetify@3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4))): + eslint-plugin-vuetify@2.3.0(eslint@8.57.0)(vuetify@3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4))): dependencies: eslint: 8.57.0 eslint-plugin-vue: 9.24.1(eslint@8.57.0) requireindex: 1.2.0 - vuetify: 3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)) + vuetify: 3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color @@ -18434,6 +18440,11 @@ snapshots: csso: 5.0.5 picocolors: 1.1.0 + swetrix@3.5.0: + dependencies: + '@types/node': 22.5.4 + tslib: 2.6.2 + symbol-tree@3.2.4: {} tar-fs@3.0.4: @@ -19042,14 +19053,14 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vuetify@2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.80.1)(sass@1.80.1)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.2): + vite-plugin-vuetify@2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.80.1)(sass@1.80.1)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.3): dependencies: - '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4))) + '@vuetify/loader-shared': 2.0.3(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4))) debug: 4.3.7 upath: 2.0.1 vite: 5.4.3(@types/node@22.5.4)(sass-embedded@1.80.1)(sass@1.80.1)(terser@5.31.3) vue: 3.4.27(typescript@5.5.4) - vuetify: 3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)) + vuetify: 3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)) transitivePeerDependencies: - supports-color optional: true @@ -19316,12 +19327,12 @@ snapshots: optionalDependencies: typescript: 5.5.4 - vuetify@3.7.2(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)): + vuetify@3.7.3(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.27(typescript@5.5.4)): dependencies: vue: 3.4.27(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 - vite-plugin-vuetify: 2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.80.1)(sass@1.80.1)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.2) + vite-plugin-vuetify: 2.0.4(vite@5.4.3(@types/node@22.5.4)(sass-embedded@1.80.1)(sass@1.80.1)(terser@5.31.3))(vue@3.4.27(typescript@5.5.4))(vuetify@3.7.3) w3c-xmlserializer@5.0.0: dependencies: From a72df884ba8415a272332f86bba8401eec7d6fc5 Mon Sep 17 00:00:00 2001 From: Kael Date: Sun, 3 Nov 2024 19:26:12 +1100 Subject: [PATCH 146/190] fix(VDialog,VMenu): remove focus listeners on unmount fixes #20422 --- .../vuetify/src/components/VDialog/VDialog.tsx | 6 +++++- packages/vuetify/src/components/VMenu/VMenu.tsx | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/vuetify/src/components/VDialog/VDialog.tsx b/packages/vuetify/src/components/VDialog/VDialog.tsx index 10063444860..9123e28fe9e 100644 --- a/packages/vuetify/src/components/VDialog/VDialog.tsx +++ b/packages/vuetify/src/components/VDialog/VDialog.tsx @@ -13,7 +13,7 @@ import { useProxiedModel } from '@/composables/proxiedModel' import { useScopeId } from '@/composables/scopeId' // Utilities -import { mergeProps, nextTick, ref, watch } from 'vue' +import { mergeProps, nextTick, onBeforeUnmount, ref, watch } from 'vue' import { focusableChildren, genericComponent, IN_BROWSER, propsFactory, useRender } from '@/util' // Types @@ -81,6 +81,10 @@ export const VDialog = genericComponent()({ } } + onBeforeUnmount(() => { + document.removeEventListener('focusin', onFocusin) + }) + if (IN_BROWSER) { watch(() => isActive.value && props.retainFocus, val => { val diff --git a/packages/vuetify/src/components/VMenu/VMenu.tsx b/packages/vuetify/src/components/VMenu/VMenu.tsx index dca8145e8d7..6997992fc43 100644 --- a/packages/vuetify/src/components/VMenu/VMenu.tsx +++ b/packages/vuetify/src/components/VMenu/VMenu.tsx @@ -33,6 +33,7 @@ import { genericComponent, getNextElement, getUid, + IN_BROWSER, isClickInsideElement, omit, propsFactory, @@ -102,7 +103,10 @@ export const VMenu = genericComponent()({ }, }) - onBeforeUnmount(() => parent?.unregister()) + onBeforeUnmount(() => { + parent?.unregister() + document.removeEventListener('focusin', onFocusIn) + }) onDeactivated(() => isActive.value = false) async function onFocusIn (e: FocusEvent) { @@ -130,12 +134,16 @@ export const VMenu = genericComponent()({ watch(isActive, val => { if (val) { parent?.register() - document.addEventListener('focusin', onFocusIn, { once: true }) + if (IN_BROWSER) { + document.addEventListener('focusin', onFocusIn, { once: true }) + } } else { parent?.unregister() - document.removeEventListener('focusin', onFocusIn) + if (IN_BROWSER) { + document.removeEventListener('focusin', onFocusIn) + } } - }) + }, { immediate: true }) function onClickOutside (e: MouseEvent) { parent?.closeParents(e) From bfe631027588b73da8cf94655ae8316c763cafe8 Mon Sep 17 00:00:00 2001 From: SonTT19 <49301480+SonTT19@users.noreply.github.com> Date: Sun, 3 Nov 2024 15:30:04 +0700 Subject: [PATCH 147/190] fix(VBtnToggle): plain variant button opacity when selected (#20279) fixes #20142 --- packages/vuetify/src/components/VBtnToggle/VBtnToggle.sass | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/vuetify/src/components/VBtnToggle/VBtnToggle.sass b/packages/vuetify/src/components/VBtnToggle/VBtnToggle.sass index 953e86af93b..85f9d3cb1a3 100644 --- a/packages/vuetify/src/components/VBtnToggle/VBtnToggle.sass +++ b/packages/vuetify/src/components/VBtnToggle/VBtnToggle.sass @@ -5,3 +5,6 @@ .v-btn-toggle > .v-btn.v-btn--active:not(.v-btn--disabled) @include tools.active-states('> .v-btn__overlay', $btn-toggle-selected-opacity) + + &.v-btn--variant-plain + opacity: 1 From 24b12d914104c6a538f78bce4db96c9749c30a73 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 3 Nov 2024 13:47:22 -0600 Subject: [PATCH 148/190] docs(roadmap): update page content --- packages/docs/src/pages/en/introduction/roadmap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/docs/src/pages/en/introduction/roadmap.md b/packages/docs/src/pages/en/introduction/roadmap.md index 5fa5614ef2a..b31aca97df4 100644 --- a/packages/docs/src/pages/en/introduction/roadmap.md +++ b/packages/docs/src/pages/en/introduction/roadmap.md @@ -24,13 +24,13 @@ The following is a list of all planned components for the year 2024. | Component | Entering Labs | Production Release | |-------------------------------------------------------------------------|----------------|-------------------------------------| -| [v3.8 (Andromeda)](https://github.com/vuetifyjs/vuetify/milestone/74) | | October 2024 { .bg-surface-light } | +| [v3.8 (Andromeda)](https://github.com/vuetifyjs/vuetify/milestone/74) | | Q4 2024 { .bg-surface-light } | | [v-number-input](/components/number-inputs/) | * | | | [v-snackbar-queue](/components/snackbar-queue/) | * | | | [v-time-picker](/components/time-pickers/) | * | | | [v-treeview](/components/treeview/) | * | | | [v-stepper-vertical](/components/vertical-steppers/) | * | | -| [v4.0 (Revisionist)](https://github.com/vuetifyjs/vuetify/milestone/62) | | December 2024 { .bg-surface-light } | +| [v4.0 (Revisionist)](https://github.com/vuetifyjs/vuetify/milestone/62) | | TBA { .bg-surface-light } | | [v-date-input](/components/date-inputs/) | * | | | [v-calendar](/components/calendars/) | * | | | [v-time-input](https://github.com/vuetifyjs/vuetify/pull/19709) | September 2024 | | From 3b1f0f5ca3d724247d45a7264416f03099918166 Mon Sep 17 00:00:00 2001 From: MajesticPotatoe Date: Mon, 4 Nov 2024 18:17:25 -0500 Subject: [PATCH 149/190] docs(VDataTable): update filtering section resolves #20052 --- .../{prop-filterable.vue => prop-filter-keys.vue} | 6 +++++- .../pages/en/components/data-tables/data-and-display.md | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) rename packages/docs/src/examples/v-data-table/{prop-filterable.vue => prop-filter-keys.vue} (96%) diff --git a/packages/docs/src/examples/v-data-table/prop-filterable.vue b/packages/docs/src/examples/v-data-table/prop-filter-keys.vue similarity index 96% rename from packages/docs/src/examples/v-data-table/prop-filterable.vue rename to packages/docs/src/examples/v-data-table/prop-filter-keys.vue index 8024b1182f2..de1454523fc 100644 --- a/packages/docs/src/examples/v-data-table/prop-filterable.vue +++ b/packages/docs/src/examples/v-data-table/prop-filter-keys.vue @@ -19,7 +19,11 @@ - + diff --git a/packages/docs/src/pages/en/components/data-tables/data-and-display.md b/packages/docs/src/pages/en/components/data-tables/data-and-display.md index b0226fe94a4..968334fca1f 100644 --- a/packages/docs/src/pages/en/components/data-tables/data-and-display.md +++ b/packages/docs/src/pages/en/components/data-tables/data-and-display.md @@ -26,11 +26,11 @@ The data table exposes a **search** prop that allows you to filter your data. -### Filterable +### Filter Keys -You can easily disable specific columns from being included when searching through table rows by setting the property **filterable** to false on the header item(s). In the example below the dessert name column is no longer searchable. +You can easily select only the column you want to filter on by using the **filter-keys** prop. This prop accepts an array of keys from the table items that will be used for filtering. You may also choose to disable columns from filtering by setting the **filter** property to `false` on the header item(s). In the example below the we only filter on the `name` column. - + ### Custom filter @@ -40,7 +40,7 @@ You can override the default filtering used with the **search** prop by supplyin (value: string, query: string, item?: any) => boolean | number | [number, number] | [number, number][] ``` -In the example below, the custom filter will only match inputs that are in completely in upper case. +Additionally, you may apply customize the filtering on a per column basis by setting custom function to the **filter** property on the header item(s). In the example below, the custom filter will only match inputs that are in completely in upper case. From fd342fa4faea171b3c221df8860e5dbb642fc013 Mon Sep 17 00:00:00 2001 From: J-Sek Date: Tue, 5 Nov 2024 00:19:12 +0100 Subject: [PATCH 150/190] docs(VDataIterator): fix example content mismatch (#20668) --- .../slot-header-and-footer.vue | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/docs/src/examples/v-data-iterator/slot-header-and-footer.vue b/packages/docs/src/examples/v-data-iterator/slot-header-and-footer.vue index bc843aef55c..bb692ff5ead 100644 --- a/packages/docs/src/examples/v-data-iterator/slot-header-and-footer.vue +++ b/packages/docs/src/examples/v-data-iterator/slot-header-and-footer.vue @@ -137,7 +137,7 @@ wireless: true, price: 149.99, description: 'Logitech G Pro X', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/1.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/3.png', }, { name: 'Razer DeathAdder V2', @@ -159,7 +159,7 @@ wireless: true, price: 89.99, description: 'Corsair Dark Core RGB', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/3.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/1.png', }, { name: 'SteelSeries Rival 3', @@ -181,7 +181,7 @@ wireless: false, price: 44.99, description: 'HyperX Pulsefire FPS Pro', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/5.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/6.png', }, { name: 'Zowie EC2', @@ -192,7 +192,7 @@ wireless: false, price: 69.99, description: 'Zowie EC2', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/6.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/7.png', }, { name: 'Roccat Kone AIMO', @@ -203,7 +203,7 @@ wireless: false, price: 79.99, description: 'Roccat Kone AIMO', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/7.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/8.png', }, { name: 'Logitech G903', @@ -214,7 +214,7 @@ wireless: true, price: 129.99, description: 'Logitech G903', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/8.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/9.png', }, { name: 'Cooler Master MM711', @@ -225,7 +225,7 @@ wireless: false, price: 49.99, description: 'Cooler Master MM711', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/9.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/5.png', }, { name: 'Glorious Model O', @@ -236,7 +236,7 @@ wireless: false, price: 49.99, description: 'Glorious Model O', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/10.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/15.png', }, { name: 'HP Omen Photon', @@ -247,7 +247,7 @@ wireless: true, price: 99.99, description: 'HP Omen Photon', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/11.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/10.png', }, { name: 'Asus ROG Chakram', @@ -258,7 +258,7 @@ wireless: true, price: 159.99, description: 'Asus ROG Chakram', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/12.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/11.png', }, { name: 'Razer Naga X', @@ -269,7 +269,7 @@ wireless: false, price: 79.99, description: 'Razer Naga X', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/13.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/12.png', }, { name: 'Mad Catz R.A.T. 8+', @@ -280,7 +280,7 @@ wireless: false, price: 99.99, description: 'Mad Catz R.A.T. 8+', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/14.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/13.png', }, { name: 'Alienware 610M', @@ -291,7 +291,7 @@ wireless: true, price: 99.99, description: 'Alienware 610M', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/15.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/14.png', }, ] @@ -315,7 +315,7 @@ wireless: true, price: 149.99, description: 'Logitech G Pro X', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/1.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/3.png', }, { name: 'Razer DeathAdder V2', @@ -337,7 +337,7 @@ wireless: true, price: 89.99, description: 'Corsair Dark Core RGB', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/3.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/1.png', }, { name: 'SteelSeries Rival 3', @@ -359,7 +359,7 @@ wireless: false, price: 44.99, description: 'HyperX Pulsefire FPS Pro', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/5.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/6.png', }, { name: 'Zowie EC2', @@ -370,7 +370,7 @@ wireless: false, price: 69.99, description: 'Zowie EC2', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/6.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/7.png', }, { name: 'Roccat Kone AIMO', @@ -381,7 +381,7 @@ wireless: false, price: 79.99, description: 'Roccat Kone AIMO', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/7.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/8.png', }, { name: 'Logitech G903', @@ -392,7 +392,7 @@ wireless: true, price: 129.99, description: 'Logitech G903', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/8.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/9.png', }, { name: 'Cooler Master MM711', @@ -403,7 +403,7 @@ wireless: false, price: 49.99, description: 'Cooler Master MM711', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/9.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/5.png', }, { name: 'Glorious Model O', @@ -414,7 +414,7 @@ wireless: false, price: 49.99, description: 'Glorious Model O', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/10.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/15.png', }, { name: 'HP Omen Photon', @@ -425,7 +425,7 @@ wireless: true, price: 99.99, description: 'HP Omen Photon', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/11.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/10.png', }, { name: 'Asus ROG Chakram', @@ -436,7 +436,7 @@ wireless: true, price: 159.99, description: 'Asus ROG Chakram', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/12.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/11.png', }, { name: 'Razer Naga X', @@ -447,7 +447,7 @@ wireless: false, price: 79.99, description: 'Razer Naga X', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/13.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/12.png', }, { name: 'Mad Catz R.A.T. 8+', @@ -458,7 +458,7 @@ wireless: false, price: 99.99, description: 'Mad Catz R.A.T. 8+', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/14.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/13.png', }, { name: 'Alienware 610M', @@ -469,7 +469,7 @@ wireless: true, price: 99.99, description: 'Alienware 610M', - src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/15.png', + src: 'https://cdn.vuetifyjs.com/docs/images/graphics/mice/14.png', }, ], } From d7f1ccf81d9c9b57167a236f64eaf2867da0eef9 Mon Sep 17 00:00:00 2001 From: J-Sek Date: Tue, 5 Nov 2024 00:19:59 +0100 Subject: [PATCH 151/190] docs(team): add J-Sek (#20667) --- packages/docs/src/data/team.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/docs/src/data/team.json b/packages/docs/src/data/team.json index 71613ddb6d8..dc76b77bfce 100644 --- a/packages/docs/src/data/team.json +++ b/packages/docs/src/data/team.json @@ -168,6 +168,20 @@ "team": "core", "joined": "May 2024" }, + "J-Sek": { + "discord": "jacek#1420", + "focus": [ + "[vuetifyjs/studio](https://github.com/vuetifyjs/studio)" + ], + "languages": [ + "Polish", + "English" + ], + "location": "Gdańsk, Poland", + "name": "Jacek Czarniecki", + "team": "core", + "joined": "Nov 2024" + }, "jacekkarczmarczyk": { "discord": "jacek#3542", "languages": [ From 95d325a387c0149442bdb6253c235e1eabe584ee Mon Sep 17 00:00:00 2001 From: John Leider Date: Tue, 5 Nov 2024 11:11:10 -0600 Subject: [PATCH 152/190] docs(AppBarBlogLink): adjust margin axis --- packages/docs/src/components/app/bar/BlogLink.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/components/app/bar/BlogLink.vue b/packages/docs/src/components/app/bar/BlogLink.vue index bd413110563..3264c9bc414 100644 --- a/packages/docs/src/components/app/bar/BlogLink.vue +++ b/packages/docs/src/components/app/bar/BlogLink.vue @@ -2,7 +2,7 @@ Date: Wed, 6 Nov 2024 07:02:13 +0100 Subject: [PATCH 153/190] docs: fix styles leaking from TeamMember (#20669) closes #20664 --- packages/docs/src/components/about/TeamMember.vue | 11 ++++++----- packages/docs/src/components/about/TeamMembers.vue | 10 ---------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/docs/src/components/about/TeamMember.vue b/packages/docs/src/components/about/TeamMember.vue index 42654721237..cd48347ecd0 100644 --- a/packages/docs/src/components/about/TeamMember.vue +++ b/packages/docs/src/components/about/TeamMember.vue @@ -1,6 +1,6 @@