{"version":3,"sources":["../src/Combobox/Combobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { clsx } from 'clsx';\nimport { X, ChevronDown, Check } from 'lucide-react';\n\nexport type ComboboxOption = {\n  value: string;\n  label: string;\n};\n\nexport type ComboboxState = 'default' | 'error' | 'success';\n\nexport interface ComboboxProps {\n  /**\n   * The label for the combobox\n   */\n  label?: string;\n  /**\n   * The placeholder text\n   */\n  placeholder?: string;\n  /**\n   * The available options\n   */\n  options: ComboboxOption[];\n  /**\n   * The selected value\n   */\n  value?: string;\n  /**\n   * Callback when value changes\n   */\n  onChange?: (value: string | undefined) => void;\n  /**\n   * The validation state\n   * @default 'default'\n   */\n  state?: ComboboxState;\n  /**\n   * Optional error message\n   */\n  error?: string;\n  /**\n   * Optional helper text\n   */\n  helperText?: string;\n  /**\n   * Whether the combobox is disabled\n   */\n  disabled?: boolean;\n  /**\n   * Custom className\n   */\n  className?: string;\n  /**\n   * Custom style\n   */\n  style?: React.CSSProperties;\n  /**\n   * Test ID for testing\n   */\n  'data-testid'?: string;\n}\n\nconst comboboxStyles = {\n  base: {\n    width: '100%',\n    height: '36px',\n    fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n    backgroundColor: '#ffffff',\n    borderRadius: '8px',\n    transition: 'all 0.2s ease-in-out',\n    outline: 'none',\n    fontSize: '13px',\n    padding: '8px',\n    paddingRight: '32px',\n    margin: '0',\n    display: 'flex',\n    alignItems: 'center',\n    cursor: 'pointer',\n    position: 'relative' as const,\n  },\n  states: {\n    default: {\n      border: '1px solid #d1d1d1', // grey-300\n      color: '#2f2f2f', // grey-900\n    },\n    defaultFocus: {\n      borderColor: '#3cad51', // brand-500\n      outline: '3px solid rgba(60, 173, 81, 0.2)',\n    },\n    error: {\n      border: '1px solid #c93232', // destructive-500\n      color: '#2f2f2f',\n    },\n    errorFocus: {\n      borderColor: '#c93232',\n      outline: '3px solid rgba(201, 50, 50, 0.2)',\n    },\n    success: {\n      border: '1px solid #16a33d', // success-500\n      color: '#2f2f2f',\n    },\n    successFocus: {\n      borderColor: '#16a33d',\n      outline: '3px solid rgba(22, 163, 61, 0.2)',\n    },\n    disabled: {\n      backgroundColor: '#f8f8f8', // grey-050\n      borderColor: '#efefef', // grey-100\n      color: '#7e7e7e', // grey-500\n      cursor: 'not-allowed',\n    },\n  },\n};\n\nconst labelStyles: React.CSSProperties = {\n  display: 'block',\n  fontSize: '13px',\n  fontWeight: '600',\n  color: '#2f2f2f',\n  marginBottom: '4px',\n  fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n};\n\nconst helperTextStyles: React.CSSProperties = {\n  fontSize: '13px',\n  margin: '0',\n  marginTop: '2px',\n  color: '#595959',\n  fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n  lineHeight: '1.4',\n};\n\nconst errorTextStyles: React.CSSProperties = {\n  ...helperTextStyles,\n  color: '#a62323', // destructive-600\n  display: 'flex',\n  alignItems: 'center',\n  gap: '4px',\n};\n\nconst dropdownStyles: React.CSSProperties = {\n  position: 'absolute',\n  top: 'calc(100% + 4px)',\n  left: '0',\n  right: '0',\n  backgroundColor: '#ffffff',\n  border: '1px solid #d1d1d1',\n  borderRadius: '8px',\n  maxHeight: '200px',\n  overflowY: 'auto',\n  boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',\n  zIndex: 1000,\n};\n\nconst optionStyles: React.CSSProperties = {\n  padding: '8px 12px',\n  fontSize: '13px',\n  cursor: 'pointer',\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n  color: '#2f2f2f', // grey-900\n};\n\n/**\n * Combobox component - Arbor Design System\n *\n * A searchable select/autocomplete component with filtering.\n * Supports labels, validation states, and helper text.\n */\nexport const Combobox = React.forwardRef<HTMLDivElement, ComboboxProps>(\n  (\n    {\n      label,\n      placeholder = 'default-text',\n      options,\n      value,\n      onChange,\n      state = 'default',\n      error,\n      helperText,\n      disabled = false,\n      className,\n      style,\n      'data-testid': dataTestId,\n    },\n    ref\n  ) => {\n    const [isOpen, setIsOpen] = React.useState(false);\n    const [searchQuery, setSearchQuery] = React.useState('');\n    const [isFocused, setIsFocused] = React.useState(false);\n    const inputRef = React.useRef<HTMLInputElement>(null);\n    const dropdownRef = React.useRef<HTMLDivElement>(null);\n    const wrapperRef = React.useRef<HTMLDivElement>(null);\n\n    const comboboxId = React.useId();\n    const helperTextId = React.useId();\n    const errorId = React.useId();\n\n    const selectedOption = options.find((opt) => opt.value === value);\n\n    const filteredOptions = React.useMemo(() => {\n      if (!searchQuery) return options;\n      return options.filter((option) =>\n        option.label.toLowerCase().includes(searchQuery.toLowerCase())\n      );\n    }, [options, searchQuery]);\n\n    // Close dropdown when clicking outside\n    React.useEffect(() => {\n      const handleClickOutside = (event: MouseEvent) => {\n        if (\n          wrapperRef.current &&\n          !wrapperRef.current.contains(event.target as Node)\n        ) {\n          setIsOpen(false);\n          setSearchQuery('');\n        }\n      };\n\n      document.addEventListener('mousedown', handleClickOutside);\n      return () => document.removeEventListener('mousedown', handleClickOutside);\n    }, []);\n\n    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n      setSearchQuery(e.target.value);\n      if (!isOpen) setIsOpen(true);\n    };\n\n    const handleSelectOption = (optionValue: string) => {\n      onChange?.(optionValue);\n      setIsOpen(false);\n      setSearchQuery('');\n      inputRef.current?.blur();\n    };\n\n    const handleClear = (e: React.MouseEvent) => {\n      e.stopPropagation();\n      onChange?.(undefined);\n      setSearchQuery('');\n      inputRef.current?.focus();\n    };\n\n    const handleInputFocus = () => {\n      setIsFocused(true);\n      if (!disabled) setIsOpen(true);\n    };\n\n    const handleInputBlur = () => {\n      setIsFocused(false);\n      // Delay to allow click on option\n      setTimeout(() => {\n        if (!wrapperRef.current?.contains(document.activeElement)) {\n          setSearchQuery('');\n        }\n      }, 200);\n    };\n\n    const currentState = error ? 'error' : state;\n    const stateStyles = comboboxStyles.states[currentState];\n    const focusStyles =\n      currentState === 'error'\n        ? comboboxStyles.states.errorFocus\n        : currentState === 'success'\n        ? comboboxStyles.states.successFocus\n        : comboboxStyles.states.defaultFocus;\n\n    const inputWrapperStyle: React.CSSProperties = {\n      ...comboboxStyles.base,\n      ...stateStyles,\n      ...(isFocused && !disabled && focusStyles),\n      ...(disabled && comboboxStyles.states.disabled),\n    };\n\n    const displayValue = selectedOption ? selectedOption.label : '';\n    const showPlaceholder = !selectedOption && !searchQuery && !isFocused;\n\n    return (\n      <div className={clsx('arbor-combobox-wrapper', className)} style={style} ref={wrapperRef} data-testid={dataTestId}>\n        {label && (\n          <label htmlFor={comboboxId} style={labelStyles}>\n            {label}\n          </label>\n        )}\n\n        <div style={{ position: 'relative' }} ref={ref}>\n          <div style={inputWrapperStyle}>\n            <input\n              ref={inputRef}\n              id={comboboxId}\n              type=\"text\"\n              value={searchQuery || displayValue}\n              onChange={handleInputChange}\n              onFocus={handleInputFocus}\n              onBlur={handleInputBlur}\n              placeholder={showPlaceholder ? placeholder : ''}\n              disabled={disabled}\n              aria-invalid={error ? 'true' : 'false'}\n              aria-describedby={error ? errorId : helperText ? helperTextId : undefined}\n              aria-expanded={isOpen}\n              aria-autocomplete=\"list\"\n              role=\"combobox\"\n              style={{\n                border: 'none',\n                outline: 'none',\n                background: 'transparent',\n                flex: 1,\n                fontSize: '13px',\n                padding: 0,\n                margin: 0,\n                color: showPlaceholder ? '#7e7e7e' : '#2f2f2f',\n                fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n              }}\n            />\n\n            <div style={{ display: 'flex', alignItems: 'center', gap: '4px', position: 'absolute', right: '8px' }}>\n              {selectedOption && !disabled && (\n                <button\n                  type=\"button\"\n                  onClick={handleClear}\n                  style={{\n                    border: 'none',\n                    background: 'transparent',\n                    padding: '2px',\n                    cursor: 'pointer',\n                    display: 'flex',\n                    alignItems: 'center',\n                    color: '#7e7e7e',\n                  }}\n                  aria-label=\"Clear selection\"\n                >\n                  <X size={16} />\n                </button>\n              )}\n\n              {currentState === 'success' && !isOpen && (\n                <Check size={16} color=\"#16a33d\" />\n              )}\n\n              <ChevronDown\n                size={16}\n                color=\"#7e7e7e\"\n                style={{\n                  transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n                  transition: 'transform 0.2s',\n                }}\n              />\n            </div>\n          </div>\n\n          {isOpen && !disabled && (\n            <div ref={dropdownRef} style={dropdownStyles}>\n              {filteredOptions.length === 0 ? (\n                <div style={{ ...optionStyles, color: '#7e7e7e', cursor: 'default' }}>\n                  No options found\n                </div>\n              ) : (\n                filteredOptions.map((option) => (\n                  <div\n                    key={option.value}\n                    onClick={() => handleSelectOption(option.value)}\n                    onMouseDown={(e) => e.preventDefault()} // Prevent blur\n                    style={{\n                      ...optionStyles,\n                      backgroundColor: option.value === value ? '#f8f8f8' : 'transparent',\n                    }}\n                    onMouseEnter={(e) => {\n                      e.currentTarget.style.backgroundColor = '#f8f8f8';\n                    }}\n                    onMouseLeave={(e) => {\n                      e.currentTarget.style.backgroundColor =\n                        option.value === value ? '#f8f8f8' : 'transparent';\n                    }}\n                  >\n                    <span>{option.label}</span>\n                    {option.value === value && <Check size={16} color=\"#16a33d\" />}\n                  </div>\n                ))\n              )}\n            </div>\n          )}\n        </div>\n\n        {error && (\n          <p id={errorId} style={errorTextStyles} role=\"alert\">\n            {error}\n          </p>\n        )}\n        {!error && helperText && (\n          <p id={helperTextId} style={helperTextStyles}>\n            {helperText}\n          </p>\n        )}\n      </div>\n    );\n  }\n);\n\nCombobox.displayName = 'Combobox';\n"],"mappings":"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","names":[]}