reka-ui 2.9.7 → 2.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Autocomplete/AutocompleteInput.cjs +12 -16
- package/dist/Autocomplete/AutocompleteInput.cjs.map +1 -1
- package/dist/Autocomplete/AutocompleteInput.js +13 -17
- package/dist/Autocomplete/AutocompleteInput.js.map +1 -1
- package/dist/ColorField/ColorFieldInput.cjs +10 -2
- package/dist/ColorField/ColorFieldInput.cjs.map +1 -1
- package/dist/ColorField/ColorFieldInput.js +10 -2
- package/dist/ColorField/ColorFieldInput.js.map +1 -1
- package/dist/Combobox/ComboboxInput.cjs +27 -9
- package/dist/Combobox/ComboboxInput.cjs.map +1 -1
- package/dist/Combobox/ComboboxInput.js +28 -10
- package/dist/Combobox/ComboboxInput.js.map +1 -1
- package/dist/DateField/DateFieldInput.cjs +4 -1
- package/dist/DateField/DateFieldInput.cjs.map +1 -1
- package/dist/DateField/DateFieldInput.js +4 -1
- package/dist/DateField/DateFieldInput.js.map +1 -1
- package/dist/DateField/DateFieldRoot.cjs +1 -0
- package/dist/DateField/DateFieldRoot.cjs.map +1 -1
- package/dist/DateField/DateFieldRoot.js +1 -0
- package/dist/DateField/DateFieldRoot.js.map +1 -1
- package/dist/DatePicker/DatePickerRoot.cjs +15 -1
- package/dist/DatePicker/DatePickerRoot.cjs.map +1 -1
- package/dist/DatePicker/DatePickerRoot.js +15 -1
- package/dist/DatePicker/DatePickerRoot.js.map +1 -1
- package/dist/DateRangeField/DateRangeFieldInput.cjs +4 -1
- package/dist/DateRangeField/DateRangeFieldInput.cjs.map +1 -1
- package/dist/DateRangeField/DateRangeFieldInput.js +4 -1
- package/dist/DateRangeField/DateRangeFieldInput.js.map +1 -1
- package/dist/DateRangeField/DateRangeFieldRoot.cjs +1 -0
- package/dist/DateRangeField/DateRangeFieldRoot.cjs.map +1 -1
- package/dist/DateRangeField/DateRangeFieldRoot.js +1 -0
- package/dist/DateRangeField/DateRangeFieldRoot.js.map +1 -1
- package/dist/Dialog/DialogOverlayImpl.cjs +6 -1
- package/dist/Dialog/DialogOverlayImpl.cjs.map +1 -1
- package/dist/Dialog/DialogOverlayImpl.js +7 -2
- package/dist/Dialog/DialogOverlayImpl.js.map +1 -1
- package/dist/DropdownMenu/DropdownMenuFilter.cjs +19 -2
- package/dist/DropdownMenu/DropdownMenuFilter.cjs.map +1 -1
- package/dist/DropdownMenu/DropdownMenuFilter.js +19 -2
- package/dist/DropdownMenu/DropdownMenuFilter.js.map +1 -1
- package/dist/FocusScope/FocusScope.cjs +2 -0
- package/dist/FocusScope/FocusScope.cjs.map +1 -1
- package/dist/FocusScope/FocusScope.js +2 -0
- package/dist/FocusScope/FocusScope.js.map +1 -1
- package/dist/Listbox/ListboxFilter.cjs +29 -10
- package/dist/Listbox/ListboxFilter.cjs.map +1 -1
- package/dist/Listbox/ListboxFilter.js +30 -11
- package/dist/Listbox/ListboxFilter.js.map +1 -1
- package/dist/Listbox/ListboxItem.cjs +7 -2
- package/dist/Listbox/ListboxItem.cjs.map +1 -1
- package/dist/Listbox/ListboxItem.js +7 -2
- package/dist/Listbox/ListboxItem.js.map +1 -1
- package/dist/Listbox/ListboxRoot.cjs +12 -6
- package/dist/Listbox/ListboxRoot.cjs.map +1 -1
- package/dist/Listbox/ListboxRoot.js +12 -6
- package/dist/Listbox/ListboxRoot.js.map +1 -1
- package/dist/Menu/MenuItemImpl.cjs +1 -1
- package/dist/Menu/MenuItemImpl.cjs.map +1 -1
- package/dist/Menu/MenuItemImpl.js +1 -1
- package/dist/Menu/MenuItemImpl.js.map +1 -1
- package/dist/NavigationMenu/NavigationMenuContentImpl.cjs +1 -0
- package/dist/NavigationMenu/NavigationMenuContentImpl.cjs.map +1 -1
- package/dist/NavigationMenu/NavigationMenuContentImpl.js +1 -0
- package/dist/NavigationMenu/NavigationMenuContentImpl.js.map +1 -1
- package/dist/NavigationMenu/NavigationMenuRoot.cjs +16 -3
- package/dist/NavigationMenu/NavigationMenuRoot.cjs.map +1 -1
- package/dist/NavigationMenu/NavigationMenuRoot.js +16 -3
- package/dist/NavigationMenu/NavigationMenuRoot.js.map +1 -1
- package/dist/NumberField/NumberFieldInput.cjs +46 -13
- package/dist/NumberField/NumberFieldInput.cjs.map +1 -1
- package/dist/NumberField/NumberFieldInput.js +47 -14
- package/dist/NumberField/NumberFieldInput.js.map +1 -1
- package/dist/PinInput/PinInputInput.cjs +37 -2
- package/dist/PinInput/PinInputInput.cjs.map +1 -1
- package/dist/PinInput/PinInputInput.js +37 -2
- package/dist/PinInput/PinInputInput.js.map +1 -1
- package/dist/ScrollArea/ScrollAreaScrollbarX.cjs +3 -0
- package/dist/ScrollArea/ScrollAreaScrollbarX.cjs.map +1 -1
- package/dist/ScrollArea/ScrollAreaScrollbarX.js +4 -1
- package/dist/ScrollArea/ScrollAreaScrollbarX.js.map +1 -1
- package/dist/ScrollArea/ScrollAreaScrollbarY.cjs +3 -0
- package/dist/ScrollArea/ScrollAreaScrollbarY.cjs.map +1 -1
- package/dist/ScrollArea/ScrollAreaScrollbarY.js +4 -1
- package/dist/ScrollArea/ScrollAreaScrollbarY.js.map +1 -1
- package/dist/Select/SelectContent.cjs +15 -2
- package/dist/Select/SelectContent.cjs.map +1 -1
- package/dist/Select/SelectContent.js +16 -3
- package/dist/Select/SelectContent.js.map +1 -1
- package/dist/TagsInput/TagsInputInput.cjs +12 -13
- package/dist/TagsInput/TagsInputInput.cjs.map +1 -1
- package/dist/TagsInput/TagsInputInput.js +13 -14
- package/dist/TagsInput/TagsInputInput.js.map +1 -1
- package/dist/TagsInput/TagsInputRoot.cjs +1 -0
- package/dist/TagsInput/TagsInputRoot.cjs.map +1 -1
- package/dist/TagsInput/TagsInputRoot.js +1 -0
- package/dist/TagsInput/TagsInputRoot.js.map +1 -1
- package/dist/TimeField/TimeFieldInput.cjs +4 -1
- package/dist/TimeField/TimeFieldInput.cjs.map +1 -1
- package/dist/TimeField/TimeFieldInput.js +4 -1
- package/dist/TimeField/TimeFieldInput.js.map +1 -1
- package/dist/TimeField/TimeFieldRoot.cjs +1 -0
- package/dist/TimeField/TimeFieldRoot.cjs.map +1 -1
- package/dist/TimeField/TimeFieldRoot.js +1 -0
- package/dist/TimeField/TimeFieldRoot.js.map +1 -1
- package/dist/TimeRangeField/TimeRangeFieldInput.cjs +4 -1
- package/dist/TimeRangeField/TimeRangeFieldInput.cjs.map +1 -1
- package/dist/TimeRangeField/TimeRangeFieldInput.js +4 -1
- package/dist/TimeRangeField/TimeRangeFieldInput.js.map +1 -1
- package/dist/TimeRangeField/TimeRangeFieldRoot.cjs +1 -0
- package/dist/TimeRangeField/TimeRangeFieldRoot.cjs.map +1 -1
- package/dist/TimeRangeField/TimeRangeFieldRoot.js +1 -0
- package/dist/TimeRangeField/TimeRangeFieldRoot.js.map +1 -1
- package/dist/date/useDateField.cjs +38 -0
- package/dist/date/useDateField.cjs.map +1 -1
- package/dist/date/useDateField.js +38 -0
- package/dist/date/useDateField.js.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.js +1 -0
- package/dist/index2.d.ts.map +1 -1
- package/dist/index3.d.cts +24 -16
- package/dist/index3.d.cts.map +1 -1
- package/dist/index3.d.ts +13 -5
- package/dist/index3.d.ts.map +1 -1
- package/dist/index4.d.cts +655 -655
- package/dist/index4.d.cts.map +1 -1
- package/dist/index4.d.ts +684 -684
- package/dist/index4.d.ts.map +1 -1
- package/dist/internal.cjs +1 -0
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.cts.map +1 -1
- package/dist/internal.d.ts +2 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -0
- package/dist/shared/useComposing.cjs +30 -0
- package/dist/shared/useComposing.cjs.map +1 -0
- package/dist/shared/useComposing.js +24 -0
- package/dist/shared/useComposing.js.map +1 -0
- package/dist/shared.cjs +2 -0
- package/dist/shared.d.cts +2 -2
- package/dist/shared.d.ts +2 -2
- package/dist/shared.js +2 -1
- package/package.json +4 -4
- package/src/Autocomplete/AutocompleteInput.vue +13 -17
- package/src/Calendar/CalendarRoot.vue +1 -1
- package/src/ColorField/ColorFieldInput.vue +11 -0
- package/src/Combobox/ComboboxInput.vue +37 -7
- package/src/DateField/DateFieldInput.vue +6 -0
- package/src/DateField/DateFieldRoot.vue +3 -0
- package/src/DatePicker/DatePickerRoot.vue +18 -2
- package/src/DateRangeField/DateRangeFieldInput.vue +6 -0
- package/src/DateRangeField/DateRangeFieldRoot.vue +4 -1
- package/src/Dialog/DialogOverlayImpl.vue +1 -0
- package/src/DropdownMenu/DropdownMenuFilter.vue +20 -1
- package/src/FocusScope/FocusScope.vue +5 -0
- package/src/Listbox/ListboxFilter.vue +39 -8
- package/src/Listbox/ListboxItem.vue +2 -2
- package/src/Listbox/ListboxRoot.vue +17 -4
- package/src/Menu/MenuItemImpl.vue +1 -1
- package/src/MonthPicker/MonthPickerRoot.vue +1 -1
- package/src/NavigationMenu/NavigationMenuContentImpl.vue +3 -0
- package/src/NavigationMenu/NavigationMenuRoot.vue +19 -3
- package/src/NavigationMenu/__test__/NavigationMenuUnmountOnHideFalse.vue +45 -0
- package/src/NumberField/NumberFieldInput.vue +45 -8
- package/src/PinInput/PinInputInput.vue +44 -1
- package/src/ScrollArea/ScrollAreaScrollbarX.vue +6 -1
- package/src/ScrollArea/ScrollAreaScrollbarY.vue +6 -1
- package/src/Select/SelectContent.vue +19 -3
- package/src/Select/__test__/SelectUnmountCleanup.vue +43 -0
- package/src/TagsInput/TagsInputInput.vue +16 -14
- package/src/TagsInput/TagsInputRoot.vue +3 -0
- package/src/TimeField/TimeFieldInput.vue +6 -0
- package/src/TimeField/TimeFieldRoot.vue +3 -0
- package/src/TimeRangeField/TimeRangeFieldInput.vue +6 -0
- package/src/TimeRangeField/TimeRangeFieldRoot.vue +3 -0
- package/src/YearPicker/YearPickerRoot.vue +1 -1
- package/src/shared/date/useDateField.ts +75 -1
- package/src/shared/index.ts +1 -0
- package/src/shared/useComposing.ts +18 -0
|
@@ -3,6 +3,7 @@ import type { PrimitiveProps } from '..'
|
|
|
3
3
|
import { useVModel } from '@vueuse/core'
|
|
4
4
|
import { computed, onMounted, onUnmounted, ref, watchSyncEffect } from 'vue'
|
|
5
5
|
import { usePrimitiveElement } from '@/Primitive'
|
|
6
|
+
import { useComposing } from '@/shared'
|
|
6
7
|
import { Primitive } from '..'
|
|
7
8
|
import { injectListboxRootContext } from './ListboxRoot.vue'
|
|
8
9
|
|
|
@@ -59,6 +60,39 @@ onMounted(() => {
|
|
|
59
60
|
onUnmounted(() => {
|
|
60
61
|
rootContext.focusable.value = true
|
|
61
62
|
})
|
|
63
|
+
|
|
64
|
+
const { isComposing, handleCompositionStart, handleCompositionEnd } = useComposing((event) => {
|
|
65
|
+
modelValue.value = (event.target as HTMLInputElement).value
|
|
66
|
+
rootContext.onCompositionEnd()
|
|
67
|
+
rootContext.highlightFirstItem()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
function onCompositionStart() {
|
|
71
|
+
rootContext.onCompositionStart()
|
|
72
|
+
handleCompositionStart()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function handleInput(event: InputEvent) {
|
|
76
|
+
if (isComposing.value)
|
|
77
|
+
return
|
|
78
|
+
modelValue.value = (event.target as HTMLInputElement).value
|
|
79
|
+
rootContext.highlightFirstItem()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function handleKeydownNavigation(event: KeyboardEvent) {
|
|
83
|
+
// Don't navigate mid-composition, arrow keys are used for IME candidate navigation
|
|
84
|
+
if (isComposing.value)
|
|
85
|
+
return
|
|
86
|
+
event.preventDefault()
|
|
87
|
+
rootContext.onKeydownNavigation(event)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function handleKeydownEnter(event: KeyboardEvent) {
|
|
91
|
+
// Don't select mid-composition, Enter commits the IME candidate
|
|
92
|
+
if (isComposing.value)
|
|
93
|
+
return
|
|
94
|
+
rootContext.onKeydownEnter(event)
|
|
95
|
+
}
|
|
62
96
|
</script>
|
|
63
97
|
|
|
64
98
|
<template>
|
|
@@ -72,14 +106,11 @@ onUnmounted(() => {
|
|
|
72
106
|
:aria-disabled="disabled ?? undefined"
|
|
73
107
|
:aria-activedescendant="activedescendant"
|
|
74
108
|
type="text"
|
|
75
|
-
@keydown.down.up.home.end
|
|
76
|
-
@keydown.enter="
|
|
77
|
-
@input="
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}"
|
|
81
|
-
@compositionstart="rootContext.onCompositionStart"
|
|
82
|
-
@compositionend="rootContext.onCompositionEnd"
|
|
109
|
+
@keydown.down.up.home.end="handleKeydownNavigation"
|
|
110
|
+
@keydown.enter="handleKeydownEnter"
|
|
111
|
+
@input="handleInput"
|
|
112
|
+
@compositionstart="onCompositionStart"
|
|
113
|
+
@compositionend="handleCompositionEnd"
|
|
83
114
|
>
|
|
84
115
|
<slot :model-value="modelValue" />
|
|
85
116
|
</Primitive>
|
|
@@ -44,7 +44,7 @@ const { CollectionItem } = useCollection()
|
|
|
44
44
|
const { forwardRef, currentElement } = useForwardExpose()
|
|
45
45
|
const rootContext = injectListboxRootContext()
|
|
46
46
|
|
|
47
|
-
const isHighlighted = computed(() => currentElement.value === rootContext.highlightedElement.value)
|
|
47
|
+
const isHighlighted = computed(() => currentElement.value != null && currentElement.value === rootContext.highlightedElement.value)
|
|
48
48
|
const isSelected = computed(() => valueComparator(rootContext.modelValue.value, props.value, rootContext.by))
|
|
49
49
|
|
|
50
50
|
const disabled = computed(() => rootContext.disabled.value || props.disabled)
|
|
@@ -76,7 +76,7 @@ provideListboxItemContext({
|
|
|
76
76
|
:id="id"
|
|
77
77
|
v-bind="$attrs"
|
|
78
78
|
:ref="forwardRef"
|
|
79
|
-
v-memo="[isHighlighted, isSelected]"
|
|
79
|
+
v-memo="[isHighlighted, isSelected, disabled, rootContext.focusable.value]"
|
|
80
80
|
role="option"
|
|
81
81
|
:tabindex="rootContext.focusable.value ? isHighlighted ? '0' : '-1' : -1"
|
|
82
82
|
:aria-selected="isSelected"
|
|
@@ -324,7 +324,7 @@ function handleMultipleReplace(event: KeyboardEvent, targetEl: HTMLElement) {
|
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
async function highlightSelected(event?: Event) {
|
|
327
|
+
async function highlightSelected(event?: Event, scroll = true) {
|
|
328
328
|
// highlightSelected is called inside a watch with immediate set to true.
|
|
329
329
|
// This results in code execution during SSR.
|
|
330
330
|
// Ensure this code only runs in a browser environment, since it performs
|
|
@@ -339,18 +339,31 @@ async function highlightSelected(event?: Event) {
|
|
|
339
339
|
else {
|
|
340
340
|
const collection = getCollectionItem()
|
|
341
341
|
const item = collection.find(i => i.dataset.state === 'checked')
|
|
342
|
+
// On the initial (mount) highlight we only set the roving-tabindex target.
|
|
343
|
+
// Focusing/scrolling here would scroll the page to a Listbox the user never
|
|
344
|
+
// interacted with (e.g. one below the fold). Later highlights scroll as before.
|
|
345
|
+
const focus = scroll ? undefined : false
|
|
342
346
|
if (item)
|
|
343
|
-
changeHighlight(item)
|
|
347
|
+
changeHighlight(item, scroll, focus)
|
|
344
348
|
else if (collection.length)
|
|
345
|
-
changeHighlight(collection[0])
|
|
349
|
+
changeHighlight(collection[0], scroll, focus)
|
|
346
350
|
}
|
|
347
351
|
}
|
|
348
352
|
|
|
353
|
+
// `false` until the initial (mount) modelValue highlight has been queued.
|
|
354
|
+
// Flipped synchronously in the watcher so the "is this the mount highlight?"
|
|
355
|
+
// decision never depends on nextTick ordering, which differs between a client
|
|
356
|
+
// mount and SSR hydration. The intent travels with the call as an argument
|
|
357
|
+
// rather than via a shared flag released on a later tick.
|
|
358
|
+
let hasHighlightedOnMount = false
|
|
359
|
+
|
|
349
360
|
// watch for only programmatic changes
|
|
350
361
|
watch(modelValue, () => {
|
|
351
362
|
if (!isUserAction.value) {
|
|
363
|
+
const scroll = hasHighlightedOnMount
|
|
364
|
+
hasHighlightedOnMount = true
|
|
352
365
|
nextTick(() => {
|
|
353
|
-
highlightSelected()
|
|
366
|
+
highlightSelected(undefined, scroll)
|
|
354
367
|
})
|
|
355
368
|
}
|
|
356
369
|
}, { immediate: true, deep: true })
|
|
@@ -33,7 +33,7 @@ const { forwardRef, currentElement } = useForwardExpose()
|
|
|
33
33
|
const { CollectionItem } = useCollection()
|
|
34
34
|
|
|
35
35
|
const isFocused = ref(false)
|
|
36
|
-
const isHighlighted = computed(() => isFocused.value || (contentContext.highlightedElement.value === currentElement.value))
|
|
36
|
+
const isHighlighted = computed(() => isFocused.value || (currentElement.value != null && contentContext.highlightedElement.value === currentElement.value))
|
|
37
37
|
|
|
38
38
|
async function handlePointerMove(event: PointerEvent) {
|
|
39
39
|
if (event.defaultPrevented || !isMouseEvent(event))
|
|
@@ -74,7 +74,7 @@ export interface MonthPickerRootProps extends PrimitiveProps {
|
|
|
74
74
|
/** A function that returns the previous page of the month picker. Receives the current placeholder as an argument. */
|
|
75
75
|
prevPage?: (placeholder: DateValue) => DateValue
|
|
76
76
|
/** The controlled selected month value of the month picker. Can be bound as `v-model`. */
|
|
77
|
-
modelValue?: DateValue | DateValue[] |
|
|
77
|
+
modelValue?: DateValue | DateValue[] | null
|
|
78
78
|
/** Whether multiple months can be selected */
|
|
79
79
|
multiple?: boolean
|
|
80
80
|
}
|
|
@@ -180,6 +180,9 @@ function handleKeydown(ev: KeyboardEvent) {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
function handleDismiss() {
|
|
183
|
+
if (menuContext.modelValue.value !== itemContext.value)
|
|
184
|
+
return
|
|
185
|
+
|
|
183
186
|
const rootContentDismissEvent = new Event(EVENT_ROOT_CONTENT_DISMISS, {
|
|
184
187
|
bubbles: true,
|
|
185
188
|
cancelable: true,
|
|
@@ -140,6 +140,7 @@ const { delayDuration, skipDelayDuration, dir: propDir, disableClickTrigger, dis
|
|
|
140
140
|
const dir = useDirection(propDir)
|
|
141
141
|
|
|
142
142
|
const isDelaySkipped = refAutoReset(false, skipDelayDuration)
|
|
143
|
+
const skipNextClose = ref(false)
|
|
143
144
|
const computedDelay = computed(() => {
|
|
144
145
|
const isOpen = modelValue.value !== ''
|
|
145
146
|
if (isOpen || isDelaySkipped.value)
|
|
@@ -150,8 +151,14 @@ const computedDelay = computed(() => {
|
|
|
150
151
|
const debouncedFn = useDebounceFn((val?: string) => {
|
|
151
152
|
// passing `undefined` meant to reset the debounce timer
|
|
152
153
|
if (typeof val === 'string') {
|
|
154
|
+
if (val === '' && skipNextClose.value) {
|
|
155
|
+
skipNextClose.value = false
|
|
156
|
+
return
|
|
157
|
+
}
|
|
153
158
|
previousValue.value = modelValue.value
|
|
154
159
|
modelValue.value = val
|
|
160
|
+
if (val === '')
|
|
161
|
+
isDelaySkipped.value = true
|
|
155
162
|
}
|
|
156
163
|
}, computedDelay)
|
|
157
164
|
|
|
@@ -188,18 +195,27 @@ provideNavigationMenuContext({
|
|
|
188
195
|
viewport.value = val
|
|
189
196
|
},
|
|
190
197
|
onTriggerEnter: (val) => {
|
|
191
|
-
|
|
198
|
+
if (modelValue.value !== '') {
|
|
199
|
+
skipNextClose.value = true
|
|
200
|
+
previousValue.value = modelValue.value
|
|
201
|
+
modelValue.value = val
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
debouncedFn(val)
|
|
205
|
+
}
|
|
192
206
|
},
|
|
193
207
|
onTriggerLeave: () => {
|
|
194
|
-
|
|
208
|
+
skipNextClose.value = false
|
|
195
209
|
debouncedFn('')
|
|
196
210
|
},
|
|
197
211
|
onContentEnter: () => {
|
|
198
212
|
debouncedFn()
|
|
199
213
|
},
|
|
200
214
|
onContentLeave: () => {
|
|
201
|
-
if (!props.disablePointerLeaveClose)
|
|
215
|
+
if (!props.disablePointerLeaveClose) {
|
|
216
|
+
skipNextClose.value = false
|
|
202
217
|
debouncedFn('')
|
|
218
|
+
}
|
|
203
219
|
},
|
|
204
220
|
onItemSelect: (val) => {
|
|
205
221
|
// When selecting item we trigger update immediately
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import {
|
|
4
|
+
NavigationMenuContent,
|
|
5
|
+
NavigationMenuItem,
|
|
6
|
+
NavigationMenuList,
|
|
7
|
+
NavigationMenuRoot,
|
|
8
|
+
NavigationMenuTrigger,
|
|
9
|
+
} from '..'
|
|
10
|
+
|
|
11
|
+
const modelValue = ref('')
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<NavigationMenuRoot
|
|
16
|
+
v-model="modelValue"
|
|
17
|
+
:unmount-on-hide="false"
|
|
18
|
+
:disable-hover-trigger="true"
|
|
19
|
+
>
|
|
20
|
+
<span data-testid="model-value">{{ modelValue }}</span>
|
|
21
|
+
<NavigationMenuList>
|
|
22
|
+
<NavigationMenuItem value="one">
|
|
23
|
+
<NavigationMenuTrigger data-testid="trigger-one">
|
|
24
|
+
One
|
|
25
|
+
</NavigationMenuTrigger>
|
|
26
|
+
<NavigationMenuContent data-testid="content-one">
|
|
27
|
+
<button data-testid="inside-one">
|
|
28
|
+
Inside one
|
|
29
|
+
</button>
|
|
30
|
+
</NavigationMenuContent>
|
|
31
|
+
</NavigationMenuItem>
|
|
32
|
+
|
|
33
|
+
<NavigationMenuItem value="two">
|
|
34
|
+
<NavigationMenuTrigger data-testid="trigger-two">
|
|
35
|
+
Two
|
|
36
|
+
</NavigationMenuTrigger>
|
|
37
|
+
<NavigationMenuContent data-testid="content-two">
|
|
38
|
+
<button data-testid="inside-two">
|
|
39
|
+
Inside two
|
|
40
|
+
</button>
|
|
41
|
+
</NavigationMenuContent>
|
|
42
|
+
</NavigationMenuItem>
|
|
43
|
+
</NavigationMenuList>
|
|
44
|
+
</NavigationMenuRoot>
|
|
45
|
+
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { PrimitiveProps } from '@/Primitive'
|
|
3
3
|
import { onMounted, ref, watch } from 'vue'
|
|
4
|
-
import { getActiveElement } from '@/shared'
|
|
4
|
+
import { getActiveElement, useComposing, useKbd } from '@/shared'
|
|
5
5
|
import { injectNumberFieldRootContext } from './NumberFieldRoot.vue'
|
|
6
6
|
|
|
7
7
|
export interface NumberFieldInputProps extends PrimitiveProps {
|
|
@@ -17,6 +17,46 @@ const props = withDefaults(defineProps<NumberFieldInputProps>(), {
|
|
|
17
17
|
|
|
18
18
|
const { primitiveElement, currentElement } = usePrimitiveElement()
|
|
19
19
|
const rootContext = injectNumberFieldRootContext()
|
|
20
|
+
const kbd = useKbd()
|
|
21
|
+
const { isComposing, handleCompositionStart, handleCompositionEnd } = useComposing()
|
|
22
|
+
|
|
23
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
24
|
+
// Don't step/apply mid-composition, keys are used for IME candidate navigation and commit.
|
|
25
|
+
// `isComposing` stays true until the tick after `compositionend`, so the commit keydown
|
|
26
|
+
// (which can report `event.isComposing === false`) is still skipped.
|
|
27
|
+
if (isComposing.value || event.isComposing)
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
switch (event.key) {
|
|
31
|
+
case kbd.ARROW_UP:
|
|
32
|
+
event.preventDefault()
|
|
33
|
+
rootContext.handleIncrease()
|
|
34
|
+
break
|
|
35
|
+
case kbd.ARROW_DOWN:
|
|
36
|
+
event.preventDefault()
|
|
37
|
+
rootContext.handleDecrease()
|
|
38
|
+
break
|
|
39
|
+
case kbd.PAGE_UP:
|
|
40
|
+
event.preventDefault()
|
|
41
|
+
rootContext.handleIncrease(10)
|
|
42
|
+
break
|
|
43
|
+
case kbd.PAGE_DOWN:
|
|
44
|
+
event.preventDefault()
|
|
45
|
+
rootContext.handleDecrease(10)
|
|
46
|
+
break
|
|
47
|
+
case kbd.HOME:
|
|
48
|
+
event.preventDefault()
|
|
49
|
+
rootContext.handleMinMaxValue('min')
|
|
50
|
+
break
|
|
51
|
+
case kbd.END:
|
|
52
|
+
event.preventDefault()
|
|
53
|
+
rootContext.handleMinMaxValue('max')
|
|
54
|
+
break
|
|
55
|
+
case kbd.ENTER:
|
|
56
|
+
rootContext.applyInputValue((event.target as HTMLInputElement)?.value)
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
}
|
|
20
60
|
|
|
21
61
|
function handleWheelEvent(event: WheelEvent) {
|
|
22
62
|
if (rootContext.disableWheelChange.value)
|
|
@@ -77,14 +117,10 @@ function handleChange() {
|
|
|
77
117
|
:aria-valuenow="rootContext.modelValue.value"
|
|
78
118
|
:aria-valuemin="rootContext.min.value"
|
|
79
119
|
:aria-valuemax="rootContext.max.value"
|
|
80
|
-
@keydown
|
|
81
|
-
@keydown.down.prevent="rootContext.handleDecrease()"
|
|
82
|
-
@keydown.page-up.prevent="rootContext.handleIncrease(10)"
|
|
83
|
-
@keydown.page-down.prevent="rootContext.handleDecrease(10)"
|
|
84
|
-
@keydown.home.prevent="rootContext.handleMinMaxValue('min')"
|
|
85
|
-
@keydown.end.prevent="rootContext.handleMinMaxValue('max')"
|
|
120
|
+
@keydown="handleKeydown"
|
|
86
121
|
@wheel="handleWheelEvent"
|
|
87
122
|
@beforeinput="(event: InputEvent) => {
|
|
123
|
+
if (event.isComposing) return
|
|
88
124
|
const target = event.target as HTMLInputElement
|
|
89
125
|
let nextValue
|
|
90
126
|
= target.value.slice(0, target.selectionStart ?? undefined)
|
|
@@ -100,8 +136,9 @@ function handleChange() {
|
|
|
100
136
|
inputValue = target.value
|
|
101
137
|
}"
|
|
102
138
|
@change="handleChange"
|
|
103
|
-
@keydown.enter="rootContext.applyInputValue($event.target?.value)"
|
|
104
139
|
@blur="rootContext.applyInputValue($event.target?.value)"
|
|
140
|
+
@compositionstart="handleCompositionStart"
|
|
141
|
+
@compositionend="handleCompositionEnd"
|
|
105
142
|
>
|
|
106
143
|
<slot />
|
|
107
144
|
</Primitive>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { PinInputContextValue } from './PinInputRoot.vue'
|
|
3
3
|
import type { PrimitiveProps } from '@/Primitive'
|
|
4
4
|
import { Primitive, usePrimitiveElement } from '@/Primitive'
|
|
5
|
-
import { getActiveElement, useArrowNavigation } from '@/shared'
|
|
5
|
+
import { getActiveElement, useArrowNavigation, useComposing } from '@/shared'
|
|
6
6
|
import { injectPinInputRootContext } from './PinInputRoot.vue'
|
|
7
7
|
|
|
8
8
|
export interface PinInputInputProps extends PrimitiveProps {
|
|
@@ -32,7 +32,45 @@ const NUMBER_REG = /^\d*$/
|
|
|
32
32
|
const NON_NUMBER_REG = /\D/g
|
|
33
33
|
|
|
34
34
|
const { primitiveElement, currentElement } = usePrimitiveElement()
|
|
35
|
+
|
|
36
|
+
const { isComposing, handleCompositionStart, handleCompositionEnd } = useComposing((event) => {
|
|
37
|
+
const target = event.target as HTMLInputElement
|
|
38
|
+
const value = event.data || target.value
|
|
39
|
+
|
|
40
|
+
if (context.isNumericMode.value) {
|
|
41
|
+
const filtered = value.replace(NON_NUMBER_REG, '')
|
|
42
|
+
if (!filtered) {
|
|
43
|
+
target.value = ''
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
if (filtered.length > 1) {
|
|
47
|
+
handleMultipleCharacter(filtered)
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
target.value = filtered
|
|
51
|
+
updateModelValueAt(props.index, filtered)
|
|
52
|
+
const nextEl = inputElements.value[props.index + 1]
|
|
53
|
+
if (nextEl)
|
|
54
|
+
nextEl.focus()
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (value.length > 1) {
|
|
59
|
+
handleMultipleCharacter(value)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
target.value = value
|
|
64
|
+
updateModelValueAt(props.index, value)
|
|
65
|
+
|
|
66
|
+
const nextEl = inputElements.value[props.index + 1]
|
|
67
|
+
if (nextEl)
|
|
68
|
+
nextEl.focus()
|
|
69
|
+
})
|
|
70
|
+
|
|
35
71
|
function handleInput(event: InputEvent) {
|
|
72
|
+
if (isComposing.value || event.isComposing)
|
|
73
|
+
return
|
|
36
74
|
const target = event.target as HTMLInputElement
|
|
37
75
|
|
|
38
76
|
if ((event.data?.length ?? 0) > 1) {
|
|
@@ -69,6 +107,9 @@ function updatePlaceholder() {
|
|
|
69
107
|
}
|
|
70
108
|
|
|
71
109
|
function handleKeydown(event: KeyboardEvent) {
|
|
110
|
+
// Don't move between inputs mid-composition, arrow keys are used for IME candidate navigation
|
|
111
|
+
if (isComposing.value || event.isComposing)
|
|
112
|
+
return
|
|
72
113
|
useArrowNavigation(event, getActiveElement() as HTMLElement, undefined, {
|
|
73
114
|
itemsArray: inputElements.value,
|
|
74
115
|
focus: true,
|
|
@@ -223,6 +264,8 @@ onUnmounted(() => {
|
|
|
223
264
|
@focus="handleFocus"
|
|
224
265
|
@blur="handleBlur"
|
|
225
266
|
@paste="handlePaste"
|
|
267
|
+
@compositionstart="handleCompositionStart"
|
|
268
|
+
@compositionend="handleCompositionEnd"
|
|
226
269
|
>
|
|
227
270
|
<slot />
|
|
228
271
|
</Primitive>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, onMounted } from 'vue'
|
|
2
|
+
import { computed, onMounted, onUnmounted } from 'vue'
|
|
3
3
|
import { useForwardExpose } from '@/shared'
|
|
4
4
|
import { injectScrollAreaRootContext } from './ScrollAreaRoot.vue'
|
|
5
5
|
import ScrollAreaScrollbarImpl from './ScrollAreaScrollbarImpl.vue'
|
|
@@ -15,6 +15,11 @@ onMounted(() => {
|
|
|
15
15
|
if (scrollbarElement.value)
|
|
16
16
|
rootContext.onScrollbarXChange(scrollbarElement.value)
|
|
17
17
|
})
|
|
18
|
+
// Clear the registration on unmount so consumers (e.g. ScrollAreaCorner) don't
|
|
19
|
+
// hold a stale reference once the scrollbar is removed (e.g. between hover cycles).
|
|
20
|
+
onUnmounted(() => {
|
|
21
|
+
rootContext.onScrollbarXChange(null)
|
|
22
|
+
})
|
|
18
23
|
const sizes = computed(() => scrollbarVisibleContext.sizes.value)
|
|
19
24
|
</script>
|
|
20
25
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, onMounted } from 'vue'
|
|
2
|
+
import { computed, onMounted, onUnmounted } from 'vue'
|
|
3
3
|
import { useForwardExpose } from '@/shared'
|
|
4
4
|
import { injectScrollAreaRootContext } from './ScrollAreaRoot.vue'
|
|
5
5
|
import ScrollAreaScrollbarImpl from './ScrollAreaScrollbarImpl.vue'
|
|
@@ -15,6 +15,11 @@ onMounted(() => {
|
|
|
15
15
|
if (scrollbarElement.value)
|
|
16
16
|
rootContext.onScrollbarYChange(scrollbarElement.value)
|
|
17
17
|
})
|
|
18
|
+
// Clear the registration on unmount so consumers (e.g. ScrollAreaCorner) don't
|
|
19
|
+
// hold a stale reference once the scrollbar is removed (e.g. between hover cycles).
|
|
20
|
+
onUnmounted(() => {
|
|
21
|
+
rootContext.onScrollbarYChange(null)
|
|
22
|
+
})
|
|
18
23
|
|
|
19
24
|
const sizes = computed(() => scrollbarVisibleContext.sizes.value)
|
|
20
25
|
</script>
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
SelectContentImplEmits,
|
|
4
4
|
SelectContentImplProps,
|
|
5
5
|
} from './SelectContentImpl.vue'
|
|
6
|
-
import { computed, onMounted, ref, watch } from 'vue'
|
|
6
|
+
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
7
7
|
|
|
8
8
|
export type SelectContentEmits = SelectContentImplEmits
|
|
9
9
|
|
|
@@ -44,15 +44,31 @@ const presenceRef = ref<InstanceType<typeof Presence>>()
|
|
|
44
44
|
const present = computed(() => props.forceMount || rootContext.open.value)
|
|
45
45
|
const renderPresence = ref(present.value)
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
let renderPresenceTimeout: ReturnType<typeof setTimeout> | undefined
|
|
48
|
+
|
|
49
|
+
function clearRenderPresenceTimeout() {
|
|
50
|
+
if (renderPresenceTimeout) {
|
|
51
|
+
clearTimeout(renderPresenceTimeout)
|
|
52
|
+
renderPresenceTimeout = undefined
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
watch(present, (_value, _oldValue, onCleanup) => {
|
|
48
57
|
// Toggle render presence after a delay (nextTick is not enough)
|
|
49
58
|
// to allow children to re-render with the latest state.
|
|
50
59
|
// Otherwise, they would remain in the old state during the transition,
|
|
51
60
|
// which would prevent the animation that depend on state (e.g., data-[state=closed])
|
|
52
61
|
// from being applied accurately.
|
|
53
62
|
// @see https://github.com/unovue/reka-ui/issues/1865
|
|
54
|
-
|
|
63
|
+
clearRenderPresenceTimeout()
|
|
64
|
+
renderPresenceTimeout = setTimeout(() => {
|
|
65
|
+
renderPresence.value = present.value
|
|
66
|
+
renderPresenceTimeout = undefined
|
|
67
|
+
})
|
|
68
|
+
onCleanup(clearRenderPresenceTimeout)
|
|
55
69
|
})
|
|
70
|
+
|
|
71
|
+
onUnmounted(clearRenderPresenceTimeout)
|
|
56
72
|
</script>
|
|
57
73
|
|
|
58
74
|
<template>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import {
|
|
4
|
+
SelectContent,
|
|
5
|
+
SelectItem,
|
|
6
|
+
SelectItemText,
|
|
7
|
+
SelectPortal,
|
|
8
|
+
SelectRoot,
|
|
9
|
+
SelectTrigger,
|
|
10
|
+
SelectValue,
|
|
11
|
+
SelectViewport,
|
|
12
|
+
} from '..'
|
|
13
|
+
|
|
14
|
+
const open = ref(true)
|
|
15
|
+
const mounted = ref(true)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<button @click="open = false">
|
|
20
|
+
Close
|
|
21
|
+
</button>
|
|
22
|
+
<button @click="mounted = false">
|
|
23
|
+
Unmount
|
|
24
|
+
</button>
|
|
25
|
+
|
|
26
|
+
<SelectRoot
|
|
27
|
+
v-if="mounted"
|
|
28
|
+
v-model:open="open"
|
|
29
|
+
>
|
|
30
|
+
<SelectTrigger aria-label="Fruit">
|
|
31
|
+
<SelectValue placeholder="Please select a fruit" />
|
|
32
|
+
</SelectTrigger>
|
|
33
|
+
<SelectPortal>
|
|
34
|
+
<SelectContent position="popper">
|
|
35
|
+
<SelectViewport>
|
|
36
|
+
<SelectItem value="apple">
|
|
37
|
+
<SelectItemText>Apple</SelectItemText>
|
|
38
|
+
</SelectItem>
|
|
39
|
+
</SelectViewport>
|
|
40
|
+
</SelectContent>
|
|
41
|
+
</SelectPortal>
|
|
42
|
+
</SelectRoot>
|
|
43
|
+
</template>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { PrimitiveProps } from '@/Primitive'
|
|
3
|
-
import { useForwardExpose } from '@/shared'
|
|
3
|
+
import { useComposing, useForwardExpose } from '@/shared'
|
|
4
4
|
|
|
5
5
|
export interface TagsInputInputProps extends PrimitiveProps {
|
|
6
6
|
/** The placeholder character to use for empty tags input. */
|
|
@@ -13,7 +13,7 @@ export interface TagsInputInputProps extends PrimitiveProps {
|
|
|
13
13
|
</script>
|
|
14
14
|
|
|
15
15
|
<script setup lang="ts">
|
|
16
|
-
import { nextTick, onMounted
|
|
16
|
+
import { nextTick, onMounted } from 'vue'
|
|
17
17
|
import { Primitive } from '@/Primitive'
|
|
18
18
|
import { injectTagsInputRootContext } from './TagsInputRoot.vue'
|
|
19
19
|
|
|
@@ -55,15 +55,7 @@ function handleTab(event: Event) {
|
|
|
55
55
|
handleCustomKeydown(event)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
const isComposing =
|
|
59
|
-
function onCompositionStart() {
|
|
60
|
-
isComposing.value = true
|
|
61
|
-
}
|
|
62
|
-
function onCompositionEnd() {
|
|
63
|
-
nextTick(() => {
|
|
64
|
-
isComposing.value = false
|
|
65
|
-
})
|
|
66
|
-
}
|
|
58
|
+
const { isComposing, handleCompositionStart, handleCompositionEnd } = useComposing()
|
|
67
59
|
async function handleCustomKeydown(event: Event) {
|
|
68
60
|
if (isComposing.value)
|
|
69
61
|
return
|
|
@@ -85,6 +77,8 @@ async function handleCustomKeydown(event: Event) {
|
|
|
85
77
|
}
|
|
86
78
|
|
|
87
79
|
function handleInput(event: InputEvent) {
|
|
80
|
+
if (isComposing.value)
|
|
81
|
+
return
|
|
88
82
|
context.isInvalidInput.value = false
|
|
89
83
|
if (event.data === null)
|
|
90
84
|
return
|
|
@@ -106,6 +100,14 @@ function handleInput(event: InputEvent) {
|
|
|
106
100
|
}
|
|
107
101
|
}
|
|
108
102
|
|
|
103
|
+
function handleInputKeydown(event: KeyboardEvent) {
|
|
104
|
+
// `isComposing` stays true until the tick after `compositionend`, so arrow/backspace
|
|
105
|
+
// tag navigation is skipped even when the commit keydown reports `event.isComposing === false`.
|
|
106
|
+
if (isComposing.value)
|
|
107
|
+
return
|
|
108
|
+
context.onInputKeydown(event)
|
|
109
|
+
}
|
|
110
|
+
|
|
109
111
|
function handlePaste(event: ClipboardEvent) {
|
|
110
112
|
if (context.addOnPaste.value) {
|
|
111
113
|
event.preventDefault()
|
|
@@ -160,9 +162,9 @@ onMounted(() => {
|
|
|
160
162
|
@keydown.enter="handleCustomKeydown"
|
|
161
163
|
@keydown.tab="handleTab"
|
|
162
164
|
@blur="handleBlur"
|
|
163
|
-
@keydown="
|
|
164
|
-
@compositionstart="
|
|
165
|
-
@compositionend="
|
|
165
|
+
@keydown="handleInputKeydown"
|
|
166
|
+
@compositionstart="handleCompositionStart"
|
|
167
|
+
@compositionend="handleCompositionEnd"
|
|
166
168
|
@paste="handlePaste"
|
|
167
169
|
>
|
|
168
170
|
<slot />
|
|
@@ -156,6 +156,9 @@ provideTagsInputRootContext({
|
|
|
156
156
|
},
|
|
157
157
|
onRemoveValue: handleRemoveTag,
|
|
158
158
|
onInputKeydown: (event) => {
|
|
159
|
+
// Don't navigate/select tags mid-composition, keys are used for IME candidate navigation
|
|
160
|
+
if (event.isComposing)
|
|
161
|
+
return
|
|
159
162
|
const target = event.target as HTMLInputElement
|
|
160
163
|
const collection = getItems().map(i => i.ref).filter(i => i.dataset.disabled !== '')
|
|
161
164
|
if (!collection.length)
|
|
@@ -23,6 +23,9 @@ const lastKeyZero = ref(false)
|
|
|
23
23
|
const {
|
|
24
24
|
handleSegmentClick,
|
|
25
25
|
handleSegmentKeydown,
|
|
26
|
+
handleSegmentBeforeInput,
|
|
27
|
+
handleSegmentCompositionStart,
|
|
28
|
+
handleSegmentCompositionEnd,
|
|
26
29
|
handleSegmentFocusOut,
|
|
27
30
|
attributes,
|
|
28
31
|
} = useDateField({
|
|
@@ -61,6 +64,9 @@ const isInvalid = computed(() => rootContext.isInvalid.value)
|
|
|
61
64
|
v-on="part !== 'literal' ? {
|
|
62
65
|
mousedown: handleSegmentClick,
|
|
63
66
|
keydown: handleSegmentKeydown,
|
|
67
|
+
beforeinput: handleSegmentBeforeInput,
|
|
68
|
+
compositionstart: handleSegmentCompositionStart,
|
|
69
|
+
compositionend: handleSegmentCompositionEnd,
|
|
64
70
|
focusout: () => {
|
|
65
71
|
hasLeftFocus = true
|
|
66
72
|
handleSegmentFocusOut()
|
|
@@ -297,6 +297,9 @@ const prevFocusableSegment = computed(() => {
|
|
|
297
297
|
const kbd = useKbd()
|
|
298
298
|
|
|
299
299
|
function handleKeydown(e: KeyboardEvent) {
|
|
300
|
+
// Don't navigate between segments mid-composition, arrow keys are used for IME candidate navigation
|
|
301
|
+
if (e.isComposing)
|
|
302
|
+
return
|
|
300
303
|
if (!isSegmentNavigationKey(e.key))
|
|
301
304
|
return
|
|
302
305
|
if (e.key === kbd.ARROW_LEFT)
|
|
@@ -26,6 +26,9 @@ const lastKeyZero = ref(false)
|
|
|
26
26
|
const {
|
|
27
27
|
handleSegmentClick,
|
|
28
28
|
handleSegmentKeydown,
|
|
29
|
+
handleSegmentBeforeInput,
|
|
30
|
+
handleSegmentCompositionStart,
|
|
31
|
+
handleSegmentCompositionEnd,
|
|
29
32
|
attributes,
|
|
30
33
|
} = useDateField({
|
|
31
34
|
hasLeftFocus,
|
|
@@ -63,6 +66,9 @@ const isInvalid = computed(() => rootContext.isInvalid.value)
|
|
|
63
66
|
v-on="part !== 'literal' ? {
|
|
64
67
|
mousedown: handleSegmentClick,
|
|
65
68
|
keydown: handleSegmentKeydown,
|
|
69
|
+
beforeinput: handleSegmentBeforeInput,
|
|
70
|
+
compositionstart: handleSegmentCompositionStart,
|
|
71
|
+
compositionend: handleSegmentCompositionEnd,
|
|
66
72
|
focusout: () => { hasLeftFocus = true },
|
|
67
73
|
focusin: (e: FocusEvent) => {
|
|
68
74
|
rootContext.setFocusedElement(e.target as HTMLElement)
|