reka-ui 2.9.6 → 2.9.8
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/Dialog/DialogOverlayImpl.cjs +2 -1
- package/dist/Dialog/DialogOverlayImpl.cjs.map +1 -1
- package/dist/Dialog/DialogOverlayImpl.js +3 -2
- package/dist/Dialog/DialogOverlayImpl.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/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 +2 -0
- package/dist/Listbox/ListboxRoot.cjs.map +1 -1
- package/dist/Listbox/ListboxRoot.js +2 -0
- package/dist/Listbox/ListboxRoot.js.map +1 -1
- package/dist/Menu/MenuContentImpl.cjs +2 -1
- package/dist/Menu/MenuContentImpl.cjs.map +1 -1
- package/dist/Menu/MenuContentImpl.js +2 -1
- package/dist/Menu/MenuContentImpl.js.map +1 -1
- package/dist/Menu/MenuItemImpl.cjs +4 -2
- package/dist/Menu/MenuItemImpl.cjs.map +1 -1
- package/dist/Menu/MenuItemImpl.js +4 -2
- 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/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/Tabs/TabsIndicator.cjs +2 -1
- package/dist/Tabs/TabsIndicator.cjs.map +1 -1
- package/dist/Tabs/TabsIndicator.js +3 -2
- package/dist/Tabs/TabsIndicator.js.map +1 -1
- package/dist/Toast/ToastAnnounce.cjs +13 -4
- package/dist/Toast/ToastAnnounce.cjs.map +1 -1
- package/dist/Toast/ToastAnnounce.js +15 -6
- package/dist/Toast/ToastAnnounce.js.map +1 -1
- package/dist/Toast/ToastRootImpl.cjs +3 -1
- package/dist/Toast/ToastRootImpl.cjs.map +1 -1
- package/dist/Toast/ToastRootImpl.js +4 -2
- package/dist/Toast/ToastRootImpl.js.map +1 -1
- package/dist/constant.d.cts.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index2.d.ts.map +1 -1
- package/dist/index3.d.ts +15 -15
- package/dist/index4.d.cts +660 -660
- package/dist/index4.d.cts.map +1 -1
- package/dist/index4.d.ts +647 -647
- package/dist/index4.d.ts.map +1 -1
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.cts.map +1 -1
- package/dist/internal.d.ts +2 -2
- package/package.json +4 -4
- package/src/Calendar/CalendarRoot.vue +1 -1
- package/src/DateRangeField/DateRangeFieldRoot.vue +1 -1
- package/src/Dialog/DialogOverlayImpl.vue +1 -0
- package/src/FocusScope/FocusScope.vue +5 -0
- package/src/Listbox/ListboxItem.vue +2 -2
- package/src/Listbox/ListboxRoot.vue +7 -0
- package/src/Menu/MenuContentImpl.vue +3 -2
- package/src/Menu/MenuItemImpl.vue +10 -2
- package/src/MonthPicker/MonthPickerRoot.vue +1 -1
- package/src/NavigationMenu/NavigationMenuContentImpl.vue +3 -0
- package/src/NavigationMenu/__test__/NavigationMenuUnmountOnHideFalse.vue +45 -0
- package/src/Select/SelectContent.vue +19 -3
- package/src/Select/__test__/SelectUnmountCleanup.vue +43 -0
- package/src/Tabs/TabsIndicator.vue +4 -2
- package/src/Toast/ToastAnnounce.vue +17 -6
- package/src/Toast/ToastRootImpl.vue +14 -1
- package/src/YearPicker/YearPickerRoot.vue +1 -1
- package/src/index.ts +7 -0
package/dist/internal.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./index2.cjs";
|
|
2
2
|
import "./index3.cjs";
|
|
3
3
|
import { MenuArrowProps, MenuCheckboxItemEmits, MenuCheckboxItemProps, MenuContentEmits, MenuContentProps, MenuEmits, MenuGroupProps, MenuItemEmits, MenuItemIndicatorProps, MenuItemProps, MenuLabelProps, MenuPortalProps, MenuProps, MenuRadioGroupEmits, MenuRadioGroupProps, MenuRadioItemEmits, MenuRadioItemProps, MenuSeparatorProps, MenuSubContentEmits, MenuSubContentProps, MenuSubEmits, MenuSubProps, MenuSubTriggerProps, PopperAnchorProps, _default$277 as _default$13, _default$278 as _default$8, _default$279 as _default, _default$280 as _default$6, _default$281 as _default$10, _default$282 as _default$3, _default$283 as _default$14, _default$284 as _default$12, _default$285 as _default$2, _default$286 as _default$1, _default$287 as _default$11, _default$288 as _default$7, _default$290 as _default$9, _default$291 as _default$4, _default$292 as _default$5, injectMenuContext, injectMenuRootContext } from "./index4.cjs";
|
|
4
|
-
import * as
|
|
4
|
+
import * as vue136 from "vue";
|
|
5
5
|
|
|
6
6
|
//#region src/Menu/MenuAnchor.vue.d.ts
|
|
7
7
|
interface MenuAnchorProps extends PopperAnchorProps {}
|
|
@@ -9,7 +9,7 @@ declare var __VLS_8: {};
|
|
|
9
9
|
type __VLS_Slots = {} & {
|
|
10
10
|
default?: (props: typeof __VLS_8) => any;
|
|
11
11
|
};
|
|
12
|
-
declare const __VLS_base:
|
|
12
|
+
declare const __VLS_base: vue136.DefineComponent<MenuAnchorProps, {}, {}, {}, {}, vue136.ComponentOptionsMixin, vue136.ComponentOptionsMixin, {}, string, vue136.PublicProps, Readonly<MenuAnchorProps> & Readonly<{}>, {}, {}, {}, {}, string, vue136.ComponentProvideOptions, false, {}, any>;
|
|
13
13
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
14
14
|
declare const _default$15: typeof __VLS_export;
|
|
15
15
|
type __VLS_WithSlots<T, S> = T & {
|
package/dist/internal.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.d.cts","names":[],"sources":["../src/Menu/MenuAnchor.vue"],"sourcesContent":[],"mappings":";;;;;;UAoBU,eAAA,SAAwB;YAsC9B;KACC,WAAA;2BACwB;AA3CoB,CAAA;AAGE,cA2C7C,UALgB,EAKN,
|
|
1
|
+
{"version":3,"file":"internal.d.cts","names":[],"sources":["../src/Menu/MenuAnchor.vue"],"sourcesContent":[],"mappings":";;;;;;UAoBU,eAAA,SAAwB;YAsC9B;KACC,WAAA;2BACwB;AA3CoB,CAAA;AAGE,cA2C7C,UALgB,EAKN,MAAA,CAAA,eALM,CAKN,eALM,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAKN,MAAA,CAAA,qBAAA,EAAA,MAAA,CAAA,qBAAA,EALM,CAAA,CAAA,EAAA,MAAA,EAKN,MAAA,CAAA,WAAA,EAAA,QALM,CAKN,eALM,CAAA,GAKN,QALM,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,MAAA,EAKN,MAAA,CAAA,uBAAA,EALM,KAAA,EAAA,CAAA,CAAA,EAAA,GAAA,CAAA;AAAA,cAQhB,YAPU,EAOW,eANS,CAAA,OAMc,UANd,EAM0B,WAN1B,CAAA;AAAA,cAMM,WADxC,EAAA,OAE0B,YAF1B;KAGG,eALW,CAAA,CAAA,EAAA,CAAA,CAAA,GAKa,CALb,GAAA;EAAA,MAAA,EAAA;IAAA,MAAA,EAON,CAPM;EAAA,CAAA;CAAA"}
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./index2.js";
|
|
2
2
|
import "./index3.js";
|
|
3
3
|
import { MenuArrowProps, MenuCheckboxItemEmits, MenuCheckboxItemProps, MenuContentEmits, MenuContentProps, MenuEmits, MenuGroupProps, MenuItemEmits, MenuItemIndicatorProps, MenuItemProps, MenuLabelProps, MenuPortalProps, MenuProps, MenuRadioGroupEmits, MenuRadioGroupProps, MenuRadioItemEmits, MenuRadioItemProps, MenuSeparatorProps, MenuSubContentEmits, MenuSubContentProps, MenuSubEmits, MenuSubProps, MenuSubTriggerProps, PopperAnchorProps, _default$277 as _default$13, _default$278 as _default$8, _default$279 as _default, _default$280 as _default$6, _default$281 as _default$10, _default$282 as _default$3, _default$283 as _default$14, _default$284 as _default$12, _default$285 as _default$2, _default$286 as _default$1, _default$287 as _default$11, _default$288 as _default$7, _default$290 as _default$9, _default$291 as _default$4, _default$292 as _default$5, injectMenuContext, injectMenuRootContext } from "./index4.js";
|
|
4
|
-
import * as
|
|
4
|
+
import * as vue50 from "vue";
|
|
5
5
|
|
|
6
6
|
//#region src/Menu/MenuAnchor.vue.d.ts
|
|
7
7
|
interface MenuAnchorProps extends PopperAnchorProps {}
|
|
@@ -9,7 +9,7 @@ declare var __VLS_8: {};
|
|
|
9
9
|
type __VLS_Slots = {} & {
|
|
10
10
|
default?: (props: typeof __VLS_8) => any;
|
|
11
11
|
};
|
|
12
|
-
declare const __VLS_base:
|
|
12
|
+
declare const __VLS_base: vue50.DefineComponent<MenuAnchorProps, {}, {}, {}, {}, vue50.ComponentOptionsMixin, vue50.ComponentOptionsMixin, {}, string, vue50.PublicProps, Readonly<MenuAnchorProps> & Readonly<{}>, {}, {}, {}, {}, string, vue50.ComponentProvideOptions, false, {}, any>;
|
|
13
13
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
14
14
|
declare const _default$15: typeof __VLS_export;
|
|
15
15
|
type __VLS_WithSlots<T, S> = T & {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reka-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.9.
|
|
4
|
+
"version": "2.9.8",
|
|
5
5
|
"description": "Vue port for Radix UI Primitives.",
|
|
6
6
|
"author": "UnoVue Contributors (https://github.com/unovue)",
|
|
7
7
|
"license": "MIT",
|
|
@@ -111,14 +111,14 @@
|
|
|
111
111
|
"@tsconfig/node24": "^24.0.0",
|
|
112
112
|
"@types/jsdom": "^28.0.0",
|
|
113
113
|
"@types/node": "^24.0.13",
|
|
114
|
-
"@vitejs/plugin-vue": "^6.0.
|
|
114
|
+
"@vitejs/plugin-vue": "^6.0.6",
|
|
115
115
|
"@vitest/coverage-istanbul": "^3.2.4",
|
|
116
|
-
"@vue/test-utils": "^2.4.
|
|
116
|
+
"@vue/test-utils": "^2.4.10",
|
|
117
117
|
"@vue/tsconfig": "^0.7.0",
|
|
118
118
|
"jsdom": "^26.1.0",
|
|
119
119
|
"size-limit": "^12.0.1",
|
|
120
120
|
"tsdown": "^0.12.9",
|
|
121
|
-
"vite": "^8.0.
|
|
121
|
+
"vite": "^8.0.12",
|
|
122
122
|
"vitest": "^3.2.4",
|
|
123
123
|
"vitest-axe": "0.1.0",
|
|
124
124
|
"vitest-canvas-mock": "^0.3.3",
|
|
@@ -98,7 +98,7 @@ export interface CalendarRootProps extends PrimitiveProps {
|
|
|
98
98
|
/** A function that returns the previous page of the calendar. It receives the current placeholder as an argument inside the component. */
|
|
99
99
|
prevPage?: (placeholder: DateValue) => DateValue
|
|
100
100
|
/** The controlled selected date value of the calendar. Can be bound as `v-model`. */
|
|
101
|
-
modelValue?: DateValue | DateValue[] |
|
|
101
|
+
modelValue?: DateValue | DateValue[] | null
|
|
102
102
|
/** Whether multiple dates can be selected */
|
|
103
103
|
multiple?: boolean
|
|
104
104
|
/** Whether or not to disable days outside the current view. */
|
|
@@ -84,7 +84,7 @@ export interface DateRangeFieldRootProps extends PrimitiveProps, FormFieldProps
|
|
|
84
84
|
|
|
85
85
|
export type DateRangeFieldRootEmits = {
|
|
86
86
|
/** Event handler called whenever the model value changes */
|
|
87
|
-
'update:modelValue': [DateRange]
|
|
87
|
+
'update:modelValue': [date: DateRange]
|
|
88
88
|
/** Event handler called whenever the placeholder value changes */
|
|
89
89
|
'update:placeholder': [date: DateValue]
|
|
90
90
|
}
|
|
@@ -185,6 +185,10 @@ watchEffect(async (cleanupFn) => {
|
|
|
185
185
|
container.addEventListener(AUTOFOCUS_ON_UNMOUNT, unmountEventHandler)
|
|
186
186
|
container.dispatchEvent(unmountEvent)
|
|
187
187
|
|
|
188
|
+
// Signal that blur events fired below are system-initiated (focus trap
|
|
189
|
+
// cleanup), not user-initiated. Consumers can use this to skip validation.
|
|
190
|
+
container.setAttribute('data-focus-scope-unmounting', '')
|
|
191
|
+
|
|
188
192
|
setTimeout(() => {
|
|
189
193
|
if (!unmountEvent.defaultPrevented)
|
|
190
194
|
focus(previouslyFocusedElement ?? document.body, { select: true })
|
|
@@ -193,6 +197,7 @@ watchEffect(async (cleanupFn) => {
|
|
|
193
197
|
container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, unmountEventHandler)
|
|
194
198
|
|
|
195
199
|
focusScopesStack.remove(focusScope)
|
|
200
|
+
container.removeAttribute('data-focus-scope-unmounting')
|
|
196
201
|
}, 0)
|
|
197
202
|
})
|
|
198
203
|
})
|
|
@@ -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"
|
|
@@ -79,6 +79,7 @@ export type ListboxRootEmits<T = AcceptableValue> = {
|
|
|
79
79
|
import type { EventHook } from '@vueuse/core'
|
|
80
80
|
import type { Ref } from 'vue'
|
|
81
81
|
import { createEventHook, useVModel } from '@vueuse/core'
|
|
82
|
+
import { isClient } from '@vueuse/shared'
|
|
82
83
|
import { nextTick, ref, toRefs, watch } from 'vue'
|
|
83
84
|
import { useCollection } from '@/Collection'
|
|
84
85
|
import { VisuallyHiddenInput } from '@/VisuallyHidden'
|
|
@@ -324,6 +325,12 @@ function handleMultipleReplace(event: KeyboardEvent, targetEl: HTMLElement) {
|
|
|
324
325
|
}
|
|
325
326
|
|
|
326
327
|
async function highlightSelected(event?: Event) {
|
|
328
|
+
// highlightSelected is called inside a watch with immediate set to true.
|
|
329
|
+
// This results in code execution during SSR.
|
|
330
|
+
// Ensure this code only runs in a browser environment, since it performs
|
|
331
|
+
// DOM-only side effects (focus, scrollIntoView, synthetic KeyboardEvent).
|
|
332
|
+
if (!isClient)
|
|
333
|
+
return
|
|
327
334
|
await nextTick()
|
|
328
335
|
if (isVirtual.value) {
|
|
329
336
|
// Trigger on nextTick for Virtualizer to be mounted
|
|
@@ -24,7 +24,7 @@ import { useBodyScrollLock } from '@/shared/useBodyScrollLock'
|
|
|
24
24
|
|
|
25
25
|
export interface MenuContentContext {
|
|
26
26
|
onItemEnter: (event: PointerEvent) => boolean
|
|
27
|
-
onItemLeave: (event: PointerEvent) =>
|
|
27
|
+
onItemLeave: (event: PointerEvent) => boolean
|
|
28
28
|
onTriggerLeave: (event: PointerEvent) => boolean
|
|
29
29
|
searchRef: Ref<string>
|
|
30
30
|
highlightedElement: Ref<HTMLElement | undefined>
|
|
@@ -303,13 +303,14 @@ provideMenuContentContext({
|
|
|
303
303
|
},
|
|
304
304
|
onItemLeave: (event) => {
|
|
305
305
|
if (isPointerMovingToSubmenu(event))
|
|
306
|
-
return
|
|
306
|
+
return true
|
|
307
307
|
|
|
308
308
|
const isInputFocused = ['INPUT', 'TEXTAREA'].includes(getActiveElement()?.tagName || '')
|
|
309
309
|
if (!isInputFocused)
|
|
310
310
|
contentElement.value?.focus()
|
|
311
311
|
|
|
312
312
|
currentItemId.value = null
|
|
313
|
+
return false
|
|
313
314
|
},
|
|
314
315
|
onTriggerLeave: (event) => {
|
|
315
316
|
// event.preventDefault() we can't prevent pointerLeave event
|
|
@@ -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))
|
|
@@ -60,7 +60,15 @@ async function handlePointerLeave(event: PointerEvent) {
|
|
|
60
60
|
if (!isMouseEvent(event))
|
|
61
61
|
return
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
// If the highlight was already claimed by another element (e.g. the pointer moved
|
|
64
|
+
// directly onto another item, whose synchronous `pointermove` ran before this
|
|
65
|
+
// `nextTick` resolved), this leave is stale and must not reset focus/roving state.
|
|
66
|
+
if (contentContext.highlightedElement.value !== currentElement.value)
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
const isMovingToSubmenu = contentContext.onItemLeave(event)
|
|
70
|
+
if (!isMovingToSubmenu && contentContext.highlightedElement.value === currentElement.value)
|
|
71
|
+
contentContext.highlightedElement.value = undefined
|
|
64
72
|
}
|
|
65
73
|
</script>
|
|
66
74
|
|
|
@@ -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,
|
|
@@ -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>
|
|
@@ -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>
|
|
@@ -8,7 +8,7 @@ export interface TabsIndicatorProps extends PrimitiveProps {}
|
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<script setup lang="ts">
|
|
11
|
-
import { useResizeObserver } from '@vueuse/core'
|
|
11
|
+
import { useMounted, useResizeObserver } from '@vueuse/core'
|
|
12
12
|
import { Primitive } from '@/Primitive'
|
|
13
13
|
|
|
14
14
|
const props = defineProps<TabsIndicatorProps>()
|
|
@@ -18,6 +18,8 @@ defineExpose({
|
|
|
18
18
|
})
|
|
19
19
|
useForwardExpose()
|
|
20
20
|
|
|
21
|
+
const isMounted = useMounted()
|
|
22
|
+
|
|
21
23
|
interface IndicatorStyle {
|
|
22
24
|
size: number | null
|
|
23
25
|
position: number | null
|
|
@@ -61,7 +63,7 @@ function updateIndicatorStyle() {
|
|
|
61
63
|
|
|
62
64
|
<template>
|
|
63
65
|
<Primitive
|
|
64
|
-
v-if="typeof indicatorStyle.size === 'number'"
|
|
66
|
+
v-if="isMounted && typeof indicatorStyle.size === 'number'"
|
|
65
67
|
v-bind="props"
|
|
66
68
|
:style="{
|
|
67
69
|
'--reka-tabs-indicator-size': `${indicatorStyle.size}px`,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { ref } from 'vue'
|
|
2
|
+
import { isClient, useTimeout } from '@vueuse/shared'
|
|
3
|
+
import { onScopeDispose, ref } from 'vue'
|
|
5
4
|
import { VisuallyHidden } from '@/VisuallyHidden'
|
|
6
5
|
import { injectToastProviderContext } from './ToastProvider.vue'
|
|
7
6
|
|
|
@@ -10,9 +9,21 @@ const providerContext = injectToastProviderContext()
|
|
|
10
9
|
const isAnnounced = useTimeout(1000)
|
|
11
10
|
const renderAnnounceText = ref(false)
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
// Render text content in the next frame to ensure toast is announced in NVDA.
|
|
13
|
+
// Double rAF mirrors Radix UI's `useNextFrame` behavior.
|
|
14
|
+
let raf1 = 0
|
|
15
|
+
let raf2 = 0
|
|
16
|
+
if (isClient) {
|
|
17
|
+
raf1 = requestAnimationFrame(() => {
|
|
18
|
+
raf2 = requestAnimationFrame(() => {
|
|
19
|
+
renderAnnounceText.value = true
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
onScopeDispose(() => {
|
|
23
|
+
cancelAnimationFrame(raf1)
|
|
24
|
+
cancelAnimationFrame(raf2)
|
|
25
|
+
})
|
|
26
|
+
}
|
|
16
27
|
</script>
|
|
17
28
|
|
|
18
29
|
<template>
|
|
@@ -183,7 +183,20 @@ provideToastRootContext({ onClose: handleClose })
|
|
|
183
183
|
role="alert"
|
|
184
184
|
:aria-live="type === 'foreground' ? 'assertive' : 'polite'"
|
|
185
185
|
>
|
|
186
|
-
|
|
186
|
+
<!--
|
|
187
|
+
Render each chunk as its own text node so screen readers get the
|
|
188
|
+
natural pause break between nodes (see comment in utils.ts).
|
|
189
|
+
Interpolating the array directly with `{{ announceTextContent }}`
|
|
190
|
+
would route through Vue's `toDisplayString`, which JSON-stringifies
|
|
191
|
+
arrays — the live region would then announce literal `[`, quotes
|
|
192
|
+
and commas instead of the toast title and description.
|
|
193
|
+
-->
|
|
194
|
+
<template
|
|
195
|
+
v-for="(text, i) in announceTextContent"
|
|
196
|
+
:key="i"
|
|
197
|
+
>
|
|
198
|
+
{{ text }}
|
|
199
|
+
</template>
|
|
187
200
|
</ToastAnnounce>
|
|
188
201
|
|
|
189
202
|
<Teleport
|
|
@@ -75,7 +75,7 @@ export interface YearPickerRootProps extends PrimitiveProps {
|
|
|
75
75
|
/** A function that returns the previous page of the year picker. Receives the current placeholder as an argument. */
|
|
76
76
|
prevPage?: (placeholder: DateValue) => DateValue
|
|
77
77
|
/** The controlled selected year value of the year picker. Can be bound as `v-model`. */
|
|
78
|
-
modelValue?: DateValue | DateValue[] |
|
|
78
|
+
modelValue?: DateValue | DateValue[] | null
|
|
79
79
|
/** Whether multiple years can be selected */
|
|
80
80
|
multiple?: boolean
|
|
81
81
|
/** Number of years to display per page */
|
package/src/index.ts
CHANGED
|
@@ -96,7 +96,14 @@ export {
|
|
|
96
96
|
} from './shared/color'
|
|
97
97
|
export {
|
|
98
98
|
type AcceptableValue,
|
|
99
|
+
type DataOrientation,
|
|
100
|
+
type Direction,
|
|
101
|
+
type FormFieldProps,
|
|
99
102
|
type GenericComponentInstance,
|
|
103
|
+
type ScrollBodyOption,
|
|
104
|
+
type SingleOrMultipleProps,
|
|
105
|
+
type SingleOrMultipleType,
|
|
106
|
+
type StringOrNumber,
|
|
100
107
|
} from './shared/types'
|
|
101
108
|
export * from './Slider'
|
|
102
109
|
export * from './Splitter'
|