| | "use strict"; |
| | "use client"; |
| | var __create = Object.create; |
| | var __defProp = Object.defineProperty; |
| | var __getOwnPropDesc = Object.getOwnPropertyDescriptor; |
| | var __getOwnPropNames = Object.getOwnPropertyNames; |
| | var __getProtoOf = Object.getPrototypeOf; |
| | var __hasOwnProp = Object.prototype.hasOwnProperty; |
| | var __export = (target, all) => { |
| | for (var name in all) |
| | __defProp(target, name, { get: all[name], enumerable: true }); |
| | }; |
| | var __copyProps = (to, from, except, desc) => { |
| | if (from && typeof from === "object" || typeof from === "function") { |
| | for (let key of __getOwnPropNames(from)) |
| | if (!__hasOwnProp.call(to, key) && key !== except) |
| | __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); |
| | } |
| | return to; |
| | }; |
| | var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( |
| | |
| | |
| | |
| | |
| | isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, |
| | mod |
| | )); |
| | var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); |
| |
|
| | |
| | var src_exports = {}; |
| | __export(src_exports, { |
| | Arrow: () => Arrow2, |
| | Content: () => Content2, |
| | Group: () => Group, |
| | Icon: () => Icon, |
| | Item: () => Item, |
| | ItemIndicator: () => ItemIndicator, |
| | ItemText: () => ItemText, |
| | Label: () => Label, |
| | Portal: () => Portal, |
| | Root: () => Root2, |
| | ScrollDownButton: () => ScrollDownButton, |
| | ScrollUpButton: () => ScrollUpButton, |
| | Select: () => Select, |
| | SelectArrow: () => SelectArrow, |
| | SelectContent: () => SelectContent, |
| | SelectGroup: () => SelectGroup, |
| | SelectIcon: () => SelectIcon, |
| | SelectItem: () => SelectItem, |
| | SelectItemIndicator: () => SelectItemIndicator, |
| | SelectItemText: () => SelectItemText, |
| | SelectLabel: () => SelectLabel, |
| | SelectPortal: () => SelectPortal, |
| | SelectScrollDownButton: () => SelectScrollDownButton, |
| | SelectScrollUpButton: () => SelectScrollUpButton, |
| | SelectSeparator: () => SelectSeparator, |
| | SelectTrigger: () => SelectTrigger, |
| | SelectValue: () => SelectValue, |
| | SelectViewport: () => SelectViewport, |
| | Separator: () => Separator, |
| | Trigger: () => Trigger, |
| | Value: () => Value, |
| | Viewport: () => Viewport, |
| | createSelectScope: () => createSelectScope |
| | }); |
| | module.exports = __toCommonJS(src_exports); |
| |
|
| | |
| | var React = __toESM(require("react")); |
| | var ReactDOM = __toESM(require("react-dom")); |
| | var import_number = require("@radix-ui/number"); |
| | var import_primitive = require("@radix-ui/primitive"); |
| | var import_react_collection = require("@radix-ui/react-collection"); |
| | var import_react_compose_refs = require("@radix-ui/react-compose-refs"); |
| | var import_react_context = require("@radix-ui/react-context"); |
| | var import_react_direction = require("@radix-ui/react-direction"); |
| | var import_react_dismissable_layer = require("@radix-ui/react-dismissable-layer"); |
| | var import_react_focus_guards = require("@radix-ui/react-focus-guards"); |
| | var import_react_focus_scope = require("@radix-ui/react-focus-scope"); |
| | var import_react_id = require("@radix-ui/react-id"); |
| | var PopperPrimitive = __toESM(require("@radix-ui/react-popper")); |
| | var import_react_popper = require("@radix-ui/react-popper"); |
| | var import_react_portal = require("@radix-ui/react-portal"); |
| | var import_react_primitive = require("@radix-ui/react-primitive"); |
| | var import_react_slot = require("@radix-ui/react-slot"); |
| | var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref"); |
| | var import_react_use_controllable_state = require("@radix-ui/react-use-controllable-state"); |
| | var import_react_use_layout_effect = require("@radix-ui/react-use-layout-effect"); |
| | var import_react_use_previous = require("@radix-ui/react-use-previous"); |
| | var import_react_visually_hidden = require("@radix-ui/react-visually-hidden"); |
| | var import_aria_hidden = require("aria-hidden"); |
| | var import_react_remove_scroll = require("react-remove-scroll"); |
| | var import_jsx_runtime = require("react/jsx-runtime"); |
| | var OPEN_KEYS = [" ", "Enter", "ArrowUp", "ArrowDown"]; |
| | var SELECTION_KEYS = [" ", "Enter"]; |
| | var SELECT_NAME = "Select"; |
| | var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)(SELECT_NAME); |
| | var [createSelectContext, createSelectScope] = (0, import_react_context.createContextScope)(SELECT_NAME, [ |
| | createCollectionScope, |
| | import_react_popper.createPopperScope |
| | ]); |
| | var usePopperScope = (0, import_react_popper.createPopperScope)(); |
| | var [SelectProvider, useSelectContext] = createSelectContext(SELECT_NAME); |
| | var [SelectNativeOptionsProvider, useSelectNativeOptionsContext] = createSelectContext(SELECT_NAME); |
| | var Select = (props) => { |
| | const { |
| | __scopeSelect, |
| | children, |
| | open: openProp, |
| | defaultOpen, |
| | onOpenChange, |
| | value: valueProp, |
| | defaultValue, |
| | onValueChange, |
| | dir, |
| | name, |
| | autoComplete, |
| | disabled, |
| | required, |
| | form |
| | } = 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 = (0, import_react_direction.useDirection)(dir); |
| | const [open = false, setOpen] = (0, import_react_use_controllable_state.useControllableState)({ |
| | prop: openProp, |
| | defaultProp: defaultOpen, |
| | onChange: onOpenChange |
| | }); |
| | const [value, setValue] = (0, import_react_use_controllable_state.useControllableState)({ |
| | prop: valueProp, |
| | defaultProp: defaultValue, |
| | onChange: onValueChange |
| | }); |
| | const triggerPointerDownPosRef = React.useRef(null); |
| | const isFormControl = trigger ? form || !!trigger.closest("form") : true; |
| | const [nativeOptionsSet, setNativeOptionsSet] = React.useState( new Set()); |
| | const nativeSelectKey = Array.from(nativeOptionsSet).map((option) => option.props.value).join(";"); |
| | return (0, import_jsx_runtime.jsx)(PopperPrimitive.Root, { ...popperScope, children: (0, import_jsx_runtime.jsxs)( |
| | SelectProvider, |
| | { |
| | required, |
| | scope: __scopeSelect, |
| | trigger, |
| | onTriggerChange: setTrigger, |
| | valueNode, |
| | onValueNodeChange: setValueNode, |
| | valueNodeHasChildren, |
| | onValueNodeHasChildrenChange: setValueNodeHasChildren, |
| | contentId: (0, import_react_id.useId)(), |
| | value, |
| | onValueChange: setValue, |
| | open, |
| | onOpenChange: setOpen, |
| | dir: direction, |
| | triggerPointerDownPosRef, |
| | disabled, |
| | children: [ |
| | (0, import_jsx_runtime.jsx)(Collection.Provider, { scope: __scopeSelect, children: (0, import_jsx_runtime.jsx)( |
| | SelectNativeOptionsProvider, |
| | { |
| | scope: props.__scopeSelect, |
| | onNativeOptionAdd: React.useCallback((option) => { |
| | 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 ? (0, import_jsx_runtime.jsxs)( |
| | BubbleSelect, |
| | { |
| | "aria-hidden": true, |
| | required, |
| | tabIndex: -1, |
| | name, |
| | autoComplete, |
| | value, |
| | onChange: (event) => setValue(event.target.value), |
| | disabled, |
| | form, |
| | children: [ |
| | value === void 0 ? (0, import_jsx_runtime.jsx)("option", { value: "" }) : null, |
| | Array.from(nativeOptionsSet) |
| | ] |
| | }, |
| | nativeSelectKey |
| | ) : null |
| | ] |
| | } |
| | ) }); |
| | }; |
| | Select.displayName = SELECT_NAME; |
| | var TRIGGER_NAME = "SelectTrigger"; |
| | var SelectTrigger = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, disabled = false, ...triggerProps } = props; |
| | const popperScope = usePopperScope(__scopeSelect); |
| | const context = useSelectContext(TRIGGER_NAME, __scopeSelect); |
| | const isDisabled = context.disabled || disabled; |
| | const composedRefs = (0, import_react_compose_refs.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 !== void 0) { |
| | context.onValueChange(nextItem.value); |
| | } |
| | }); |
| | const handleOpen = (pointerEvent) => { |
| | if (!isDisabled) { |
| | context.onOpenChange(true); |
| | resetTypeahead(); |
| | } |
| | if (pointerEvent) { |
| | context.triggerPointerDownPosRef.current = { |
| | x: Math.round(pointerEvent.pageX), |
| | y: Math.round(pointerEvent.pageY) |
| | }; |
| | } |
| | }; |
| | return (0, import_jsx_runtime.jsx)(PopperPrimitive.Anchor, { asChild: true, ...popperScope, children: (0, import_jsx_runtime.jsx)( |
| | import_react_primitive.Primitive.button, |
| | { |
| | type: "button", |
| | role: "combobox", |
| | "aria-controls": context.contentId, |
| | "aria-expanded": context.open, |
| | "aria-required": context.required, |
| | "aria-autocomplete": "none", |
| | dir: context.dir, |
| | "data-state": context.open ? "open" : "closed", |
| | disabled: isDisabled, |
| | "data-disabled": isDisabled ? "" : void 0, |
| | "data-placeholder": shouldShowPlaceholder(context.value) ? "" : void 0, |
| | ...triggerProps, |
| | ref: composedRefs, |
| | onClick: (0, import_primitive.composeEventHandlers)(triggerProps.onClick, (event) => { |
| | event.currentTarget.focus(); |
| | if (pointerTypeRef.current !== "mouse") { |
| | handleOpen(event); |
| | } |
| | }), |
| | onPointerDown: (0, import_primitive.composeEventHandlers)(triggerProps.onPointerDown, (event) => { |
| | pointerTypeRef.current = event.pointerType; |
| | const target = event.target; |
| | if (target.hasPointerCapture(event.pointerId)) { |
| | target.releasePointerCapture(event.pointerId); |
| | } |
| | if (event.button === 0 && event.ctrlKey === false && event.pointerType === "mouse") { |
| | handleOpen(event); |
| | event.preventDefault(); |
| | } |
| | }), |
| | onKeyDown: (0, import_primitive.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; |
| | var VALUE_NAME = "SelectValue"; |
| | var SelectValue = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, className, style, children, placeholder = "", ...valueProps } = props; |
| | const context = useSelectContext(VALUE_NAME, __scopeSelect); |
| | const { onValueNodeHasChildrenChange } = context; |
| | const hasChildren = children !== void 0; |
| | const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, context.onValueNodeChange); |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => { |
| | onValueNodeHasChildrenChange(hasChildren); |
| | }, [onValueNodeHasChildrenChange, hasChildren]); |
| | return (0, import_jsx_runtime.jsx)( |
| | import_react_primitive.Primitive.span, |
| | { |
| | ...valueProps, |
| | ref: composedRefs, |
| | style: { pointerEvents: "none" }, |
| | children: shouldShowPlaceholder(context.value) ? (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: placeholder }) : children |
| | } |
| | ); |
| | } |
| | ); |
| | SelectValue.displayName = VALUE_NAME; |
| | var ICON_NAME = "SelectIcon"; |
| | var SelectIcon = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, children, ...iconProps } = props; |
| | return (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.span, { "aria-hidden": true, ...iconProps, ref: forwardedRef, children: children || "\u25BC" }); |
| | } |
| | ); |
| | SelectIcon.displayName = ICON_NAME; |
| | var PORTAL_NAME = "SelectPortal"; |
| | var SelectPortal = (props) => { |
| | return (0, import_jsx_runtime.jsx)(import_react_portal.Portal, { asChild: true, ...props }); |
| | }; |
| | SelectPortal.displayName = PORTAL_NAME; |
| | var CONTENT_NAME = "SelectContent"; |
| | var SelectContent = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const context = useSelectContext(CONTENT_NAME, props.__scopeSelect); |
| | const [fragment, setFragment] = React.useState(); |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => { |
| | setFragment(new DocumentFragment()); |
| | }, []); |
| | if (!context.open) { |
| | const frag = fragment; |
| | return frag ? ReactDOM.createPortal( |
| | (0, import_jsx_runtime.jsx)(SelectContentProvider, { scope: props.__scopeSelect, children: (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: props.__scopeSelect, children: (0, import_jsx_runtime.jsx)("div", { children: props.children }) }) }), |
| | frag |
| | ) : null; |
| | } |
| | return (0, import_jsx_runtime.jsx)(SelectContentImpl, { ...props, ref: forwardedRef }); |
| | } |
| | ); |
| | SelectContent.displayName = CONTENT_NAME; |
| | var CONTENT_MARGIN = 10; |
| | var [SelectContentProvider, useSelectContentContext] = createSelectContext(CONTENT_NAME); |
| | var CONTENT_IMPL_NAME = "SelectContentImpl"; |
| | var SelectContentImpl = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { |
| | __scopeSelect, |
| | position = "item-aligned", |
| | onCloseAutoFocus, |
| | onEscapeKeyDown, |
| | onPointerDownOutside, |
| | |
| | |
| | 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 = (0, import_react_compose_refs.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); |
| | React.useEffect(() => { |
| | if (content) return (0, import_aria_hidden.hideOthers)(content); |
| | }, [content]); |
| | (0, import_react_focus_guards.useFocusGuards)(); |
| | const focusFirst = React.useCallback( |
| | (candidates) => { |
| | 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 (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return; |
| | candidate?.scrollIntoView({ block: "nearest" }); |
| | 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] |
| | ); |
| | React.useEffect(() => { |
| | if (isPositioned) { |
| | focusSelectedItem(); |
| | } |
| | }, [isPositioned, focusSelectedItem]); |
| | const { onOpenChange, triggerPointerDownPosRef } = context; |
| | React.useEffect(() => { |
| | if (content) { |
| | let pointerMoveDelta = { x: 0, y: 0 }; |
| | const handlePointerMove = (event) => { |
| | 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) => { |
| | if (pointerMoveDelta.x <= 10 && pointerMoveDelta.y <= 10) { |
| | event.preventDefault(); |
| | } else { |
| | if (!content.contains(event.target)) { |
| | 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) { |
| | setTimeout(() => nextItem.ref.current.focus()); |
| | } |
| | }); |
| | const itemRefCallback = React.useCallback( |
| | (node, value, disabled) => { |
| | const isFirstValidItem = !firstValidItemFoundRef.current && !disabled; |
| | const isSelectedItem = context.value !== void 0 && context.value === 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, value, disabled) => { |
| | const isFirstValidItem = !firstValidItemFoundRef.current && !disabled; |
| | const isSelectedItem = context.value !== void 0 && context.value === value; |
| | if (isSelectedItem || isFirstValidItem) { |
| | setSelectedItemText(node); |
| | } |
| | }, |
| | [context.value] |
| | ); |
| | const SelectPosition = position === "popper" ? SelectPopperPosition : SelectItemAlignedPosition; |
| | const popperContentProps = SelectPosition === SelectPopperPosition ? { |
| | side, |
| | sideOffset, |
| | align, |
| | alignOffset, |
| | arrowPadding, |
| | collisionBoundary, |
| | collisionPadding, |
| | sticky, |
| | hideWhenDetached, |
| | avoidCollisions |
| | } : {}; |
| | return (0, import_jsx_runtime.jsx)( |
| | SelectContentProvider, |
| | { |
| | scope: __scopeSelect, |
| | content, |
| | viewport, |
| | onViewportChange: setViewport, |
| | itemRefCallback, |
| | selectedItem, |
| | onItemLeave: handleItemLeave, |
| | itemTextRefCallback, |
| | focusSelectedItem, |
| | selectedItemText, |
| | position, |
| | isPositioned, |
| | searchRef, |
| | children: (0, import_jsx_runtime.jsx)(import_react_remove_scroll.RemoveScroll, { as: import_react_slot.Slot, allowPinchZoom: true, children: (0, import_jsx_runtime.jsx)( |
| | import_react_focus_scope.FocusScope, |
| | { |
| | asChild: true, |
| | trapped: context.open, |
| | onMountAutoFocus: (event) => { |
| | event.preventDefault(); |
| | }, |
| | onUnmountAutoFocus: (0, import_primitive.composeEventHandlers)(onCloseAutoFocus, (event) => { |
| | context.trigger?.focus({ preventScroll: true }); |
| | event.preventDefault(); |
| | }), |
| | children: (0, import_jsx_runtime.jsx)( |
| | import_react_dismissable_layer.DismissableLayer, |
| | { |
| | asChild: true, |
| | disableOutsidePointerEvents: true, |
| | onEscapeKeyDown, |
| | onPointerDownOutside, |
| | onFocusOutside: (event) => event.preventDefault(), |
| | onDismiss: () => context.onOpenChange(false), |
| | children: (0, import_jsx_runtime.jsx)( |
| | SelectPosition, |
| | { |
| | role: "listbox", |
| | id: context.contentId, |
| | "data-state": context.open ? "open" : "closed", |
| | dir: context.dir, |
| | onContextMenu: (event) => event.preventDefault(), |
| | ...contentProps, |
| | ...popperContentProps, |
| | onPlaced: () => setIsPositioned(true), |
| | ref: composedRefs, |
| | style: { |
| | |
| | display: "flex", |
| | flexDirection: "column", |
| | |
| | outline: "none", |
| | ...contentProps.style |
| | }, |
| | onKeyDown: (0, import_primitive.composeEventHandlers)(contentProps.onKeyDown, (event) => { |
| | const isModifierKey = event.ctrlKey || event.altKey || event.metaKey; |
| | 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; |
| | const currentIndex = candidateNodes.indexOf(currentElement); |
| | candidateNodes = candidateNodes.slice(currentIndex + 1); |
| | } |
| | setTimeout(() => focusFirst(candidateNodes)); |
| | event.preventDefault(); |
| | } |
| | }) |
| | } |
| | ) |
| | } |
| | ) |
| | } |
| | ) }) |
| | } |
| | ); |
| | } |
| | ); |
| | SelectContentImpl.displayName = CONTENT_IMPL_NAME; |
| | var ITEM_ALIGNED_POSITION_NAME = "SelectItemAlignedPosition"; |
| | var SelectItemAlignedPosition = React.forwardRef((props, 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 = (0, import_react_compose_refs.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(); |
| | 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 = (0, import_number.clamp)(left, [ |
| | CONTENT_MARGIN, |
| | |
| | |
| | |
| | |
| | |
| | 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 = (0, import_number.clamp)(right, [ |
| | CONTENT_MARGIN, |
| | Math.max(CONTENT_MARGIN, leftEdge - contentWidth) |
| | ]); |
| | contentWrapper.style.minWidth = minContentWidth + "px"; |
| | contentWrapper.style.right = clampedRight + "px"; |
| | } |
| | 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; |
| | 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 = "0px"; |
| | const viewportOffsetBottom = content.clientHeight - viewport.offsetTop - viewport.offsetHeight; |
| | const clampedTriggerMiddleToBottomEdge = Math.max( |
| | triggerMiddleToBottomEdge, |
| | selectedItemHalfHeight + |
| | (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 = "0px"; |
| | const clampedTopEdgeToTriggerMiddle = Math.max( |
| | topEdgeToTriggerMiddle, |
| | contentBorderTopWidth + viewport.offsetTop + |
| | (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?.(); |
| | requestAnimationFrame(() => shouldExpandOnScrollRef.current = true); |
| | } |
| | }, [ |
| | getItems, |
| | context.trigger, |
| | context.valueNode, |
| | contentWrapper, |
| | content, |
| | viewport, |
| | selectedItem, |
| | selectedItemText, |
| | context.dir, |
| | onPlaced |
| | ]); |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => position(), [position]); |
| | const [contentZIndex, setContentZIndex] = React.useState(); |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => { |
| | if (content) setContentZIndex(window.getComputedStyle(content).zIndex); |
| | }, [content]); |
| | const handleScrollButtonChange = React.useCallback( |
| | (node) => { |
| | if (node && shouldRepositionRef.current === true) { |
| | position(); |
| | focusSelectedItem?.(); |
| | shouldRepositionRef.current = false; |
| | } |
| | }, |
| | [position, focusSelectedItem] |
| | ); |
| | return (0, import_jsx_runtime.jsx)( |
| | SelectViewportProvider, |
| | { |
| | scope: __scopeSelect, |
| | contentWrapper, |
| | shouldExpandOnScrollRef, |
| | onScrollButtonChange: handleScrollButtonChange, |
| | children: (0, import_jsx_runtime.jsx)( |
| | "div", |
| | { |
| | ref: setContentWrapper, |
| | style: { |
| | display: "flex", |
| | flexDirection: "column", |
| | position: "fixed", |
| | zIndex: contentZIndex |
| | }, |
| | children: (0, import_jsx_runtime.jsx)( |
| | import_react_primitive.Primitive.div, |
| | { |
| | ...popperProps, |
| | ref: composedRefs, |
| | style: { |
| | |
| | |
| | boxSizing: "border-box", |
| | |
| | maxHeight: "100%", |
| | ...popperProps.style |
| | } |
| | } |
| | ) |
| | } |
| | ) |
| | } |
| | ); |
| | }); |
| | SelectItemAlignedPosition.displayName = ITEM_ALIGNED_POSITION_NAME; |
| | var POPPER_POSITION_NAME = "SelectPopperPosition"; |
| | var SelectPopperPosition = React.forwardRef((props, forwardedRef) => { |
| | const { |
| | __scopeSelect, |
| | align = "start", |
| | collisionPadding = CONTENT_MARGIN, |
| | ...popperProps |
| | } = props; |
| | const popperScope = usePopperScope(__scopeSelect); |
| | return (0, import_jsx_runtime.jsx)( |
| | PopperPrimitive.Content, |
| | { |
| | ...popperScope, |
| | ...popperProps, |
| | ref: forwardedRef, |
| | align, |
| | collisionPadding, |
| | style: { |
| | |
| | boxSizing: "border-box", |
| | ...popperProps.style, |
| | |
| | ...{ |
| | "--radix-select-content-transform-origin": "var(--radix-popper-transform-origin)", |
| | "--radix-select-content-available-width": "var(--radix-popper-available-width)", |
| | "--radix-select-content-available-height": "var(--radix-popper-available-height)", |
| | "--radix-select-trigger-width": "var(--radix-popper-anchor-width)", |
| | "--radix-select-trigger-height": "var(--radix-popper-anchor-height)" |
| | } |
| | } |
| | } |
| | ); |
| | }); |
| | SelectPopperPosition.displayName = POPPER_POSITION_NAME; |
| | var [SelectViewportProvider, useSelectViewportContext] = createSelectContext(CONTENT_NAME, {}); |
| | var VIEWPORT_NAME = "SelectViewport"; |
| | var SelectViewport = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, nonce, ...viewportProps } = props; |
| | const contentContext = useSelectContentContext(VIEWPORT_NAME, __scopeSelect); |
| | const viewportContext = useSelectViewportContext(VIEWPORT_NAME, __scopeSelect); |
| | const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, contentContext.onViewportChange); |
| | const prevScrollTopRef = React.useRef(0); |
| | return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ |
| | (0, import_jsx_runtime.jsx)( |
| | "style", |
| | { |
| | dangerouslySetInnerHTML: { |
| | __html: `[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}` |
| | }, |
| | nonce |
| | } |
| | ), |
| | (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: __scopeSelect, children: (0, import_jsx_runtime.jsx)( |
| | import_react_primitive.Primitive.div, |
| | { |
| | "data-radix-select-viewport": "", |
| | role: "presentation", |
| | ...viewportProps, |
| | ref: composedRefs, |
| | style: { |
| | |
| | |
| | |
| | position: "relative", |
| | flex: 1, |
| | |
| | |
| | |
| | |
| | overflow: "hidden auto", |
| | ...viewportProps.style |
| | }, |
| | onScroll: (0, import_primitive.composeEventHandlers)(viewportProps.onScroll, (event) => { |
| | 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; |
| | contentWrapper.style.justifyContent = "flex-end"; |
| | } |
| | } |
| | } |
| | } |
| | prevScrollTopRef.current = viewport.scrollTop; |
| | }) |
| | } |
| | ) }) |
| | ] }); |
| | } |
| | ); |
| | SelectViewport.displayName = VIEWPORT_NAME; |
| | var GROUP_NAME = "SelectGroup"; |
| | var [SelectGroupContextProvider, useSelectGroupContext] = createSelectContext(GROUP_NAME); |
| | var SelectGroup = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, ...groupProps } = props; |
| | const groupId = (0, import_react_id.useId)(); |
| | return (0, import_jsx_runtime.jsx)(SelectGroupContextProvider, { scope: __scopeSelect, id: groupId, children: (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { role: "group", "aria-labelledby": groupId, ...groupProps, ref: forwardedRef }) }); |
| | } |
| | ); |
| | SelectGroup.displayName = GROUP_NAME; |
| | var LABEL_NAME = "SelectLabel"; |
| | var SelectLabel = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, ...labelProps } = props; |
| | const groupContext = useSelectGroupContext(LABEL_NAME, __scopeSelect); |
| | return (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { id: groupContext.id, ...labelProps, ref: forwardedRef }); |
| | } |
| | ); |
| | SelectLabel.displayName = LABEL_NAME; |
| | var ITEM_NAME = "SelectItem"; |
| | var [SelectItemContextProvider, useSelectItemContext] = createSelectContext(ITEM_NAME); |
| | var SelectItem = React.forwardRef( |
| | (props, 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.value === value; |
| | const [textValue, setTextValue] = React.useState(textValueProp ?? ""); |
| | const [isFocused, setIsFocused] = React.useState(false); |
| | const composedRefs = (0, import_react_compose_refs.useComposedRefs)( |
| | forwardedRef, |
| | (node) => contentContext.itemRefCallback?.(node, value, disabled) |
| | ); |
| | const textId = (0, import_react_id.useId)(); |
| | const pointerTypeRef = React.useRef("touch"); |
| | const handleSelect = () => { |
| | if (!disabled) { |
| | context.onValueChange(value); |
| | context.onOpenChange(false); |
| | } |
| | }; |
| | if (value === "") { |
| | throw new Error( |
| | "A <Select.Item /> 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 (0, import_jsx_runtime.jsx)( |
| | SelectItemContextProvider, |
| | { |
| | scope: __scopeSelect, |
| | value, |
| | disabled, |
| | textId, |
| | isSelected, |
| | onItemTextChange: React.useCallback((node) => { |
| | setTextValue((prevTextValue) => prevTextValue || (node?.textContent ?? "").trim()); |
| | }, []), |
| | children: (0, import_jsx_runtime.jsx)( |
| | Collection.ItemSlot, |
| | { |
| | scope: __scopeSelect, |
| | value, |
| | disabled, |
| | textValue, |
| | children: (0, import_jsx_runtime.jsx)( |
| | import_react_primitive.Primitive.div, |
| | { |
| | role: "option", |
| | "aria-labelledby": textId, |
| | "data-highlighted": isFocused ? "" : void 0, |
| | "aria-selected": isSelected && isFocused, |
| | "data-state": isSelected ? "checked" : "unchecked", |
| | "aria-disabled": disabled || void 0, |
| | "data-disabled": disabled ? "" : void 0, |
| | tabIndex: disabled ? void 0 : -1, |
| | ...itemProps, |
| | ref: composedRefs, |
| | onFocus: (0, import_primitive.composeEventHandlers)(itemProps.onFocus, () => setIsFocused(true)), |
| | onBlur: (0, import_primitive.composeEventHandlers)(itemProps.onBlur, () => setIsFocused(false)), |
| | onClick: (0, import_primitive.composeEventHandlers)(itemProps.onClick, () => { |
| | if (pointerTypeRef.current !== "mouse") handleSelect(); |
| | }), |
| | onPointerUp: (0, import_primitive.composeEventHandlers)(itemProps.onPointerUp, () => { |
| | if (pointerTypeRef.current === "mouse") handleSelect(); |
| | }), |
| | onPointerDown: (0, import_primitive.composeEventHandlers)(itemProps.onPointerDown, (event) => { |
| | pointerTypeRef.current = event.pointerType; |
| | }), |
| | onPointerMove: (0, import_primitive.composeEventHandlers)(itemProps.onPointerMove, (event) => { |
| | pointerTypeRef.current = event.pointerType; |
| | if (disabled) { |
| | contentContext.onItemLeave?.(); |
| | } else if (pointerTypeRef.current === "mouse") { |
| | event.currentTarget.focus({ preventScroll: true }); |
| | } |
| | }), |
| | onPointerLeave: (0, import_primitive.composeEventHandlers)(itemProps.onPointerLeave, (event) => { |
| | if (event.currentTarget === document.activeElement) { |
| | contentContext.onItemLeave?.(); |
| | } |
| | }), |
| | onKeyDown: (0, import_primitive.composeEventHandlers)(itemProps.onKeyDown, (event) => { |
| | const isTypingAhead = contentContext.searchRef?.current !== ""; |
| | if (isTypingAhead && event.key === " ") return; |
| | if (SELECTION_KEYS.includes(event.key)) handleSelect(); |
| | if (event.key === " ") event.preventDefault(); |
| | }) |
| | } |
| | ) |
| | } |
| | ) |
| | } |
| | ); |
| | } |
| | ); |
| | SelectItem.displayName = ITEM_NAME; |
| | var ITEM_TEXT_NAME = "SelectItemText"; |
| | var SelectItemText = React.forwardRef( |
| | (props, forwardedRef) => { |
| | 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 = (0, import_react_compose_refs.useComposedRefs)( |
| | forwardedRef, |
| | (node) => setItemTextNode(node), |
| | itemContext.onItemTextChange, |
| | (node) => contentContext.itemTextRefCallback?.(node, itemContext.value, itemContext.disabled) |
| | ); |
| | const textContent = itemTextNode?.textContent; |
| | const nativeOption = React.useMemo( |
| | () => (0, import_jsx_runtime.jsx)("option", { value: itemContext.value, disabled: itemContext.disabled, children: textContent }, itemContext.value), |
| | [itemContext.disabled, itemContext.value, textContent] |
| | ); |
| | const { onNativeOptionAdd, onNativeOptionRemove } = nativeOptionsContext; |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => { |
| | onNativeOptionAdd(nativeOption); |
| | return () => onNativeOptionRemove(nativeOption); |
| | }, [onNativeOptionAdd, onNativeOptionRemove, nativeOption]); |
| | return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ |
| | (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.span, { id: itemContext.textId, ...itemTextProps, ref: composedRefs }), |
| | itemContext.isSelected && context.valueNode && !context.valueNodeHasChildren ? ReactDOM.createPortal(itemTextProps.children, context.valueNode) : null |
| | ] }); |
| | } |
| | ); |
| | SelectItemText.displayName = ITEM_TEXT_NAME; |
| | var ITEM_INDICATOR_NAME = "SelectItemIndicator"; |
| | var SelectItemIndicator = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, ...itemIndicatorProps } = props; |
| | const itemContext = useSelectItemContext(ITEM_INDICATOR_NAME, __scopeSelect); |
| | return itemContext.isSelected ? (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.span, { "aria-hidden": true, ...itemIndicatorProps, ref: forwardedRef }) : null; |
| | } |
| | ); |
| | SelectItemIndicator.displayName = ITEM_INDICATOR_NAME; |
| | var SCROLL_UP_BUTTON_NAME = "SelectScrollUpButton"; |
| | var SelectScrollUpButton = React.forwardRef((props, 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 = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, viewportContext.onScrollButtonChange); |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => { |
| | if (contentContext.viewport && contentContext.isPositioned) { |
| | let handleScroll2 = function() { |
| | const canScrollUp2 = viewport.scrollTop > 0; |
| | setCanScrollUp(canScrollUp2); |
| | }; |
| | var handleScroll = handleScroll2; |
| | const viewport = contentContext.viewport; |
| | handleScroll2(); |
| | viewport.addEventListener("scroll", handleScroll2); |
| | return () => viewport.removeEventListener("scroll", handleScroll2); |
| | } |
| | }, [contentContext.viewport, contentContext.isPositioned]); |
| | return canScrollUp ? (0, import_jsx_runtime.jsx)( |
| | SelectScrollButtonImpl, |
| | { |
| | ...props, |
| | ref: composedRefs, |
| | onAutoScroll: () => { |
| | const { viewport, selectedItem } = contentContext; |
| | if (viewport && selectedItem) { |
| | viewport.scrollTop = viewport.scrollTop - selectedItem.offsetHeight; |
| | } |
| | } |
| | } |
| | ) : null; |
| | }); |
| | SelectScrollUpButton.displayName = SCROLL_UP_BUTTON_NAME; |
| | var SCROLL_DOWN_BUTTON_NAME = "SelectScrollDownButton"; |
| | var SelectScrollDownButton = React.forwardRef((props, 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 = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, viewportContext.onScrollButtonChange); |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => { |
| | if (contentContext.viewport && contentContext.isPositioned) { |
| | let handleScroll2 = function() { |
| | const maxScroll = viewport.scrollHeight - viewport.clientHeight; |
| | const canScrollDown2 = Math.ceil(viewport.scrollTop) < maxScroll; |
| | setCanScrollDown(canScrollDown2); |
| | }; |
| | var handleScroll = handleScroll2; |
| | const viewport = contentContext.viewport; |
| | handleScroll2(); |
| | viewport.addEventListener("scroll", handleScroll2); |
| | return () => viewport.removeEventListener("scroll", handleScroll2); |
| | } |
| | }, [contentContext.viewport, contentContext.isPositioned]); |
| | return canScrollDown ? (0, import_jsx_runtime.jsx)( |
| | SelectScrollButtonImpl, |
| | { |
| | ...props, |
| | ref: composedRefs, |
| | onAutoScroll: () => { |
| | const { viewport, selectedItem } = contentContext; |
| | if (viewport && selectedItem) { |
| | viewport.scrollTop = viewport.scrollTop + selectedItem.offsetHeight; |
| | } |
| | } |
| | } |
| | ) : null; |
| | }); |
| | SelectScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME; |
| | var SelectScrollButtonImpl = React.forwardRef((props, 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]); |
| | (0, import_react_use_layout_effect.useLayoutEffect)(() => { |
| | const activeItem = getItems().find((item) => item.ref.current === document.activeElement); |
| | activeItem?.ref.current?.scrollIntoView({ block: "nearest" }); |
| | }, [getItems]); |
| | return (0, import_jsx_runtime.jsx)( |
| | import_react_primitive.Primitive.div, |
| | { |
| | "aria-hidden": true, |
| | ...scrollIndicatorProps, |
| | ref: forwardedRef, |
| | style: { flexShrink: 0, ...scrollIndicatorProps.style }, |
| | onPointerDown: (0, import_primitive.composeEventHandlers)(scrollIndicatorProps.onPointerDown, () => { |
| | if (autoScrollTimerRef.current === null) { |
| | autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50); |
| | } |
| | }), |
| | onPointerMove: (0, import_primitive.composeEventHandlers)(scrollIndicatorProps.onPointerMove, () => { |
| | contentContext.onItemLeave?.(); |
| | if (autoScrollTimerRef.current === null) { |
| | autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50); |
| | } |
| | }), |
| | onPointerLeave: (0, import_primitive.composeEventHandlers)(scrollIndicatorProps.onPointerLeave, () => { |
| | clearAutoScrollTimer(); |
| | }) |
| | } |
| | ); |
| | }); |
| | var SEPARATOR_NAME = "SelectSeparator"; |
| | var SelectSeparator = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { __scopeSelect, ...separatorProps } = props; |
| | return (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { "aria-hidden": true, ...separatorProps, ref: forwardedRef }); |
| | } |
| | ); |
| | SelectSeparator.displayName = SEPARATOR_NAME; |
| | var ARROW_NAME = "SelectArrow"; |
| | var SelectArrow = React.forwardRef( |
| | (props, 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" ? (0, import_jsx_runtime.jsx)(PopperPrimitive.Arrow, { ...popperScope, ...arrowProps, ref: forwardedRef }) : null; |
| | } |
| | ); |
| | SelectArrow.displayName = ARROW_NAME; |
| | function shouldShowPlaceholder(value) { |
| | return value === "" || value === void 0; |
| | } |
| | var BubbleSelect = React.forwardRef( |
| | (props, forwardedRef) => { |
| | const { value, ...selectProps } = props; |
| | const ref = React.useRef(null); |
| | const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref); |
| | const prevValue = (0, import_react_use_previous.usePrevious)(value); |
| | React.useEffect(() => { |
| | const select = ref.current; |
| | const selectProto = window.HTMLSelectElement.prototype; |
| | const descriptor = Object.getOwnPropertyDescriptor( |
| | selectProto, |
| | "value" |
| | ); |
| | const setValue = descriptor.set; |
| | if (prevValue !== value && setValue) { |
| | const event = new Event("change", { bubbles: true }); |
| | setValue.call(select, value); |
| | select.dispatchEvent(event); |
| | } |
| | }, [prevValue, value]); |
| | return (0, import_jsx_runtime.jsx)(import_react_visually_hidden.VisuallyHidden, { asChild: true, children: (0, import_jsx_runtime.jsx)("select", { ...selectProps, ref: composedRefs, defaultValue: value }) }); |
| | } |
| | ); |
| | BubbleSelect.displayName = "BubbleSelect"; |
| | function useTypeaheadSearch(onSearchChange) { |
| | const handleSearchChange = (0, import_react_use_callback_ref.useCallbackRef)(onSearchChange); |
| | const searchRef = React.useRef(""); |
| | const timerRef = React.useRef(0); |
| | const handleTypeaheadSearch = React.useCallback( |
| | (key) => { |
| | const search = searchRef.current + key; |
| | handleSearchChange(search); |
| | (function updateSearch(value) { |
| | searchRef.current = value; |
| | window.clearTimeout(timerRef.current); |
| | if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3); |
| | })(search); |
| | }, |
| | [handleSearchChange] |
| | ); |
| | const resetTypeahead = React.useCallback(() => { |
| | searchRef.current = ""; |
| | window.clearTimeout(timerRef.current); |
| | }, []); |
| | React.useEffect(() => { |
| | return () => window.clearTimeout(timerRef.current); |
| | }, []); |
| | return [searchRef, handleTypeaheadSearch, resetTypeahead]; |
| | } |
| | function findNextItem(items, search, currentItem) { |
| | 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 : void 0; |
| | } |
| | function wrapArray(array, startIndex) { |
| | return array.map((_, index) => array[(startIndex + index) % array.length]); |
| | } |
| | var Root2 = Select; |
| | var Trigger = SelectTrigger; |
| | var Value = SelectValue; |
| | var Icon = SelectIcon; |
| | var Portal = SelectPortal; |
| | var Content2 = SelectContent; |
| | var Viewport = SelectViewport; |
| | var Group = SelectGroup; |
| | var Label = SelectLabel; |
| | var Item = SelectItem; |
| | var ItemText = SelectItemText; |
| | var ItemIndicator = SelectItemIndicator; |
| | var ScrollUpButton = SelectScrollUpButton; |
| | var ScrollDownButton = SelectScrollDownButton; |
| | var Separator = SelectSeparator; |
| | var Arrow2 = SelectArrow; |
| | |
| |
|