@brycks/core-front 0.3.6 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/data/Table/Table.cjs +1 -1
- package/dist/components/data/Table/Table.cjs.map +1 -1
- package/dist/components/data/Table/Table.js +145 -132
- package/dist/components/data/Table/Table.js.map +1 -1
- package/dist/components/data.cjs +1 -1
- package/dist/components/data.js +23 -21
- package/dist/components/feedback/Banner/Banner.cjs +2 -0
- package/dist/components/feedback/Banner/Banner.cjs.map +1 -0
- package/dist/components/feedback/Banner/Banner.js +77 -0
- package/dist/components/feedback/Banner/Banner.js.map +1 -0
- package/dist/components/feedback/ConfirmDialog/ConfirmDialog.cjs +2 -0
- package/dist/components/feedback/ConfirmDialog/ConfirmDialog.cjs.map +1 -0
- package/dist/components/feedback/ConfirmDialog/ConfirmDialog.js +68 -0
- package/dist/components/feedback/ConfirmDialog/ConfirmDialog.js.map +1 -0
- package/dist/components/feedback/Modal/Modal.cjs +1 -1
- package/dist/components/feedback/Modal/Modal.cjs.map +1 -1
- package/dist/components/feedback/Modal/Modal.js +91 -83
- package/dist/components/feedback/Modal/Modal.js.map +1 -1
- package/dist/components/feedback/Popover/Popover.cjs +2 -2
- package/dist/components/feedback/Popover/Popover.cjs.map +1 -1
- package/dist/components/feedback/Popover/Popover.js +43 -44
- package/dist/components/feedback/Popover/Popover.js.map +1 -1
- package/dist/components/feedback.cjs +1 -1
- package/dist/components/feedback.js +17 -13
- package/dist/components/feedback.js.map +1 -1
- package/dist/components/form/Combobox/Combobox.cjs +2 -2
- package/dist/components/form/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/form/Combobox/Combobox.js +166 -146
- package/dist/components/form/Combobox/Combobox.js.map +1 -1
- package/dist/components/form/SearchInput/SearchInput.cjs +2 -0
- package/dist/components/form/SearchInput/SearchInput.cjs.map +1 -0
- package/dist/components/form/SearchInput/SearchInput.js +68 -0
- package/dist/components/form/SearchInput/SearchInput.js.map +1 -0
- package/dist/components/form.cjs +1 -1
- package/dist/components/form.js +15 -13
- package/dist/components/form.js.map +1 -1
- package/dist/components/layout/Card/Card.cjs +1 -1
- package/dist/components/layout/Card/Card.cjs.map +1 -1
- package/dist/components/layout/Card/Card.js +7 -5
- package/dist/components/layout/Card/Card.js.map +1 -1
- package/dist/components/navigation/SegmentedControl/SegmentedControl.cjs +2 -0
- package/dist/components/navigation/SegmentedControl/SegmentedControl.cjs.map +1 -0
- package/dist/components/navigation/SegmentedControl/SegmentedControl.js +90 -0
- package/dist/components/navigation/SegmentedControl/SegmentedControl.js.map +1 -0
- package/dist/components/navigation.cjs +1 -1
- package/dist/components/navigation.js +25 -23
- package/dist/components/navigation.js.map +1 -1
- package/dist/components/utility/Avatar/Avatar.cjs +1 -1
- package/dist/components/utility/Avatar/Avatar.cjs.map +1 -1
- package/dist/components/utility/Avatar/Avatar.js +18 -18
- package/dist/components/utility/Avatar/Avatar.js.map +1 -1
- package/dist/components/utility/Badge/Badge.cjs +1 -1
- package/dist/components/utility/Badge/Badge.cjs.map +1 -1
- package/dist/components/utility/Badge/Badge.js +31 -23
- package/dist/components/utility/Badge/Badge.js.map +1 -1
- package/dist/components/utility/Kbd/Kbd.cjs +2 -0
- package/dist/components/utility/Kbd/Kbd.cjs.map +1 -0
- package/dist/components/utility/Kbd/Kbd.js +20 -0
- package/dist/components/utility/Kbd/Kbd.js.map +1 -0
- package/dist/components/utility/Logo/Logo.cjs +1 -1
- package/dist/components/utility/Logo/Logo.cjs.map +1 -1
- package/dist/components/utility/Logo/Logo.js +19 -19
- package/dist/components/utility/Logo/Logo.js.map +1 -1
- package/dist/components/utility.cjs +1 -1
- package/dist/components/utility.js +9 -7
- package/dist/components/utility.js.map +1 -1
- package/dist/data.d.ts +34 -1
- package/dist/feedback.d.ts +67 -2
- package/dist/form.d.ts +31 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +184 -3
- package/dist/index.js +177 -165
- package/dist/index.js.map +1 -1
- package/dist/navigation.d.ts +39 -0
- package/dist/styles.css +1 -1
- package/dist/utility.d.ts +19 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.js","sources":["../../../../src/components/form/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * Combobox Component\n *\n * A searchable select/autocomplete component with keyboard navigation.\n * Combines the functionality of Input with dropdown selection.\n *\n * @module components/form/Combobox\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n useMemo,\n type CSSProperties,\n type ReactNode,\n type KeyboardEvent,\n type ChangeEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { useId } from '../../../hooks/useId'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport {\n componentHeights,\n componentPaddingX,\n componentGap,\n iconSizes,\n} from '../../../design-system/primitives'\n\nexport type ComboboxSize = 'sm' | 'md' | 'lg'\n\nexport interface ComboboxOption {\n /** Unique identifier for the option */\n value: string\n /** Display label */\n label: string\n /** Optional description */\n description?: string\n /** Optional icon */\n icon?: ReactNode\n /** Whether the option is disabled */\n disabled?: boolean\n}\n\nexport interface ComboboxProps {\n /** Available options */\n options: ComboboxOption[]\n /** Currently selected value (controlled) */\n value?: string | null\n /** Default selected value (uncontrolled) */\n defaultValue?: string | null\n /** Callback when selection changes */\n onChange?: (value: string | null) => void\n /** Callback when input value changes */\n onInputChange?: (value: string) => void\n /** Placeholder text */\n placeholder?: string\n /** Component size */\n size?: ComboboxSize\n /** Whether the combobox is disabled */\n disabled?: boolean\n /** Whether the combobox is invalid */\n isInvalid?: boolean\n /** Whether the combobox is required */\n required?: boolean\n /** Whether to allow clearing the selection */\n clearable?: boolean\n /** Label for accessibility */\n 'aria-label'?: string\n /** ID of element that labels this combobox */\n 'aria-labelledby'?: string\n /** Custom filter function */\n filterFn?: (option: ComboboxOption, inputValue: string) => boolean\n /** Text to show when no options match */\n emptyText?: string\n /** Whether to allow creating new options */\n creatable?: boolean\n /** Callback when creating new option */\n onCreate?: (inputValue: string) => void\n /** Label of the create-option button */\n createLabel?: (inputValue: string) => ReactNode\n /** Accessible label of the clear button */\n clearLabel?: string\n /** Accessible label of the options listbox (when no aria-label is given) */\n listboxLabel?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeConfig: Record<ComboboxSize, { height: number; fontSize: number; padding: number; iconSize: number }> = {\n sm: { height: componentHeights.sm, fontSize: fontSizes.base - 1, padding: componentPaddingX.sm, iconSize: iconSizes.sm },\n md: { height: componentHeights.md, fontSize: fontSizes.base, padding: componentPaddingX.md, iconSize: iconSizes.md },\n lg: { height: componentHeights.lg, fontSize: fontSizes.md, padding: componentPaddingX.lg, iconSize: iconSizes.lg },\n}\n\nconst defaultFilterFn = (option: ComboboxOption, inputValue: string): boolean => {\n const search = inputValue.toLowerCase()\n return (\n option.label.toLowerCase().includes(search) ||\n option.value.toLowerCase().includes(search) ||\n (option.description?.toLowerCase().includes(search) ?? false)\n )\n}\n\nfunction ChevronDownIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const Combobox = forwardRef<HTMLInputElement, ComboboxProps>(function Combobox(\n {\n options,\n value: controlledValue,\n defaultValue = null,\n onChange,\n onInputChange,\n placeholder = 'Select or search...',\n size = 'md',\n disabled = false,\n isInvalid = false,\n required = false,\n clearable = true,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n filterFn = defaultFilterFn,\n emptyText = 'No options found',\n creatable = false,\n onCreate,\n createLabel = (input) => `Create \"${input}\"`,\n clearLabel = 'Clear selection',\n listboxLabel = 'Options',\n className,\n testId,\n },\n ref\n) {\n const listboxId = useId('combobox-listbox')\n const [internalValue, setInternalValue] = useState(defaultValue)\n const [inputValue, setInputValue] = useState('')\n const [isOpen, setIsOpen] = useState(false)\n const [activeIndex, setActiveIndex] = useState(-1)\n const [isFocused, setIsFocused] = useState(false)\n\n const containerRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLUListElement>(null)\n\n const value = controlledValue !== undefined ? controlledValue : internalValue\n const config = sizeConfig[size]\n\n // Get selected option\n const selectedOption = useMemo(\n () => options.find((opt) => opt.value === value),\n [options, value]\n )\n\n // Filter options based on input\n const filteredOptions = useMemo(() => {\n if (!inputValue) return options\n return options.filter((opt) => filterFn(opt, inputValue))\n }, [options, inputValue, filterFn])\n\n // Sync input with selected value\n useEffect(() => {\n if (!isOpen && selectedOption) {\n setInputValue(selectedOption.label)\n } else if (!isOpen && !value) {\n setInputValue('')\n }\n }, [isOpen, selectedOption, value])\n\n const handleSelect = useCallback(\n (optionValue: string | null) => {\n if (controlledValue === undefined) {\n setInternalValue(optionValue)\n }\n onChange?.(optionValue)\n setIsOpen(false)\n setActiveIndex(-1)\n inputRef.current?.focus()\n },\n [controlledValue, onChange]\n )\n\n const handleInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value\n setInputValue(newValue)\n onInputChange?.(newValue)\n if (!isOpen) setIsOpen(true)\n setActiveIndex(0)\n },\n [isOpen, onInputChange]\n )\n\n const handleClear = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation()\n handleSelect(null)\n setInputValue('')\n inputRef.current?.focus()\n },\n [handleSelect]\n )\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n if (!isOpen) {\n setIsOpen(true)\n setActiveIndex(0)\n } else {\n setActiveIndex((prev) => Math.min(prev + 1, filteredOptions.length - 1))\n }\n break\n case 'ArrowUp':\n e.preventDefault()\n if (isOpen) {\n setActiveIndex((prev) => Math.max(prev - 1, 0))\n }\n break\n case 'Enter':\n e.preventDefault()\n if (isOpen && activeIndex >= 0 && filteredOptions[activeIndex]) {\n if (!filteredOptions[activeIndex].disabled) {\n handleSelect(filteredOptions[activeIndex].value)\n }\n } else if (creatable && inputValue && filteredOptions.length === 0) {\n onCreate?.(inputValue)\n }\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n setActiveIndex(-1)\n if (selectedOption) {\n setInputValue(selectedOption.label)\n }\n break\n case 'Tab':\n if (isOpen) {\n setIsOpen(false)\n setActiveIndex(-1)\n }\n break\n }\n },\n [isOpen, activeIndex, filteredOptions, handleSelect, creatable, inputValue, onCreate, selectedOption]\n )\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) {\n setIsOpen(false)\n setActiveIndex(-1)\n if (selectedOption) {\n setInputValue(selectedOption.label)\n }\n }\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, selectedOption])\n\n // Scroll active option into view\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const list = listRef.current\n const activeItem = list?.children[activeIndex] as HTMLElement | undefined\n activeItem?.scrollIntoView({ block: 'nearest' })\n }, [isOpen, activeIndex])\n\n // Calculate dropdown position\n const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0 })\n\n useEffect(() => {\n if (!isOpen || !containerRef.current) return\n\n const updatePosition = () => {\n const rect = containerRef.current!.getBoundingClientRect()\n setDropdownPosition({\n top: rect.bottom + window.scrollY + spacing[1],\n left: rect.left + window.scrollX,\n width: rect.width,\n })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen])\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n display: 'inline-flex',\n width: '100%',\n }\n\n const inputWrapperStyle: CSSProperties = {\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n height: config.height,\n backgroundColor: disabled ? 'var(--brycks-background-muted)' : 'var(--brycks-background-default)',\n border: `1px solid ${\n isInvalid\n ? 'var(--brycks-error-default)'\n : isFocused\n ? 'var(--brycks-primary-default)'\n : 'var(--brycks-border-default)'\n }`,\n borderRadius: 'var(--brycks-radius-md)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n cursor: disabled ? 'not-allowed' : 'text',\n boxShadow: isFocused ? 'var(--brycks-focus-ring)' : undefined,\n }\n\n const inputStyle: CSSProperties = {\n flex: 1,\n height: '100%',\n padding: `0 ${config.padding}px`,\n paddingRight: spacing[10],\n fontSize: config.fontSize,\n color: disabled ? 'var(--brycks-foreground-disabled)' : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n cursor: disabled ? 'not-allowed' : 'text',\n }\n\n const iconsStyle: CSSProperties = {\n position: 'absolute',\n right: config.padding,\n display: 'flex',\n alignItems: 'center',\n gap: spacing[1],\n pointerEvents: 'none',\n }\n\n const clearButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: spacing[5],\n height: spacing[5],\n color: 'var(--brycks-foreground-muted)',\n cursor: 'pointer',\n borderRadius: 'var(--brycks-radius-sm)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n pointerEvents: 'auto',\n }\n\n const chevronStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--brycks-foreground-muted)',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0)',\n transition: `transform ${durations.fast}ms ${easings.easeOut}`,\n }\n\n const dropdownStyle: CSSProperties = {\n position: 'absolute',\n top: dropdownPosition.top,\n left: dropdownPosition.left,\n width: dropdownPosition.width,\n maxHeight: 300,\n overflowY: 'auto',\n backgroundColor: 'var(--brycks-background-elevated)',\n border: '1px solid var(--brycks-border-default)',\n borderRadius: 'var(--brycks-radius-lg)',\n boxShadow: 'var(--brycks-shadow-lg)',\n zIndex: 'var(--brycks-z-dropdown)' as unknown as number,\n padding: spacing[1],\n animation: `brycks-dropdown-in ${durations.quick}ms ${easings.easeOut}`,\n }\n\n const optionStyle = (isActive: boolean, isDisabled: boolean, isSelected: boolean): CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.md,\n padding: `${spacing[2]}px ${componentPaddingX.sm}px`,\n fontSize: config.fontSize,\n color: isDisabled\n ? 'var(--brycks-foreground-disabled)'\n : 'var(--brycks-foreground-default)',\n backgroundColor: isActive\n ? 'var(--brycks-background-muted)'\n : isSelected\n ? 'var(--brycks-primary-muted)'\n : 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: isDisabled ? 'not-allowed' : 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n })\n\n const emptyStyle: CSSProperties = {\n padding: `${spacing[4]}px ${spacing[3]}px`,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-muted)',\n textAlign: 'center',\n }\n\n return (\n <div\n ref={containerRef}\n className={cx('brycks-combobox', `brycks-combobox--${size}`, className)}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n style={inputWrapperStyle}\n onClick={() => !disabled && inputRef.current?.focus()}\n >\n <input\n ref={(node) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) ref.current = node\n }}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={isOpen && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined}\n aria-invalid={isInvalid}\n aria-required={required}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n value={inputValue}\n placeholder={placeholder}\n disabled={disabled}\n style={inputStyle}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setIsFocused(true)\n setIsOpen(true)\n }}\n onBlur={() => setIsFocused(false)}\n />\n <div style={iconsStyle}>\n {clearable && value && !disabled && (\n <button\n type=\"button\"\n aria-label={clearLabel}\n style={clearButtonStyle}\n onClick={handleClear}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n e.currentTarget.style.color = 'var(--brycks-foreground-default)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n e.currentTarget.style.color = 'var(--brycks-foreground-muted)'\n }}\n >\n <ClearIcon />\n </button>\n )}\n <span style={chevronStyle}>\n <ChevronDownIcon />\n </span>\n </div>\n </div>\n\n {isOpen &&\n createPortal(\n <>\n <style>\n {`\n @keyframes brycks-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}\n </style>\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n aria-label={ariaLabel || listboxLabel}\n style={dropdownStyle}\n >\n {filteredOptions.length > 0 ? (\n filteredOptions.map((option, index) => (\n <li\n key={option.value}\n id={`${listboxId}-option-${index}`}\n role=\"option\"\n aria-selected={option.value === value}\n aria-disabled={option.disabled}\n style={optionStyle(index === activeIndex, !!option.disabled, option.value === value)}\n onClick={() => !option.disabled && handleSelect(option.value)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {option.icon && <span style={{ flexShrink: 0 }}>{option.icon}</span>}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: option.value === value ? 500 : 400 }}>{option.label}</div>\n {option.description && (\n <div style={{ fontSize: fontSizes.sm, color: 'var(--brycks-foreground-muted)' }}>\n {option.description}\n </div>\n )}\n </div>\n {option.value === value && (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" style={{ flexShrink: 0 }}>\n <path\n d=\"M3 8l3 3 7-7\"\n stroke=\"var(--brycks-primary-default)\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )}\n </li>\n ))\n ) : (\n <li style={emptyStyle}>\n {creatable && inputValue ? (\n <button\n type=\"button\"\n style={{\n ...optionStyle(true, false, false),\n width: '100%',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => onCreate?.(inputValue)}\n >\n {createLabel(inputValue)}\n </button>\n ) : (\n emptyText\n )}\n </li>\n )}\n </ul>\n </>,\n document.body\n )}\n </div>\n )\n})\n\nCombobox.displayName = 'Combobox'\n"],"names":["sizeConfig","componentHeights","fontSizes","componentPaddingX","iconSizes","defaultFilterFn","option","inputValue","search","ChevronDownIcon","jsx","ClearIcon","Combobox","forwardRef","options","controlledValue","defaultValue","onChange","onInputChange","placeholder","size","disabled","isInvalid","required","clearable","ariaLabel","ariaLabelledby","filterFn","emptyText","creatable","onCreate","createLabel","input","clearLabel","listboxLabel","className","testId","ref","listboxId","useId","internalValue","setInternalValue","useState","setInputValue","isOpen","setIsOpen","activeIndex","setActiveIndex","isFocused","setIsFocused","containerRef","useRef","inputRef","listRef","value","config","selectedOption","useMemo","opt","filteredOptions","useEffect","handleSelect","useCallback","optionValue","handleInputChange","newValue","handleClear","handleKeyDown","prev","handleClick","e","dropdownPosition","setDropdownPosition","updatePosition","rect","spacing","containerStyle","inputWrapperStyle","durations","easings","inputStyle","iconsStyle","clearButtonStyle","chevronStyle","dropdownStyle","optionStyle","isActive","isDisabled","isSelected","componentGap","emptyStyle","jsxs","cx","node","createPortal","Fragment","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Combobox.js","sources":["../../../../src/components/form/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * Combobox Component\n *\n * A searchable select/autocomplete component with keyboard navigation.\n * Combines the functionality of Input with dropdown selection.\n *\n * @module components/form/Combobox\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n useMemo,\n type CSSProperties,\n type ReactNode,\n type KeyboardEvent,\n type ChangeEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { useId } from '../../../hooks/useId'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport {\n componentHeights,\n componentPaddingX,\n componentGap,\n iconSizes,\n} from '../../../design-system/primitives'\n\nexport type ComboboxSize = 'sm' | 'md' | 'lg'\n\nexport interface ComboboxOption {\n /** Unique identifier for the option */\n value: string\n /** Display label */\n label: string\n /** Optional description */\n description?: string\n /** Optional icon */\n icon?: ReactNode\n /** Whether the option is disabled */\n disabled?: boolean\n}\n\nexport interface ComboboxProps {\n /** Available options */\n options: ComboboxOption[]\n /** Currently selected value (controlled) */\n value?: string | null\n /** Default selected value (uncontrolled) */\n defaultValue?: string | null\n /** Callback when selection changes */\n onChange?: (value: string | null) => void\n /** Callback when input value changes */\n onInputChange?: (value: string) => void\n /** Placeholder text */\n placeholder?: string\n /** Component size */\n size?: ComboboxSize\n /** Whether the combobox is disabled */\n disabled?: boolean\n /** Whether the combobox is invalid */\n isInvalid?: boolean\n /** Whether the combobox is required */\n required?: boolean\n /** Whether to allow clearing the selection */\n clearable?: boolean\n /** Label for accessibility */\n 'aria-label'?: string\n /** ID of element that labels this combobox */\n 'aria-labelledby'?: string\n /** Custom filter function */\n filterFn?: (option: ComboboxOption, inputValue: string) => boolean\n /** Text to show when no options match */\n emptyText?: string\n /** Whether options are being loaded asynchronously */\n isLoading?: boolean\n /** Text to show while loading */\n loadingText?: string\n /** Whether to allow creating new options */\n creatable?: boolean\n /** Callback when creating new option */\n onCreate?: (inputValue: string) => void\n /** Label of the create-option button */\n createLabel?: (inputValue: string) => ReactNode\n /** Accessible label of the clear button */\n clearLabel?: string\n /** Accessible label of the options listbox (when no aria-label is given) */\n listboxLabel?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeConfig: Record<ComboboxSize, { height: number; fontSize: number; padding: number; iconSize: number }> = {\n sm: { height: componentHeights.sm, fontSize: fontSizes.base - 1, padding: componentPaddingX.sm, iconSize: iconSizes.sm },\n md: { height: componentHeights.md, fontSize: fontSizes.base, padding: componentPaddingX.md, iconSize: iconSizes.md },\n lg: { height: componentHeights.lg, fontSize: fontSizes.md, padding: componentPaddingX.lg, iconSize: iconSizes.lg },\n}\n\nconst defaultFilterFn = (option: ComboboxOption, inputValue: string): boolean => {\n const search = inputValue.toLowerCase()\n return (\n option.label.toLowerCase().includes(search) ||\n option.value.toLowerCase().includes(search) ||\n (option.description?.toLowerCase().includes(search) ?? false)\n )\n}\n\nfunction ChevronDownIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const Combobox = forwardRef<HTMLInputElement, ComboboxProps>(function Combobox(\n {\n options,\n value: controlledValue,\n defaultValue = null,\n onChange,\n onInputChange,\n placeholder = 'Select or search...',\n size = 'md',\n disabled = false,\n isInvalid = false,\n required = false,\n clearable = true,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n filterFn = defaultFilterFn,\n emptyText = 'No options found',\n isLoading = false,\n loadingText = 'Loading…',\n creatable = false,\n onCreate,\n createLabel = (input) => `Create \"${input}\"`,\n clearLabel = 'Clear selection',\n listboxLabel = 'Options',\n className,\n testId,\n },\n ref\n) {\n const listboxId = useId('combobox-listbox')\n const [internalValue, setInternalValue] = useState(defaultValue)\n const [inputValue, setInputValue] = useState('')\n const [isOpen, setIsOpen] = useState(false)\n const [activeIndex, setActiveIndex] = useState(-1)\n const [isFocused, setIsFocused] = useState(false)\n\n const containerRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLUListElement>(null)\n\n const value = controlledValue !== undefined ? controlledValue : internalValue\n const config = sizeConfig[size]\n\n // Get selected option\n const selectedOption = useMemo(\n () => options.find((opt) => opt.value === value),\n [options, value]\n )\n\n // Filter options based on input\n const filteredOptions = useMemo(() => {\n if (!inputValue) return options\n return options.filter((opt) => filterFn(opt, inputValue))\n }, [options, inputValue, filterFn])\n\n // Sync input with selected value\n useEffect(() => {\n if (!isOpen && selectedOption) {\n setInputValue(selectedOption.label)\n } else if (!isOpen && !value) {\n setInputValue('')\n }\n }, [isOpen, selectedOption, value])\n\n const handleSelect = useCallback(\n (optionValue: string | null) => {\n if (controlledValue === undefined) {\n setInternalValue(optionValue)\n }\n onChange?.(optionValue)\n setIsOpen(false)\n setActiveIndex(-1)\n inputRef.current?.focus()\n },\n [controlledValue, onChange]\n )\n\n const handleInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value\n setInputValue(newValue)\n onInputChange?.(newValue)\n if (!isOpen) setIsOpen(true)\n setActiveIndex(0)\n },\n [isOpen, onInputChange]\n )\n\n const handleClear = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation()\n handleSelect(null)\n setInputValue('')\n inputRef.current?.focus()\n },\n [handleSelect]\n )\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n if (!isOpen) {\n setIsOpen(true)\n setActiveIndex(0)\n } else {\n setActiveIndex((prev) => Math.min(prev + 1, filteredOptions.length - 1))\n }\n break\n case 'ArrowUp':\n e.preventDefault()\n if (isOpen) {\n setActiveIndex((prev) => Math.max(prev - 1, 0))\n }\n break\n case 'Enter':\n e.preventDefault()\n if (isOpen && activeIndex >= 0 && filteredOptions[activeIndex]) {\n if (!filteredOptions[activeIndex].disabled) {\n handleSelect(filteredOptions[activeIndex].value)\n }\n } else if (creatable && inputValue && filteredOptions.length === 0) {\n onCreate?.(inputValue)\n }\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n setActiveIndex(-1)\n if (selectedOption) {\n setInputValue(selectedOption.label)\n }\n break\n case 'Tab':\n if (isOpen) {\n setIsOpen(false)\n setActiveIndex(-1)\n }\n break\n }\n },\n [isOpen, activeIndex, filteredOptions, handleSelect, creatable, inputValue, onCreate, selectedOption]\n )\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) {\n setIsOpen(false)\n setActiveIndex(-1)\n if (selectedOption) {\n setInputValue(selectedOption.label)\n }\n }\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, selectedOption])\n\n // Scroll active option into view\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const list = listRef.current\n const activeItem = list?.children[activeIndex] as HTMLElement | undefined\n activeItem?.scrollIntoView({ block: 'nearest' })\n }, [isOpen, activeIndex])\n\n // Calculate dropdown position\n const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0 })\n\n useEffect(() => {\n if (!isOpen || !containerRef.current) return\n\n const updatePosition = () => {\n const rect = containerRef.current!.getBoundingClientRect()\n setDropdownPosition({\n top: rect.bottom + window.scrollY + spacing[1],\n left: rect.left + window.scrollX,\n width: rect.width,\n })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen])\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n display: 'inline-flex',\n width: '100%',\n }\n\n const inputWrapperStyle: CSSProperties = {\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n height: config.height,\n backgroundColor: disabled ? 'var(--brycks-background-muted)' : 'var(--brycks-background-default)',\n border: `1px solid ${\n isInvalid\n ? 'var(--brycks-error-default)'\n : isFocused\n ? 'var(--brycks-primary-default)'\n : 'var(--brycks-border-default)'\n }`,\n borderRadius: 'var(--brycks-radius-md)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n cursor: disabled ? 'not-allowed' : 'text',\n boxShadow: isFocused ? 'var(--brycks-focus-ring)' : undefined,\n }\n\n const inputStyle: CSSProperties = {\n flex: 1,\n height: '100%',\n padding: `0 ${config.padding}px`,\n paddingRight: spacing[10],\n fontSize: config.fontSize,\n color: disabled ? 'var(--brycks-foreground-disabled)' : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n cursor: disabled ? 'not-allowed' : 'text',\n }\n\n const iconsStyle: CSSProperties = {\n position: 'absolute',\n right: config.padding,\n display: 'flex',\n alignItems: 'center',\n gap: spacing[1],\n pointerEvents: 'none',\n }\n\n const clearButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: spacing[5],\n height: spacing[5],\n color: 'var(--brycks-foreground-muted)',\n cursor: 'pointer',\n borderRadius: 'var(--brycks-radius-sm)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n pointerEvents: 'auto',\n }\n\n const chevronStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--brycks-foreground-muted)',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0)',\n transition: `transform ${durations.fast}ms ${easings.easeOut}`,\n }\n\n const dropdownStyle: CSSProperties = {\n position: 'absolute',\n top: dropdownPosition.top,\n left: dropdownPosition.left,\n width: dropdownPosition.width,\n maxHeight: 300,\n overflowY: 'auto',\n backgroundColor: 'var(--brycks-background-elevated)',\n border: '1px solid var(--brycks-border-default)',\n borderRadius: 'var(--brycks-radius-lg)',\n boxShadow: 'var(--brycks-shadow-lg)',\n zIndex: 'var(--brycks-z-dropdown)' as unknown as number,\n padding: spacing[1],\n animation: `brycks-dropdown-in ${durations.quick}ms ${easings.easeOut}`,\n }\n\n const optionStyle = (isActive: boolean, isDisabled: boolean, isSelected: boolean): CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.md,\n padding: `${spacing[2]}px ${componentPaddingX.sm}px`,\n fontSize: config.fontSize,\n color: isDisabled\n ? 'var(--brycks-foreground-disabled)'\n : 'var(--brycks-foreground-default)',\n backgroundColor: isActive\n ? 'var(--brycks-background-muted)'\n : isSelected\n ? 'var(--brycks-primary-muted)'\n : 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: isDisabled ? 'not-allowed' : 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n })\n\n const emptyStyle: CSSProperties = {\n padding: `${spacing[4]}px ${spacing[3]}px`,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-muted)',\n textAlign: 'center',\n }\n\n return (\n <div\n ref={containerRef}\n className={cx('brycks-combobox', `brycks-combobox--${size}`, className)}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n style={inputWrapperStyle}\n onClick={() => !disabled && inputRef.current?.focus()}\n >\n <input\n ref={(node) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) ref.current = node\n }}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={isOpen && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined}\n aria-invalid={isInvalid}\n aria-required={required}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n value={inputValue}\n placeholder={placeholder}\n disabled={disabled}\n style={inputStyle}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setIsFocused(true)\n setIsOpen(true)\n }}\n onBlur={() => setIsFocused(false)}\n />\n <div style={iconsStyle}>\n {clearable && value && !disabled && (\n <button\n type=\"button\"\n aria-label={clearLabel}\n style={clearButtonStyle}\n onClick={handleClear}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n e.currentTarget.style.color = 'var(--brycks-foreground-default)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n e.currentTarget.style.color = 'var(--brycks-foreground-muted)'\n }}\n >\n <ClearIcon />\n </button>\n )}\n <span style={chevronStyle}>\n <ChevronDownIcon />\n </span>\n </div>\n </div>\n\n {isOpen &&\n createPortal(\n <>\n <style>\n {`\n @keyframes brycks-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}\n </style>\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n aria-label={ariaLabel || listboxLabel}\n aria-busy={isLoading || undefined}\n style={dropdownStyle}\n >\n {isLoading ? (\n <li style={emptyStyle} role=\"status\" aria-live=\"polite\">\n <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: spacing[2] }}>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n className=\"brycks-animate-spin\"\n aria-hidden=\"true\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" opacity=\"0.2\" />\n <path d=\"M12 2C6.47715 2 2 6.47715 2 12\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" />\n </svg>\n {loadingText}\n </span>\n </li>\n ) : filteredOptions.length > 0 ? (\n filteredOptions.map((option, index) => (\n <li\n key={option.value}\n id={`${listboxId}-option-${index}`}\n role=\"option\"\n aria-selected={option.value === value}\n aria-disabled={option.disabled}\n style={optionStyle(index === activeIndex, !!option.disabled, option.value === value)}\n onClick={() => !option.disabled && handleSelect(option.value)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {option.icon && <span style={{ flexShrink: 0 }}>{option.icon}</span>}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: option.value === value ? 500 : 400 }}>{option.label}</div>\n {option.description && (\n <div style={{ fontSize: fontSizes.sm, color: 'var(--brycks-foreground-muted)' }}>\n {option.description}\n </div>\n )}\n </div>\n {option.value === value && (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" style={{ flexShrink: 0 }}>\n <path\n d=\"M3 8l3 3 7-7\"\n stroke=\"var(--brycks-primary-default)\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )}\n </li>\n ))\n ) : (\n <li style={emptyStyle}>\n {creatable && inputValue ? (\n <button\n type=\"button\"\n style={{\n ...optionStyle(true, false, false),\n width: '100%',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => onCreate?.(inputValue)}\n >\n {createLabel(inputValue)}\n </button>\n ) : (\n emptyText\n )}\n </li>\n )}\n </ul>\n </>,\n document.body\n )}\n </div>\n )\n})\n\nCombobox.displayName = 'Combobox'\n"],"names":["sizeConfig","componentHeights","fontSizes","componentPaddingX","iconSizes","defaultFilterFn","option","inputValue","search","ChevronDownIcon","jsx","ClearIcon","Combobox","forwardRef","options","controlledValue","defaultValue","onChange","onInputChange","placeholder","size","disabled","isInvalid","required","clearable","ariaLabel","ariaLabelledby","filterFn","emptyText","isLoading","loadingText","creatable","onCreate","createLabel","input","clearLabel","listboxLabel","className","testId","ref","listboxId","useId","internalValue","setInternalValue","useState","setInputValue","isOpen","setIsOpen","activeIndex","setActiveIndex","isFocused","setIsFocused","containerRef","useRef","inputRef","listRef","value","config","selectedOption","useMemo","opt","filteredOptions","useEffect","handleSelect","useCallback","optionValue","handleInputChange","newValue","handleClear","handleKeyDown","prev","handleClick","e","dropdownPosition","setDropdownPosition","updatePosition","rect","spacing","containerStyle","inputWrapperStyle","durations","easings","inputStyle","iconsStyle","clearButtonStyle","chevronStyle","dropdownStyle","optionStyle","isActive","isDisabled","isSelected","componentGap","emptyStyle","jsxs","cx","node","createPortal","Fragment","index"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),C=require("../Input/Input.cjs");function m(){return e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[e.jsx("circle",{cx:"7",cy:"7",r:"4.5",stroke:"currentColor",strokeWidth:"1.5"}),e.jsx("path",{d:"M10.5 10.5L14 14",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]})}function y(){return e.jsx("svg",{width:"14",height:"14",viewBox:"0 0 14 14",fill:"none","aria-hidden":"true",children:e.jsx("path",{d:"M4 4l6 6M10 4l-6 6",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})})}const u=n.forwardRef(function({value:a,defaultValue:h="",onValueChange:r,onClear:c,size:d="md",placeholder:p="Search…",leftElement:x,clearLabel:k="Clear search",className:f,testId:j,disabled:s,...v},I){const[b,o]=n.useState(h),t=a!==void 0,i=t?a:b,S=n.useCallback(l=>{t||o(l.target.value),r?.(l.target.value)},[t,r]),g=n.useCallback(()=>{t||o(""),r?.(""),c?.()},[t,r,c]);return e.jsx(C.Input,{ref:I,type:"search",role:"searchbox",size:d,placeholder:p,value:i,onChange:S,disabled:s,className:f,testId:j,leftElement:x??e.jsx(m,{}),rightElement:i&&!s?e.jsx("button",{type:"button",className:"brycks-search-input__clear","aria-label":k,onClick:g,tabIndex:-1,children:e.jsx(y,{})}):void 0,...v})});u.displayName="SearchInput";exports.SearchInput=u;
|
|
2
|
+
//# sourceMappingURL=SearchInput.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchInput.cjs","sources":["../../../../src/components/form/SearchInput/SearchInput.tsx"],"sourcesContent":["/**\n * SearchInput Component\n *\n * A search field built on top of Input: a leading search icon and a trailing\n * clear button that appears once there is text. Works controlled (`value` +\n * `onValueChange`) or uncontrolled (`defaultValue`).\n *\n * All color styles are inherited from Input; the clear button hover state is\n * handled via a CSS class for easy customization.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n type ChangeEvent,\n type ReactNode,\n type InputHTMLAttributes,\n} from 'react'\nimport { Input, type InputSize } from '../Input'\n\ntype NativeInputProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'value' | 'defaultValue' | 'onChange' | 'type'\n>\n\nexport interface SearchInputProps extends NativeInputProps {\n /** Current value (controlled) */\n value?: string\n /** Initial value (uncontrolled) */\n defaultValue?: string\n /** Callback when the value changes (typing or clearing) */\n onValueChange?: (value: string) => void\n /** Callback fired when the clear button is pressed */\n onClear?: () => void\n /** Input size */\n size?: InputSize\n /** Placeholder text */\n placeholder?: string\n /** Custom leading element (defaults to a search icon) */\n leftElement?: ReactNode\n /** Accessible label of the clear button */\n clearLabel?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nfunction SearchIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M10.5 10.5L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(function SearchInput(\n {\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n onClear,\n size = 'md',\n placeholder = 'Search…',\n leftElement,\n clearLabel = 'Clear search',\n className,\n testId,\n disabled,\n ...props\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState(defaultValue)\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : internalValue\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n if (!isControlled) setInternalValue(e.target.value)\n onValueChange?.(e.target.value)\n },\n [isControlled, onValueChange]\n )\n\n const handleClear = useCallback(() => {\n if (!isControlled) setInternalValue('')\n onValueChange?.('')\n onClear?.()\n }, [isControlled, onValueChange, onClear])\n\n return (\n <Input\n ref={ref}\n type=\"search\"\n role=\"searchbox\"\n size={size}\n placeholder={placeholder}\n value={value}\n onChange={handleChange}\n disabled={disabled}\n className={className}\n testId={testId}\n leftElement={leftElement ?? <SearchIcon />}\n rightElement={\n value && !disabled ? (\n <button\n type=\"button\"\n className=\"brycks-search-input__clear\"\n aria-label={clearLabel}\n onClick={handleClear}\n tabIndex={-1}\n >\n <ClearIcon />\n </button>\n ) : undefined\n }\n {...props}\n />\n )\n})\n\nSearchInput.displayName = 'SearchInput'\n"],"names":["SearchIcon","jsxs","jsx","ClearIcon","SearchInput","forwardRef","controlledValue","defaultValue","onValueChange","onClear","size","placeholder","leftElement","clearLabel","className","testId","disabled","props","ref","internalValue","setInternalValue","useState","isControlled","value","handleChange","useCallback","e","handleClear","Input"],"mappings":"wKAiDA,SAASA,GAAa,CACpB,OACEC,EAAAA,KAAC,MAAA,CAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,cAAY,OACtE,SAAA,CAAAC,EAAAA,IAAC,SAAA,CAAO,GAAG,IAAI,GAAG,IAAI,EAAE,MAAM,OAAO,eAAe,YAAY,KAAA,CAAM,EACtEA,EAAAA,IAAC,QAAK,EAAE,mBAAmB,OAAO,eAAe,YAAY,MAAM,cAAc,OAAA,CAAQ,CAAA,EAC3F,CAEJ,CAEA,SAASC,GAAY,CACnB,OACED,MAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,cAAY,OACtE,SAAAA,EAAAA,IAAC,OAAA,CAAK,EAAE,qBAAqB,OAAO,eAAe,YAAY,MAAM,cAAc,OAAA,CAAQ,CAAA,CAC7F,CAEJ,CAEO,MAAME,EAAcC,EAAAA,WAA+C,SACxE,CACE,MAAOC,EACP,aAAAC,EAAe,GACf,cAAAC,EACA,QAAAC,EACA,KAAAC,EAAO,KACP,YAAAC,EAAc,UACd,YAAAC,EACA,WAAAC,EAAa,eACb,UAAAC,EACA,OAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,KAAM,CAACC,EAAeC,CAAgB,EAAIC,EAAAA,SAASd,CAAY,EACzDe,EAAehB,IAAoB,OACnCiB,EAAQD,EAAehB,EAAkBa,EAEzCK,EAAeC,EAAAA,YAClBC,GAAqC,CAC/BJ,GAAcF,EAAiBM,EAAE,OAAO,KAAK,EAClDlB,IAAgBkB,EAAE,OAAO,KAAK,CAChC,EACA,CAACJ,EAAcd,CAAa,CAAA,EAGxBmB,EAAcF,EAAAA,YAAY,IAAM,CAC/BH,GAAcF,EAAiB,EAAE,EACtCZ,IAAgB,EAAE,EAClBC,IAAA,CACF,EAAG,CAACa,EAAcd,EAAeC,CAAO,CAAC,EAEzC,OACEP,EAAAA,IAAC0B,EAAAA,MAAA,CACC,IAAAV,EACA,KAAK,SACL,KAAK,YACL,KAAAR,EACA,YAAAC,EACA,MAAAY,EACA,SAAUC,EACV,SAAAR,EACA,UAAAF,EACA,OAAAC,EACA,YAAaH,GAAeV,MAACF,EAAA,CAAA,CAAW,EACxC,aACEuB,GAAS,CAACP,EACRd,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,UAAU,6BACV,aAAYW,EACZ,QAASc,EACT,SAAU,GAEV,eAACxB,EAAA,CAAA,CAAU,CAAA,CAAA,EAEX,OAEL,GAAGc,CAAA,CAAA,CAGV,CAAC,EAEDb,EAAY,YAAc"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as e, jsxs as g } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as S, useState as w, useCallback as s } from "react";
|
|
3
|
+
import { Input as y } from "../Input/Input.js";
|
|
4
|
+
function L() {
|
|
5
|
+
return /* @__PURE__ */ g("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
|
|
6
|
+
/* @__PURE__ */ e("circle", { cx: "7", cy: "7", r: "4.5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
7
|
+
/* @__PURE__ */ e("path", { d: "M10.5 10.5L14 14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
8
|
+
] });
|
|
9
|
+
}
|
|
10
|
+
function M() {
|
|
11
|
+
return /* @__PURE__ */ e("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ e("path", { d: "M4 4l6 6M10 4l-6 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
|
|
12
|
+
}
|
|
13
|
+
const W = S(function({
|
|
14
|
+
value: n,
|
|
15
|
+
defaultValue: h = "",
|
|
16
|
+
onValueChange: t,
|
|
17
|
+
onClear: o,
|
|
18
|
+
size: u = "md",
|
|
19
|
+
placeholder: d = "Search…",
|
|
20
|
+
leftElement: p,
|
|
21
|
+
clearLabel: f = "Clear search",
|
|
22
|
+
className: k,
|
|
23
|
+
testId: m,
|
|
24
|
+
disabled: a,
|
|
25
|
+
...v
|
|
26
|
+
}, x) {
|
|
27
|
+
const [I, i] = w(h), r = n !== void 0, c = r ? n : I, C = s(
|
|
28
|
+
(l) => {
|
|
29
|
+
r || i(l.target.value), t?.(l.target.value);
|
|
30
|
+
},
|
|
31
|
+
[r, t]
|
|
32
|
+
), b = s(() => {
|
|
33
|
+
r || i(""), t?.(""), o?.();
|
|
34
|
+
}, [r, t, o]);
|
|
35
|
+
return /* @__PURE__ */ e(
|
|
36
|
+
y,
|
|
37
|
+
{
|
|
38
|
+
ref: x,
|
|
39
|
+
type: "search",
|
|
40
|
+
role: "searchbox",
|
|
41
|
+
size: u,
|
|
42
|
+
placeholder: d,
|
|
43
|
+
value: c,
|
|
44
|
+
onChange: C,
|
|
45
|
+
disabled: a,
|
|
46
|
+
className: k,
|
|
47
|
+
testId: m,
|
|
48
|
+
leftElement: p ?? /* @__PURE__ */ e(L, {}),
|
|
49
|
+
rightElement: c && !a ? /* @__PURE__ */ e(
|
|
50
|
+
"button",
|
|
51
|
+
{
|
|
52
|
+
type: "button",
|
|
53
|
+
className: "brycks-search-input__clear",
|
|
54
|
+
"aria-label": f,
|
|
55
|
+
onClick: b,
|
|
56
|
+
tabIndex: -1,
|
|
57
|
+
children: /* @__PURE__ */ e(M, {})
|
|
58
|
+
}
|
|
59
|
+
) : void 0,
|
|
60
|
+
...v
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
W.displayName = "SearchInput";
|
|
65
|
+
export {
|
|
66
|
+
W as SearchInput
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=SearchInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchInput.js","sources":["../../../../src/components/form/SearchInput/SearchInput.tsx"],"sourcesContent":["/**\n * SearchInput Component\n *\n * A search field built on top of Input: a leading search icon and a trailing\n * clear button that appears once there is text. Works controlled (`value` +\n * `onValueChange`) or uncontrolled (`defaultValue`).\n *\n * All color styles are inherited from Input; the clear button hover state is\n * handled via a CSS class for easy customization.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n type ChangeEvent,\n type ReactNode,\n type InputHTMLAttributes,\n} from 'react'\nimport { Input, type InputSize } from '../Input'\n\ntype NativeInputProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'value' | 'defaultValue' | 'onChange' | 'type'\n>\n\nexport interface SearchInputProps extends NativeInputProps {\n /** Current value (controlled) */\n value?: string\n /** Initial value (uncontrolled) */\n defaultValue?: string\n /** Callback when the value changes (typing or clearing) */\n onValueChange?: (value: string) => void\n /** Callback fired when the clear button is pressed */\n onClear?: () => void\n /** Input size */\n size?: InputSize\n /** Placeholder text */\n placeholder?: string\n /** Custom leading element (defaults to a search icon) */\n leftElement?: ReactNode\n /** Accessible label of the clear button */\n clearLabel?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nfunction SearchIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M10.5 10.5L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(function SearchInput(\n {\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n onClear,\n size = 'md',\n placeholder = 'Search…',\n leftElement,\n clearLabel = 'Clear search',\n className,\n testId,\n disabled,\n ...props\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState(defaultValue)\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : internalValue\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n if (!isControlled) setInternalValue(e.target.value)\n onValueChange?.(e.target.value)\n },\n [isControlled, onValueChange]\n )\n\n const handleClear = useCallback(() => {\n if (!isControlled) setInternalValue('')\n onValueChange?.('')\n onClear?.()\n }, [isControlled, onValueChange, onClear])\n\n return (\n <Input\n ref={ref}\n type=\"search\"\n role=\"searchbox\"\n size={size}\n placeholder={placeholder}\n value={value}\n onChange={handleChange}\n disabled={disabled}\n className={className}\n testId={testId}\n leftElement={leftElement ?? <SearchIcon />}\n rightElement={\n value && !disabled ? (\n <button\n type=\"button\"\n className=\"brycks-search-input__clear\"\n aria-label={clearLabel}\n onClick={handleClear}\n tabIndex={-1}\n >\n <ClearIcon />\n </button>\n ) : undefined\n }\n {...props}\n />\n )\n})\n\nSearchInput.displayName = 'SearchInput'\n"],"names":["SearchIcon","jsxs","jsx","ClearIcon","SearchInput","forwardRef","controlledValue","defaultValue","onValueChange","onClear","size","placeholder","leftElement","clearLabel","className","testId","disabled","props","ref","internalValue","setInternalValue","useState","isControlled","value","handleChange","useCallback","e","handleClear","Input"],"mappings":";;;AAiDA,SAASA,IAAa;AACpB,SACE,gBAAAC,EAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACtE,UAAA;AAAA,IAAA,gBAAAC,EAAC,UAAA,EAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM,QAAO,gBAAe,aAAY,MAAA,CAAM;AAAA,IACtE,gBAAAA,EAAC,UAAK,GAAE,oBAAmB,QAAO,gBAAe,aAAY,OAAM,eAAc,QAAA,CAAQ;AAAA,EAAA,GAC3F;AAEJ;AAEA,SAASC,IAAY;AACnB,SACE,gBAAAD,EAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACtE,UAAA,gBAAAA,EAAC,QAAA,EAAK,GAAE,sBAAqB,QAAO,gBAAe,aAAY,OAAM,eAAc,QAAA,CAAQ,EAAA,CAC7F;AAEJ;AAEO,MAAME,IAAcC,EAA+C,SACxE;AAAA,EACE,OAAOC;AAAA,EACP,cAAAC,IAAe;AAAA,EACf,eAAAC;AAAA,EACA,SAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,aAAAC,IAAc;AAAA,EACd,aAAAC;AAAA,EACA,YAAAC,IAAa;AAAA,EACb,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AACA,QAAM,CAACC,GAAeC,CAAgB,IAAIC,EAASd,CAAY,GACzDe,IAAehB,MAAoB,QACnCiB,IAAQD,IAAehB,IAAkBa,GAEzCK,IAAeC;AAAA,IACnB,CAACC,MAAqC;AACpC,MAAKJ,KAAcF,EAAiBM,EAAE,OAAO,KAAK,GAClDlB,IAAgBkB,EAAE,OAAO,KAAK;AAAA,IAChC;AAAA,IACA,CAACJ,GAAcd,CAAa;AAAA,EAAA,GAGxBmB,IAAcF,EAAY,MAAM;AACpC,IAAKH,KAAcF,EAAiB,EAAE,GACtCZ,IAAgB,EAAE,GAClBC,IAAA;AAAA,EACF,GAAG,CAACa,GAAcd,GAAeC,CAAO,CAAC;AAEzC,SACE,gBAAAP;AAAA,IAAC0B;AAAA,IAAA;AAAA,MACC,KAAAV;AAAA,MACA,MAAK;AAAA,MACL,MAAK;AAAA,MACL,MAAAR;AAAA,MACA,aAAAC;AAAA,MACA,OAAAY;AAAA,MACA,UAAUC;AAAA,MACV,UAAAR;AAAA,MACA,WAAAF;AAAA,MACA,QAAAC;AAAA,MACA,aAAaH,KAAe,gBAAAV,EAACF,GAAA,CAAA,CAAW;AAAA,MACxC,cACEuB,KAAS,CAACP,IACR,gBAAAd;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,cAAYW;AAAA,UACZ,SAASc;AAAA,UACT,UAAU;AAAA,UAEV,4BAACxB,GAAA,CAAA,CAAU;AAAA,QAAA;AAAA,MAAA,IAEX;AAAA,MAEL,GAAGc;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AAEDb,EAAY,cAAc;"}
|
package/dist/components/form.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./form/Input/Input.cjs"),t=require("./form/TextField/TextField.cjs"),i=require("./form/Select/Select.cjs"),o=require("./form/Checkbox/Checkbox.cjs"),u=require("./form/Switch/Switch.cjs"),c=require("./form/Textarea/Textarea.cjs"),e=require("./form/Radio/Radio.cjs"),n=require("./form/Slider/Slider.cjs"),a=require("./form/DateInput/DateInput.cjs"),l=require("./form/FileInput/FileInput.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./form/Input/Input.cjs"),t=require("./form/TextField/TextField.cjs"),i=require("./form/Select/Select.cjs"),o=require("./form/Checkbox/Checkbox.cjs"),u=require("./form/Switch/Switch.cjs"),c=require("./form/Textarea/Textarea.cjs"),e=require("./form/Radio/Radio.cjs"),n=require("./form/Slider/Slider.cjs"),a=require("./form/DateInput/DateInput.cjs"),l=require("./form/FileInput/FileInput.cjs"),s=require("./form/FormField/FormField.cjs"),F=require("./form/FieldError/FieldError.cjs"),q=require("./form/Form/Form.cjs"),p=require("./form/FormLabel/FormLabel.cjs"),d=require("./form/FormGroup/FormGroup.cjs"),m=require("./form/Combobox/Combobox.cjs"),S=require("./form/Rating/Rating.cjs"),I=require("./form/TagInput/TagInput.cjs"),b=require("./form/MultiSelect/MultiSelect.cjs"),T=require("./form/TimePicker/TimePicker.cjs"),x=require("./form/DateRangePicker/DateRangePicker.cjs"),g=require("./form/SearchInput/SearchInput.cjs");exports.Input=r.Input;exports.TextField=t.TextField;exports.Select=i.Select;exports.Checkbox=o.Checkbox;exports.Switch=u.Switch;exports.Textarea=c.Textarea;exports.Radio=e.Radio;exports.RadioGroup=e.RadioGroup;exports.Slider=n.Slider;exports.DateInput=a.DateInput;exports.FileInput=l.FileInput;exports.FormField=s.FormField;exports.FieldError=F.FieldError;exports.Form=q.Form;exports.FormLabel=p.FormLabel;exports.FormGroup=d.FormGroup;exports.Combobox=m.Combobox;exports.Rating=S.Rating;exports.TagInput=I.TagInput;exports.MultiSelect=b.MultiSelect;exports.TimePicker=T.TimePicker;exports.DateRangePicker=x.DateRangePicker;exports.SearchInput=g.SearchInput;
|
|
2
2
|
//# sourceMappingURL=form.cjs.map
|
package/dist/components/form.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Input as e } from "./form/Input/Input.js";
|
|
2
|
-
import { TextField as
|
|
2
|
+
import { TextField as p } from "./form/TextField/TextField.js";
|
|
3
3
|
import { Select as x } from "./form/Select/Select.js";
|
|
4
4
|
import { Checkbox as i } from "./form/Checkbox/Checkbox.js";
|
|
5
5
|
import { Switch as l } from "./form/Switch/Switch.js";
|
|
6
|
-
import { Textarea as
|
|
7
|
-
import { Radio as
|
|
8
|
-
import { Slider as
|
|
9
|
-
import { DateInput as
|
|
6
|
+
import { Textarea as F } from "./form/Textarea/Textarea.js";
|
|
7
|
+
import { Radio as n, RadioGroup as d } from "./form/Radio/Radio.js";
|
|
8
|
+
import { Slider as S } from "./form/Slider/Slider.js";
|
|
9
|
+
import { DateInput as R } from "./form/DateInput/DateInput.js";
|
|
10
10
|
import { FileInput as g } from "./form/FileInput/FileInput.js";
|
|
11
|
-
import { FormField as
|
|
11
|
+
import { FormField as k } from "./form/FormField/FormField.js";
|
|
12
12
|
import { FieldError as D } from "./form/FieldError/FieldError.js";
|
|
13
13
|
import { Form as P } from "./form/Form/Form.js";
|
|
14
14
|
import { FormLabel as E } from "./form/FormLabel/FormLabel.js";
|
|
@@ -19,28 +19,30 @@ import { TagInput as z } from "./form/TagInput/TagInput.js";
|
|
|
19
19
|
import { MultiSelect as B } from "./form/MultiSelect/MultiSelect.js";
|
|
20
20
|
import { TimePicker as J } from "./form/TimePicker/TimePicker.js";
|
|
21
21
|
import { DateRangePicker as N } from "./form/DateRangePicker/DateRangePicker.js";
|
|
22
|
+
import { SearchInput as Q } from "./form/SearchInput/SearchInput.js";
|
|
22
23
|
export {
|
|
23
24
|
i as Checkbox,
|
|
24
25
|
q as Combobox,
|
|
25
|
-
|
|
26
|
+
R as DateInput,
|
|
26
27
|
N as DateRangePicker,
|
|
27
28
|
D as FieldError,
|
|
28
29
|
g as FileInput,
|
|
29
30
|
P as Form,
|
|
30
|
-
|
|
31
|
+
k as FormField,
|
|
31
32
|
M as FormGroup,
|
|
32
33
|
E as FormLabel,
|
|
33
34
|
e as Input,
|
|
34
35
|
B as MultiSelect,
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
n as Radio,
|
|
37
|
+
d as RadioGroup,
|
|
37
38
|
v as Rating,
|
|
39
|
+
Q as SearchInput,
|
|
38
40
|
x as Select,
|
|
39
|
-
|
|
41
|
+
S as Slider,
|
|
40
42
|
l as Switch,
|
|
41
43
|
z as TagInput,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
p as TextField,
|
|
45
|
+
F as Textarea,
|
|
44
46
|
J as TimePicker
|
|
45
47
|
};
|
|
46
48
|
//# sourceMappingURL=form.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"form.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),t=require("react"),i=require("../../../utils/styles.cjs"),f=t.forwardRef(function({variant:r="outline",padding:a="md",interactive:e=!1,selected:d=!1,className:c,style:s,children:y,testId:b,..._},k){return o.jsx("div",{ref:k,className:i.cx("brycks-card",`brycks-card--${r}`,`brycks-card--padding-${a}`,e&&"brycks-card--interactive",d&&"brycks-card--selected",c),style:s,"data-testid":b,..._,children:y})});f.displayName="Card";const l=t.forwardRef(function({divider:r=!1,className:a,style:e,children:d,...c},s){return o.jsx("div",{ref:s,className:i.cx("brycks-card__header",r&&"brycks-card__header--divider",a),style:e,...c,children:d})});l.displayName="CardHeader";const u=t.forwardRef(function({className:r,style:a,children:e,...d},c){return o.jsx("div",{ref:c,className:i.cx("brycks-card__body",r),style:a,...d,children:e})});u.displayName="CardBody";const C=t.forwardRef(function({divider:r=!1,align:a="right",className:e,style:d,children:c,...s},y){return o.jsx("div",{ref:y,className:i.cx("brycks-card__footer",r&&"brycks-card__footer--divider",`brycks-card__footer--${a}`,e),style:d,...s,children:c})});C.displayName="CardFooter";exports.Card=f;exports.CardBody=u;exports.CardFooter=C;exports.CardHeader=l;
|
|
2
2
|
//# sourceMappingURL=Card.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.cjs","sources":["../../../../src/components/layout/Card/Card.tsx"],"sourcesContent":["/**\n * Card Component\n *\n * A flexible card container with optional header, footer, and body sections.\n * Supports different variants and padding sizes.\n *\n * All color styles are handled via CSS classes for easy customization.\n */\n\nimport { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type CardVariant = 'elevated' | 'outline' | 'filled' | 'ghost'\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl'\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card variant */\n variant?: CardVariant\n /** Card padding */\n padding?: CardPadding\n /** Whether the card is interactive (adds hover effect) */\n interactive?: boolean\n /** Whether the card is selected */\n selected?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider below the header */\n divider?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport interface CardFooterProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider above the footer */\n divider?: boolean\n /** Footer alignment */\n align?: 'left' | 'center' | 'right' | 'between'\n /** Custom class name */\n className?: string\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n {\n variant = '
|
|
1
|
+
{"version":3,"file":"Card.cjs","sources":["../../../../src/components/layout/Card/Card.tsx"],"sourcesContent":["/**\n * Card Component\n *\n * A flexible card container with optional header, footer, and body sections.\n * Supports different variants and padding sizes.\n *\n * All color styles are handled via CSS classes for easy customization.\n */\n\nimport { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type CardVariant = 'elevated' | 'outline' | 'filled' | 'ghost'\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl'\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card variant */\n variant?: CardVariant\n /** Card padding */\n padding?: CardPadding\n /** Whether the card is interactive (adds hover effect) */\n interactive?: boolean\n /** Whether the card is selected */\n selected?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider below the header */\n divider?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport interface CardFooterProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider above the footer */\n divider?: boolean\n /** Footer alignment */\n align?: 'left' | 'center' | 'right' | 'between'\n /** Custom class name */\n className?: string\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n {\n // Flat-by-default: a 1px border conveys depth. Opt into shadow with\n // `variant=\"elevated\"`.\n variant = 'outline',\n padding = 'md',\n interactive = false,\n selected = false,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-card',\n `brycks-card--${variant}`,\n `brycks-card--padding-${padding}`,\n interactive && 'brycks-card--interactive',\n selected && 'brycks-card--selected',\n className\n )}\n style={style}\n data-testid={testId}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nCard.displayName = 'Card'\n\nexport const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(function CardHeader(\n { divider = false, className, style, children, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx('brycks-card__header', divider && 'brycks-card__header--divider', className)}\n style={style}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nCardHeader.displayName = 'CardHeader'\n\nexport const CardBody = forwardRef<HTMLDivElement, CardBodyProps>(function CardBody(\n { className, style, children, ...props },\n ref\n) {\n return (\n <div ref={ref} className={cx('brycks-card__body', className)} style={style} {...props}>\n {children}\n </div>\n )\n})\n\nCardBody.displayName = 'CardBody'\n\nexport const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(function CardFooter(\n { divider = false, align = 'right', className, style, children, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-card__footer',\n divider && 'brycks-card__footer--divider',\n `brycks-card__footer--${align}`,\n className\n )}\n style={style}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nCardFooter.displayName = 'CardFooter'\n"],"names":["Card","forwardRef","variant","padding","interactive","selected","className","style","children","testId","props","ref","jsx","cx","CardHeader","divider","CardBody","CardFooter","align"],"mappings":"+KAmDaA,EAAOC,EAAAA,WAAsC,SACxD,CAGE,QAAAC,EAAU,UACV,QAAAC,EAAU,KACV,YAAAC,EAAc,GACd,SAAAC,EAAW,GACX,UAAAC,EACA,MAAAC,EACA,SAAAC,EACA,OAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,OACEC,EAAAA,IAAC,MAAA,CACC,IAAAD,EACA,UAAWE,EAAAA,GACT,cACA,gBAAgBX,CAAO,GACvB,wBAAwBC,CAAO,GAC/BC,GAAe,2BACfC,GAAY,wBACZC,CAAA,EAEF,MAAAC,EACA,cAAaE,EACZ,GAAGC,EAEH,SAAAF,CAAA,CAAA,CAGP,CAAC,EAEDR,EAAK,YAAc,OAEZ,MAAMc,EAAab,EAAAA,WAA4C,SACpE,CAAE,QAAAc,EAAU,GAAO,UAAAT,EAAW,MAAAC,EAAO,SAAAC,EAAU,GAAGE,CAAA,EAClDC,EACA,CACA,OACEC,EAAAA,IAAC,MAAA,CACC,IAAAD,EACA,UAAWE,EAAAA,GAAG,sBAAuBE,GAAW,+BAAgCT,CAAS,EACzF,MAAAC,EACC,GAAGG,EAEH,SAAAF,CAAA,CAAA,CAGP,CAAC,EAEDM,EAAW,YAAc,aAElB,MAAME,EAAWf,EAAAA,WAA0C,SAChE,CAAE,UAAAK,EAAW,MAAAC,EAAO,SAAAC,EAAU,GAAGE,CAAA,EACjCC,EACA,CACA,OACEC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAAA,GAAG,oBAAqBP,CAAS,EAAG,MAAAC,EAAe,GAAGG,EAC7E,SAAAF,CAAA,CACH,CAEJ,CAAC,EAEDQ,EAAS,YAAc,WAEhB,MAAMC,EAAahB,EAAAA,WAA4C,SACpE,CAAE,QAAAc,EAAU,GAAO,MAAAG,EAAQ,QAAS,UAAAZ,EAAW,MAAAC,EAAO,SAAAC,EAAU,GAAGE,CAAA,EACnEC,EACA,CACA,OACEC,EAAAA,IAAC,MAAA,CACC,IAAAD,EACA,UAAWE,EAAAA,GACT,sBACAE,GAAW,+BACX,wBAAwBG,CAAK,GAC7BZ,CAAA,EAEF,MAAAC,EACC,GAAGG,EAEH,SAAAF,CAAA,CAAA,CAGP,CAAC,EAEDS,EAAW,YAAc"}
|
|
@@ -2,13 +2,15 @@ import { jsx as o } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as t } from "react";
|
|
3
3
|
import { cx as i } from "../../../utils/styles.js";
|
|
4
4
|
const b = t(function({
|
|
5
|
-
|
|
5
|
+
// Flat-by-default: a 1px border conveys depth. Opt into shadow with
|
|
6
|
+
// `variant="elevated"`.
|
|
7
|
+
variant: r = "outline",
|
|
6
8
|
padding: a = "md",
|
|
7
9
|
interactive: d = !1,
|
|
8
10
|
selected: e = !1,
|
|
9
11
|
className: c,
|
|
10
12
|
style: s,
|
|
11
|
-
children:
|
|
13
|
+
children: y,
|
|
12
14
|
testId: f,
|
|
13
15
|
...m
|
|
14
16
|
}, l) {
|
|
@@ -27,7 +29,7 @@ const b = t(function({
|
|
|
27
29
|
style: s,
|
|
28
30
|
"data-testid": f,
|
|
29
31
|
...m,
|
|
30
|
-
children:
|
|
32
|
+
children: y
|
|
31
33
|
}
|
|
32
34
|
);
|
|
33
35
|
});
|
|
@@ -49,11 +51,11 @@ const _ = t(function({ className: r, style: a, children: d, ...e }, c) {
|
|
|
49
51
|
return /* @__PURE__ */ o("div", { ref: c, className: i("brycks-card__body", r), style: a, ...e, children: d });
|
|
50
52
|
});
|
|
51
53
|
_.displayName = "CardBody";
|
|
52
|
-
const k = t(function({ divider: r = !1, align: a = "right", className: d, style: e, children: c, ...s },
|
|
54
|
+
const k = t(function({ divider: r = !1, align: a = "right", className: d, style: e, children: c, ...s }, y) {
|
|
53
55
|
return /* @__PURE__ */ o(
|
|
54
56
|
"div",
|
|
55
57
|
{
|
|
56
|
-
ref:
|
|
58
|
+
ref: y,
|
|
57
59
|
className: i(
|
|
58
60
|
"brycks-card__footer",
|
|
59
61
|
r && "brycks-card__footer--divider",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.js","sources":["../../../../src/components/layout/Card/Card.tsx"],"sourcesContent":["/**\n * Card Component\n *\n * A flexible card container with optional header, footer, and body sections.\n * Supports different variants and padding sizes.\n *\n * All color styles are handled via CSS classes for easy customization.\n */\n\nimport { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type CardVariant = 'elevated' | 'outline' | 'filled' | 'ghost'\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl'\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card variant */\n variant?: CardVariant\n /** Card padding */\n padding?: CardPadding\n /** Whether the card is interactive (adds hover effect) */\n interactive?: boolean\n /** Whether the card is selected */\n selected?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider below the header */\n divider?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport interface CardFooterProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider above the footer */\n divider?: boolean\n /** Footer alignment */\n align?: 'left' | 'center' | 'right' | 'between'\n /** Custom class name */\n className?: string\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n {\n variant = '
|
|
1
|
+
{"version":3,"file":"Card.js","sources":["../../../../src/components/layout/Card/Card.tsx"],"sourcesContent":["/**\n * Card Component\n *\n * A flexible card container with optional header, footer, and body sections.\n * Supports different variants and padding sizes.\n *\n * All color styles are handled via CSS classes for easy customization.\n */\n\nimport { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type CardVariant = 'elevated' | 'outline' | 'filled' | 'ghost'\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl'\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card variant */\n variant?: CardVariant\n /** Card padding */\n padding?: CardPadding\n /** Whether the card is interactive (adds hover effect) */\n interactive?: boolean\n /** Whether the card is selected */\n selected?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider below the header */\n divider?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport interface CardFooterProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether to show a divider above the footer */\n divider?: boolean\n /** Footer alignment */\n align?: 'left' | 'center' | 'right' | 'between'\n /** Custom class name */\n className?: string\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n {\n // Flat-by-default: a 1px border conveys depth. Opt into shadow with\n // `variant=\"elevated\"`.\n variant = 'outline',\n padding = 'md',\n interactive = false,\n selected = false,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-card',\n `brycks-card--${variant}`,\n `brycks-card--padding-${padding}`,\n interactive && 'brycks-card--interactive',\n selected && 'brycks-card--selected',\n className\n )}\n style={style}\n data-testid={testId}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nCard.displayName = 'Card'\n\nexport const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(function CardHeader(\n { divider = false, className, style, children, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx('brycks-card__header', divider && 'brycks-card__header--divider', className)}\n style={style}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nCardHeader.displayName = 'CardHeader'\n\nexport const CardBody = forwardRef<HTMLDivElement, CardBodyProps>(function CardBody(\n { className, style, children, ...props },\n ref\n) {\n return (\n <div ref={ref} className={cx('brycks-card__body', className)} style={style} {...props}>\n {children}\n </div>\n )\n})\n\nCardBody.displayName = 'CardBody'\n\nexport const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(function CardFooter(\n { divider = false, align = 'right', className, style, children, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-card__footer',\n divider && 'brycks-card__footer--divider',\n `brycks-card__footer--${align}`,\n className\n )}\n style={style}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nCardFooter.displayName = 'CardFooter'\n"],"names":["Card","forwardRef","variant","padding","interactive","selected","className","style","children","testId","props","ref","jsx","cx","CardHeader","divider","CardBody","CardFooter","align"],"mappings":";;;AAmDO,MAAMA,IAAOC,EAAsC,SACxD;AAAA;AAAA;AAAA,EAGE,SAAAC,IAAU;AAAA,EACV,SAAAC,IAAU;AAAA,EACV,aAAAC,IAAc;AAAA,EACd,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AACA,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACA,gBAAgBX,CAAO;AAAA,QACvB,wBAAwBC,CAAO;AAAA,QAC/BC,KAAe;AAAA,QACfC,KAAY;AAAA,QACZC;AAAA,MAAA;AAAA,MAEF,OAAAC;AAAA,MACA,eAAaE;AAAA,MACZ,GAAGC;AAAA,MAEH,UAAAF;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AAEDR,EAAK,cAAc;AAEZ,MAAMc,IAAab,EAA4C,SACpE,EAAE,SAAAc,IAAU,IAAO,WAAAT,GAAW,OAAAC,GAAO,UAAAC,GAAU,GAAGE,EAAA,GAClDC,GACA;AACA,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,WAAWE,EAAG,uBAAuBE,KAAW,gCAAgCT,CAAS;AAAA,MACzF,OAAAC;AAAA,MACC,GAAGG;AAAA,MAEH,UAAAF;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AAEDM,EAAW,cAAc;AAElB,MAAME,IAAWf,EAA0C,SAChE,EAAE,WAAAK,GAAW,OAAAC,GAAO,UAAAC,GAAU,GAAGE,EAAA,GACjCC,GACA;AACA,SACE,gBAAAC,EAAC,OAAA,EAAI,KAAAD,GAAU,WAAWE,EAAG,qBAAqBP,CAAS,GAAG,OAAAC,GAAe,GAAGG,GAC7E,UAAAF,EAAA,CACH;AAEJ,CAAC;AAEDQ,EAAS,cAAc;AAEhB,MAAMC,IAAahB,EAA4C,SACpE,EAAE,SAAAc,IAAU,IAAO,OAAAG,IAAQ,SAAS,WAAAZ,GAAW,OAAAC,GAAO,UAAAC,GAAU,GAAGE,EAAA,GACnEC,GACA;AACA,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACAE,KAAW;AAAA,QACX,wBAAwBG,CAAK;AAAA,QAC7BZ;AAAA,MAAA;AAAA,MAEF,OAAAC;AAAA,MACC,GAAGG;AAAA,MAEH,UAAAF;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AAEDS,EAAW,cAAc;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),o=require("react"),b=require("../../../utils/styles.cjs");function S({options:l,value:u,onValueChange:c,size:m="md",fullWidth:f=!1,"aria-label":g,"aria-labelledby":y,className:k,testId:h},x){const d=o.useRef([]),r=l.map((e,n)=>e.disabled?-1:n).filter(e=>e!==-1),w=e=>{d.current[e]?.focus()},v=(e,n)=>{if(r.length===0)return;const s=r.indexOf(n);let t=null;switch(e.key){case"ArrowRight":case"ArrowDown":t=r[(s+1)%r.length];break;case"ArrowLeft":case"ArrowUp":t=r[(s-1+r.length)%r.length];break;case"Home":t=r[0];break;case"End":t=r[r.length-1];break;default:return}t!==null&&(e.preventDefault(),w(t),c(l[t].value))};return a.jsx("div",{ref:x,role:"radiogroup","aria-label":g,"aria-labelledby":y,className:b.cx("brycks-segmented",`brycks-segmented--${m}`,f&&"brycks-segmented--full-width",k),"data-testid":h,children:l.map((e,n)=>{const s=e.value===u;return a.jsxs("button",{ref:t=>{d.current[n]=t},type:"button",role:"radio","aria-checked":s,disabled:e.disabled,tabIndex:s?0:-1,className:b.cx("brycks-segmented__item",s&&"brycks-segmented__item--selected"),onClick:()=>!e.disabled&&c(e.value),onKeyDown:t=>v(t,n),children:[e.icon&&a.jsx("span",{className:"brycks-segmented__icon",children:e.icon}),e.label]},e.value)})})}const i=o.forwardRef(S);i.displayName="SegmentedControl";exports.SegmentedControl=i;
|
|
2
|
+
//# sourceMappingURL=SegmentedControl.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SegmentedControl.cjs","sources":["../../../../src/components/navigation/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["/**\n * SegmentedControl Component\n *\n * A compact single-select control for switching between a small set of\n * mutually-exclusive options (e.g. a view toggle: list / kanban / table).\n *\n * Implemented as an ARIA `radiogroup` with roving focus: arrow keys move the\n * selection, Home/End jump to the ends. All color styles are handled via CSS\n * classes for easy customization.\n */\n\nimport React, {\n forwardRef,\n useRef,\n type ReactNode,\n type KeyboardEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type SegmentedControlSize = 'sm' | 'md' | 'lg'\n\nexport interface SegmentedControlOption<T extends string = string> {\n /** Unique value */\n value: T\n /** Display label */\n label: ReactNode\n /** Optional leading icon */\n icon?: ReactNode\n /** Whether the option is disabled */\n disabled?: boolean\n}\n\nexport interface SegmentedControlProps<T extends string = string> {\n /** Available options */\n options: SegmentedControlOption<T>[]\n /** Currently selected value (controlled) */\n value: T\n /** Callback when the selection changes */\n onValueChange: (value: T) => void\n /** Component size */\n size?: SegmentedControlSize\n /** Whether the control should fill its container width */\n fullWidth?: boolean\n /** Accessible label for the group */\n 'aria-label'?: string\n /** ID of an element that labels the group */\n 'aria-labelledby'?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nfunction SegmentedControlInner<T extends string = string>(\n {\n options,\n value,\n onValueChange,\n size = 'md',\n fullWidth = false,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n className,\n testId,\n }: SegmentedControlProps<T>,\n ref: React.ForwardedRef<HTMLDivElement>\n) {\n const buttonsRef = useRef<(HTMLButtonElement | null)[]>([])\n\n const enabledIndexes = options\n .map((opt, i) => (opt.disabled ? -1 : i))\n .filter((i) => i !== -1)\n\n const focusByIndex = (index: number) => {\n const btn = buttonsRef.current[index]\n btn?.focus()\n }\n\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n if (enabledIndexes.length === 0) return\n\n const posInEnabled = enabledIndexes.indexOf(currentIndex)\n let nextIndex: number | null = null\n\n switch (e.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = enabledIndexes[(posInEnabled + 1) % enabledIndexes.length]\n break\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = enabledIndexes[(posInEnabled - 1 + enabledIndexes.length) % enabledIndexes.length]\n break\n case 'Home':\n nextIndex = enabledIndexes[0]\n break\n case 'End':\n nextIndex = enabledIndexes[enabledIndexes.length - 1]\n break\n default:\n return\n }\n\n if (nextIndex !== null) {\n e.preventDefault()\n focusByIndex(nextIndex)\n onValueChange(options[nextIndex].value)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"radiogroup\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n className={cx(\n 'brycks-segmented',\n `brycks-segmented--${size}`,\n fullWidth && 'brycks-segmented--full-width',\n className\n )}\n data-testid={testId}\n >\n {options.map((option, index) => {\n const isSelected = option.value === value\n return (\n <button\n key={option.value}\n ref={(node) => {\n buttonsRef.current[index] = node\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n disabled={option.disabled}\n // Roving tabindex: only the selected (or first enabled) item is tabbable.\n tabIndex={isSelected ? 0 : -1}\n className={cx(\n 'brycks-segmented__item',\n isSelected && 'brycks-segmented__item--selected'\n )}\n onClick={() => !option.disabled && onValueChange(option.value)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n >\n {option.icon && <span className=\"brycks-segmented__icon\">{option.icon}</span>}\n {option.label}\n </button>\n )\n })}\n </div>\n )\n}\n\nexport const SegmentedControl = forwardRef(SegmentedControlInner) as <T extends string = string>(\n props: SegmentedControlProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> }\n) => React.JSX.Element\n\n// @ts-expect-error -- attach displayName to the cast forwardRef\nSegmentedControl.displayName = 'SegmentedControl'\n"],"names":["SegmentedControlInner","options","value","onValueChange","size","fullWidth","ariaLabel","ariaLabelledby","className","testId","ref","buttonsRef","useRef","enabledIndexes","opt","i","focusByIndex","index","handleKeyDown","currentIndex","posInEnabled","nextIndex","jsx","cx","option","isSelected","jsxs","node","e","SegmentedControl","forwardRef"],"mappings":"+KAqDA,SAASA,EACP,CACE,QAAAC,EACA,MAAAC,EACA,cAAAC,EACA,KAAAC,EAAO,KACP,UAAAC,EAAY,GACZ,aAAcC,EACd,kBAAmBC,EACnB,UAAAC,EACA,OAAAC,CACF,EACAC,EACA,CACA,MAAMC,EAAaC,EAAAA,OAAqC,EAAE,EAEpDC,EAAiBZ,EACpB,IAAI,CAACa,EAAKC,IAAOD,EAAI,SAAW,GAAKC,CAAE,EACvC,OAAQA,GAAMA,IAAM,EAAE,EAEnBC,EAAgBC,GAAkB,CAC1BN,EAAW,QAAQM,CAAK,GAC/B,MAAA,CACP,EAEMC,EAAgB,CAAC,EAAqCC,IAAyB,CACnF,GAAIN,EAAe,SAAW,EAAG,OAEjC,MAAMO,EAAeP,EAAe,QAAQM,CAAY,EACxD,IAAIE,EAA2B,KAE/B,OAAQ,EAAE,IAAA,CACR,IAAK,aACL,IAAK,YACHA,EAAYR,GAAgBO,EAAe,GAAKP,EAAe,MAAM,EACrE,MACF,IAAK,YACL,IAAK,UACHQ,EAAYR,GAAgBO,EAAe,EAAIP,EAAe,QAAUA,EAAe,MAAM,EAC7F,MACF,IAAK,OACHQ,EAAYR,EAAe,CAAC,EAC5B,MACF,IAAK,MACHQ,EAAYR,EAAeA,EAAe,OAAS,CAAC,EACpD,MACF,QACE,MAAA,CAGAQ,IAAc,OAChB,EAAE,eAAA,EACFL,EAAaK,CAAS,EACtBlB,EAAcF,EAAQoB,CAAS,EAAE,KAAK,EAE1C,EAEA,OACEC,EAAAA,IAAC,MAAA,CACC,IAAAZ,EACA,KAAK,aACL,aAAYJ,EACZ,kBAAiBC,EACjB,UAAWgB,EAAAA,GACT,mBACA,qBAAqBnB,CAAI,GACzBC,GAAa,+BACbG,CAAA,EAEF,cAAaC,EAEZ,SAAAR,EAAQ,IAAI,CAACuB,EAAQP,IAAU,CAC9B,MAAMQ,EAAaD,EAAO,QAAUtB,EACpC,OACEwB,EAAAA,KAAC,SAAA,CAEC,IAAMC,GAAS,CACbhB,EAAW,QAAQM,CAAK,EAAIU,CAC9B,EACA,KAAK,SACL,KAAK,QACL,eAAcF,EACd,SAAUD,EAAO,SAEjB,SAAUC,EAAa,EAAI,GAC3B,UAAWF,EAAAA,GACT,yBACAE,GAAc,kCAAA,EAEhB,QAAS,IAAM,CAACD,EAAO,UAAYrB,EAAcqB,EAAO,KAAK,EAC7D,UAAYI,GAAMV,EAAcU,EAAGX,CAAK,EAEvC,SAAA,CAAAO,EAAO,MAAQF,EAAAA,IAAC,OAAA,CAAK,UAAU,yBAA0B,WAAO,KAAK,EACrEE,EAAO,KAAA,CAAA,EAlBHA,EAAO,KAAA,CAqBlB,CAAC,CAAA,CAAA,CAGP,CAEO,MAAMK,EAAmBC,EAAAA,WAAW9B,CAAqB,EAKhE6B,EAAiB,YAAc"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { jsx as c, jsxs as x } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as v, useRef as I } from "react";
|
|
3
|
+
import { cx as b } from "../../../utils/styles.js";
|
|
4
|
+
function _({
|
|
5
|
+
options: l,
|
|
6
|
+
value: o,
|
|
7
|
+
onValueChange: s,
|
|
8
|
+
size: i = "md",
|
|
9
|
+
fullWidth: m = !1,
|
|
10
|
+
"aria-label": u,
|
|
11
|
+
"aria-labelledby": f,
|
|
12
|
+
className: g,
|
|
13
|
+
testId: y
|
|
14
|
+
}, k) {
|
|
15
|
+
const d = I([]), a = l.map((e, n) => e.disabled ? -1 : n).filter((e) => e !== -1), h = (e) => {
|
|
16
|
+
d.current[e]?.focus();
|
|
17
|
+
}, w = (e, n) => {
|
|
18
|
+
if (a.length === 0) return;
|
|
19
|
+
const t = a.indexOf(n);
|
|
20
|
+
let r = null;
|
|
21
|
+
switch (e.key) {
|
|
22
|
+
case "ArrowRight":
|
|
23
|
+
case "ArrowDown":
|
|
24
|
+
r = a[(t + 1) % a.length];
|
|
25
|
+
break;
|
|
26
|
+
case "ArrowLeft":
|
|
27
|
+
case "ArrowUp":
|
|
28
|
+
r = a[(t - 1 + a.length) % a.length];
|
|
29
|
+
break;
|
|
30
|
+
case "Home":
|
|
31
|
+
r = a[0];
|
|
32
|
+
break;
|
|
33
|
+
case "End":
|
|
34
|
+
r = a[a.length - 1];
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
r !== null && (e.preventDefault(), h(r), s(l[r].value));
|
|
40
|
+
};
|
|
41
|
+
return /* @__PURE__ */ c(
|
|
42
|
+
"div",
|
|
43
|
+
{
|
|
44
|
+
ref: k,
|
|
45
|
+
role: "radiogroup",
|
|
46
|
+
"aria-label": u,
|
|
47
|
+
"aria-labelledby": f,
|
|
48
|
+
className: b(
|
|
49
|
+
"brycks-segmented",
|
|
50
|
+
`brycks-segmented--${i}`,
|
|
51
|
+
m && "brycks-segmented--full-width",
|
|
52
|
+
g
|
|
53
|
+
),
|
|
54
|
+
"data-testid": y,
|
|
55
|
+
children: l.map((e, n) => {
|
|
56
|
+
const t = e.value === o;
|
|
57
|
+
return /* @__PURE__ */ x(
|
|
58
|
+
"button",
|
|
59
|
+
{
|
|
60
|
+
ref: (r) => {
|
|
61
|
+
d.current[n] = r;
|
|
62
|
+
},
|
|
63
|
+
type: "button",
|
|
64
|
+
role: "radio",
|
|
65
|
+
"aria-checked": t,
|
|
66
|
+
disabled: e.disabled,
|
|
67
|
+
tabIndex: t ? 0 : -1,
|
|
68
|
+
className: b(
|
|
69
|
+
"brycks-segmented__item",
|
|
70
|
+
t && "brycks-segmented__item--selected"
|
|
71
|
+
),
|
|
72
|
+
onClick: () => !e.disabled && s(e.value),
|
|
73
|
+
onKeyDown: (r) => w(r, n),
|
|
74
|
+
children: [
|
|
75
|
+
e.icon && /* @__PURE__ */ c("span", { className: "brycks-segmented__icon", children: e.icon }),
|
|
76
|
+
e.label
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
e.value
|
|
80
|
+
);
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const p = v(_);
|
|
86
|
+
p.displayName = "SegmentedControl";
|
|
87
|
+
export {
|
|
88
|
+
p as SegmentedControl
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=SegmentedControl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SegmentedControl.js","sources":["../../../../src/components/navigation/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["/**\n * SegmentedControl Component\n *\n * A compact single-select control for switching between a small set of\n * mutually-exclusive options (e.g. a view toggle: list / kanban / table).\n *\n * Implemented as an ARIA `radiogroup` with roving focus: arrow keys move the\n * selection, Home/End jump to the ends. All color styles are handled via CSS\n * classes for easy customization.\n */\n\nimport React, {\n forwardRef,\n useRef,\n type ReactNode,\n type KeyboardEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type SegmentedControlSize = 'sm' | 'md' | 'lg'\n\nexport interface SegmentedControlOption<T extends string = string> {\n /** Unique value */\n value: T\n /** Display label */\n label: ReactNode\n /** Optional leading icon */\n icon?: ReactNode\n /** Whether the option is disabled */\n disabled?: boolean\n}\n\nexport interface SegmentedControlProps<T extends string = string> {\n /** Available options */\n options: SegmentedControlOption<T>[]\n /** Currently selected value (controlled) */\n value: T\n /** Callback when the selection changes */\n onValueChange: (value: T) => void\n /** Component size */\n size?: SegmentedControlSize\n /** Whether the control should fill its container width */\n fullWidth?: boolean\n /** Accessible label for the group */\n 'aria-label'?: string\n /** ID of an element that labels the group */\n 'aria-labelledby'?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nfunction SegmentedControlInner<T extends string = string>(\n {\n options,\n value,\n onValueChange,\n size = 'md',\n fullWidth = false,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n className,\n testId,\n }: SegmentedControlProps<T>,\n ref: React.ForwardedRef<HTMLDivElement>\n) {\n const buttonsRef = useRef<(HTMLButtonElement | null)[]>([])\n\n const enabledIndexes = options\n .map((opt, i) => (opt.disabled ? -1 : i))\n .filter((i) => i !== -1)\n\n const focusByIndex = (index: number) => {\n const btn = buttonsRef.current[index]\n btn?.focus()\n }\n\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n if (enabledIndexes.length === 0) return\n\n const posInEnabled = enabledIndexes.indexOf(currentIndex)\n let nextIndex: number | null = null\n\n switch (e.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = enabledIndexes[(posInEnabled + 1) % enabledIndexes.length]\n break\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = enabledIndexes[(posInEnabled - 1 + enabledIndexes.length) % enabledIndexes.length]\n break\n case 'Home':\n nextIndex = enabledIndexes[0]\n break\n case 'End':\n nextIndex = enabledIndexes[enabledIndexes.length - 1]\n break\n default:\n return\n }\n\n if (nextIndex !== null) {\n e.preventDefault()\n focusByIndex(nextIndex)\n onValueChange(options[nextIndex].value)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"radiogroup\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n className={cx(\n 'brycks-segmented',\n `brycks-segmented--${size}`,\n fullWidth && 'brycks-segmented--full-width',\n className\n )}\n data-testid={testId}\n >\n {options.map((option, index) => {\n const isSelected = option.value === value\n return (\n <button\n key={option.value}\n ref={(node) => {\n buttonsRef.current[index] = node\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n disabled={option.disabled}\n // Roving tabindex: only the selected (or first enabled) item is tabbable.\n tabIndex={isSelected ? 0 : -1}\n className={cx(\n 'brycks-segmented__item',\n isSelected && 'brycks-segmented__item--selected'\n )}\n onClick={() => !option.disabled && onValueChange(option.value)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n >\n {option.icon && <span className=\"brycks-segmented__icon\">{option.icon}</span>}\n {option.label}\n </button>\n )\n })}\n </div>\n )\n}\n\nexport const SegmentedControl = forwardRef(SegmentedControlInner) as <T extends string = string>(\n props: SegmentedControlProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> }\n) => React.JSX.Element\n\n// @ts-expect-error -- attach displayName to the cast forwardRef\nSegmentedControl.displayName = 'SegmentedControl'\n"],"names":["SegmentedControlInner","options","value","onValueChange","size","fullWidth","ariaLabel","ariaLabelledby","className","testId","ref","buttonsRef","useRef","enabledIndexes","opt","i","focusByIndex","index","handleKeyDown","currentIndex","posInEnabled","nextIndex","jsx","cx","option","isSelected","jsxs","node","e","SegmentedControl","forwardRef"],"mappings":";;;AAqDA,SAASA,EACP;AAAA,EACE,SAAAC;AAAA,EACA,OAAAC;AAAA,EACA,eAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,WAAAC,IAAY;AAAA,EACZ,cAAcC;AAAA,EACd,mBAAmBC;AAAA,EACnB,WAAAC;AAAA,EACA,QAAAC;AACF,GACAC,GACA;AACA,QAAMC,IAAaC,EAAqC,EAAE,GAEpDC,IAAiBZ,EACpB,IAAI,CAACa,GAAKC,MAAOD,EAAI,WAAW,KAAKC,CAAE,EACvC,OAAO,CAACA,MAAMA,MAAM,EAAE,GAEnBC,IAAe,CAACC,MAAkB;AAEtC,IADYN,EAAW,QAAQM,CAAK,GAC/B,MAAA;AAAA,EACP,GAEMC,IAAgB,CAAC,GAAqCC,MAAyB;AACnF,QAAIN,EAAe,WAAW,EAAG;AAEjC,UAAMO,IAAeP,EAAe,QAAQM,CAAY;AACxD,QAAIE,IAA2B;AAE/B,YAAQ,EAAE,KAAA;AAAA,MACR,KAAK;AAAA,MACL,KAAK;AACH,QAAAA,IAAYR,GAAgBO,IAAe,KAAKP,EAAe,MAAM;AACrE;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,QAAAQ,IAAYR,GAAgBO,IAAe,IAAIP,EAAe,UAAUA,EAAe,MAAM;AAC7F;AAAA,MACF,KAAK;AACH,QAAAQ,IAAYR,EAAe,CAAC;AAC5B;AAAA,MACF,KAAK;AACH,QAAAQ,IAAYR,EAAeA,EAAe,SAAS,CAAC;AACpD;AAAA,MACF;AACE;AAAA,IAAA;AAGJ,IAAIQ,MAAc,SAChB,EAAE,eAAA,GACFL,EAAaK,CAAS,GACtBlB,EAAcF,EAAQoB,CAAS,EAAE,KAAK;AAAA,EAE1C;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAZ;AAAA,MACA,MAAK;AAAA,MACL,cAAYJ;AAAA,MACZ,mBAAiBC;AAAA,MACjB,WAAWgB;AAAA,QACT;AAAA,QACA,qBAAqBnB,CAAI;AAAA,QACzBC,KAAa;AAAA,QACbG;AAAA,MAAA;AAAA,MAEF,eAAaC;AAAA,MAEZ,UAAAR,EAAQ,IAAI,CAACuB,GAAQP,MAAU;AAC9B,cAAMQ,IAAaD,EAAO,UAAUtB;AACpC,eACE,gBAAAwB;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,KAAK,CAACC,MAAS;AACb,cAAAhB,EAAW,QAAQM,CAAK,IAAIU;AAAA,YAC9B;AAAA,YACA,MAAK;AAAA,YACL,MAAK;AAAA,YACL,gBAAcF;AAAA,YACd,UAAUD,EAAO;AAAA,YAEjB,UAAUC,IAAa,IAAI;AAAA,YAC3B,WAAWF;AAAA,cACT;AAAA,cACAE,KAAc;AAAA,YAAA;AAAA,YAEhB,SAAS,MAAM,CAACD,EAAO,YAAYrB,EAAcqB,EAAO,KAAK;AAAA,YAC7D,WAAW,CAACI,MAAMV,EAAcU,GAAGX,CAAK;AAAA,YAEvC,UAAA;AAAA,cAAAO,EAAO,QAAQ,gBAAAF,EAAC,QAAA,EAAK,WAAU,0BAA0B,YAAO,MAAK;AAAA,cACrEE,EAAO;AAAA,YAAA;AAAA,UAAA;AAAA,UAlBHA,EAAO;AAAA,QAAA;AAAA,MAqBlB,CAAC;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,MAAMK,IAAmBC,EAAW9B,CAAqB;AAKhE6B,EAAiB,cAAc;"}
|