,
diff --git a/packages/react/src/ui/Select/components/SelectTrigger.tsx b/packages/react/src/ui/Select/components/SelectTrigger.tsx
index c07a3a028b..eab0ef7db2 100644
--- a/packages/react/src/ui/Select/components/SelectTrigger.tsx
+++ b/packages/react/src/ui/Select/components/SelectTrigger.tsx
@@ -1,8 +1,8 @@
-import * as SelectPrimitive from "@radix-ui/react-select"
+import { cn } from "@/lib/utils.ts"
import * as React from "react"
import { useContext } from "react"
-import { cn } from "../../../lib/utils.ts"
import { SelectContext } from "../SelectContext.tsx"
+import * as SelectPrimitive from "./radix-ui"
/**
* Select Trigger component
diff --git a/packages/react/src/ui/Select/components/radix-ui/README.md b/packages/react/src/ui/Select/components/radix-ui/README.md
new file mode 100644
index 0000000000..333521411e
--- /dev/null
+++ b/packages/react/src/ui/Select/components/radix-ui/README.md
@@ -0,0 +1,6 @@
+# IMPORTANT
+
+This code was extracted from Radix-ui select in order to add support for
+multiselection to the Select primitive
+
+https://github.com/radix-ui/primitives/blob/b3ee588dcb339d6c6ce524fcdd968c5eeb4e8458/packages/react/select/src/select.tsx
diff --git a/packages/react/src/ui/Select/components/radix-ui/index.ts b/packages/react/src/ui/Select/components/radix-ui/index.ts
new file mode 100644
index 0000000000..1690e35022
--- /dev/null
+++ b/packages/react/src/ui/Select/components/radix-ui/index.ts
@@ -0,0 +1,56 @@
+"use client"
+export {
+ Arrow,
+ Content,
+ Group,
+ Icon,
+ Item,
+ ItemIndicator,
+ ItemText,
+ Label,
+ Portal,
+ //
+ Root,
+ ScrollDownButton,
+ ScrollUpButton,
+ //
+ Select,
+ SelectArrow,
+ SelectContent,
+ SelectGroup,
+ SelectIcon,
+ SelectItem,
+ SelectItemIndicator,
+ SelectItemText,
+ SelectLabel,
+ SelectPortal,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+ SelectViewport,
+ Separator,
+ Trigger,
+ Value,
+ Viewport,
+ createSelectScope,
+} from "./select"
+export type {
+ SelectArrowProps,
+ SelectContentProps,
+ SelectGroupProps,
+ SelectIconProps,
+ SelectItemIndicatorProps,
+ SelectItemProps,
+ SelectItemTextProps,
+ SelectLabelProps,
+ SelectPortalProps,
+ SelectProps,
+ SelectScrollDownButtonProps,
+ SelectScrollUpButtonProps,
+ SelectSeparatorProps,
+ SelectTriggerProps,
+ SelectValueProps,
+ SelectViewportProps,
+} from "./select"
diff --git a/packages/react/src/ui/Select/components/radix-ui/select.tsx b/packages/react/src/ui/Select/components/radix-ui/select.tsx
new file mode 100644
index 0000000000..d51aaa708f
--- /dev/null
+++ b/packages/react/src/ui/Select/components/radix-ui/select.tsx
@@ -0,0 +1,2109 @@
+import { clamp } from "@radix-ui/number"
+import { composeEventHandlers } from "@radix-ui/primitive"
+import { createCollection } from "@radix-ui/react-collection"
+import { useComposedRefs } from "@radix-ui/react-compose-refs"
+import { createContextScope } from "@radix-ui/react-context"
+import { useDirection } from "@radix-ui/react-direction"
+import { DismissableLayer } from "@radix-ui/react-dismissable-layer"
+import { useFocusGuards } from "@radix-ui/react-focus-guards"
+import { FocusScope } from "@radix-ui/react-focus-scope"
+import { useId } from "@radix-ui/react-id"
+import * as PopperPrimitive from "@radix-ui/react-popper"
+import { createPopperScope } from "@radix-ui/react-popper"
+import { Portal as PortalPrimitive } from "@radix-ui/react-portal"
+import { Primitive } from "@radix-ui/react-primitive"
+import { createSlot } from "@radix-ui/react-slot"
+import { useCallbackRef } from "@radix-ui/react-use-callback-ref"
+import { useControllableState } from "@radix-ui/react-use-controllable-state"
+import { useLayoutEffect } from "@radix-ui/react-use-layout-effect"
+import { usePrevious } from "@radix-ui/react-use-previous"
+import { VISUALLY_HIDDEN_STYLES } from "@radix-ui/react-visually-hidden"
+import { hideOthers } from "aria-hidden"
+import * as React from "react"
+import * as ReactDOM from "react-dom"
+import { RemoveScroll } from "react-remove-scroll"
+
+import type { Scope } from "@radix-ui/react-context"
+
+type Direction = "ltr" | "rtl"
+
+const OPEN_KEYS = [" ", "Enter", "ArrowUp", "ArrowDown"]
+const SELECTION_KEYS = [" ", "Enter"]
+
+/* -------------------------------------------------------------------------------------------------
+ * Select
+ * -----------------------------------------------------------------------------------------------*/
+
+const SELECT_NAME = "Select"
+
+type ItemData = { value: string; disabled: boolean; textValue: string }
+const [Collection, useCollection, createCollectionScope] = createCollection<
+ SelectItemElement,
+ ItemData
+>(SELECT_NAME)
+
+type ScopedProps = P & { __scopeSelect?: Scope }
+const [createSelectContext, createSelectScope] = createContextScope(
+ SELECT_NAME,
+ [createCollectionScope, createPopperScope]
+)
+const usePopperScope = createPopperScope()
+
+type SelectContextValue = {
+ trigger: SelectTriggerElement | null
+ onTriggerChange(node: SelectTriggerElement | null): void
+ valueNode: SelectValueElement | null
+ onValueNodeChange(node: SelectValueElement): void
+ valueNodeHasChildren: boolean
+ onValueNodeHasChildrenChange(hasChildren: boolean): void
+ contentId: string
+ value: T[] | T | undefined
+ onValueChange(value: T[] | T): void
+ onItemCheckChange?: (value: T, checked: boolean) => void
+ open: boolean
+ required?: boolean
+ multiple?: boolean
+ onOpenChange(open: boolean): void
+ dir: SelectProps["dir"]
+ triggerPointerDownPosRef: React.MutableRefObject<{
+ x: number
+ y: number
+ } | null>
+ disabled?: boolean
+}
+
+const [SelectProvider, useSelectContext] =
+ createSelectContext(SELECT_NAME)
+
+type NativeOption = React.ReactElement>
+
+type SelectNativeOptionsContextValue = {
+ onNativeOptionAdd(option: NativeOption): void
+ onNativeOptionRemove(option: NativeOption): void
+}
+const [SelectNativeOptionsProvider, useSelectNativeOptionsContext] =
+ createSelectContext(SELECT_NAME)
+
+interface SelectSharedProps {
+ children?: React.ReactNode
+ open?: boolean
+ defaultOpen?: boolean
+ onOpenChange?: (open: boolean) => void
+ dir?: Direction
+ name?: string
+ autoComplete?: string
+ disabled?: boolean
+ required?: boolean
+ form?: string
+ onItemCheckChange?: (value: string, checked: boolean) => void
+}
+
+type SelectProps = SelectSharedProps &
+ (
+ | {
+ value?: T
+ defaultValue?: T
+ onValueChange?(value: T): void
+ multiple?: false | never
+ }
+ | {
+ value?: T[]
+ defaultValue?: T[]
+ onValueChange?(value: T[]): void
+ multiple: true
+ }
+ )
+
+export type { SelectProps as SelectPrimitiveProps }
+
+const Select = (
+ props: ScopedProps>
+) => {
+ const {
+ __scopeSelect,
+ children,
+ open: openProp,
+ defaultOpen,
+ onOpenChange,
+ value: valueProp,
+ defaultValue,
+ onValueChange,
+ onItemCheckChange,
+ dir,
+ name,
+ autoComplete,
+ disabled,
+ required,
+ form,
+ multiple,
+ } = props
+ const popperScope = usePopperScope(__scopeSelect)
+ const [trigger, setTrigger] = React.useState(
+ null
+ )
+ const [valueNode, setValueNode] = React.useState(
+ null
+ )
+ const [valueNodeHasChildren, setValueNodeHasChildren] = React.useState(false)
+ const direction = useDirection(dir)
+ const [open, setOpen] = useControllableState({
+ prop: openProp,
+ defaultProp: defaultOpen ?? false,
+ onChange: onOpenChange,
+ caller: SELECT_NAME,
+ })
+ const [value, setValue] = useControllableState({
+ prop: valueProp,
+ defaultProp: defaultValue,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ onChange: onValueChange as any,
+ caller: SELECT_NAME,
+ })
+ const triggerPointerDownPosRef = React.useRef<{
+ x: number
+ y: number
+ } | null>(null)
+
+ // We set this to true by default so that events bubble to forms without JS (SSR)
+ const isFormControl = trigger ? form || !!trigger.closest("form") : true
+ const [nativeOptionsSet, setNativeOptionsSet] = React.useState(
+ new Set()
+ )
+
+ // The native `select` only associates the correct default value if the corresponding
+ // `option` is rendered as a child **at the same time** as itself.
+ // Because it might take a few renders for our items to gather the information to build
+ // the native `option`(s), we generate a key on the `select` to make sure React re-builds it
+ // each time the options change.
+ const nativeSelectKey = Array.from(nativeOptionsSet)
+ .map((option) => option.props.value)
+ .join(";")
+
+ return (
+
+ setValue(value)}
+ onItemCheckChange={onItemCheckChange}
+ open={open}
+ onOpenChange={setOpen}
+ dir={direction}
+ triggerPointerDownPosRef={triggerPointerDownPosRef}
+ disabled={disabled}
+ multiple={multiple}
+ >
+
+ {
+ setNativeOptionsSet((prev) => new Set(prev).add(option))
+ }, [])}
+ onNativeOptionRemove={React.useCallback((option) => {
+ setNativeOptionsSet((prev) => {
+ const optionsSet = new Set(prev)
+ optionsSet.delete(option)
+ return optionsSet
+ })
+ }, [])}
+ >
+ {children}
+
+
+
+ {isFormControl ? (
+ {
+ if (multiple) {
+ setValue(
+ Array.from(event.currentTarget.selectedOptions).map(
+ (option) => option.value as T
+ )
+ )
+ } else {
+ setValue(event.target.value as T)
+ }
+ }}
+ disabled={disabled}
+ form={form}
+ multiple={multiple}
+ >
+ {value === undefined ? : null}
+ {Array.from(nativeOptionsSet)}
+
+ ) : null}
+
+
+ )
+}
+
+Select.displayName = SELECT_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectTrigger
+ * -----------------------------------------------------------------------------------------------*/
+
+const TRIGGER_NAME = "SelectTrigger"
+
+type SelectTriggerElement = React.ElementRef
+type PrimitiveButtonProps = React.ComponentPropsWithoutRef<
+ typeof Primitive.button
+>
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectTriggerProps extends PrimitiveButtonProps {}
+
+const SelectTrigger = React.forwardRef<
+ SelectTriggerElement,
+ SelectTriggerProps
+>((props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, disabled = false, ...triggerProps } = props
+ const popperScope = usePopperScope(__scopeSelect)
+ const context = useSelectContext(TRIGGER_NAME, __scopeSelect)
+ const isDisabled = context.disabled || disabled
+ const composedRefs = useComposedRefs(forwardedRef, context.onTriggerChange)
+ const getItems = useCollection(__scopeSelect)
+ const pointerTypeRef =
+ React.useRef("touch")
+
+ const [searchRef, handleTypeaheadSearch, resetTypeahead] = useTypeaheadSearch(
+ (search) => {
+ const enabledItems = getItems().filter((item) => !item.disabled)
+ const currentItem = enabledItems.find(
+ (item) => item.value === context.value
+ )
+ const nextItem = findNextItem(enabledItems, search, currentItem)
+ if (nextItem !== undefined) {
+ context.onValueChange(nextItem.value)
+ }
+ }
+ )
+
+ const handleOpen = (pointerEvent?: React.MouseEvent | React.PointerEvent) => {
+ if (!isDisabled) {
+ context.onOpenChange(true)
+ // reset typeahead when we open
+ resetTypeahead()
+ }
+
+ if (pointerEvent) {
+ context.triggerPointerDownPosRef.current = {
+ x: Math.round(pointerEvent.pageX),
+ y: Math.round(pointerEvent.pageY),
+ }
+ }
+ }
+
+ return (
+
+ {
+ // Whilst browsers generally have no issue focusing the trigger when clicking
+ // on a label, Safari seems to struggle with the fact that there's no `onClick`.
+ // We force `focus` in this case. Note: this doesn't create any other side-effect
+ // because we are preventing default in `onPointerDown` so effectively
+ // this only runs for a label "click"
+ event.currentTarget.focus()
+
+ // Open on click when using a touch or pen device
+ if (pointerTypeRef.current !== "mouse") {
+ handleOpen(event)
+ }
+ })}
+ onPointerDown={composeEventHandlers(
+ triggerProps.onPointerDown,
+ (event) => {
+ pointerTypeRef.current = event.pointerType
+
+ // prevent implicit pointer capture
+ // https://www.w3.org/TR/pointerevents3/#implicit-pointer-capture
+ const target = event.target as HTMLElement
+ if (target.hasPointerCapture(event.pointerId)) {
+ target.releasePointerCapture(event.pointerId)
+ }
+
+ // 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); also not for touch
+ // devices because that would open the menu on scroll. (pen devices behave as touch on iOS).
+ if (
+ event.button === 0 &&
+ event.ctrlKey === false &&
+ event.pointerType === "mouse"
+ ) {
+ handleOpen(event)
+ // prevent trigger from stealing focus from the active item after opening.
+ event.preventDefault()
+ }
+ }
+ )}
+ onKeyDown={composeEventHandlers(triggerProps.onKeyDown, (event) => {
+ const isTypingAhead = searchRef.current !== ""
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey
+ if (!isModifierKey && event.key.length === 1)
+ handleTypeaheadSearch(event.key)
+ if (isTypingAhead && event.key === " ") return
+ if (OPEN_KEYS.includes(event.key)) {
+ handleOpen()
+ event.preventDefault()
+ }
+ })}
+ />
+
+ )
+})
+
+SelectTrigger.displayName = TRIGGER_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectValue
+ * -----------------------------------------------------------------------------------------------*/
+
+const VALUE_NAME = "SelectValue"
+
+type SelectValueElement = React.ElementRef
+type PrimitiveSpanProps = React.ComponentPropsWithoutRef
+interface SelectValueProps extends Omit {
+ placeholder?: React.ReactNode
+}
+
+const SelectValue = React.forwardRef(
+ (props: ScopedProps, forwardedRef) => {
+ // We ignore `className` and `style` as this part shouldn't be styled.
+ const {
+ __scopeSelect,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ className,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ style,
+ children,
+ placeholder = "",
+ ...valueProps
+ } = props
+ const context = useSelectContext(VALUE_NAME, __scopeSelect)
+ const { onValueNodeHasChildrenChange } = context
+ const hasChildren = children !== undefined
+ const composedRefs = useComposedRefs(
+ forwardedRef,
+ context.onValueNodeChange
+ )
+
+ useLayoutEffect(() => {
+ onValueNodeHasChildrenChange(hasChildren)
+ }, [onValueNodeHasChildrenChange, hasChildren])
+
+ return (
+
+ {shouldShowPlaceholder(context.value) ? <>{placeholder}> : children}
+
+ )
+ }
+)
+
+SelectValue.displayName = VALUE_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectIcon
+ * -----------------------------------------------------------------------------------------------*/
+
+const ICON_NAME = "SelectIcon"
+
+type SelectIconElement = React.ElementRef
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectIconProps extends PrimitiveSpanProps {}
+
+const SelectIcon = React.forwardRef(
+ (props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, children, ...iconProps } = props
+ return (
+
+ {children || "▼"}
+
+ )
+ }
+)
+
+SelectIcon.displayName = ICON_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectPortal
+ * -----------------------------------------------------------------------------------------------*/
+
+const PORTAL_NAME = "SelectPortal"
+
+type PortalProps = React.ComponentPropsWithoutRef
+interface SelectPortalProps {
+ children?: React.ReactNode
+ /**
+ * Specify a container element to portal the content into.
+ */
+ container?: PortalProps["container"]
+}
+
+const SelectPortal: React.FC = (
+ props: ScopedProps
+) => {
+ return
+}
+
+SelectPortal.displayName = PORTAL_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectContent
+ * -----------------------------------------------------------------------------------------------*/
+
+const CONTENT_NAME = "SelectContent"
+
+type SelectContentElement = SelectContentImplElement
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectContentProps extends SelectContentImplProps {}
+
+const SelectContent = React.forwardRef<
+ SelectContentElement,
+ SelectContentProps
+>((props: ScopedProps, forwardedRef) => {
+ const context = useSelectContext(CONTENT_NAME, props.__scopeSelect)
+ const [fragment, setFragment] = React.useState()
+
+ // setting the fragment in `useLayoutEffect` as `DocumentFragment` doesn't exist on the server
+ useLayoutEffect(() => {
+ setFragment(new DocumentFragment())
+ }, [])
+
+ if (!context.open) {
+ const frag = fragment as Element | undefined
+ return frag
+ ? ReactDOM.createPortal(
+
+
+ {props.children}
+
+ ,
+ frag
+ )
+ : null
+ }
+
+ return
+})
+
+SelectContent.displayName = CONTENT_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectContentImpl
+ * -----------------------------------------------------------------------------------------------*/
+
+const CONTENT_MARGIN = 10
+
+type SelectContentContextValue = {
+ content?: SelectContentElement | null
+ viewport?: SelectViewportElement | null
+ onViewportChange?: (node: SelectViewportElement | null) => void
+ itemRefCallback?: (
+ node: SelectItemElement | null,
+ value: string,
+ disabled: boolean
+ ) => void
+ selectedItem?: SelectItemElement | null
+ onItemLeave?: () => void
+ itemTextRefCallback?: (
+ node: SelectItemTextElement | null,
+ value: string,
+ disabled: boolean
+ ) => void
+ focusSelectedItem?: () => void
+ selectedItemText?: SelectItemTextElement | null
+ position?: SelectContentProps["position"]
+ isPositioned?: boolean
+ searchRef?: React.RefObject
+}
+
+const [SelectContentProvider, useSelectContentContext] =
+ createSelectContext(CONTENT_NAME)
+
+const CONTENT_IMPL_NAME = "SelectContentImpl"
+
+type SelectContentImplElement =
+ | SelectPopperPositionElement
+ | SelectItemAlignedPositionElement
+type DismissableLayerProps = React.ComponentPropsWithoutRef<
+ typeof DismissableLayer
+>
+type FocusScopeProps = React.ComponentPropsWithoutRef
+
+type SelectPopperPrivateProps = { onPlaced?: PopperContentProps["onPlaced"] }
+
+interface SelectContentImplProps
+ extends Omit,
+ Omit {
+ /**
+ * Event handler called when auto-focusing on close.
+ * Can be prevented.
+ */
+ onCloseAutoFocus?: FocusScopeProps["onUnmountAutoFocus"]
+ /**
+ * Event handler called when the escape key is down.
+ * Can be prevented.
+ */
+ onEscapeKeyDown?: DismissableLayerProps["onEscapeKeyDown"]
+ /**
+ * Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`.
+ * Can be prevented.
+ */
+ onPointerDownOutside?: DismissableLayerProps["onPointerDownOutside"]
+
+ position?: "item-aligned" | "popper"
+}
+
+const Slot = createSlot("SelectContent.RemoveScroll")
+
+const SelectContentImpl = React.forwardRef<
+ SelectContentImplElement,
+ SelectContentImplProps
+>((props: ScopedProps, forwardedRef) => {
+ const {
+ __scopeSelect,
+ position = "item-aligned",
+ onCloseAutoFocus,
+ onEscapeKeyDown,
+ onPointerDownOutside,
+ //
+ // PopperContent props
+ side,
+ sideOffset,
+ align,
+ alignOffset,
+ arrowPadding,
+ collisionBoundary,
+ collisionPadding,
+ sticky,
+ hideWhenDetached,
+ avoidCollisions,
+ //
+ ...contentProps
+ } = props
+ const context = useSelectContext(CONTENT_NAME, __scopeSelect)
+ const [content, setContent] = React.useState(
+ null
+ )
+ const [viewport, setViewport] = React.useState(
+ null
+ )
+ const composedRefs = useComposedRefs(forwardedRef, (node) => setContent(node))
+ const [selectedItem, setSelectedItem] =
+ React.useState(null)
+ const [selectedItemText, setSelectedItemText] =
+ React.useState(null)
+ const getItems = useCollection(__scopeSelect)
+ const [isPositioned, setIsPositioned] = React.useState(false)
+ const firstValidItemFoundRef = React.useRef(false)
+
+ // aria-hide everything except the content (better supported equivalent to setting aria-modal)
+ React.useEffect(() => {
+ if (content) return hideOthers(content)
+ }, [content])
+
+ // Make sure the whole tree has focus guards as our `Select` may be
+ // the last element in the DOM (because of the `Portal`)
+ useFocusGuards()
+
+ const focusFirst = React.useCallback(
+ (candidates: Array) => {
+ const [firstItem, ...restItems] = getItems().map(
+ (item) => item.ref.current
+ )
+ const [lastItem] = restItems.slice(-1)
+
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement
+ for (const candidate of candidates) {
+ // if focus is already where we want to go, we don't want to keep going through the candidates
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return
+ candidate?.scrollIntoView({ block: "nearest" })
+ // viewport might have padding so scroll to its edges when focusing first/last items.
+ if (candidate === firstItem && viewport) viewport.scrollTop = 0
+ if (candidate === lastItem && viewport)
+ viewport.scrollTop = viewport.scrollHeight
+ candidate?.focus()
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return
+ }
+ },
+ [getItems, viewport]
+ )
+
+ const focusSelectedItem = React.useCallback(
+ () => focusFirst([selectedItem, content]),
+ [focusFirst, selectedItem, content]
+ )
+
+ // Since this is not dependent on layout, we want to ensure this runs at the same time as
+ // other effects across components. Hence why we don't call `focusSelectedItem` inside `position`.
+ React.useEffect(() => {
+ if (isPositioned) {
+ focusSelectedItem()
+ }
+ }, [isPositioned, focusSelectedItem])
+
+ // prevent selecting items on `pointerup` in some cases after opening from `pointerdown`
+ // and close on `pointerup` outside.
+ const { onOpenChange, triggerPointerDownPosRef } = context
+ React.useEffect(() => {
+ if (content) {
+ let pointerMoveDelta = { x: 0, y: 0 }
+
+ const handlePointerMove = (event: PointerEvent) => {
+ pointerMoveDelta = {
+ x: Math.abs(
+ Math.round(event.pageX) - (triggerPointerDownPosRef.current?.x ?? 0)
+ ),
+ y: Math.abs(
+ Math.round(event.pageY) - (triggerPointerDownPosRef.current?.y ?? 0)
+ ),
+ }
+ }
+ const handlePointerUp = (event: PointerEvent) => {
+ // If the pointer hasn't moved by a certain threshold then we prevent selecting item on `pointerup`.
+ if (pointerMoveDelta.x <= 10 && pointerMoveDelta.y <= 10) {
+ event.preventDefault()
+ } else {
+ // otherwise, if the event was outside the content, close.
+ if (!content.contains(event.target as HTMLElement)) {
+ onOpenChange(false)
+ }
+ }
+ document.removeEventListener("pointermove", handlePointerMove)
+ triggerPointerDownPosRef.current = null
+ }
+
+ if (triggerPointerDownPosRef.current !== null) {
+ document.addEventListener("pointermove", handlePointerMove)
+ document.addEventListener("pointerup", handlePointerUp, {
+ capture: true,
+ once: true,
+ })
+ }
+
+ return () => {
+ document.removeEventListener("pointermove", handlePointerMove)
+ document.removeEventListener("pointerup", handlePointerUp, {
+ capture: true,
+ })
+ }
+ }
+ }, [content, onOpenChange, triggerPointerDownPosRef])
+
+ React.useEffect(() => {
+ const close = () => onOpenChange(false)
+ window.addEventListener("blur", close)
+ window.addEventListener("resize", close)
+ return () => {
+ window.removeEventListener("blur", close)
+ window.removeEventListener("resize", close)
+ }
+ }, [onOpenChange])
+
+ const [searchRef, handleTypeaheadSearch] = useTypeaheadSearch((search) => {
+ const enabledItems = getItems().filter((item) => !item.disabled)
+ const currentItem = enabledItems.find(
+ (item) => item.ref.current === document.activeElement
+ )
+ const nextItem = findNextItem(enabledItems, search, currentItem)
+ if (nextItem) {
+ /**
+ * Imperative focus during keydown is risky so we prevent React's batching updates
+ * to avoid potential bugs. See: https://github.com/facebook/react/issues/20332
+ */
+ setTimeout(() => (nextItem.ref.current as HTMLElement).focus())
+ }
+ })
+
+ const itemRefCallback = React.useCallback(
+ (node: SelectItemElement | null, value: string, disabled: boolean) => {
+ const contextValueArray = (
+ Array.isArray(context.value) ? context.value : [context.value]
+ ).filter((item) => item !== undefined)
+
+ const isFirstValidItem = !firstValidItemFoundRef.current && !disabled
+ const isSelectedItem =
+ context.value !== undefined && contextValueArray.includes(value)
+ if (isSelectedItem || isFirstValidItem) {
+ setSelectedItem(node)
+ if (isFirstValidItem) firstValidItemFoundRef.current = true
+ }
+ },
+ [context.value]
+ )
+ const handleItemLeave = React.useCallback(() => content?.focus(), [content])
+ const itemTextRefCallback = React.useCallback(
+ (node: SelectItemTextElement | null, value: string, disabled: boolean) => {
+ const isFirstValidItem = !firstValidItemFoundRef.current && !disabled
+ const isSelectedItem =
+ context.value !== undefined && context.value === value
+ if (isSelectedItem || isFirstValidItem) {
+ setSelectedItemText(node)
+ }
+ },
+ [context.value]
+ )
+
+ const SelectPosition =
+ position === "popper" ? SelectPopperPosition : SelectItemAlignedPosition
+
+ // Silently ignore props that are not supported by `SelectItemAlignedPosition`
+ const popperContentProps =
+ SelectPosition === SelectPopperPosition
+ ? {
+ side,
+ sideOffset,
+ align,
+ alignOffset,
+ arrowPadding,
+ collisionBoundary,
+ collisionPadding,
+ sticky,
+ hideWhenDetached,
+ avoidCollisions,
+ }
+ : {}
+
+ return (
+
+
+ {
+ // we prevent open autofocus because we manually focus the selected item
+ event.preventDefault()
+ }}
+ onUnmountAutoFocus={composeEventHandlers(
+ onCloseAutoFocus,
+ (event) => {
+ context.trigger?.focus({ preventScroll: true })
+ event.preventDefault()
+ }
+ )}
+ >
+ event.preventDefault()}
+ onDismiss={() => context.onOpenChange(false)}
+ >
+ event.preventDefault()}
+ {...contentProps}
+ {...popperContentProps}
+ onPlaced={() => setIsPositioned(true)}
+ ref={composedRefs}
+ style={{
+ // flex layout so we can place the scroll buttons properly
+ display: "flex",
+ flexDirection: "column",
+ // reset the outline by default as the content MAY get focused
+ outline: "none",
+ ...contentProps.style,
+ }}
+ onKeyDown={composeEventHandlers(
+ contentProps.onKeyDown,
+ (event) => {
+ const isModifierKey =
+ event.ctrlKey || event.altKey || event.metaKey
+
+ // select should not be navigated using tab key so we prevent it
+ if (event.key === "Tab") event.preventDefault()
+
+ if (!isModifierKey && event.key.length === 1)
+ handleTypeaheadSearch(event.key)
+
+ if (
+ ["ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)
+ ) {
+ const items = getItems().filter((item) => !item.disabled)
+ let candidateNodes = items.map((item) => item.ref.current!)
+
+ if (["ArrowUp", "End"].includes(event.key)) {
+ candidateNodes = candidateNodes.slice().reverse()
+ }
+ if (["ArrowUp", "ArrowDown"].includes(event.key)) {
+ const currentElement = event.target as SelectItemElement
+ const currentIndex =
+ candidateNodes.indexOf(currentElement)
+ candidateNodes = candidateNodes.slice(currentIndex + 1)
+ }
+
+ /**
+ * Imperative focus during keydown is risky so we prevent React's batching updates
+ * to avoid potential bugs. See: https://github.com/facebook/react/issues/20332
+ */
+ setTimeout(() => focusFirst(candidateNodes))
+
+ event.preventDefault()
+ }
+ }
+ )}
+ />
+
+
+
+
+ )
+})
+
+SelectContentImpl.displayName = CONTENT_IMPL_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectItemAlignedPosition
+ * -----------------------------------------------------------------------------------------------*/
+
+const ITEM_ALIGNED_POSITION_NAME = "SelectItemAlignedPosition"
+
+type SelectItemAlignedPositionElement = React.ElementRef
+interface SelectItemAlignedPositionProps
+ extends PrimitiveDivProps,
+ SelectPopperPrivateProps {}
+
+const SelectItemAlignedPosition = React.forwardRef<
+ SelectItemAlignedPositionElement,
+ SelectItemAlignedPositionProps
+>((props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, onPlaced, ...popperProps } = props
+ const context = useSelectContext(CONTENT_NAME, __scopeSelect)
+ const contentContext = useSelectContentContext(CONTENT_NAME, __scopeSelect)
+ const [contentWrapper, setContentWrapper] =
+ React.useState(null)
+ const [content, setContent] =
+ React.useState(null)
+ const composedRefs = useComposedRefs(forwardedRef, (node) => setContent(node))
+ const getItems = useCollection(__scopeSelect)
+ const shouldExpandOnScrollRef = React.useRef(false)
+ const shouldRepositionRef = React.useRef(true)
+
+ const { viewport, selectedItem, selectedItemText, focusSelectedItem } =
+ contentContext
+ const position = React.useCallback(() => {
+ if (
+ context.trigger &&
+ context.valueNode &&
+ contentWrapper &&
+ content &&
+ viewport &&
+ selectedItem &&
+ selectedItemText
+ ) {
+ const triggerRect = context.trigger.getBoundingClientRect()
+
+ // -----------------------------------------------------------------------------------------
+ // Horizontal positioning
+ // -----------------------------------------------------------------------------------------
+ const contentRect = content.getBoundingClientRect()
+ const valueNodeRect = context.valueNode.getBoundingClientRect()
+ const itemTextRect = selectedItemText.getBoundingClientRect()
+
+ if (context.dir !== "rtl") {
+ const itemTextOffset = itemTextRect.left - contentRect.left
+ const left = valueNodeRect.left - itemTextOffset
+ const leftDelta = triggerRect.left - left
+ const minContentWidth = triggerRect.width + leftDelta
+ const contentWidth = Math.max(minContentWidth, contentRect.width)
+ const rightEdge = window.innerWidth - CONTENT_MARGIN
+ const clampedLeft = clamp(left, [
+ CONTENT_MARGIN,
+ // Prevents the content from going off the starting edge of the
+ // viewport. It may still go off the ending edge, but this can be
+ // controlled by the user since they may want to manage overflow in a
+ // specific way.
+ // https://github.com/radix-ui/primitives/issues/2049
+ Math.max(CONTENT_MARGIN, rightEdge - contentWidth),
+ ])
+
+ contentWrapper.style.minWidth = minContentWidth + "px"
+ contentWrapper.style.left = clampedLeft + "px"
+ } else {
+ const itemTextOffset = contentRect.right - itemTextRect.right
+ const right = window.innerWidth - valueNodeRect.right - itemTextOffset
+ const rightDelta = window.innerWidth - triggerRect.right - right
+ const minContentWidth = triggerRect.width + rightDelta
+ const contentWidth = Math.max(minContentWidth, contentRect.width)
+ const leftEdge = window.innerWidth - CONTENT_MARGIN
+ const clampedRight = clamp(right, [
+ CONTENT_MARGIN,
+ Math.max(CONTENT_MARGIN, leftEdge - contentWidth),
+ ])
+
+ contentWrapper.style.minWidth = minContentWidth + "px"
+ contentWrapper.style.right = clampedRight + "px"
+ }
+
+ // -----------------------------------------------------------------------------------------
+ // Vertical positioning
+ // -----------------------------------------------------------------------------------------
+ const items = getItems()
+ const availableHeight = window.innerHeight - CONTENT_MARGIN * 2
+ const itemsHeight = viewport.scrollHeight
+
+ const contentStyles = window.getComputedStyle(content)
+ const contentBorderTopWidth = parseInt(contentStyles.borderTopWidth, 10)
+ const contentPaddingTop = parseInt(contentStyles.paddingTop, 10)
+ const contentBorderBottomWidth = parseInt(
+ contentStyles.borderBottomWidth,
+ 10
+ )
+ const contentPaddingBottom = parseInt(contentStyles.paddingBottom, 10)
+ const fullContentHeight = contentBorderTopWidth + contentPaddingTop + itemsHeight + contentPaddingBottom + contentBorderBottomWidth; // prettier-ignore
+ const minContentHeight = Math.min(
+ selectedItem.offsetHeight * 5,
+ fullContentHeight
+ )
+
+ const viewportStyles = window.getComputedStyle(viewport)
+ const viewportPaddingTop = parseInt(viewportStyles.paddingTop, 10)
+ const viewportPaddingBottom = parseInt(viewportStyles.paddingBottom, 10)
+
+ const topEdgeToTriggerMiddle =
+ triggerRect.top + triggerRect.height / 2 - CONTENT_MARGIN
+ const triggerMiddleToBottomEdge = availableHeight - topEdgeToTriggerMiddle
+
+ const selectedItemHalfHeight = selectedItem.offsetHeight / 2
+ const itemOffsetMiddle = selectedItem.offsetTop + selectedItemHalfHeight
+ const contentTopToItemMiddle =
+ contentBorderTopWidth + contentPaddingTop + itemOffsetMiddle
+ const itemMiddleToContentBottom =
+ fullContentHeight - contentTopToItemMiddle
+
+ const willAlignWithoutTopOverflow =
+ contentTopToItemMiddle <= topEdgeToTriggerMiddle
+
+ if (willAlignWithoutTopOverflow) {
+ const isLastItem =
+ items.length > 0 &&
+ selectedItem === items[items.length - 1]!.ref.current
+ contentWrapper.style.bottom = 0 + "px"
+ const viewportOffsetBottom =
+ content.clientHeight - viewport.offsetTop - viewport.offsetHeight
+ const clampedTriggerMiddleToBottomEdge = Math.max(
+ triggerMiddleToBottomEdge,
+ selectedItemHalfHeight +
+ // viewport might have padding bottom, include it to avoid a scrollable viewport
+ (isLastItem ? viewportPaddingBottom : 0) +
+ viewportOffsetBottom +
+ contentBorderBottomWidth
+ )
+ const height = contentTopToItemMiddle + clampedTriggerMiddleToBottomEdge
+ contentWrapper.style.height = height + "px"
+ } else {
+ const isFirstItem =
+ items.length > 0 && selectedItem === items[0]!.ref.current
+ contentWrapper.style.top = 0 + "px"
+ const clampedTopEdgeToTriggerMiddle = Math.max(
+ topEdgeToTriggerMiddle,
+ contentBorderTopWidth +
+ viewport.offsetTop +
+ // viewport might have padding top, include it to avoid a scrollable viewport
+ (isFirstItem ? viewportPaddingTop : 0) +
+ selectedItemHalfHeight
+ )
+ const height = clampedTopEdgeToTriggerMiddle + itemMiddleToContentBottom
+ contentWrapper.style.height = height + "px"
+ viewport.scrollTop =
+ contentTopToItemMiddle - topEdgeToTriggerMiddle + viewport.offsetTop
+ }
+
+ contentWrapper.style.margin = `${CONTENT_MARGIN}px 0`
+ contentWrapper.style.minHeight = minContentHeight + "px"
+ contentWrapper.style.maxHeight = availableHeight + "px"
+ // -----------------------------------------------------------------------------------------
+
+ onPlaced?.()
+
+ // we don't want the initial scroll position adjustment to trigger "expand on scroll"
+ // so we explicitly turn it on only after they've registered.
+ requestAnimationFrame(() => (shouldExpandOnScrollRef.current = true))
+ }
+ }, [
+ getItems,
+ context.trigger,
+ context.valueNode,
+ contentWrapper,
+ content,
+ viewport,
+ selectedItem,
+ selectedItemText,
+ context.dir,
+ onPlaced,
+ ])
+
+ useLayoutEffect(() => position(), [position])
+
+ // copy z-index from content to wrapper
+ const [contentZIndex, setContentZIndex] = React.useState()
+ useLayoutEffect(() => {
+ if (content) setContentZIndex(window.getComputedStyle(content).zIndex)
+ }, [content])
+
+ // When the viewport becomes scrollable at the top, the scroll up button will mount.
+ // Because it is part of the normal flow, it will push down the viewport, thus throwing our
+ // trigger => selectedItem alignment off by the amount the viewport was pushed down.
+ // We wait for this to happen and then re-run the positining logic one more time to account for it.
+ const handleScrollButtonChange = React.useCallback(
+ (node: SelectScrollButtonImplElement | null) => {
+ if (node && shouldRepositionRef.current === true) {
+ position()
+ focusSelectedItem?.()
+ shouldRepositionRef.current = false
+ }
+ },
+ [position, focusSelectedItem]
+ )
+
+ return (
+
+
+
+ )
+})
+
+SelectItemAlignedPosition.displayName = ITEM_ALIGNED_POSITION_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectPopperPosition
+ * -----------------------------------------------------------------------------------------------*/
+
+const POPPER_POSITION_NAME = "SelectPopperPosition"
+
+type SelectPopperPositionElement = React.ElementRef<
+ typeof PopperPrimitive.Content
+>
+type PopperContentProps = React.ComponentPropsWithoutRef<
+ typeof PopperPrimitive.Content
+>
+interface SelectPopperPositionProps
+ extends PopperContentProps,
+ SelectPopperPrivateProps {}
+
+const SelectPopperPosition = React.forwardRef<
+ SelectPopperPositionElement,
+ SelectPopperPositionProps
+>((props: ScopedProps, forwardedRef) => {
+ const {
+ __scopeSelect,
+ align = "start",
+ collisionPadding = CONTENT_MARGIN,
+ ...popperProps
+ } = props
+ const popperScope = usePopperScope(__scopeSelect)
+
+ return (
+
+ )
+})
+
+SelectPopperPosition.displayName = POPPER_POSITION_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectViewport
+ * -----------------------------------------------------------------------------------------------*/
+
+type SelectViewportContextValue = {
+ contentWrapper?: HTMLDivElement | null
+ shouldExpandOnScrollRef?: React.RefObject
+ onScrollButtonChange?: (node: SelectScrollButtonImplElement | null) => void
+}
+
+const [SelectViewportProvider, useSelectViewportContext] =
+ createSelectContext(CONTENT_NAME, {})
+
+const VIEWPORT_NAME = "SelectViewport"
+
+type SelectViewportElement = React.ElementRef
+type PrimitiveDivProps = React.ComponentPropsWithoutRef
+interface SelectViewportProps extends PrimitiveDivProps {
+ nonce?: string
+}
+
+const SelectViewport = React.forwardRef<
+ SelectViewportElement,
+ SelectViewportProps
+>((props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, nonce, ...viewportProps } = props
+ const contentContext = useSelectContentContext(VIEWPORT_NAME, __scopeSelect)
+ const viewportContext = useSelectViewportContext(VIEWPORT_NAME, __scopeSelect)
+ const composedRefs = useComposedRefs(
+ forwardedRef,
+ contentContext.onViewportChange
+ )
+ const prevScrollTopRef = React.useRef(0)
+ return (
+ <>
+ {/* Hide scrollbars cross-browser and enable momentum scroll for touch devices */}
+
+
+ {
+ const viewport = event.currentTarget
+ const { contentWrapper, shouldExpandOnScrollRef } = viewportContext
+ if (shouldExpandOnScrollRef?.current && contentWrapper) {
+ const scrolledBy = Math.abs(
+ prevScrollTopRef.current - viewport.scrollTop
+ )
+ if (scrolledBy > 0) {
+ const availableHeight = window.innerHeight - CONTENT_MARGIN * 2
+ const cssMinHeight = parseFloat(contentWrapper.style.minHeight)
+ const cssHeight = parseFloat(contentWrapper.style.height)
+ const prevHeight = Math.max(cssMinHeight, cssHeight)
+
+ if (prevHeight < availableHeight) {
+ const nextHeight = prevHeight + scrolledBy
+ const clampedNextHeight = Math.min(
+ availableHeight,
+ nextHeight
+ )
+ const heightDiff = nextHeight - clampedNextHeight
+
+ contentWrapper.style.height = clampedNextHeight + "px"
+ if (contentWrapper.style.bottom === "0px") {
+ viewport.scrollTop = heightDiff > 0 ? heightDiff : 0
+ // ensure the content stays pinned to the bottom
+ contentWrapper.style.justifyContent = "flex-end"
+ }
+ }
+ }
+ }
+ prevScrollTopRef.current = viewport.scrollTop
+ })}
+ />
+
+ >
+ )
+})
+
+SelectViewport.displayName = VIEWPORT_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectGroup
+ * -----------------------------------------------------------------------------------------------*/
+
+const GROUP_NAME = "SelectGroup"
+
+type SelectGroupContextValue = { id: string }
+
+const [SelectGroupContextProvider, useSelectGroupContext] =
+ createSelectContext(GROUP_NAME)
+
+type SelectGroupElement = React.ElementRef
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectGroupProps extends PrimitiveDivProps {}
+
+const SelectGroup = React.forwardRef(
+ (props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, ...groupProps } = props
+ const groupId = useId()
+ return (
+
+
+
+ )
+ }
+)
+
+SelectGroup.displayName = GROUP_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectLabel
+ * -----------------------------------------------------------------------------------------------*/
+
+const LABEL_NAME = "SelectLabel"
+
+type SelectLabelElement = React.ElementRef
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectLabelProps extends PrimitiveDivProps {}
+
+const SelectLabel = React.forwardRef(
+ (props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, ...labelProps } = props
+ const groupContext = useSelectGroupContext(LABEL_NAME, __scopeSelect)
+ return (
+
+ )
+ }
+)
+
+SelectLabel.displayName = LABEL_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectItem
+ * -----------------------------------------------------------------------------------------------*/
+
+const ITEM_NAME = "SelectItem"
+
+type SelectItemContextValue = {
+ value: T
+ disabled: boolean
+ textId: string
+ isSelected: boolean
+ onItemTextChange(node: SelectItemTextElement | null): void
+}
+
+export const [SelectItemContextProvider, useSelectItemContext] =
+ createSelectContext(ITEM_NAME)
+
+type SelectItemElement = React.ElementRef
+interface SelectItemProps extends PrimitiveDivProps {
+ value: string
+ disabled?: boolean
+ textValue?: string
+}
+
+const SelectItem = React.forwardRef(
+ (props: ScopedProps, forwardedRef) => {
+ const {
+ __scopeSelect,
+ value,
+ disabled = false,
+ textValue: textValueProp,
+ ...itemProps
+ } = props
+ const context = useSelectContext(ITEM_NAME, __scopeSelect)
+ const contentContext = useSelectContentContext(ITEM_NAME, __scopeSelect)
+ const isSelected = context.multiple
+ ? context.value?.includes(value) || false
+ : context.value === value
+ const [textValue, setTextValue] = React.useState(textValueProp ?? "")
+ const [isFocused, setIsFocused] = React.useState(false)
+ const composedRefs = useComposedRefs(forwardedRef, (node) =>
+ contentContext.itemRefCallback?.(node, value, disabled)
+ )
+ const textId = useId()
+ const pointerTypeRef =
+ React.useRef("touch")
+
+ const handleSelect = () => {
+ if (disabled) {
+ return
+ }
+
+ context.onItemCheckChange?.(value, !isSelected)
+
+ if (context.multiple) {
+ const initValue = (context.value as string[]) ?? []
+ const newValue = isSelected
+ ? initValue.filter((item) => item !== value)
+ : [...(initValue as string[]), value]
+
+ context.onValueChange(newValue)
+ } else {
+ context.onValueChange(value)
+ context.onOpenChange(false)
+ }
+ }
+
+ if (value === "") {
+ throw new Error(
+ "A must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder."
+ )
+ }
+
+ return (
+ {
+ setTextValue(
+ (prevTextValue) => prevTextValue || (node?.textContent ?? "").trim()
+ )
+ }, [])}
+ >
+
+
+ setIsFocused(true)
+ )}
+ onBlur={composeEventHandlers(itemProps.onBlur, () =>
+ setIsFocused(false)
+ )}
+ onClick={composeEventHandlers(itemProps.onClick, () => {
+ // Open on click when using a touch or pen device
+ if (pointerTypeRef.current !== "mouse") handleSelect()
+ })}
+ onPointerUp={composeEventHandlers(itemProps.onPointerUp, () => {
+ // Using a mouse you should be able to do pointer down, move through
+ // the list, and release the pointer over the item to select it.
+ if (pointerTypeRef.current === "mouse") handleSelect()
+ })}
+ onPointerDown={composeEventHandlers(
+ itemProps.onPointerDown,
+ (event) => {
+ pointerTypeRef.current = event.pointerType
+ }
+ )}
+ onPointerMove={composeEventHandlers(
+ itemProps.onPointerMove,
+ (event) => {
+ // Remember pointer type when sliding over to this item from another one
+ pointerTypeRef.current = event.pointerType
+ if (disabled) {
+ contentContext.onItemLeave?.()
+ } else if (pointerTypeRef.current === "mouse") {
+ // even though safari doesn't support this option, it's acceptable
+ // as it only means it might scroll a few pixels when using the pointer.
+ event.currentTarget.focus({ preventScroll: true })
+ }
+ }
+ )}
+ onPointerLeave={composeEventHandlers(
+ itemProps.onPointerLeave,
+ (event) => {
+ if (event.currentTarget === document.activeElement) {
+ contentContext.onItemLeave?.()
+ }
+ }
+ )}
+ onKeyDown={composeEventHandlers(itemProps.onKeyDown, (event) => {
+ const isTypingAhead = contentContext.searchRef?.current !== ""
+ if (isTypingAhead && event.key === " ") return
+ if (SELECTION_KEYS.includes(event.key)) handleSelect()
+ // prevent page scroll if using the space key to select an item
+ if (event.key === " ") event.preventDefault()
+ })}
+ />
+
+
+ )
+ }
+)
+
+SelectItem.displayName = ITEM_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectItemText
+ * -----------------------------------------------------------------------------------------------*/
+
+const ITEM_TEXT_NAME = "SelectItemText"
+
+type SelectItemTextElement = React.ElementRef
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectItemTextProps extends PrimitiveSpanProps {}
+
+const SelectItemText = React.forwardRef<
+ SelectItemTextElement,
+ SelectItemTextProps
+>((props: ScopedProps, forwardedRef) => {
+ // We ignore `className` and `style` as this part shouldn't be styled.
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { __scopeSelect, className, style, ...itemTextProps } = props
+ const context = useSelectContext(ITEM_TEXT_NAME, __scopeSelect)
+ const contentContext = useSelectContentContext(ITEM_TEXT_NAME, __scopeSelect)
+ const itemContext = useSelectItemContext(ITEM_TEXT_NAME, __scopeSelect)
+ const nativeOptionsContext = useSelectNativeOptionsContext(
+ ITEM_TEXT_NAME,
+ __scopeSelect
+ )
+ const [itemTextNode, setItemTextNode] =
+ React.useState(null)
+ const composedRefs = useComposedRefs(
+ forwardedRef,
+ (node) => setItemTextNode(node),
+ itemContext.onItemTextChange,
+ (node) =>
+ contentContext.itemTextRefCallback?.(
+ node,
+ itemContext.value,
+ itemContext.disabled
+ )
+ )
+
+ const textContent = itemTextNode?.textContent
+ const nativeOption = React.useMemo(
+ () => (
+
+ ),
+ [itemContext.disabled, itemContext.value, textContent]
+ )
+
+ const { onNativeOptionAdd, onNativeOptionRemove } = nativeOptionsContext
+ useLayoutEffect(() => {
+ onNativeOptionAdd(nativeOption)
+ return () => onNativeOptionRemove(nativeOption)
+ }, [onNativeOptionAdd, onNativeOptionRemove, nativeOption])
+
+ return (
+ <>
+
+
+ {/* Portal the select item text into the trigger value node */}
+ {itemContext.isSelected &&
+ context.valueNode &&
+ !context.valueNodeHasChildren
+ ? ReactDOM.createPortal(itemTextProps.children, context.valueNode)
+ : null}
+ >
+ )
+})
+
+SelectItemText.displayName = ITEM_TEXT_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectItemIndicator
+ * -----------------------------------------------------------------------------------------------*/
+
+const ITEM_INDICATOR_NAME = "SelectItemIndicator"
+
+type SelectItemIndicatorElement = React.ElementRef
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectItemIndicatorProps extends PrimitiveSpanProps {}
+
+const SelectItemIndicator = React.forwardRef<
+ SelectItemIndicatorElement,
+ SelectItemIndicatorProps
+>((props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, ...itemIndicatorProps } = props
+ const itemContext = useSelectItemContext(ITEM_INDICATOR_NAME, __scopeSelect)
+ return itemContext.isSelected ? (
+
+ ) : null
+})
+
+SelectItemIndicator.displayName = ITEM_INDICATOR_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectScrollUpButton
+ * -----------------------------------------------------------------------------------------------*/
+
+const SCROLL_UP_BUTTON_NAME = "SelectScrollUpButton"
+
+type SelectScrollUpButtonElement = SelectScrollButtonImplElement
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectScrollUpButtonProps
+ extends Omit {}
+
+const SelectScrollUpButton = React.forwardRef<
+ SelectScrollUpButtonElement,
+ SelectScrollUpButtonProps
+>((props: ScopedProps, forwardedRef) => {
+ const contentContext = useSelectContentContext(
+ SCROLL_UP_BUTTON_NAME,
+ props.__scopeSelect
+ )
+ const viewportContext = useSelectViewportContext(
+ SCROLL_UP_BUTTON_NAME,
+ props.__scopeSelect
+ )
+ const [canScrollUp, setCanScrollUp] = React.useState(false)
+ const composedRefs = useComposedRefs(
+ forwardedRef,
+ viewportContext.onScrollButtonChange
+ )
+
+ useLayoutEffect(() => {
+ if (contentContext.viewport && contentContext.isPositioned) {
+ const viewport = contentContext.viewport
+ function handleScroll() {
+ const canScrollUp = viewport.scrollTop > 0
+ setCanScrollUp(canScrollUp)
+ }
+ handleScroll()
+ viewport.addEventListener("scroll", handleScroll)
+ return () => viewport.removeEventListener("scroll", handleScroll)
+ }
+ }, [contentContext.viewport, contentContext.isPositioned])
+
+ return canScrollUp ? (
+ {
+ const { viewport, selectedItem } = contentContext
+ if (viewport && selectedItem) {
+ viewport.scrollTop = viewport.scrollTop - selectedItem.offsetHeight
+ }
+ }}
+ />
+ ) : null
+})
+
+SelectScrollUpButton.displayName = SCROLL_UP_BUTTON_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectScrollDownButton
+ * -----------------------------------------------------------------------------------------------*/
+
+const SCROLL_DOWN_BUTTON_NAME = "SelectScrollDownButton"
+
+type SelectScrollDownButtonElement = SelectScrollButtonImplElement
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectScrollDownButtonProps
+ extends Omit {}
+
+const SelectScrollDownButton = React.forwardRef<
+ SelectScrollDownButtonElement,
+ SelectScrollDownButtonProps
+>((props: ScopedProps, forwardedRef) => {
+ const contentContext = useSelectContentContext(
+ SCROLL_DOWN_BUTTON_NAME,
+ props.__scopeSelect
+ )
+ const viewportContext = useSelectViewportContext(
+ SCROLL_DOWN_BUTTON_NAME,
+ props.__scopeSelect
+ )
+ const [canScrollDown, setCanScrollDown] = React.useState(false)
+ const composedRefs = useComposedRefs(
+ forwardedRef,
+ viewportContext.onScrollButtonChange
+ )
+
+ useLayoutEffect(() => {
+ if (contentContext.viewport && contentContext.isPositioned) {
+ const viewport = contentContext.viewport
+ function handleScroll() {
+ const maxScroll = viewport.scrollHeight - viewport.clientHeight
+ // we use Math.ceil here because if the UI is zoomed-in
+ // `scrollTop` is not always reported as an integer
+ const canScrollDown = Math.ceil(viewport.scrollTop) < maxScroll
+ setCanScrollDown(canScrollDown)
+ }
+ handleScroll()
+ viewport.addEventListener("scroll", handleScroll)
+ return () => viewport.removeEventListener("scroll", handleScroll)
+ }
+ }, [contentContext.viewport, contentContext.isPositioned])
+
+ return canScrollDown ? (
+ {
+ const { viewport, selectedItem } = contentContext
+ if (viewport && selectedItem) {
+ viewport.scrollTop = viewport.scrollTop + selectedItem.offsetHeight
+ }
+ }}
+ />
+ ) : null
+})
+
+SelectScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME
+
+type SelectScrollButtonImplElement = React.ElementRef
+interface SelectScrollButtonImplProps extends PrimitiveDivProps {
+ onAutoScroll(): void
+}
+
+const SelectScrollButtonImpl = React.forwardRef<
+ SelectScrollButtonImplElement,
+ SelectScrollButtonImplProps
+>((props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, onAutoScroll, ...scrollIndicatorProps } = props
+ const contentContext = useSelectContentContext(
+ "SelectScrollButton",
+ __scopeSelect
+ )
+ const autoScrollTimerRef = React.useRef(null)
+ const getItems = useCollection(__scopeSelect)
+
+ const clearAutoScrollTimer = React.useCallback(() => {
+ if (autoScrollTimerRef.current !== null) {
+ window.clearInterval(autoScrollTimerRef.current)
+ autoScrollTimerRef.current = null
+ }
+ }, [])
+
+ React.useEffect(() => {
+ return () => clearAutoScrollTimer()
+ }, [clearAutoScrollTimer])
+
+ // When the viewport becomes scrollable on either side, the relevant scroll button will mount.
+ // Because it is part of the normal flow, it will push down (top button) or shrink (bottom button)
+ // the viewport, potentially causing the active item to now be partially out of view.
+ // We re-run the `scrollIntoView` logic to make sure it stays within the viewport.
+ useLayoutEffect(() => {
+ const activeItem = getItems().find(
+ (item) => item.ref.current === document.activeElement
+ )
+ activeItem?.ref.current?.scrollIntoView({ block: "nearest" })
+ }, [getItems])
+
+ return (
+ {
+ if (autoScrollTimerRef.current === null) {
+ autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50)
+ }
+ }
+ )}
+ onPointerMove={composeEventHandlers(
+ scrollIndicatorProps.onPointerMove,
+ () => {
+ contentContext.onItemLeave?.()
+ if (autoScrollTimerRef.current === null) {
+ autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50)
+ }
+ }
+ )}
+ onPointerLeave={composeEventHandlers(
+ scrollIndicatorProps.onPointerLeave,
+ () => {
+ clearAutoScrollTimer()
+ }
+ )}
+ />
+ )
+})
+
+SelectScrollButtonImpl.displayName = "SelectScrollButtonImpl"
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectSeparator
+ * -----------------------------------------------------------------------------------------------*/
+
+const SEPARATOR_NAME = "SelectSeparator"
+
+type SelectSeparatorElement = React.ElementRef
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectSeparatorProps extends PrimitiveDivProps {}
+
+const SelectSeparator = React.forwardRef<
+ SelectSeparatorElement,
+ SelectSeparatorProps
+>((props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, ...separatorProps } = props
+ return
+})
+
+SelectSeparator.displayName = SEPARATOR_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectArrow
+ * -----------------------------------------------------------------------------------------------*/
+
+const ARROW_NAME = "SelectArrow"
+
+type SelectArrowElement = React.ElementRef
+type PopperArrowProps = React.ComponentPropsWithoutRef<
+ typeof PopperPrimitive.Arrow
+>
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SelectArrowProps extends PopperArrowProps {}
+
+const SelectArrow = React.forwardRef(
+ (props: ScopedProps, forwardedRef) => {
+ const { __scopeSelect, ...arrowProps } = props
+ const popperScope = usePopperScope(__scopeSelect)
+ const context = useSelectContext(ARROW_NAME, __scopeSelect)
+ const contentContext = useSelectContentContext(ARROW_NAME, __scopeSelect)
+ return context.open && contentContext.position === "popper" ? (
+
+ ) : null
+ }
+)
+
+SelectArrow.displayName = ARROW_NAME
+
+/* -------------------------------------------------------------------------------------------------
+ * SelectBubbleInput
+ * -----------------------------------------------------------------------------------------------*/
+
+const BUBBLE_INPUT_NAME = "SelectBubbleInput"
+
+type InputProps = React.ComponentPropsWithoutRef
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface SwitchBubbleInputProps extends InputProps {}
+
+function doValuesMatch(
+ a: SwitchBubbleInputProps["value"],
+ b: SwitchBubbleInputProps["value"]
+) {
+ if (Array.isArray(a) && Array.isArray(b)) {
+ if (a.length !== b.length) return false
+ return a.every((item, index) => item === b[index])
+ }
+ if (Array.isArray(a) || Array.isArray(b)) return false
+ return a === b
+}
+
+const SelectBubbleInput = React.forwardRef<
+ HTMLSelectElement,
+ SwitchBubbleInputProps
+>(
+ (
+ { __scopeSelect, value, ...props }: ScopedProps,
+ forwardedRef
+ ) => {
+ const ref = React.useRef(null)
+ const composedRefs = useComposedRefs(forwardedRef, ref)
+ const prevValue = usePrevious(value)
+
+ // Bubble value change to parents (e.g form change event)
+ React.useEffect(() => {
+ const select = ref.current
+ if (!select) return
+ if (doValuesMatch(prevValue, value)) return
+
+ const setOptionSelected = Object.getOwnPropertyDescriptor(
+ window.HTMLOptionElement.prototype,
+ "selected"
+ )?.set
+
+ if (setOptionSelected) {
+ const selectedValues = Array.isArray(value) ? value : [value]
+ for (const option of select.options) {
+ setOptionSelected.call(option, selectedValues.includes(option.value))
+ }
+ }
+
+ select.dispatchEvent(new Event("change", { bubbles: true }))
+ }, [prevValue, value])
+
+ /**
+ * We purposefully use a `select` here to support form autofill as much as
+ * possible.
+ *
+ * We purposefully do not add the `value` attribute here to allow the value
+ * to be set programmatically and bubble to any parent form `onChange`
+ * event. Adding the `value` will cause React to consider the programmatic
+ * dispatch a duplicate and it will get swallowed.
+ *
+ * We use visually hidden styles rather than `display: "none"` because
+ * Safari autofill won't work otherwise.
+ */
+ return (
+
+ )
+ }
+)
+
+SelectBubbleInput.displayName = BUBBLE_INPUT_NAME
+
+/* -----------------------------------------------------------------------------------------------*/
+
+function shouldShowPlaceholder(value?: string[] | string) {
+ if (Array.isArray(value)) {
+ return value.length === 0 || value.every((v) => v === "")
+ }
+ return value === "" || value === undefined
+}
+
+function useTypeaheadSearch(onSearchChange: (search: string) => void) {
+ const handleSearchChange = useCallbackRef(onSearchChange)
+ const searchRef = React.useRef("")
+ const timerRef = React.useRef(0)
+
+ const handleTypeaheadSearch = React.useCallback(
+ (key: string) => {
+ const search = searchRef.current + key
+ handleSearchChange(search)
+ ;(function updateSearch(value: string) {
+ searchRef.current = value
+ window.clearTimeout(timerRef.current)
+ // Reset `searchRef` 1 second after it was last updated
+ if (value !== "")
+ timerRef.current = window.setTimeout(() => updateSearch(""), 1000)
+ })(search)
+ },
+ [handleSearchChange]
+ )
+
+ const resetTypeahead = React.useCallback(() => {
+ searchRef.current = ""
+ window.clearTimeout(timerRef.current)
+ }, [])
+
+ React.useEffect(() => {
+ return () => window.clearTimeout(timerRef.current)
+ }, [])
+
+ return [searchRef, handleTypeaheadSearch, resetTypeahead] as const
+}
+
+/**
+ * This is the "meat" of the typeahead matching logic. It takes in a list of items,
+ * the search and the current item, and returns the next item (or `undefined`).
+ *
+ * We normalize the search because if a user has repeatedly pressed a character,
+ * we want the exact same behavior as if we only had that one character
+ * (ie. cycle through items starting with that character)
+ *
+ * We also reorder the items by wrapping the array around the current item.
+ * This is so we always look forward from the current item, and picking the first
+ * item will always be the correct one.
+ *
+ * Finally, if the normalized search is exactly one character, we exclude the
+ * current item from the values because otherwise it would be the first to match always
+ * and focus would never move. This is as opposed to the regular case, where we
+ * don't want focus to move if the current item still matches.
+ */
+function findNextItem(
+ items: T[],
+ search: string,
+ currentItem?: T
+) {
+ const isRepeated =
+ search.length > 1 && Array.from(search).every((char) => char === search[0])
+ const normalizedSearch = isRepeated ? search[0]! : search
+ const currentItemIndex = currentItem ? items.indexOf(currentItem) : -1
+ let wrappedItems = wrapArray(items, Math.max(currentItemIndex, 0))
+ const excludeCurrentItem = normalizedSearch.length === 1
+ if (excludeCurrentItem)
+ wrappedItems = wrappedItems.filter((v) => v !== currentItem)
+ const nextItem = wrappedItems.find((item) =>
+ item.textValue.toLowerCase().startsWith(normalizedSearch.toLowerCase())
+ )
+ return nextItem !== currentItem ? nextItem : undefined
+}
+
+/**
+ * Wraps an array around itself at a given start index
+ * Example: `wrapArray(['a', 'b', 'c', 'd'], 2) === ['c', 'd', 'a', 'b']`
+ */
+function wrapArray(array: T[], startIndex: number) {
+ return array.map((_, index) => array[(startIndex + index) % array.length]!)
+}
+
+const Root = Select
+const Trigger = SelectTrigger
+const Value = SelectValue
+const Icon = SelectIcon
+const Portal = SelectPortal
+const Content = SelectContent
+const Viewport = SelectViewport
+const Group = SelectGroup
+const Label = SelectLabel
+const Item = SelectItem
+const ItemText = SelectItemText
+const ItemIndicator = SelectItemIndicator
+const ScrollUpButton = SelectScrollUpButton
+const ScrollDownButton = SelectScrollDownButton
+const Separator = SelectSeparator
+const Arrow = SelectArrow
+
+export {
+ Arrow,
+ Content,
+ createSelectScope,
+ Group,
+ Icon,
+ Item,
+ ItemIndicator,
+ ItemText,
+ Label,
+ Portal,
+ //
+ Root,
+ ScrollDownButton,
+ ScrollUpButton,
+ //
+ Select,
+ SelectArrow,
+ SelectContent,
+ SelectGroup,
+ SelectIcon,
+ SelectItem,
+ SelectItemIndicator,
+ SelectItemText,
+ SelectLabel,
+ SelectPortal,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+ SelectViewport,
+ Separator,
+ Trigger,
+ Value,
+ Viewport,
+}
+export type {
+ SelectArrowProps,
+ SelectContentProps,
+ SelectGroupProps,
+ SelectIconProps,
+ SelectItemIndicatorProps,
+ SelectItemProps,
+ SelectItemTextProps,
+ SelectLabelProps,
+ SelectPortalProps,
+ SelectProps,
+ SelectScrollDownButtonProps,
+ SelectScrollUpButtonProps,
+ SelectSeparatorProps,
+ SelectTriggerProps,
+ SelectValueProps,
+ SelectViewportProps,
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 81cba10b7f..7d76149143 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -105,6 +105,12 @@ importers:
'@number-flow/react':
specifier: ^0.5.10
version: 0.5.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/number':
+ specifier: ^1.1.1
+ version: 1.1.1
+ '@radix-ui/primitive':
+ specifier: ^1.1.2
+ version: 1.1.3
'@radix-ui/react-accordion':
specifier: ^1.1.2
version: 1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -117,15 +123,39 @@ importers:
'@radix-ui/react-collapsible':
specifier: ^1.1.2
version: 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-collection':
+ specifier: ^1.1.7
+ version: 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-compose-refs':
+ specifier: ^1.1.2
+ version: 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-context':
+ specifier: ^1.1.2
+ version: 1.1.2(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-dialog':
specifier: ^1.1.4
version: 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-direction':
+ specifier: ^1.1.1
+ version: 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-dismissable-layer':
+ specifier: ^1.1.10
+ version: 1.1.11(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-dropdown-menu':
specifier: ^2.0.6
version: 2.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-focus-guards':
+ specifier: ^1.1.2
+ version: 1.1.3(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-focus-scope':
+ specifier: ^1.1.7
+ version: 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-hover-card':
- specifier: ^1.1.6
- version: 1.1.6(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^1.1.15
+ version: 1.1.15(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-id':
+ specifier: ^1.1.1
+ version: 1.1.1(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-label':
specifier: ^2.1.0
version: 2.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -135,6 +165,15 @@ importers:
'@radix-ui/react-popover':
specifier: ^1.0.7
version: 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-popper':
+ specifier: ^1.2.7
+ version: 1.2.8(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-portal':
+ specifier: ^1.1.9
+ version: 1.1.9(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive':
+ specifier: ^2.1.3
+ version: 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-progress':
specifier: ^1.1.0
version: 1.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -148,8 +187,8 @@ importers:
specifier: ^1.1.0
version: 1.2.0(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-switch':
- specifier: ^1.2.2
- version: 1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^1.2.6
+ version: 1.2.6(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-tabs':
specifier: ^1.0.4
version: 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -162,6 +201,21 @@ importers:
'@radix-ui/react-tooltip':
specifier: ^1.0.7
version: 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref':
+ specifier: ^1.1.1
+ version: 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-controllable-state':
+ specifier: ^1.2.2
+ version: 1.2.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-layout-effect':
+ specifier: ^1.1.1
+ version: 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-previous':
+ specifier: ^1.1.1
+ version: 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-visually-hidden':
+ specifier: ^1.2.3
+ version: 1.2.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tailwindcss/container-queries':
specifier: ^0.1.1
version: 0.1.1(tailwindcss@3.4.17)
@@ -246,6 +300,9 @@ importers:
'@vueless/storybook-dark-mode':
specifier: ^9.0.7
version: 9.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ aria-hidden:
+ specifier: ^1.2.6
+ version: 1.2.6
canvas-confetti:
specifier: ^1.9.3
version: 1.9.3
@@ -300,6 +357,9 @@ importers:
react-masonry:
specifier: ^1.0.7
version: 1.0.7
+ react-remove-scroll:
+ specifier: ^2.7.1
+ version: 2.7.1(@types/react@18.3.18)(react@18.3.1)
recharts:
specifier: ^2.12.7
version: 2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -3294,11 +3354,14 @@ packages:
'@radix-ui/number@1.1.0':
resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==}
+ '@radix-ui/number@1.1.1':
+ resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==}
+
'@radix-ui/primitive@1.1.1':
resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==}
- '@radix-ui/primitive@1.1.2':
- resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==}
+ '@radix-ui/primitive@1.1.3':
+ resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
'@radix-ui/react-accordion@1.2.2':
resolution: {integrity: sha512-b1oh54x4DMCdGsB4/7ahiSrViXxaBwRPotiZNnYXjLha9vfuURSAZErki6qjDoSIV0eXx5v57XnTGVtGwnfp2g==}
@@ -3326,8 +3389,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-arrow@1.1.2':
- resolution: {integrity: sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==}
+ '@radix-ui/react-arrow@1.1.7':
+ resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3391,6 +3454,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-collection@1.1.7':
+ resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-compose-refs@1.1.1':
resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==}
peerDependencies:
@@ -3449,8 +3525,17 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-dismissable-layer@1.1.4':
- resolution: {integrity: sha512-XDUI0IVYVSwjMXxM6P4Dfti7AH+Y4oS/TB+sglZ/EXc7cqLwGAmp1NlMrcUjj7ks6R5WTZuWKv44FBbLpwU3sA==}
+ '@radix-ui/react-direction@1.1.1':
+ resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/react-dismissable-layer@1.1.11':
+ resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3462,8 +3547,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-dismissable-layer@1.1.5':
- resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==}
+ '@radix-ui/react-dismissable-layer@1.1.4':
+ resolution: {integrity: sha512-XDUI0IVYVSwjMXxM6P4Dfti7AH+Y4oS/TB+sglZ/EXc7cqLwGAmp1NlMrcUjj7ks6R5WTZuWKv44FBbLpwU3sA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3497,6 +3582,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-focus-guards@1.1.3':
+ resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-focus-scope@1.1.1':
resolution: {integrity: sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==}
peerDependencies:
@@ -3510,8 +3604,21 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-hover-card@1.1.6':
- resolution: {integrity: sha512-E4ozl35jq0VRlrdc4dhHrNSV0JqBb4Jy73WAhBEK7JoYnQ83ED5r0Rb/XdVKw89ReAJN38N492BAPBZQ57VmqQ==}
+ '@radix-ui/react-focus-scope@1.1.7':
+ resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/react-hover-card@1.1.15':
+ resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3532,6 +3639,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-id@1.1.1':
+ resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-label@2.1.1':
resolution: {integrity: sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==}
peerDependencies:
@@ -3597,8 +3713,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-popper@1.2.2':
- resolution: {integrity: sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==}
+ '@radix-ui/react-popper@1.2.8':
+ resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3623,8 +3739,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-portal@1.1.4':
- resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==}
+ '@radix-ui/react-portal@1.1.9':
+ resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3649,8 +3765,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-primitive@2.0.1':
- resolution: {integrity: sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==}
+ '@radix-ui/react-presence@1.1.5':
+ resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3662,8 +3778,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-primitive@2.0.2':
- resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==}
+ '@radix-ui/react-primitive@2.0.1':
+ resolution: {integrity: sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3675,8 +3791,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-primitive@2.1.0':
- resolution: {integrity: sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==}
+ '@radix-ui/react-primitive@2.1.3':
+ resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3749,8 +3865,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-slot@1.1.2':
- resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==}
+ '@radix-ui/react-slot@1.2.0':
+ resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -3758,8 +3874,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-slot@1.2.0':
- resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==}
+ '@radix-ui/react-slot@1.2.3':
+ resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -3767,8 +3883,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-switch@1.2.2':
- resolution: {integrity: sha512-7Z8n6L+ifMIIYZ83f28qWSceUpkXuslI2FJ34+kDMTiyj91ENdpdQ7VCidrzj5JfwfZTeano/BnGBbu/jqa5rQ==}
+ '@radix-ui/react-switch@1.2.6':
+ resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -3841,6 +3957,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-use-callback-ref@1.1.1':
+ resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-use-controllable-state@1.1.0':
resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==}
peerDependencies:
@@ -3877,6 +4002,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-use-escape-keydown@1.1.1':
+ resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-use-layout-effect@1.1.0':
resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==}
peerDependencies:
@@ -3922,6 +4056,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-use-rect@1.1.1':
+ resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-use-size@1.1.0':
resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==}
peerDependencies:
@@ -3953,9 +4096,25 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-visually-hidden@1.2.3':
+ resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/rect@1.1.0':
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
+ '@radix-ui/rect@1.1.1':
+ resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
+
'@react-aria/focus@3.20.5':
resolution: {integrity: sha512-JpFtXmWQ0Oca7FcvkqgjSyo6xEP7v3oQOLUId6o0xTvm4AD5W0mU2r3lYrbhsJ+XxdUUX4AVR5473sZZ85kU4A==}
peerDependencies:
@@ -5909,8 +6068,8 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- aria-hidden@1.2.4:
- resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
+ aria-hidden@1.2.6:
+ resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
engines: {node: '>=10'}
aria-query@5.3.0:
@@ -10909,6 +11068,16 @@ packages:
'@types/react':
optional: true
+ react-remove-scroll@2.7.1:
+ resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
react-shallow-renderer@16.15.0:
resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==}
peerDependencies:
@@ -16055,9 +16224,11 @@ snapshots:
'@radix-ui/number@1.1.0': {}
+ '@radix-ui/number@1.1.1': {}
+
'@radix-ui/primitive@1.1.1': {}
- '@radix-ui/primitive@1.1.2': {}
+ '@radix-ui/primitive@1.1.3': {}
'@radix-ui/react-accordion@1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@@ -16085,9 +16256,9 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-arrow@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -16150,6 +16321,18 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
+ '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-slot': 1.2.3(@types/react@18.3.18)(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.18
+ '@types/react-dom': 18.3.5(@types/react@18.3.18)
+
'@radix-ui/react-compose-refs@1.1.1(@types/react@18.3.18)(react@18.3.1)':
dependencies:
react: 18.3.1
@@ -16188,10 +16371,10 @@ snapshots:
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot': 1.1.1(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- aria-hidden: 1.2.4
+ aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-remove-scroll: 2.6.3(@types/react@18.3.18)(react@18.3.1)
+ react-remove-scroll: 2.7.1(@types/react@18.3.18)(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
@@ -16202,24 +16385,30 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
- '@radix-ui/react-dismissable-layer@1.1.4(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-direction@1.1.1(@types/react@18.3.18)(react@18.3.1)':
dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.18)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.18
+
+ '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-dismissable-layer@1.1.4(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
'@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
@@ -16249,6 +16438,12 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
+ '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.18)(react@18.3.1)':
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.18
+
'@radix-ui/react-focus-scope@1.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)
@@ -16260,17 +16455,28 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-hover-card@1.1.6(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-popper': 1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-portal': 1.1.4(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.18
+ '@types/react-dom': 18.3.5(@types/react@18.3.18)
+
+ '@radix-ui/react-hover-card@1.1.15(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -16284,6 +16490,13 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
+ '@radix-ui/react-id@1.1.1(@types/react@18.3.18)(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.18
+
'@radix-ui/react-label@2.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -16311,7 +16524,7 @@ snapshots:
'@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot': 1.1.1(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- aria-hidden: 1.2.4
+ aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-remove-scroll: 2.6.3(@types/react@18.3.18)(react@18.3.1)
@@ -16356,7 +16569,7 @@ snapshots:
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot': 1.1.1(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- aria-hidden: 1.2.4
+ aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-remove-scroll: 2.6.3(@types/react@18.3.18)(react@18.3.1)
@@ -16382,18 +16595,18 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-popper@1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-arrow': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/rect': 1.1.0
+ '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/rect': 1.1.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -16410,10 +16623,10 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-portal@1.1.4(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -16430,27 +16643,28 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-primitive@2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@radix-ui/react-slot': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-primitive@2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-primitive@2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@radix-ui/react-slot': 1.1.2(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
- '@radix-ui/react-primitive@2.1.0(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@radix-ui/react-slot': 1.2.0(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-slot': 1.2.3(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -16522,7 +16736,7 @@ snapshots:
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- aria-hidden: 1.2.4
+ aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-remove-scroll: 2.6.3(@types/react@18.3.18)(react@18.3.1)
@@ -16537,26 +16751,26 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
- '@radix-ui/react-slot@1.1.2(@types/react@18.3.18)(react@18.3.1)':
+ '@radix-ui/react-slot@1.2.0(@types/react@18.3.18)(react@18.3.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.18
- '@radix-ui/react-slot@1.2.0(@types/react@18.3.18)(react@18.3.1)':
+ '@radix-ui/react-slot@1.2.3(@types/react@18.3.18)(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.18
- '@radix-ui/react-switch@1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@radix-ui/primitive': 1.1.2
+ '@radix-ui/primitive': 1.1.3
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-context': 1.1.2(@types/react@18.3.18)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.18)(react@18.3.1)
'@radix-ui/react-use-size': 1.1.1(@types/react@18.3.18)(react@18.3.1)
@@ -16634,6 +16848,12 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
+ '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.18)(react@18.3.1)':
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.18
+
'@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.18)(react@18.3.1)':
dependencies:
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1)
@@ -16663,6 +16883,13 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
+ '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.18)(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.18)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.18
+
'@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.18)(react@18.3.1)':
dependencies:
react: 18.3.1
@@ -16694,6 +16921,13 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
+ '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.18)(react@18.3.1)':
+ dependencies:
+ '@radix-ui/rect': 1.1.1
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.18
+
'@radix-ui/react-use-size@1.1.0(@types/react@18.3.18)(react@18.3.1)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.18)(react@18.3.1)
@@ -16717,8 +16951,19 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
+ '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.18
+ '@types/react-dom': 18.3.5(@types/react@18.3.18)
+
'@radix-ui/rect@1.1.0': {}
+ '@radix-ui/rect@1.1.1': {}
+
'@react-aria/focus@3.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@react-aria/interactions': 3.25.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -19147,7 +19392,7 @@ snapshots:
argparse@2.0.1: {}
- aria-hidden@1.2.4:
+ aria-hidden@1.2.6:
dependencies:
tslib: 2.8.1
@@ -21828,7 +22073,7 @@ snapshots:
isstream: 0.1.2
jsonwebtoken: 9.0.2
mime-types: 2.1.35
- retry-axios: 2.6.0(axios@1.8.4(debug@4.4.1))
+ retry-axios: 2.6.0(axios@1.8.4)
tough-cookie: 4.1.4
transitivePeerDependencies:
- supports-color
@@ -25294,6 +25539,17 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.18
+ react-remove-scroll@2.7.1(@types/react@18.3.18)(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+ react-remove-scroll-bar: 2.3.8(@types/react@18.3.18)(react@18.3.1)
+ react-style-singleton: 2.2.3(@types/react@18.3.18)(react@18.3.1)
+ tslib: 2.8.1
+ use-callback-ref: 1.3.3(@types/react@18.3.18)(react@18.3.1)
+ use-sidecar: 1.1.3(@types/react@18.3.18)(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.18
+
react-shallow-renderer@16.15.0(react@18.3.1):
dependencies:
object-assign: 4.1.1
@@ -25613,7 +25869,7 @@ snapshots:
onetime: 2.0.1
signal-exit: 3.0.7
- retry-axios@2.6.0(axios@1.8.4(debug@4.4.1)):
+ retry-axios@2.6.0(axios@1.8.4):
dependencies:
axios: 1.8.4(debug@4.4.1)