react-wheel-select 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +575 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +241 -0
- package/dist/index.d.ts +241 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +391 -0
- package/package.json +93 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/WheelSelect.tsx","../src/components/BaseSelectCompat.tsx"],"names":["defaultTheme","defaultSizing","defaultBehavior","DefaultChevronIcon","size","className","jsxs","jsx","DefaultArrowIcon","toCssValue","value","defaultValue","mergeDeep","target","source","result","key","WheelSelectInner","props","ref","options","onChange","placeholder","disabled","required","name","id","style","themeProp","sizingProp","behaviorProp","icons","a11y","callbacks","renderTrigger","renderOption","zIndex","theme","useMemo","sizing","behavior","isOpen","setIsOpen","useState","activeIndex","setActiveIndex","o","triggerRect","setTriggerRect","triggerRef","useRef","selectRef","wheelRef","itemRefs","initialScrollIndexRef","scrollTimeoutRef","isScrollingRef","selectedOption","displayLabel","useEffect","idx","spacerHeight","wheelH","optionH","openPicker","useCallback","targetIndex","closePicker","commitSelection","newValue","option","wheel","item","wheelHeight","itemHeight","scrollTarget","calculateActiveFromScroll","wheelRect","wheelCenter","closestIndex","closestDistance","index","itemRect","itemCenter","distance","handleScroll","handlePickerKeyDown","e","prev","newIndex","firstEnabled","lastEnabled","handleItemClick","handleBackdropClick","handleNativeChange","scrollToIndex","useImperativeHandle","cssVariables","colorSchemeClass","renderPicker","portalTarget","createPortal","isActive","isSelected","el","WheelSelect","forwardRef","WheelSelect_default","ChevronIcon","ArrowLeftIcon","BaseSelectCompat","handleItemSelect","handleWheelClick","optionEl","optionId","renderFallbackPicker"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n forwardRef,\n useImperativeHandle,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type CSSProperties,\n} from 'react'\nimport { createPortal } from 'react-dom'\n\n// ============================================================================\n// Types & Interfaces\n// ============================================================================\n\n/**\n * Represents a single option in the select dropdown\n */\nexport interface WheelSelectOption<T extends string = string> {\n /** Unique value for the option */\n value: T\n /** Display label for the option */\n label: string\n /** Optional disabled state */\n disabled?: boolean\n /** Optional custom data attached to the option */\n data?: Record<string, unknown>\n}\n\n/**\n * Theme configuration for the wheel select\n */\nexport interface WheelSelectTheme {\n /** Color scheme: 'dark' | 'light' | 'auto' */\n colorScheme?: 'dark' | 'light' | 'auto'\n /** Custom colors */\n colors?: {\n /** Text color */\n text?: string\n /** Text color when inactive/faded */\n textMuted?: string\n /** Background color for active item pill */\n activeBg?: string\n /** Background color for hover states */\n hoverBg?: string\n /** Backdrop overlay color */\n backdropBg?: string\n /** Focus ring color */\n focusRing?: string\n }\n /** Border radius for pill shapes */\n borderRadius?: number | string\n /** Font settings */\n font?: {\n /** Font family */\n family?: string\n /** Font size for options */\n size?: number | string\n /** Font weight for options */\n weight?: number | string\n /** Font size for trigger */\n triggerSize?: number | string\n }\n /** Animation settings */\n animation?: {\n /** Duration in ms */\n duration?: number\n /** Easing function */\n easing?: string\n /** Disable all animations */\n disabled?: boolean\n }\n /** Spacing settings */\n spacing?: {\n /** Gap between trigger text and icon */\n triggerGap?: number | string\n /** Padding for trigger button */\n triggerPadding?: string\n /** Gap between option text and icon */\n optionGap?: number | string\n /** Padding for options */\n optionPadding?: string\n }\n}\n\n/**\n * Sizing configuration for the wheel\n */\nexport interface WheelSelectSizing {\n /** Height of the wheel viewport */\n wheelHeight?: number | string\n /** Minimum width of the wheel */\n wheelMinWidth?: number | string\n /** Height of each option item */\n optionHeight?: number | string\n /** Icon size */\n iconSize?: number\n}\n\n/**\n * Behavior configuration\n */\nexport interface WheelSelectBehavior {\n /** Close on outside click (default: true) */\n closeOnOutsideClick?: boolean\n /** Close on Escape key (default: true) */\n closeOnEscape?: boolean\n /** Close on selection (default: true) */\n closeOnSelect?: boolean\n /** Scroll debounce delay in ms (default: 50) */\n scrollDebounceMs?: number\n /** Enable keyboard navigation (default: true) */\n keyboardNavigation?: boolean\n /** Portal target element (default: document.body) */\n portalTarget?: HTMLElement | null\n /** Focus trigger after close (default: true) */\n focusTriggerOnClose?: boolean\n}\n\n/**\n * Custom icon components\n */\nexport interface WheelSelectIcons {\n /** Custom chevron icon for closed state */\n chevron?: ReactNode\n /** Custom arrow icon for active item */\n arrow?: ReactNode\n /** Hide chevron icon */\n hideChevron?: boolean\n /** Hide arrow icon on active item */\n hideArrow?: boolean\n}\n\n/**\n * Accessibility configuration\n */\nexport interface WheelSelectA11y {\n /** Aria label for the trigger button */\n triggerLabel?: string\n /** Aria label for the picker dialog */\n pickerLabel?: string\n /** Custom aria-describedby id */\n describedBy?: string\n}\n\n/**\n * Event callbacks\n */\nexport interface WheelSelectCallbacks<T extends string = string> {\n /** Called when the picker opens */\n onOpen?: () => void\n /** Called when the picker closes */\n onClose?: () => void\n /** Called when value changes */\n onChange?: (value: T, option: WheelSelectOption<T>) => void\n /** Called when active (highlighted) item changes during scroll */\n onActiveChange?: (index: number, option: WheelSelectOption<T>) => void\n /** Called on keyboard navigation */\n onKeyDown?: (event: KeyboardEvent) => void\n}\n\n/**\n * Ref handle for imperative control\n */\nexport interface WheelSelectRef {\n /** Open the picker programmatically */\n open: () => void\n /** Close the picker programmatically */\n close: () => void\n /** Toggle the picker */\n toggle: () => void\n /** Focus the trigger */\n focus: () => void\n /** Get current open state */\n isOpen: () => boolean\n /** Scroll to a specific option by index */\n scrollToIndex: (index: number) => void\n /** Get the underlying native select element */\n getNativeSelect: () => HTMLSelectElement | null\n}\n\n/**\n * Main component props\n */\nexport interface WheelSelectProps<T extends string = string> {\n /** Array of options */\n options: WheelSelectOption<T>[]\n /** Currently selected value */\n value: T\n /** Change handler */\n onChange: (value: T) => void\n /** Placeholder text when no value selected */\n placeholder?: string\n /** Disabled state */\n disabled?: boolean\n /** Required field indicator */\n required?: boolean\n /** Name attribute for form submission */\n name?: string\n /** ID attribute */\n id?: string\n /** Additional CSS class */\n className?: string\n /** Inline styles */\n style?: CSSProperties\n /** Theme configuration */\n theme?: WheelSelectTheme\n /** Sizing configuration */\n sizing?: WheelSelectSizing\n /** Behavior configuration */\n behavior?: WheelSelectBehavior\n /** Custom icons */\n icons?: WheelSelectIcons\n /** Accessibility configuration */\n a11y?: WheelSelectA11y\n /** Event callbacks */\n callbacks?: WheelSelectCallbacks<T>\n /** Custom trigger renderer */\n renderTrigger?: (props: {\n value: T\n label: string\n isOpen: boolean\n disabled: boolean\n onClick: () => void\n }) => ReactNode\n /** Custom option renderer */\n renderOption?: (props: {\n option: WheelSelectOption<T>\n index: number\n isActive: boolean\n isSelected: boolean\n }) => ReactNode\n /** Z-index for the picker overlay */\n zIndex?: number\n}\n\n// ============================================================================\n// Default Values\n// ============================================================================\n\nconst defaultTheme: Required<WheelSelectTheme> = {\n colorScheme: 'dark',\n colors: {\n text: 'inherit',\n textMuted: 'inherit',\n activeBg: 'rgba(255, 255, 255, 0.12)',\n hoverBg: 'rgba(255, 255, 255, 0.12)',\n backdropBg: 'rgba(0, 0, 0, 0.5)',\n focusRing: 'rgba(255, 255, 255, 0.5)',\n },\n borderRadius: 12,\n font: {\n family: 'inherit',\n size: 28,\n weight: 500,\n triggerSize: 'inherit',\n },\n animation: {\n duration: 200,\n easing: 'ease',\n disabled: false,\n },\n spacing: {\n triggerGap: 16,\n triggerPadding: '8px 16px',\n optionGap: 16,\n optionPadding: '0 20px',\n },\n}\n\nconst defaultSizing: Required<WheelSelectSizing> = {\n wheelHeight: 320,\n wheelMinWidth: 220,\n optionHeight: 56,\n iconSize: 20,\n}\n\nconst defaultBehavior: Required<WheelSelectBehavior> = {\n closeOnOutsideClick: true,\n closeOnEscape: true,\n closeOnSelect: true,\n scrollDebounceMs: 50,\n keyboardNavigation: true,\n portalTarget: null,\n focusTriggerOnClose: true,\n}\n\n// ============================================================================\n// Icon Components\n// ============================================================================\n\ninterface IconProps {\n size?: number\n className?: string\n}\n\nconst DefaultChevronIcon = ({ size = 20, className }: IconProps) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n aria-hidden=\"true\"\n >\n <polyline points=\"8 9 12 5 16 9\" />\n <polyline points=\"8 15 12 19 16 15\" />\n </svg>\n)\n\nconst DefaultArrowIcon = ({ size = 20, className }: IconProps) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n aria-hidden=\"true\"\n >\n <line x1=\"19\" y1=\"12\" x2=\"5\" y2=\"12\" />\n <polyline points=\"12 19 5 12 12 5\" />\n </svg>\n)\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\nconst toCssValue = (value: number | string | undefined, defaultValue: string = '0'): string => {\n if (value === undefined) return defaultValue\n return typeof value === 'number' ? `${value}px` : value\n}\n\nconst mergeDeep = <T extends Record<string, unknown>>(target: T, source: Partial<T>): T => {\n const result = { ...target }\n for (const key in source) {\n if (source[key] !== undefined) {\n if (\n typeof source[key] === 'object' &&\n source[key] !== null &&\n !Array.isArray(source[key])\n ) {\n result[key] = mergeDeep(\n target[key] as Record<string, unknown>,\n source[key] as Record<string, unknown>\n ) as T[Extract<keyof T, string>]\n } else {\n result[key] = source[key] as T[Extract<keyof T, string>]\n }\n }\n }\n return result\n}\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nfunction WheelSelectInner<T extends string = string>(\n props: WheelSelectProps<T>,\n ref: React.ForwardedRef<WheelSelectRef>\n) {\n const {\n options,\n value,\n onChange,\n placeholder = 'Select...',\n disabled = false,\n required = false,\n name,\n id,\n className = '',\n style,\n theme: themeProp,\n sizing: sizingProp,\n behavior: behaviorProp,\n icons,\n a11y,\n callbacks,\n renderTrigger,\n renderOption,\n zIndex = 10001,\n } = props\n\n // Merge configurations with defaults\n const theme = useMemo(\n () => mergeDeep(defaultTheme, themeProp || {}),\n [themeProp]\n )\n const sizing = useMemo(\n () => mergeDeep(defaultSizing, sizingProp || {}),\n [sizingProp]\n )\n const behavior = useMemo(\n () => mergeDeep(defaultBehavior, behaviorProp || {}),\n [behaviorProp]\n )\n\n // State\n const [isOpen, setIsOpen] = useState(false)\n const [activeIndex, setActiveIndex] = useState(() =>\n Math.max(0, options.findIndex(o => o.value === value))\n )\n const [triggerRect, setTriggerRect] = useState<DOMRect | null>(null)\n\n // Refs\n const triggerRef = useRef<HTMLButtonElement>(null)\n const selectRef = useRef<HTMLSelectElement>(null)\n const wheelRef = useRef<HTMLDivElement>(null)\n const itemRefs = useRef<(HTMLDivElement | null)[]>([])\n const initialScrollIndexRef = useRef<number | null>(null)\n const scrollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const isScrollingRef = useRef(false)\n\n // Computed values\n const selectedOption = useMemo(\n () => options.find(o => o.value === value),\n [options, value]\n )\n const displayLabel = selectedOption?.label ?? placeholder\n\n // Keep active index in sync when value changes externally\n useEffect(() => {\n const idx = options.findIndex(o => o.value === value)\n if (idx !== -1) {\n setActiveIndex(idx)\n }\n }, [value, options])\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (scrollTimeoutRef.current) {\n clearTimeout(scrollTimeoutRef.current)\n }\n }\n }, [])\n\n // Calculate spacer height based on wheel and option heights\n const spacerHeight = useMemo(() => {\n const wheelH = typeof sizing.wheelHeight === 'number' ? sizing.wheelHeight : 320\n const optionH = typeof sizing.optionHeight === 'number' ? sizing.optionHeight : 56\n return (wheelH / 2) - (optionH / 2)\n }, [sizing.wheelHeight, sizing.optionHeight])\n\n // Open picker\n const openPicker = useCallback(() => {\n if (disabled) return\n if (triggerRef.current) {\n setTriggerRect(triggerRef.current.getBoundingClientRect())\n }\n const idx = options.findIndex(o => o.value === value)\n const targetIndex = idx !== -1 ? idx : 0\n initialScrollIndexRef.current = targetIndex\n setActiveIndex(targetIndex)\n setIsOpen(true)\n callbacks?.onOpen?.()\n }, [disabled, options, value, callbacks])\n\n // Close picker\n const closePicker = useCallback(() => {\n setIsOpen(false)\n if (behavior.focusTriggerOnClose) {\n triggerRef.current?.focus()\n }\n callbacks?.onClose?.()\n }, [behavior.focusTriggerOnClose, callbacks])\n\n // Commit selection\n const commitSelection = useCallback((newValue: T) => {\n const option = options.find(o => o.value === newValue)\n if (!option || option.disabled) return\n\n onChange(newValue)\n callbacks?.onChange?.(newValue, option)\n\n if (selectRef.current) {\n selectRef.current.value = newValue\n }\n\n if (behavior.closeOnSelect) {\n setIsOpen(false)\n if (behavior.focusTriggerOnClose) {\n triggerRef.current?.focus()\n }\n callbacks?.onClose?.()\n }\n }, [onChange, options, behavior.closeOnSelect, behavior.focusTriggerOnClose, callbacks])\n\n // Scroll to selected item when picker opens\n useEffect(() => {\n if (isOpen && initialScrollIndexRef.current !== null) {\n const targetIndex = initialScrollIndexRef.current\n initialScrollIndexRef.current = null\n\n requestAnimationFrame(() => {\n const wheel = wheelRef.current\n const item = itemRefs.current[targetIndex]\n if (wheel && item) {\n const wheelHeight = wheel.clientHeight\n const itemHeight = item.clientHeight\n const itemTop = item.offsetTop\n const scrollTarget = itemTop - (wheelHeight / 2) + (itemHeight / 2)\n wheel.scrollTop = scrollTarget\n }\n })\n }\n }, [isOpen])\n\n // Focus wheel when picker opens\n useEffect(() => {\n if (isOpen && wheelRef.current) {\n wheelRef.current.focus()\n }\n }, [isOpen])\n\n // Calculate active index from scroll position\n const calculateActiveFromScroll = useCallback(() => {\n const wheel = wheelRef.current\n if (!wheel) return\n\n const wheelRect = wheel.getBoundingClientRect()\n const wheelCenter = wheelRect.top + wheelRect.height / 2\n\n let closestIndex = 0\n let closestDistance = Infinity\n\n itemRefs.current.forEach((item, index) => {\n if (!item) return\n const itemRect = item.getBoundingClientRect()\n const itemCenter = itemRect.top + itemRect.height / 2\n const distance = Math.abs(itemCenter - wheelCenter)\n\n if (distance < closestDistance) {\n closestDistance = distance\n closestIndex = index\n }\n })\n\n setActiveIndex(closestIndex)\n const option = options[closestIndex]\n if (option) {\n callbacks?.onActiveChange?.(closestIndex, option)\n }\n }, [options, callbacks])\n\n // Handle scroll with debounce\n const handleScroll = useCallback(() => {\n isScrollingRef.current = true\n\n if (scrollTimeoutRef.current) {\n clearTimeout(scrollTimeoutRef.current)\n }\n\n scrollTimeoutRef.current = setTimeout(() => {\n isScrollingRef.current = false\n calculateActiveFromScroll()\n }, behavior.scrollDebounceMs)\n }, [calculateActiveFromScroll, behavior.scrollDebounceMs])\n\n // Keyboard navigation\n const handlePickerKeyDown = useCallback((e: KeyboardEvent) => {\n if (!behavior.keyboardNavigation) return\n\n callbacks?.onKeyDown?.(e)\n\n switch (e.key) {\n case 'Escape':\n if (behavior.closeOnEscape) {\n e.preventDefault()\n closePicker()\n }\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex(prev => {\n let newIndex = prev - 1\n // Skip disabled options\n while (newIndex >= 0 && options[newIndex]?.disabled) {\n newIndex--\n }\n if (newIndex < 0) return prev\n const item = itemRefs.current[newIndex]\n item?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n return newIndex\n })\n break\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex(prev => {\n let newIndex = prev + 1\n // Skip disabled options\n while (newIndex < options.length && options[newIndex]?.disabled) {\n newIndex++\n }\n if (newIndex >= options.length) return prev\n const item = itemRefs.current[newIndex]\n item?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n return newIndex\n })\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n const option = options[activeIndex]\n if (option && !option.disabled) {\n commitSelection(option.value)\n }\n break\n case 'Home':\n e.preventDefault()\n const firstEnabled = options.findIndex(o => !o.disabled)\n if (firstEnabled !== -1) {\n setActiveIndex(firstEnabled)\n itemRefs.current[firstEnabled]?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n }\n break\n case 'End':\n e.preventDefault()\n const lastEnabled = options.findLastIndex(o => !o.disabled)\n if (lastEnabled !== -1) {\n setActiveIndex(lastEnabled)\n itemRefs.current[lastEnabled]?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n }\n break\n }\n }, [behavior.keyboardNavigation, behavior.closeOnEscape, options, activeIndex, closePicker, commitSelection, callbacks])\n\n // Handle item click\n const handleItemClick = useCallback((index: number) => (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (scrollTimeoutRef.current) {\n clearTimeout(scrollTimeoutRef.current)\n scrollTimeoutRef.current = null\n }\n const option = options[index]\n if (option && !option.disabled) {\n commitSelection(option.value)\n }\n }, [options, commitSelection])\n\n // Handle backdrop click\n const handleBackdropClick = useCallback((e: MouseEvent) => {\n if (behavior.closeOnOutsideClick && e.target === e.currentTarget) {\n closePicker()\n }\n }, [behavior.closeOnOutsideClick, closePicker])\n\n // Handle native select change\n const handleNativeChange = useCallback((e: React.ChangeEvent<HTMLSelectElement>) => {\n onChange(e.target.value as T)\n }, [onChange])\n\n // Scroll to specific index\n const scrollToIndex = useCallback((index: number) => {\n const item = itemRefs.current[index]\n item?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n }, [])\n\n // Imperative handle\n useImperativeHandle(ref, () => ({\n open: openPicker,\n close: closePicker,\n toggle: () => isOpen ? closePicker() : openPicker(),\n focus: () => triggerRef.current?.focus(),\n isOpen: () => isOpen,\n scrollToIndex,\n getNativeSelect: () => selectRef.current,\n }), [isOpen, openPicker, closePicker, scrollToIndex])\n\n // Generate CSS custom properties\n const cssVariables = useMemo((): CSSProperties => ({\n '--ws-color-text': theme.colors.text,\n '--ws-color-text-muted': theme.colors.textMuted,\n '--ws-color-active-bg': theme.colors.activeBg,\n '--ws-color-hover-bg': theme.colors.hoverBg,\n '--ws-color-backdrop-bg': theme.colors.backdropBg,\n '--ws-color-focus-ring': theme.colors.focusRing,\n '--ws-border-radius': toCssValue(theme.borderRadius),\n '--ws-font-family': theme.font.family,\n '--ws-font-size': toCssValue(theme.font.size),\n '--ws-font-weight': String(theme.font.weight),\n '--ws-font-size-trigger': toCssValue(theme.font.triggerSize),\n '--ws-animation-duration': theme.animation.disabled ? '0ms' : `${theme.animation.duration}ms`,\n '--ws-animation-easing': theme.animation.easing,\n '--ws-trigger-gap': toCssValue(theme.spacing.triggerGap),\n '--ws-trigger-padding': theme.spacing.triggerPadding,\n '--ws-option-gap': toCssValue(theme.spacing.optionGap),\n '--ws-option-padding': theme.spacing.optionPadding,\n '--ws-wheel-height': toCssValue(sizing.wheelHeight),\n '--ws-wheel-min-width': toCssValue(sizing.wheelMinWidth),\n '--ws-option-height': toCssValue(sizing.optionHeight),\n '--ws-icon-size': `${sizing.iconSize}px`,\n '--ws-spacer-height': `${spacerHeight}px`,\n '--ws-z-index': String(zIndex),\n } as CSSProperties), [theme, sizing, spacerHeight, zIndex])\n\n // Determine color scheme class\n const colorSchemeClass = theme.colorScheme === 'auto'\n ? ''\n : theme.colorScheme === 'light'\n ? 'ws-light'\n : 'ws-dark'\n\n // Render the picker portal\n const renderPicker = () => {\n if (!isOpen || !triggerRect) return null\n\n const portalTarget = behavior.portalTarget ?? document.body\n\n return createPortal(\n <div\n className=\"ws-backdrop\"\n onClick={handleBackdropClick}\n role=\"presentation\"\n style={cssVariables}\n >\n <div\n className=\"ws-picker\"\n style={{\n left: triggerRect.left,\n top: triggerRect.top + triggerRect.height / 2,\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={a11y?.pickerLabel ?? 'Select an option'}\n >\n <div\n ref={wheelRef}\n className=\"ws-wheel\"\n role=\"listbox\"\n tabIndex={0}\n onKeyDown={handlePickerKeyDown}\n onScroll={handleScroll}\n aria-activedescendant={`ws-option-${id ?? 'default'}-${activeIndex}`}\n aria-describedby={a11y?.describedBy}\n >\n <div className=\"ws-spacer\" aria-hidden=\"true\" />\n\n {options.map((option, index) => {\n const isActive = index === activeIndex\n const isSelected = option.value === value\n\n if (renderOption) {\n return (\n <div\n key={option.value}\n ref={el => { itemRefs.current[index] = el }}\n id={`ws-option-${id ?? 'default'}-${index}`}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled}\n className={`ws-option ${isActive ? 'ws-active' : ''} ${option.disabled ? 'ws-disabled' : ''}`}\n onClick={handleItemClick(index)}\n >\n {renderOption({ option, index, isActive, isSelected })}\n </div>\n )\n }\n\n return (\n <div\n key={option.value}\n ref={el => { itemRefs.current[index] = el }}\n id={`ws-option-${id ?? 'default'}-${index}`}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled}\n className={`ws-option ${isActive ? 'ws-active' : ''} ${option.disabled ? 'ws-disabled' : ''}`}\n onClick={handleItemClick(index)}\n >\n <span className=\"ws-option-text\">{option.label}</span>\n {isActive && !icons?.hideArrow && (\n icons?.arrow ?? <DefaultArrowIcon size={sizing.iconSize} className=\"ws-arrow\" />\n )}\n </div>\n )\n })}\n\n <div className=\"ws-spacer\" aria-hidden=\"true\" />\n </div>\n </div>\n </div>,\n portalTarget\n )\n }\n\n return (\n <span\n className={`ws-root ${colorSchemeClass} ${className}`}\n style={{ ...cssVariables, ...style }}\n >\n {/* Hidden native select for form submission */}\n <select\n ref={selectRef}\n name={name}\n id={id ? `${id}-native` : undefined}\n value={value}\n onChange={handleNativeChange}\n className=\"ws-native-select\"\n tabIndex={-1}\n aria-hidden=\"true\"\n required={required}\n disabled={disabled}\n >\n {!selectedOption && <option value=\"\">{placeholder}</option>}\n {options.map(option => (\n <option\n key={option.value}\n value={option.value}\n disabled={option.disabled}\n >\n {option.label}\n </option>\n ))}\n </select>\n\n {/* Trigger button */}\n {renderTrigger ? (\n renderTrigger({\n value,\n label: displayLabel,\n isOpen,\n disabled,\n onClick: openPicker,\n })\n ) : (\n <button\n ref={triggerRef}\n type=\"button\"\n id={id}\n className={`ws-trigger ${isOpen ? 'ws-open' : ''}`}\n onClick={openPicker}\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-label={a11y?.triggerLabel}\n aria-describedby={a11y?.describedBy}\n style={{ visibility: isOpen ? 'hidden' : 'visible' }}\n >\n <span className=\"ws-trigger-text\">{displayLabel}</span>\n {!icons?.hideChevron && (\n icons?.chevron ?? <DefaultChevronIcon size={sizing.iconSize} className=\"ws-chevron\" />\n )}\n </button>\n )}\n\n {/* Picker portal */}\n {renderPicker()}\n </span>\n )\n}\n\n// Forward ref with generic support\nexport const WheelSelect = forwardRef(WheelSelectInner) as <T extends string = string>(\n props: WheelSelectProps<T> & { ref?: React.ForwardedRef<WheelSelectRef> }\n) => ReturnType<typeof WheelSelectInner>\n\nexport default WheelSelect\n","import {\n useState,\n useRef,\n useEffect,\n useCallback, \n type KeyboardEvent,\n type MouseEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport './BaseSelectCompat.css'\n\nexport interface SelectOption {\n value: string\n label: string\n}\n\nexport interface BaseSelectCompatProps {\n options: SelectOption[]\n value: string\n onChange: (value: string) => void\n name?: string\n id?: string\n className?: string\n}\n\n// Chevron up/down icon for closed state (diamond/double chevron style)\nconst ChevronIcon = () => (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"base-select-chevron\"\n >\n <polyline points=\"8 9 12 5 16 9\" />\n <polyline points=\"8 15 12 19 16 15\" />\n </svg>\n)\n\n// Left arrow icon for active item in open state\nconst ArrowLeftIcon = () => (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"base-select-arrow\"\n >\n <line x1=\"19\" y1=\"12\" x2=\"5\" y2=\"12\" />\n <polyline points=\"12 19 5 12 12 5\" />\n </svg>\n)\n\n/**\n * BaseSelectCompat - A progressively enhanced select component\n *\n * Uses native stylable select (appearance: base-select) when supported,\n * falls back to a custom inline wheel picker for older browsers.\n */\nexport function BaseSelectCompat({\n options,\n value,\n onChange,\n name,\n id,\n className = '',\n}: BaseSelectCompatProps) {\n // Always use fallback mode for consistent custom styling across browsers\n // The native base-select doesn't match our design requirements\n const useNative = false\n const [isOpen, setIsOpen] = useState(false)\n const [activeIndex, setActiveIndex] = useState(() =>\n Math.max(0, options.findIndex(o => o.value === value))\n )\n\n const triggerRef = useRef<HTMLButtonElement>(null)\n const selectRef = useRef<HTMLSelectElement>(null)\n const wheelRef = useRef<HTMLDivElement>(null)\n const itemRefs = useRef<(HTMLDivElement | null)[]>([])\n\n\n // Track trigger position for inline picker placement\n const [triggerRect, setTriggerRect] = useState<DOMRect | null>(null)\n\n // Keep active index in sync when value changes externally\n useEffect(() => {\n const idx = options.findIndex(o => o.value === value)\n if (idx !== -1) {\n setActiveIndex(idx)\n }\n }, [value, options])\n\n // Get the current selected label\n const selectedOption = options.find(o => o.value === value)\n const displayLabel = selectedOption?.label ?? options[0]?.label ?? ''\n\n // Track the initial index to scroll to when opening\n const initialScrollIndexRef = useRef<number | null>(null)\n\n // Handle opening the picker\n const openPicker = useCallback(() => {\n if (triggerRef.current) {\n setTriggerRect(triggerRef.current.getBoundingClientRect())\n }\n // Calculate and store the index to scroll to\n const idx = options.findIndex(o => o.value === value)\n const targetIndex = idx !== -1 ? idx : 0\n initialScrollIndexRef.current = targetIndex\n setActiveIndex(targetIndex)\n setIsOpen(true)\n }, [options, value])\n\n // Handle closing without selection\n const closePicker = useCallback(() => {\n setIsOpen(false)\n triggerRef.current?.focus()\n }, [])\n\n // Handle selection commit\n const commitSelection = useCallback((newValue: string) => {\n onChange(newValue)\n // Sync with native select\n if (selectRef.current) {\n selectRef.current.value = newValue\n }\n setIsOpen(false)\n triggerRef.current?.focus()\n }, [onChange])\n\n // Scroll to the selected item when picker opens (only once)\n useEffect(() => {\n if (isOpen && initialScrollIndexRef.current !== null) {\n const targetIndex = initialScrollIndexRef.current\n // Clear the ref so we don't scroll again\n initialScrollIndexRef.current = null\n\n // Use requestAnimationFrame to ensure DOM is ready\n requestAnimationFrame(() => {\n const wheel = wheelRef.current\n const item = itemRefs.current[targetIndex]\n if (wheel && item) {\n // Center the item in the wheel (instant scroll, no smooth)\n const wheelHeight = wheel.clientHeight\n const itemHeight = item.clientHeight\n const itemTop = item.offsetTop\n const scrollTarget = itemTop - (wheelHeight / 2) + (itemHeight / 2)\n wheel.scrollTop = scrollTarget\n }\n })\n }\n }, [isOpen])\n\n /**\n * Calculate which item is closest to the center of the scroll container.\n *\n * Math explanation:\n * 1. Find the vertical center of the scroll container viewport\n * 2. For each item, calculate its center position relative to scroll\n * 3. Find the item whose center is closest to the viewport center\n */\n const calculateActiveFromScroll = useCallback(() => {\n const wheel = wheelRef.current\n if (!wheel) return\n\n const wheelRect = wheel.getBoundingClientRect()\n const wheelCenter = wheelRect.top + wheelRect.height / 2\n\n let closestIndex = 0\n let closestDistance = Infinity\n\n itemRefs.current.forEach((item, index) => {\n if (!item) return\n const itemRect = item.getBoundingClientRect()\n const itemCenter = itemRect.top + itemRect.height / 2\n const distance = Math.abs(itemCenter - wheelCenter)\n\n if (distance < closestDistance) {\n closestDistance = distance\n closestIndex = index\n }\n })\n\n setActiveIndex(closestIndex)\n }, [])\n\n // Track scroll state to avoid interference with clicks\n const isScrollingRef = useRef(false)\n const scrollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n /**\n * Handle scroll events - only update visual highlight, don't auto-commit.\n * User must click an item or press Enter to commit selection.\n * Uses a timeout to detect scroll end and avoid interfering with clicks.\n */\n const handleScroll = useCallback(() => {\n isScrollingRef.current = true\n\n // Clear any existing timeout\n if (scrollTimeoutRef.current) {\n clearTimeout(scrollTimeoutRef.current)\n }\n\n // Update active index after a short delay (scroll end detection)\n scrollTimeoutRef.current = setTimeout(() => {\n isScrollingRef.current = false\n calculateActiveFromScroll()\n }, 50)\n }, [calculateActiveFromScroll])\n\n\n // Handle keyboard navigation in picker\n const handlePickerKeyDown = useCallback((e: KeyboardEvent) => {\n switch (e.key) {\n case 'Escape':\n e.preventDefault()\n closePicker()\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex(prev => {\n const newIndex = Math.max(0, prev - 1)\n // Scroll the new active item into view\n const item = itemRefs.current[newIndex]\n item?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n return newIndex\n })\n break\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex(prev => {\n const newIndex = Math.min(options.length - 1, prev + 1)\n const item = itemRefs.current[newIndex]\n item?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n return newIndex\n })\n break\n case 'Enter':\n e.preventDefault()\n if (options[activeIndex]) {\n commitSelection(options[activeIndex].value)\n }\n break\n }\n }, [activeIndex, options, closePicker, commitSelection])\n\n // Handle clicking on an item\n const handleItemSelect = useCallback((index: number) => {\n if (options[index]) {\n commitSelection(options[index].value)\n }\n }, [options, commitSelection])\n\n // Use onClick for click detection - more reliable than pointer events\n const handleItemClick = useCallback((index: number) => (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n // Clear any pending scroll timeout to prevent interference\n if (scrollTimeoutRef.current) {\n clearTimeout(scrollTimeoutRef.current)\n scrollTimeoutRef.current = null\n }\n handleItemSelect(index)\n }, [handleItemSelect])\n\n // Fallback: handle click on wheel using event delegation\n const handleWheelClick = useCallback((e: MouseEvent) => {\n const target = e.target as HTMLElement\n const optionEl = target.closest('.base-select-option') as HTMLElement\n if (optionEl) {\n const optionId = optionEl.id // e.g., \"option-3\"\n const index = parseInt(optionId.replace('option-', ''), 10)\n if (!isNaN(index) && options[index]) {\n handleItemSelect(index)\n }\n }\n }, [options, handleItemSelect])\n\n // Handle backdrop click\n const handleBackdropClick = useCallback((e: MouseEvent) => {\n if (e.target === e.currentTarget) {\n closePicker()\n }\n }, [closePicker])\n\n // Focus trap - focus the wheel when picker opens\n useEffect(() => {\n if (isOpen && wheelRef.current) {\n wheelRef.current.focus()\n }\n }, [isOpen])\n\n // Cleanup scroll timeout on unmount or when picker closes\n useEffect(() => {\n return () => {\n if (scrollTimeoutRef.current) {\n clearTimeout(scrollTimeoutRef.current)\n }\n }\n }, [])\n\n // Handle native select change (for native mode)\n const handleNativeChange = useCallback((e: React.ChangeEvent<HTMLSelectElement>) => {\n onChange(e.target.value)\n }, [onChange])\n\n // Render the fallback inline wheel picker\n const renderFallbackPicker = () => {\n if (!isOpen || !triggerRect) return null\n\n return createPortal(\n <div\n className=\"base-select-backdrop\"\n onClick={handleBackdropClick}\n role=\"presentation\"\n >\n <div\n className=\"base-select-picker\"\n style={{\n // Position the picker so the active item aligns with the trigger\n left: triggerRect.left,\n top: triggerRect.top + triggerRect.height / 2,\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Select an option\"\n >\n <div\n ref={wheelRef}\n className=\"base-select-wheel\"\n role=\"listbox\"\n tabIndex={0}\n onKeyDown={handlePickerKeyDown}\n onScroll={handleScroll}\n onClick={handleWheelClick}\n aria-activedescendant={`option-${activeIndex}`}\n >\n {/* Spacer to allow first item to be centered */}\n <div className=\"base-select-spacer\" aria-hidden=\"true\" />\n\n {options.map((option, index) => (\n <div\n key={option.value}\n ref={el => { itemRefs.current[index] = el }}\n id={`option-${index}`}\n role=\"option\"\n aria-selected={index === activeIndex}\n className={`base-select-option ${index === activeIndex ? 'active' : ''}`}\n onClick={handleItemClick(index)}\n >\n <span className=\"base-select-option-text\">{option.label}</span>\n {index === activeIndex && <ArrowLeftIcon />}\n </div>\n ))}\n\n {/* Spacer to allow last item to be centered */}\n <div className=\"base-select-spacer\" aria-hidden=\"true\" />\n </div>\n </div>\n </div>,\n document.body\n )\n }\n\n // Native mode with appearance: base-select\n if (useNative) {\n return (\n <span className={`base-select-compat native ${className}`}>\n <select\n ref={selectRef}\n name={name}\n id={id}\n value={value}\n onChange={handleNativeChange}\n className=\"base-select-native\"\n >\n {options.map(option => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </span>\n )\n }\n\n // Fallback mode with custom inline wheel picker\n return (\n <span className={`base-select-compat fallback ${className}`}>\n {/* Hidden native select for form submission and semantics */}\n <select\n ref={selectRef}\n name={name}\n id={id}\n value={value}\n onChange={handleNativeChange}\n className=\"base-select-hidden\"\n tabIndex={-1}\n aria-hidden=\"true\"\n >\n {options.map(option => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n\n {/* Text trigger with pill background on hover - hidden when picker is open */}\n <button\n ref={triggerRef}\n type=\"button\"\n className={`base-select-trigger ${isOpen ? 'open' : ''}`}\n onClick={openPicker}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n style={{ visibility: isOpen ? 'hidden' : 'visible' }}\n >\n <span className=\"base-select-trigger-text\">{displayLabel}</span>\n <ChevronIcon />\n </button>\n\n {/* Fallback inline picker */}\n {renderFallbackPicker()}\n </span>\n )\n}\n\nexport default BaseSelectCompat\n"]}
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.base-select-compat.native{display:inline}.base-select-native{appearance:base-select;border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;padding:0;margin:0;opacity:1;transition:opacity .15s ease}.base-select-native:hover{opacity:.7}.base-select-native:active{opacity:.5}.base-select-native::picker(select){appearance:base-select}.base-select-compat.fallback{display:inline;position:relative}.base-select-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.base-select-trigger{border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;margin:0;display:inline-flex;align-items:center;gap:16px;padding:8px 16px;border-radius:12px;transition:background-color .2s ease}.base-select-trigger:hover{background-color:#ffffff1f}.base-select-trigger:focus{outline:none}.base-select-trigger:focus-visible{outline:2px solid rgba(255,255,255,.5);outline-offset:2px}.base-select-trigger.open{background-color:#ffffff1f}.base-select-chevron{opacity:.5;flex-shrink:0}.base-select-backdrop{position:fixed;inset:0;z-index:10001;background:#00000080;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);animation:backdrop-fade-in .2s ease}@keyframes backdrop-fade-in{0%{opacity:0}to{opacity:1}}.base-select-picker{position:absolute;transform:translateY(-50%);animation:picker-fade-in .2s ease}@keyframes picker-fade-in{0%{opacity:0;transform:translateY(-50%) scale(.95)}to{opacity:1;transform:translateY(-50%) scale(1)}}.base-select-wheel{height:320px;min-width:220px;overflow-y:auto;overflow-x:hidden;scroll-snap-type:y proximity;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none}.base-select-wheel::-webkit-scrollbar{display:none}.base-select-wheel:focus{outline:none}.base-select-spacer{height:132px;flex-shrink:0}.base-select-option{height:56px;min-width:200px;display:flex;align-items:center;justify-content:flex-start;gap:16px;padding:0 20px;scroll-snap-align:center;font-size:28px;font-weight:500;color:#fff;cursor:pointer;opacity:.35;transition:opacity .15s ease,background-color .15s ease;user-select:none;border-radius:12px;touch-action:manipulation;position:relative;z-index:1}.base-select-option:hover{opacity:.5}.base-select-option.active{opacity:1;background-color:#ffffff1f}.base-select-option.active:hover{opacity:1}.base-select-option-text{flex:1;pointer-events:none}.base-select-arrow{opacity:.7;flex-shrink:0;pointer-events:none}.base-select-compat.light .base-select-trigger:hover,.base-select-compat.light .base-select-trigger.open{background-color:#00000014}
|
|
2
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/BaseSelectCompat.css"],"sourcesContent":["/**\n * BaseSelectCompat Styles\n *\n * Provides styling for both the native base-select mode and the fallback inline wheel picker.\n * Design matches an inline wheel picker with pill-shaped active item.\n */\n\n/* ========================================\n NATIVE MODE (appearance: base-select)\n ======================================== */\n\n.base-select-compat.native {\n display: inline;\n}\n\n/*\n * Native select styled with base-select.\n * When the browser supports appearance: base-select, we can style the\n * native select and its dropdown picker natively.\n */\n.base-select-native {\n /* Use the new stylable select API */\n appearance: base-select;\n\n /* Match the inline text trigger style */\n border: none;\n background: transparent;\n font: inherit;\n color: inherit;\n cursor: pointer;\n padding: 0;\n margin: 0;\n\n /* Subtle interaction feedback */\n opacity: 1;\n transition: opacity 0.15s ease;\n}\n\n.base-select-native:hover {\n opacity: 0.7;\n}\n\n.base-select-native:active {\n opacity: 0.5;\n}\n\n/* Style the picker popup for browsers that support it */\n.base-select-native::picker(select) {\n appearance: base-select;\n}\n\n/* ========================================\n FALLBACK MODE (Custom Inline Wheel Picker)\n ======================================== */\n\n.base-select-compat.fallback {\n display: inline;\n position: relative;\n}\n\n/* Hidden native select for form submission */\n.base-select-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n/* ========================================\n TRIGGER BUTTON\n ======================================== */\n\n/*\n * Text trigger - plain inline text with chevron icon.\n * Shows pill background only on hover.\n */\n.base-select-trigger {\n /* Reset button styles */\n border: none;\n background: transparent;\n font: inherit;\n color: inherit;\n cursor: pointer;\n margin: 0;\n\n /* Inline flex for text + icon alignment */\n display: inline-flex;\n align-items: center;\n gap: 16px;\n\n /* Padding for pill shape */\n padding: 8px 16px;\n border-radius: 12px;\n\n /* Smooth transitions */\n transition: background-color 0.2s ease;\n}\n\n.base-select-trigger:hover {\n background-color: rgba(255, 255, 255, 0.12);\n}\n\n.base-select-trigger:focus {\n outline: none;\n}\n\n.base-select-trigger:focus-visible {\n outline: 2px solid rgba(255, 255, 255, 0.5);\n outline-offset: 2px;\n}\n\n.base-select-trigger.open {\n background-color: rgba(255, 255, 255, 0.12);\n}\n\n.base-select-trigger-text {\n /* Text styling */\n}\n\n.base-select-chevron {\n opacity: 0.5;\n flex-shrink: 0;\n}\n\n/* ========================================\n BACKDROP\n ======================================== */\n\n/*\n * Backdrop covers the entire viewport with a subtle blur.\n * Clicking it closes the picker without changing value.\n * The blur is subtle enough to keep surrounding text readable.\n */\n.base-select-backdrop {\n position: fixed;\n inset: 0;\n z-index: 10001;\n\n /* Subtle dimmed and blurred background - keeps text readable */\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n\n /* Fade in animation */\n animation: backdrop-fade-in 0.2s ease;\n}\n\n@keyframes backdrop-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ========================================\n PICKER CONTAINER\n ======================================== */\n\n/*\n * The picker is positioned to align with the trigger.\n * It contains the scrollable wheel of options.\n */\n.base-select-picker {\n position: absolute;\n transform: translateY(-50%);\n\n /* Scale in animation */\n animation: picker-fade-in 0.2s ease;\n}\n\n@keyframes picker-fade-in {\n from {\n opacity: 0;\n transform: translateY(-50%) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(-50%) scale(1);\n }\n}\n\n/* ========================================\n WHEEL (Scrollable Options)\n ======================================== */\n\n/*\n * The wheel is a scrollable container with CSS scroll snapping.\n * This creates the iOS-style picker wheel behavior.\n */\n.base-select-wheel {\n /* Fixed viewport height to show ~5 items */\n height: 320px;\n min-width: 220px;\n overflow-y: auto;\n overflow-x: hidden;\n\n /* CSS Scroll Snapping - proximity allows clicks to work better */\n scroll-snap-type: y proximity;\n\n /* Touch momentum scrolling */\n -webkit-overflow-scrolling: touch;\n\n /* Hide scrollbar for cleaner look */\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.base-select-wheel::-webkit-scrollbar {\n display: none;\n}\n\n.base-select-wheel:focus {\n outline: none;\n}\n\n/*\n * Spacers at top and bottom allow first/last items to be centered.\n * Height matches approximately half the wheel height minus half item height.\n */\n.base-select-spacer {\n height: 132px;\n flex-shrink: 0;\n}\n\n/* ========================================\n OPTIONS\n ======================================== */\n\n/*\n * Each option snaps to center when scrolling.\n * Active option has pill background and arrow icon.\n * Inactive options are faded.\n */\n.base-select-option {\n /* Fixed height for consistent scroll behavior */\n height: 56px;\n min-width: 200px;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 16px;\n\n /* Padding for text - full clickable area */\n padding: 0 20px;\n\n /* Snap to center of container */\n scroll-snap-align: center;\n\n /* Text styling */\n font-size: 28px;\n font-weight: 500;\n color: white;\n cursor: pointer;\n\n /* Fade inactive items */\n opacity: 0.35;\n transition: opacity 0.15s ease, background-color 0.15s ease;\n\n /* Prevent text selection during scroll */\n user-select: none;\n\n /* Rounded for pill shape when active */\n border-radius: 12px;\n\n /* Ensure clicks are captured */\n touch-action: manipulation;\n position: relative;\n z-index: 1;\n}\n\n.base-select-option:hover {\n opacity: 0.5;\n}\n\n/*\n * Active option styling - full opacity with pill background.\n * This is the item closest to the center of the wheel.\n */\n.base-select-option.active {\n opacity: 1;\n background-color: rgba(255, 255, 255, 0.12);\n}\n\n.base-select-option.active:hover {\n opacity: 1;\n}\n\n.base-select-option-text {\n flex: 1;\n /* Allow clicks to pass through to parent */\n pointer-events: none;\n}\n\n.base-select-arrow {\n opacity: 0.7;\n flex-shrink: 0;\n /* Allow clicks to pass through to parent */\n pointer-events: none;\n}\n\n/* ========================================\n LIGHT MODE VARIANT\n ======================================== */\n\n/* For light backgrounds, use dark colors */\n.base-select-compat.light .base-select-trigger:hover {\n background-color: rgba(0, 0, 0, 0.08);\n}\n\n.base-select-compat.light .base-select-trigger.open {\n background-color: rgba(0, 0, 0, 0.08);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { CSSProperties, ReactNode, KeyboardEvent } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents a single option in the select dropdown
|
|
6
|
+
*/
|
|
7
|
+
interface WheelSelectOption<T extends string = string> {
|
|
8
|
+
/** Unique value for the option */
|
|
9
|
+
value: T;
|
|
10
|
+
/** Display label for the option */
|
|
11
|
+
label: string;
|
|
12
|
+
/** Optional disabled state */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Optional custom data attached to the option */
|
|
15
|
+
data?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Theme configuration for the wheel select
|
|
19
|
+
*/
|
|
20
|
+
interface WheelSelectTheme {
|
|
21
|
+
/** Color scheme: 'dark' | 'light' | 'auto' */
|
|
22
|
+
colorScheme?: 'dark' | 'light' | 'auto';
|
|
23
|
+
/** Custom colors */
|
|
24
|
+
colors?: {
|
|
25
|
+
/** Text color */
|
|
26
|
+
text?: string;
|
|
27
|
+
/** Text color when inactive/faded */
|
|
28
|
+
textMuted?: string;
|
|
29
|
+
/** Background color for active item pill */
|
|
30
|
+
activeBg?: string;
|
|
31
|
+
/** Background color for hover states */
|
|
32
|
+
hoverBg?: string;
|
|
33
|
+
/** Backdrop overlay color */
|
|
34
|
+
backdropBg?: string;
|
|
35
|
+
/** Focus ring color */
|
|
36
|
+
focusRing?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Border radius for pill shapes */
|
|
39
|
+
borderRadius?: number | string;
|
|
40
|
+
/** Font settings */
|
|
41
|
+
font?: {
|
|
42
|
+
/** Font family */
|
|
43
|
+
family?: string;
|
|
44
|
+
/** Font size for options */
|
|
45
|
+
size?: number | string;
|
|
46
|
+
/** Font weight for options */
|
|
47
|
+
weight?: number | string;
|
|
48
|
+
/** Font size for trigger */
|
|
49
|
+
triggerSize?: number | string;
|
|
50
|
+
};
|
|
51
|
+
/** Animation settings */
|
|
52
|
+
animation?: {
|
|
53
|
+
/** Duration in ms */
|
|
54
|
+
duration?: number;
|
|
55
|
+
/** Easing function */
|
|
56
|
+
easing?: string;
|
|
57
|
+
/** Disable all animations */
|
|
58
|
+
disabled?: boolean;
|
|
59
|
+
};
|
|
60
|
+
/** Spacing settings */
|
|
61
|
+
spacing?: {
|
|
62
|
+
/** Gap between trigger text and icon */
|
|
63
|
+
triggerGap?: number | string;
|
|
64
|
+
/** Padding for trigger button */
|
|
65
|
+
triggerPadding?: string;
|
|
66
|
+
/** Gap between option text and icon */
|
|
67
|
+
optionGap?: number | string;
|
|
68
|
+
/** Padding for options */
|
|
69
|
+
optionPadding?: string;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Sizing configuration for the wheel
|
|
74
|
+
*/
|
|
75
|
+
interface WheelSelectSizing {
|
|
76
|
+
/** Height of the wheel viewport */
|
|
77
|
+
wheelHeight?: number | string;
|
|
78
|
+
/** Minimum width of the wheel */
|
|
79
|
+
wheelMinWidth?: number | string;
|
|
80
|
+
/** Height of each option item */
|
|
81
|
+
optionHeight?: number | string;
|
|
82
|
+
/** Icon size */
|
|
83
|
+
iconSize?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Behavior configuration
|
|
87
|
+
*/
|
|
88
|
+
interface WheelSelectBehavior {
|
|
89
|
+
/** Close on outside click (default: true) */
|
|
90
|
+
closeOnOutsideClick?: boolean;
|
|
91
|
+
/** Close on Escape key (default: true) */
|
|
92
|
+
closeOnEscape?: boolean;
|
|
93
|
+
/** Close on selection (default: true) */
|
|
94
|
+
closeOnSelect?: boolean;
|
|
95
|
+
/** Scroll debounce delay in ms (default: 50) */
|
|
96
|
+
scrollDebounceMs?: number;
|
|
97
|
+
/** Enable keyboard navigation (default: true) */
|
|
98
|
+
keyboardNavigation?: boolean;
|
|
99
|
+
/** Portal target element (default: document.body) */
|
|
100
|
+
portalTarget?: HTMLElement | null;
|
|
101
|
+
/** Focus trigger after close (default: true) */
|
|
102
|
+
focusTriggerOnClose?: boolean;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Custom icon components
|
|
106
|
+
*/
|
|
107
|
+
interface WheelSelectIcons {
|
|
108
|
+
/** Custom chevron icon for closed state */
|
|
109
|
+
chevron?: ReactNode;
|
|
110
|
+
/** Custom arrow icon for active item */
|
|
111
|
+
arrow?: ReactNode;
|
|
112
|
+
/** Hide chevron icon */
|
|
113
|
+
hideChevron?: boolean;
|
|
114
|
+
/** Hide arrow icon on active item */
|
|
115
|
+
hideArrow?: boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Accessibility configuration
|
|
119
|
+
*/
|
|
120
|
+
interface WheelSelectA11y {
|
|
121
|
+
/** Aria label for the trigger button */
|
|
122
|
+
triggerLabel?: string;
|
|
123
|
+
/** Aria label for the picker dialog */
|
|
124
|
+
pickerLabel?: string;
|
|
125
|
+
/** Custom aria-describedby id */
|
|
126
|
+
describedBy?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Event callbacks
|
|
130
|
+
*/
|
|
131
|
+
interface WheelSelectCallbacks<T extends string = string> {
|
|
132
|
+
/** Called when the picker opens */
|
|
133
|
+
onOpen?: () => void;
|
|
134
|
+
/** Called when the picker closes */
|
|
135
|
+
onClose?: () => void;
|
|
136
|
+
/** Called when value changes */
|
|
137
|
+
onChange?: (value: T, option: WheelSelectOption<T>) => void;
|
|
138
|
+
/** Called when active (highlighted) item changes during scroll */
|
|
139
|
+
onActiveChange?: (index: number, option: WheelSelectOption<T>) => void;
|
|
140
|
+
/** Called on keyboard navigation */
|
|
141
|
+
onKeyDown?: (event: KeyboardEvent) => void;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Ref handle for imperative control
|
|
145
|
+
*/
|
|
146
|
+
interface WheelSelectRef {
|
|
147
|
+
/** Open the picker programmatically */
|
|
148
|
+
open: () => void;
|
|
149
|
+
/** Close the picker programmatically */
|
|
150
|
+
close: () => void;
|
|
151
|
+
/** Toggle the picker */
|
|
152
|
+
toggle: () => void;
|
|
153
|
+
/** Focus the trigger */
|
|
154
|
+
focus: () => void;
|
|
155
|
+
/** Get current open state */
|
|
156
|
+
isOpen: () => boolean;
|
|
157
|
+
/** Scroll to a specific option by index */
|
|
158
|
+
scrollToIndex: (index: number) => void;
|
|
159
|
+
/** Get the underlying native select element */
|
|
160
|
+
getNativeSelect: () => HTMLSelectElement | null;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Main component props
|
|
164
|
+
*/
|
|
165
|
+
interface WheelSelectProps<T extends string = string> {
|
|
166
|
+
/** Array of options */
|
|
167
|
+
options: WheelSelectOption<T>[];
|
|
168
|
+
/** Currently selected value */
|
|
169
|
+
value: T;
|
|
170
|
+
/** Change handler */
|
|
171
|
+
onChange: (value: T) => void;
|
|
172
|
+
/** Placeholder text when no value selected */
|
|
173
|
+
placeholder?: string;
|
|
174
|
+
/** Disabled state */
|
|
175
|
+
disabled?: boolean;
|
|
176
|
+
/** Required field indicator */
|
|
177
|
+
required?: boolean;
|
|
178
|
+
/** Name attribute for form submission */
|
|
179
|
+
name?: string;
|
|
180
|
+
/** ID attribute */
|
|
181
|
+
id?: string;
|
|
182
|
+
/** Additional CSS class */
|
|
183
|
+
className?: string;
|
|
184
|
+
/** Inline styles */
|
|
185
|
+
style?: CSSProperties;
|
|
186
|
+
/** Theme configuration */
|
|
187
|
+
theme?: WheelSelectTheme;
|
|
188
|
+
/** Sizing configuration */
|
|
189
|
+
sizing?: WheelSelectSizing;
|
|
190
|
+
/** Behavior configuration */
|
|
191
|
+
behavior?: WheelSelectBehavior;
|
|
192
|
+
/** Custom icons */
|
|
193
|
+
icons?: WheelSelectIcons;
|
|
194
|
+
/** Accessibility configuration */
|
|
195
|
+
a11y?: WheelSelectA11y;
|
|
196
|
+
/** Event callbacks */
|
|
197
|
+
callbacks?: WheelSelectCallbacks<T>;
|
|
198
|
+
/** Custom trigger renderer */
|
|
199
|
+
renderTrigger?: (props: {
|
|
200
|
+
value: T;
|
|
201
|
+
label: string;
|
|
202
|
+
isOpen: boolean;
|
|
203
|
+
disabled: boolean;
|
|
204
|
+
onClick: () => void;
|
|
205
|
+
}) => ReactNode;
|
|
206
|
+
/** Custom option renderer */
|
|
207
|
+
renderOption?: (props: {
|
|
208
|
+
option: WheelSelectOption<T>;
|
|
209
|
+
index: number;
|
|
210
|
+
isActive: boolean;
|
|
211
|
+
isSelected: boolean;
|
|
212
|
+
}) => ReactNode;
|
|
213
|
+
/** Z-index for the picker overlay */
|
|
214
|
+
zIndex?: number;
|
|
215
|
+
}
|
|
216
|
+
declare function WheelSelectInner<T extends string = string>(props: WheelSelectProps<T>, ref: React.ForwardedRef<WheelSelectRef>): react_jsx_runtime.JSX.Element;
|
|
217
|
+
declare const WheelSelect: <T extends string = string>(props: WheelSelectProps<T> & {
|
|
218
|
+
ref?: React.ForwardedRef<WheelSelectRef>;
|
|
219
|
+
}) => ReturnType<typeof WheelSelectInner>;
|
|
220
|
+
|
|
221
|
+
interface SelectOption {
|
|
222
|
+
value: string;
|
|
223
|
+
label: string;
|
|
224
|
+
}
|
|
225
|
+
interface BaseSelectCompatProps {
|
|
226
|
+
options: SelectOption[];
|
|
227
|
+
value: string;
|
|
228
|
+
onChange: (value: string) => void;
|
|
229
|
+
name?: string;
|
|
230
|
+
id?: string;
|
|
231
|
+
className?: string;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* BaseSelectCompat - A progressively enhanced select component
|
|
235
|
+
*
|
|
236
|
+
* Uses native stylable select (appearance: base-select) when supported,
|
|
237
|
+
* falls back to a custom inline wheel picker for older browsers.
|
|
238
|
+
*/
|
|
239
|
+
declare function BaseSelectCompat({ options, value, onChange, name, id, className, }: BaseSelectCompatProps): react_jsx_runtime.JSX.Element;
|
|
240
|
+
|
|
241
|
+
export { BaseSelectCompat, type BaseSelectCompatProps, type SelectOption, WheelSelect, type WheelSelectA11y, type WheelSelectBehavior, type WheelSelectCallbacks, type WheelSelectIcons, type WheelSelectOption, type WheelSelectProps, type WheelSelectRef, type WheelSelectSizing, type WheelSelectTheme, WheelSelect as default };
|