Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(VSelect): port to v3 #14504

Merged
merged 45 commits into from Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
bb083f0
feat(VSelect): port to v3
johnleider Dec 13, 2021
d1852d1
refactor(VSelect): implement using VTextField
johnleider Jan 5, 2022
ff65d1b
fix selection
KaelWD Jan 6, 2022
7549119
chore(VSelect): clean-up code, update item types
johnleider Jan 6, 2022
dd333a0
refactor(VSelect/VInput): remove unnecessary control slot
johnleider Jan 7, 2022
6af350c
chore(VSelect): remove old files
johnleider Jan 7, 2022
51d9a1a
types(VInput): remove unused slot declaration
johnleider Jan 7, 2022
3e8cc0b
chore(VTextField): remove unused code
johnleider Jan 7, 2022
eaf7711
refactor(VSelect): update selected items display and comp styling
johnleider Jan 12, 2022
764193a
feat(validation): add isDirty to VInputSlot and classes
johnleider Jan 14, 2022
b649953
feat(VInput): add isDirty to slot props
johnleider Jan 14, 2022
7322998
chore(forwardRef.ts): apply updates made on feat/v3-combobox
johnleider Jan 14, 2022
738993b
fix(VSelect): hide field input
johnleider Jan 14, 2022
7af1777
fix(VSelect): reset model on clear, improve selections display
johnleider Jan 14, 2022
a9fec93
fix(VSelect): open menu when field is clicked
johnleider Jan 16, 2022
5b45713
refactor: re-implement how focus is used
johnleider Jan 18, 2022
416892a
refactor(VTextField): change focus process and add events
johnleider Jan 18, 2022
89627d0
fix(VSelect): show correct cursor
johnleider Jan 18, 2022
49ff4f2
refactor: updates from feedback
johnleider Jan 19, 2022
af60b72
chore(VInput): remove deprecated functionality
johnleider Jan 19, 2022
047ab44
feat(VSelect): add support for chips
johnleider Jan 21, 2022
a491312
fix(VSelect): reset model on clear
johnleider Jan 21, 2022
14bdeb3
feat(VSelect): add hide-selected prop
johnleider Jan 21, 2022
7e2aa72
feat(VSelect): add no-data-text support
johnleider Jan 21, 2022
204ab52
feat(VSelect): add select menu icon
johnleider Jan 21, 2022
41a6c42
fix(VSelect): open menu when pressing enter or space, close with esc
johnleider Jan 25, 2022
598fadc
fix(VSelect): height calculation when using chips
johnleider Jan 25, 2022
e6bd75b
fix: correctly forward slots
KaelWD Jan 25, 2022
a72e9f7
fix(VTextField): keep label active when dirty without modelValue
KaelWD Jan 25, 2022
314f008
refactor(VInput/Field/TextField): change how color and state propagates
johnleider Jan 25, 2022
e9101e3
chore: code clean-up
johnleider Jan 26, 2022
d2dd4ad
fix(VTextField): show placeholder on focus / persistent
johnleider Jan 26, 2022
7ff6220
fix(VSelect): adjust control sizing
johnleider Jan 26, 2022
9022b2d
fix(VSelect): align height with text fields
KaelWD Jan 26, 2022
e0413b6
Merge branch 'next' into feat/v3-select
johnleider Feb 1, 2022
b2d2d95
Merge branch 'next' into feat/v3-select
johnleider Feb 1, 2022
dd93f15
fix(VSelect): show placeholder with no selections
johnleider Feb 1, 2022
6030edb
refactor(VTextarea): update to latest code examples from text-field
johnleider Feb 1, 2022
38d72e7
lint(VSlider/VRangeSlider): update how focus composable is used
johnleider Feb 1, 2022
661c82a
fix(VFileInput): styling and functionality conflicts
johnleider Feb 1, 2022
bc5f0d8
lint(VSelect): remove unused selector
johnleider Feb 1, 2022
82dcfbe
test: resolve cypress errors
johnleider Feb 1, 2022
7c361e6
fix(VTextField): activate field when using persistent-placeholder
johnleider Feb 1, 2022
188e167
chore: fix chip display issues and code clean-up
johnleider Feb 2, 2022
56c3160
fix(VTextField): propagate prepend/append clicks
johnleider Feb 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 47 additions & 39 deletions packages/vuetify/src/components/VField/VField.tsx
Expand Up @@ -11,10 +11,10 @@ import { LoaderSlot, makeLoaderProps, useLoader } from '@/composables/loader'
import { makeThemeProps, provideTheme } from '@/composables/theme'
import { useBackgroundColor, useTextColor } from '@/composables/color'
import { useProxiedModel } from '@/composables/proxiedModel'
import { useFocus } from '@/composables/focus'
import { makeFocusProps, useFocus } from '@/composables/focus'

// Utilities
import { computed, inject, ref, toRef, watch, watchEffect } from 'vue'
import { computed, ref, toRef, watch } from 'vue'
import {
convertToUnit,
genericComponent,
Expand All @@ -24,10 +24,11 @@ import {
propsFactory,
standardEasing,
useRender,
wrapInArray,
} from '@/util'

// Types
import type { VInputSlot, VInputSymbol } from '@/components/VInput/VInput'
import type { VInputSlot } from '@/components/VInput/VInput'
import type { LoaderSlotProps } from '@/composables/loader'
import type { PropType, Ref } from 'vue'
import type { MakeSlots } from '@/util'
Expand All @@ -36,8 +37,8 @@ const allowedVariants = ['underlined', 'outlined', 'filled', 'contained', 'plain
type Variant = typeof allowedVariants[number]

export interface DefaultInputSlot {
isActive: boolean
isFocused: boolean
isActive: Ref<boolean>
isFocused: Ref<boolean>
controlRef: Ref<HTMLElement | undefined>
focus: () => void
blur: () => void
Expand Down Expand Up @@ -71,56 +72,62 @@ export const makeVFieldProps = propsFactory({
...makeLoaderProps(),
}, 'v-field')

export type VFieldSlots = MakeSlots<{
clear: []
prependInner: [DefaultInputSlot & VInputSlot]
appendInner: [DefaultInputSlot & VInputSlot]
label: [DefaultInputSlot & VInputSlot]
loader: [LoaderSlotProps]
default: [VFieldSlot]
}>

export const VField = genericComponent<new <T>() => {
$props: {
modelValue?: T
'onUpdate:modelValue'?: (val: T) => any
}
$slots: MakeSlots<{
clear: []
prependInner: [DefaultInputSlot & VInputSlot]
appendInner: [DefaultInputSlot & VInputSlot]
label: [DefaultInputSlot & VInputSlot]
loader: [LoaderSlotProps]
default: [VFieldSlot]
}>
$slots: VFieldSlots
}>()({
name: 'VField',

inheritAttrs: false,

props: {
active: Boolean,
disabled: Boolean,
error: Boolean,
id: String,
modelValue: null,

...makeFocusProps(),
...makeVFieldProps(),
},

emits: {
'click:clear': (e: Event) => true,
'click:clear': (e: MouseEvent) => true,
'click:prepend-inner': (e: MouseEvent) => true,
'click:append-inner': (e: MouseEvent) => true,
'click:control': (props: DefaultInputSlot) => true,
'update:active': (active: boolean) => true,
'click:control': (e: MouseEvent) => true,
'update:focused': (focused: boolean) => true,
'update:modelValue': (val: any) => true,
},

setup (props, { attrs, emit, slots }) {
const model = useProxiedModel(props, 'modelValue')

const { themeClasses } = provideTheme(props)
const { loaderClasses } = useLoader(props)
const isActive = useProxiedModel(props, 'active')
const { isFocused, focus, blur } = useFocus()
const { focusClasses, isFocused, focus, blur } = useFocus(props)

const isDirty = computed(() => wrapInArray(model.value || []).length > 0)
const isActive = computed(() => isDirty.value || isFocused.value)
const hasLabel = computed(() => !props.singleLine && !!(props.label || slots.label))

const uid = getUid()
const id = computed(() => props.id || `input-${uid}`)

const labelRef = ref<VFieldLabel>()
const floatingLabelRef = ref<VFieldLabel>()
const controlRef = ref<HTMLElement>()
const id = computed(() => props.id || `input-${uid}`)
const hasLabel = computed(() => !props.singleLine && !!(props.label || slots.label))

watchEffect(() => isActive.value = isFocused.value)

const { backgroundColorClasses, backgroundColorStyles } = useBackgroundColor(toRef(props, 'bgColor'))
const { textColorClasses, textColorStyles } = useTextColor(computed(() => {
Expand Down Expand Up @@ -168,8 +175,8 @@ export const VField = genericComponent<new <T>() => {
}, { flush: 'post' })

const slotProps = computed<DefaultInputSlot>(() => ({
isActive: isActive.value,
isFocused: isFocused.value,
isActive,
isFocused,
controlRef,
blur,
focus,
Expand All @@ -180,11 +187,9 @@ export const VField = genericComponent<new <T>() => {
e.preventDefault()
}

emit('click:control', slotProps.value)
emit('click:control', e)
}

const VInput = inject('VInput' as any as typeof VInputSymbol, undefined)

useRender(() => {
const isOutlined = props.variant === 'outlined'
const hasPrepend = (slots.prependInner || props.prependInnerIcon)
Expand All @@ -204,7 +209,8 @@ export const VField = genericComponent<new <T>() => {
{
'v-field--active': isActive.value,
'v-field--appended': hasAppend,
'v-field--focused': isFocused.value,
'v-field--disabled': props.disabled,
'v-field--error': props.error,
'v-field--has-background': !!props.bgColor,
'v-field--persistent-clear': props.persistentClear,
'v-field--prepended': hasPrepend,
Expand All @@ -213,8 +219,9 @@ export const VField = genericComponent<new <T>() => {
[`v-field--variant-${props.variant}`]: true,
},
themeClasses.value,
loaderClasses.value,
backgroundColorClasses.value,
focusClasses.value,
loaderClasses.value,
textColorClasses.value,
]}
style={[
Expand All @@ -229,7 +236,7 @@ export const VField = genericComponent<new <T>() => {
<LoaderSlot
name="v-field"
active={ props.loading }
color={ VInput ? (!VInput.value.isValid.value ? undefined : props.color) : props.color }
color={ props.error ? 'error' : props.color }
v-slots={{ default: slots.loader }}
/>

Expand All @@ -242,7 +249,7 @@ export const VField = genericComponent<new <T>() => {
<VIcon icon={ props.prependInnerIcon } />
) }

{ slots?.prependInner?.(VInput?.value) }
{ slots?.prependInner?.(slotProps.value) }
</div>
) }

Expand All @@ -258,13 +265,10 @@ export const VField = genericComponent<new <T>() => {
</VFieldLabel>

{ slots.default?.({
...VInput?.value,
...slotProps.value,
props: {
id: id.value,
class: 'v-field__input',
onFocus: () => (isFocused.value = true),
onBlur: () => (isFocused.value = false),
},
focus,
blur,
Expand All @@ -275,12 +279,16 @@ export const VField = genericComponent<new <T>() => {
<VExpandXTransition>
<div
class="v-field__clearable"
onClick={ (e: Event) => emit('click:clear', e) }
v-show={ props.active }
v-show={ isDirty.value }
>
{ slots.clear
? slots.clear()
: <VIcon icon={ props.clearIcon } />
: (
<VIcon
onClick={ (e: MouseEvent) => emit('click:clear', e) }
icon={ props.clearIcon }
/>
)
}
</div>
</VExpandXTransition>
Expand All @@ -291,7 +299,7 @@ export const VField = genericComponent<new <T>() => {
class="v-field__append-inner"
onClick={ e => emit('click:append-inner', e) }
>
{ slots?.appendInner?.(VInput?.value) }
{ slots?.appendInner?.(slotProps.value) }

{ props.appendInnerIcon && (
<VIcon icon={ props.appendInnerIcon } />
Expand Down