-import { inject } from 'vue'
-import { SELECT_ITEM_INJECTION_KEY } from './SelectItem.vue'
+import { injectSelectItemContext } from './SelectItem.vue'
import { Primitive, type PrimitiveProps } from '@/Primitive'
export interface SelectItemIndicatorProps extends PrimitiveProps {}
@@ -8,11 +7,11 @@ const props = withDefaults(defineProps
(), {
as: 'span',
})
-const itemContext = inject(SELECT_ITEM_INJECTION_KEY)
+const itemContext = injectSelectItemContext()
-
+
diff --git a/packages/radix-vue/src/Select/SelectItemText.vue b/packages/radix-vue/src/Select/SelectItemText.vue
index 8e4a7209d..381a5f551 100644
--- a/packages/radix-vue/src/Select/SelectItemText.vue
+++ b/packages/radix-vue/src/Select/SelectItemText.vue
@@ -1,13 +1,13 @@
-
+
-
+
diff --git a/packages/radix-vue/src/Select/SelectLabel.vue b/packages/radix-vue/src/Select/SelectLabel.vue
index 0728e118c..c5ea31c10 100644
--- a/packages/radix-vue/src/Select/SelectLabel.vue
+++ b/packages/radix-vue/src/Select/SelectLabel.vue
@@ -7,16 +7,13 @@ export interface SelectLabelProps extends PrimitiveProps {
diff --git a/packages/radix-vue/src/Select/SelectProvider.vue b/packages/radix-vue/src/Select/SelectProvider.vue
index 4cdb5cea6..fe6e3ded0 100644
--- a/packages/radix-vue/src/Select/SelectProvider.vue
+++ b/packages/radix-vue/src/Select/SelectProvider.vue
@@ -1,12 +1,12 @@
diff --git a/packages/radix-vue/src/Select/SelectRoot.vue b/packages/radix-vue/src/Select/SelectRoot.vue
index 2334e24dc..167bd4607 100644
--- a/packages/radix-vue/src/Select/SelectRoot.vue
+++ b/packages/radix-vue/src/Select/SelectRoot.vue
@@ -1,8 +1,8 @@
@@ -47,7 +47,7 @@ watch(currentElement, () => {
ref="primitiveElement"
@auto-scroll="
() => {
- const { viewport, selectedItem } = contentContext!;
+ const { viewport, selectedItem } = contentContext;
if (viewport?.value && selectedItem?.value) {
viewport.value.scrollTop = viewport.value.scrollTop + selectedItem.value.offsetHeight;
}
diff --git a/packages/radix-vue/src/Select/SelectScrollUpButton.vue b/packages/radix-vue/src/Select/SelectScrollUpButton.vue
index dd03a2669..70a902a13 100644
--- a/packages/radix-vue/src/Select/SelectScrollUpButton.vue
+++ b/packages/radix-vue/src/Select/SelectScrollUpButton.vue
@@ -1,17 +1,17 @@
@@ -43,7 +43,7 @@ watch(currentElement, () => {
v-if="canScrollUp"
ref="primitiveElement"
@auto-scroll="() => {
- const { viewport, selectedItem } = contentContext!;
+ const { viewport, selectedItem } = contentContext;
if (viewport?.value && selectedItem?.value) {
viewport.value.scrollTop = viewport.value.scrollTop - selectedItem.value.offsetHeight;
}
diff --git a/packages/radix-vue/src/Select/SelectTrigger.vue b/packages/radix-vue/src/Select/SelectTrigger.vue
index 3557a347e..15efdef24 100644
--- a/packages/radix-vue/src/Select/SelectTrigger.vue
+++ b/packages/radix-vue/src/Select/SelectTrigger.vue
@@ -5,10 +5,9 @@ export interface SelectTriggerProps extends PrimitiveProps {
@@ -40,7 +40,7 @@ onMounted(() => {
:as-child="asChild"
:style="{ pointerEvents: 'none' }"
>
-
+
{{ placeholder }}
diff --git a/packages/radix-vue/src/Select/SelectViewport.vue b/packages/radix-vue/src/Select/SelectViewport.vue
index 7ed6777c2..6bb56629a 100644
--- a/packages/radix-vue/src/Select/SelectViewport.vue
+++ b/packages/radix-vue/src/Select/SelectViewport.vue
@@ -1,32 +1,24 @@
@@ -49,7 +48,7 @@ const context = inject(SLIDER_INJECTION_KEY)
event.preventDefault();
// Touch devices have a delay before focusing so won't focus if touch immediately moves
// away from target (sliding). We want thumb to focus regardless.
- if (context!.thumbElements.value.includes(target)) {
+ if (rootContext.thumbElements.value.includes(target)) {
target.focus();
}
else {
diff --git a/packages/radix-vue/src/Slider/SliderRange.vue b/packages/radix-vue/src/Slider/SliderRange.vue
index ea9895fbe..0dbbbc71f 100644
--- a/packages/radix-vue/src/Slider/SliderRange.vue
+++ b/packages/radix-vue/src/Slider/SliderRange.vue
@@ -3,27 +3,27 @@ export interface SliderRangeProps extends PrimitiveProps {}
import type { DataOrientation, Direction } from '../shared/types'
-import { useCollection } from '@/shared'
+import { createContext, useCollection } from '@/shared'
export interface SliderRootProps extends PrimitiveProps {
name?: string
@@ -16,7 +16,12 @@ export interface SliderRootProps extends PrimitiveProps {
minStepsBetweenThumbs?: number
}
-export interface SliderProvideValue {
+export type SliderRootEmits = {
+ 'update:modelValue': [payload: number[] | undefined]
+ 'valueCommit': [payload: number[]]
+}
+
+export interface SliderRootContext {
orientation: Ref
disabled: Ref
min: Ref
@@ -26,13 +31,8 @@ export interface SliderProvideValue {
thumbElements: Ref
}
-export type SliderRootEmits = {
- 'update:modelValue': [payload: number[] | undefined]
- 'valueCommit': [payload: number[]]
-}
-
-export const SLIDER_INJECTION_KEY
- = Symbol() as InjectionKey
+export const [injectSliderRootContext, provideSliderRootContext]
+ = createContext('SliderRoot')
export default {
inheritAttrs: false,
@@ -42,7 +42,7 @@ export default {
diff --git a/packages/radix-vue/src/Slider/SliderVertical.vue b/packages/radix-vue/src/Slider/SliderVertical.vue
index 81561be28..16857ed3a 100644
--- a/packages/radix-vue/src/Slider/SliderVertical.vue
+++ b/packages/radix-vue/src/Slider/SliderVertical.vue
@@ -1,9 +1,9 @@
diff --git a/packages/radix-vue/src/Tabs/TabsContent.vue b/packages/radix-vue/src/Tabs/TabsContent.vue
index 0bf4db6a1..f81b8beb4 100644
--- a/packages/radix-vue/src/Tabs/TabsContent.vue
+++ b/packages/radix-vue/src/Tabs/TabsContent.vue
@@ -6,19 +6,19 @@ export interface TabsContentProps extends PrimitiveProps {
-
+
diff --git a/packages/radix-vue/src/Tabs/TabsRoot.vue b/packages/radix-vue/src/Tabs/TabsRoot.vue
index cd65bf16b..01da7ef3f 100644
--- a/packages/radix-vue/src/Tabs/TabsRoot.vue
+++ b/packages/radix-vue/src/Tabs/TabsRoot.vue
@@ -1,11 +1,21 @@
@@ -38,25 +38,25 @@ const isSelected = computed(() => props.value === context?.modelValue.value)
:data-state="isSelected ? 'active' : 'inactive'"
:disabled="disabled"
:data-disabled="disabled ? '' : undefined"
- :data-orientation="context?.orientation.value"
+ :data-orientation="rootContext.orientation.value"
@mousedown.left="(event) => {
// only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
// but not when the control key is pressed (avoiding MacOS right click)
if (!disabled && event.ctrlKey === false) {
- context?.changeModelValue(value);
+ rootContext.changeModelValue(value);
}
else {
// prevent focus to avoid accidental activation
event.preventDefault();
}
}"
- @keydown.enter.space="context?.changeModelValue(value)"
+ @keydown.enter.space="rootContext.changeModelValue(value)"
@focus="() => {
// handle 'automatic' activation if necessary
// ie. activate tab following focus
- const isAutomaticActivation = context?.activationMode !== 'manual';
+ const isAutomaticActivation = rootContext.activationMode !== 'manual';
if (!isSelected && !disabled && isAutomaticActivation) {
- context?.changeModelValue(value);
+ rootContext.changeModelValue(value);
}
}"
>
diff --git a/packages/radix-vue/src/Toggle/ToggleRoot.vue b/packages/radix-vue/src/Toggle/ToggleRoot.vue
index 156c9dd33..7e5e6d4cb 100644
--- a/packages/radix-vue/src/Toggle/ToggleRoot.vue
+++ b/packages/radix-vue/src/Toggle/ToggleRoot.vue
@@ -1,5 +1,5 @@
diff --git a/packages/radix-vue/src/ToggleGroup/ToggleGroupItem.vue b/packages/radix-vue/src/ToggleGroup/ToggleGroupItem.vue
index 6b48d4c81..773609183 100644
--- a/packages/radix-vue/src/ToggleGroup/ToggleGroupItem.vue
+++ b/packages/radix-vue/src/ToggleGroup/ToggleGroupItem.vue
@@ -8,8 +8,8 @@ export interface ToggleGroupItemProps extends ToggleProps {
context?.modelValue.value?.includes(props.value))
v-bind="props"
:disabled="disabled"
:pressed="
- context?.type === 'single'
- ? context?.modelValue.value === value
- : context?.modelValue.value?.includes(value)
+ rootContext.type === 'single'
+ ? rootContext.modelValue.value === value
+ : rootContext.modelValue.value?.includes(value)
"
- @update:pressed="context?.changeModelValue(value)"
+ @update:pressed="rootContext.changeModelValue(value)"
>
diff --git a/packages/radix-vue/src/ToggleGroup/ToggleGroupRoot.vue b/packages/radix-vue/src/ToggleGroup/ToggleGroupRoot.vue
index a5b308c59..f960a2d10 100644
--- a/packages/radix-vue/src/ToggleGroup/ToggleGroupRoot.vue
+++ b/packages/radix-vue/src/ToggleGroup/ToggleGroupRoot.vue
@@ -1,8 +1,9 @@
diff --git a/packages/radix-vue/src/Toolbar/ToolbarSeparator.vue b/packages/radix-vue/src/Toolbar/ToolbarSeparator.vue
index 19dd87589..f9713aaaf 100644
--- a/packages/radix-vue/src/Toolbar/ToolbarSeparator.vue
+++ b/packages/radix-vue/src/Toolbar/ToolbarSeparator.vue
@@ -1,18 +1,17 @@
diff --git a/packages/radix-vue/src/Toolbar/ToolbarToggleGroup.vue b/packages/radix-vue/src/Toolbar/ToolbarToggleGroup.vue
index b168054b4..977c4d4a9 100644
--- a/packages/radix-vue/src/Toolbar/ToolbarToggleGroup.vue
+++ b/packages/radix-vue/src/Toolbar/ToolbarToggleGroup.vue
@@ -1,6 +1,5 @@
diff --git a/packages/radix-vue/src/Tooltip/TooltipContentHoverable.vue b/packages/radix-vue/src/Tooltip/TooltipContentHoverable.vue
index 3fe6da59f..16887d3c8 100644
--- a/packages/radix-vue/src/Tooltip/TooltipContentHoverable.vue
+++ b/packages/radix-vue/src/Tooltip/TooltipContentHoverable.vue
@@ -1,7 +1,7 @@
@@ -101,11 +101,11 @@ onMounted(() => {
@escape-key-down="emits('escapeKeyDown', $event)"
@pointer-down-outside="emits('pointerDownOutside', $event)"
@focus-outside.prevent
- @dismiss="context.onClose()"
+ @dismiss="rootContext.onClose()"
>
-
+
{{ ariaLabel }}
diff --git a/packages/radix-vue/src/Tooltip/TooltipProvider.vue b/packages/radix-vue/src/Tooltip/TooltipProvider.vue
index c3d4a6414..0bcc2a387 100644
--- a/packages/radix-vue/src/Tooltip/TooltipProvider.vue
+++ b/packages/radix-vue/src/Tooltip/TooltipProvider.vue
@@ -1,7 +1,7 @@
@@ -49,9 +49,9 @@ onMounted(() => {
{
@@ -59,20 +59,20 @@ onMounted(() => {
if (
!hasPointerMoveOpened && !providerContext.isPointerInTransitRef.value
) {
- context.onTriggerEnter();
+ rootContext.onTriggerEnter();
hasPointerMoveOpened = true;
}
}"
@pointerleave="(event) => {
- context.onTriggerLeave();
+ rootContext.onTriggerLeave();
hasPointerMoveOpened = false;
}"
@pointerdown="handlePointerDown"
@focus="() => {
- if (!isPointerDown) context.onOpen()
+ if (!isPointerDown) rootContext.onOpen()
}"
- @blur="context.onClose()"
- @click="context.onClose()"
+ @blur="rootContext.onClose()"
+ @click="rootContext.onClose()"
>
diff --git a/packages/radix-vue/src/shared/createContext.ts b/packages/radix-vue/src/shared/createContext.ts
index 550f3c2db..6f5d68099 100644
--- a/packages/radix-vue/src/shared/createContext.ts
+++ b/packages/radix-vue/src/shared/createContext.ts
@@ -1,25 +1,50 @@
import { type InjectionKey, inject, provide } from 'vue'
-export function createContext(rootComponentName: string) {
- const injectionKey: InjectionKey = Symbol(
- `${rootComponentName}Context`,
- )
+/**
+ * @param providerComponentName - The name(s) of the component(s) providing the context.
+ *
+ * There are situations where context can come from multiple components. In such cases, you might need to give an array of component names to provide your context, instead of just a single string.
+ *
+ * @param contextName The description for injection key symbol.
+ */
+export function createContext(
+ providerComponentName: string | string[],
+ contextName?: string,
+) {
+ const symbolDescription
+ = typeof providerComponentName === 'string' && !contextName
+ ? `${providerComponentName}Context`
+ : contextName
+
+ const injectionKey: InjectionKey = Symbol(symbolDescription)
/**
- * @throws When failed to inject context and fallback not specified.
+ * @param fallback The context value to return if the injection fails.
+ *
+ * @throws When context injection failed and no fallback is specified.
* This happens when the component injecting the context is not a child of the root component providing the context.
*/
- const injectContext = (
- fallback?: T,
- ): T extends null ? ContextValue | null : ContextValue => {
+ const injectContext = <
+ T extends ContextValue | null | undefined = ContextValue,
+ >(
+ fallback?: T,
+ ): T extends null ? ContextValue | null : ContextValue => {
const context = inject(injectionKey, fallback)
if (context)
return context
if (context === null)
- return null as any
+ return context as any
- throw new Error(`Component must be used within ${rootComponentName}`)
+ throw new Error(
+ `Injection \`${injectionKey.toString()}\` not found. Component must be used within ${
+ Array.isArray(providerComponentName)
+ ? `one of the following components: ${providerComponentName.join(
+ ', ',
+ )}`
+ : `\`${providerComponentName}\``
+ }`,
+ )
}
const provideContext = (contextValue: ContextValue) => {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index afe8199fd..504682d44 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -10234,7 +10234,6 @@ packages:
resolution: {directory: packages/radix-vue, type: directory}
id: file:packages/radix-vue
name: radix-vue
- version: 0.4.1
dependencies:
'@floating-ui/dom': 1.4.2
'@floating-ui/vue': 1.0.1(vue@3.3.4)