UNPKG

eventx-design-system

Version:
189 lines (182 loc) 6.94 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useRef, useEffect } from 'react'; import styled, { css } from 'styled-components'; import { colors, typography, spacing, borderRadius, transitions, shadows, zIndex } from '../tokens/design-tokens'; // Container do select const SelectContainer = styled.div ` position: relative; width: ${({ fullWidth }) => fullWidth ? '100%' : 'auto'}; `; // Trigger do select const SelectTrigger = styled.button ` display: flex; align-items: center; justify-content: space-between; width: 100%; background-color: ${colors.neutral[50]}; border: 2px solid ${colors.neutral[300]}; border-radius: ${borderRadius.base}; padding: ${spacing[3]} ${spacing[4]}; font-family: ${typography.fontFamily.secondary}; font-size: ${typography.fontSize.base}; font-weight: ${typography.fontWeight.normal}; color: ${colors.neutral[950]}; cursor: pointer; transition: all ${transitions.duration[200]} ${transitions.easing.inOut}; text-align: left; ${({ size }) => { switch (size) { case 'sm': return css ` padding: ${spacing[2]} ${spacing[3]}; font-size: ${typography.fontSize.sm}; min-height: 32px; `; case 'lg': return css ` padding: ${spacing[4]} ${spacing[5]}; font-size: ${typography.fontSize.lg}; min-height: 48px; `; default: return css ` padding: ${spacing[3]} ${spacing[4]}; font-size: ${typography.fontSize.base}; min-height: 40px; `; } }} ${({ variant }) => { switch (variant) { case 'error': return css ` border-color: ${colors.semantic.error[500]}; &:focus { border-color: ${colors.semantic.error[500]}; box-shadow: 0 0 0 3px ${colors.semantic.error[100]}; } `; case 'success': return css ` border-color: ${colors.semantic.success[500]}; &:focus { border-color: ${colors.semantic.success[500]}; box-shadow: 0 0 0 3px ${colors.semantic.success[100]}; } `; default: return css ` &:hover:not(:disabled) { border-color: ${colors.neutral[400]}; } &:focus { border-color: ${colors.brand.primary[500]}; box-shadow: 0 0 0 3px ${colors.brand.primary[100]}; } `; } }} ${({ disabled }) => disabled && css ` background-color: ${colors.neutral[100]}; color: ${colors.neutral[500]}; cursor: not-allowed; opacity: 0.6; `} ${({ isOpen }) => isOpen && css ` border-color: ${colors.brand.primary[500]}; box-shadow: 0 0 0 3px ${colors.brand.primary[100]}; `} `; // Ícone de seta const ArrowIcon = styled.span ` display: inline-block; width: 0; height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4px solid ${colors.neutral[500]}; margin-left: ${spacing[2]}; transition: transform ${transitions.duration[200]} ${transitions.easing.inOut}; transform: ${({ isOpen }) => (isOpen ? 'rotate(180deg)' : 'rotate(0deg)')}; `; // Dropdown do select const SelectDropdown = styled.div ` position: absolute; top: 100%; left: 0; right: 0; background-color: ${colors.neutral[50]}; border: 1px solid ${colors.neutral[200]}; border-radius: ${borderRadius.base}; box-shadow: ${shadows.lg}; z-index: ${zIndex.dropdown}; max-height: 200px; overflow-y: auto; opacity: ${({ isOpen }) => (isOpen ? 1 : 0)}; visibility: ${({ isOpen }) => (isOpen ? 'visible' : 'hidden')}; transform: ${({ isOpen }) => (isOpen ? 'translateY(0)' : 'translateY(-4px)')}; transition: all ${transitions.duration[200]} ${transitions.easing.inOut}; margin-top: ${spacing[1]}; `; // Opção do select const SelectOption = styled.div ` padding: ${spacing[2]} ${spacing[4]}; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; color: ${({ disabled, isSelected }) => { if (disabled) return colors.neutral[400]; if (isSelected) return colors.brand.primary[950]; return colors.neutral[950]; }}; background-color: ${({ isSelected }) => isSelected ? colors.brand.primary[50] : 'transparent'}; font-family: ${typography.fontFamily.secondary}; font-size: ${typography.fontSize.base}; transition: all ${transitions.duration[150]} ${transitions.easing.inOut}; &:hover:not(:disabled) { background-color: ${({ isSelected }) => isSelected ? colors.brand.primary[100] : colors.neutral[100]}; } ${({ disabled }) => disabled && css ` opacity: 0.5; `} `; // Placeholder const Placeholder = styled.span ` color: ${colors.neutral[500]}; `; export const Select = ({ options, value, onChange, placeholder = 'Selecione uma opção', disabled = false, size = 'md', variant = 'default', fullWidth = true, className, ...props }) => { const [isOpen, setIsOpen] = useState(false); const containerRef = useRef(null); const selectedOption = options.find(option => option.value === value); useEffect(() => { const handleClickOutside = (event) => { if (containerRef.current && !containerRef.current.contains(event.target)) { setIsOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); const handleTriggerClick = () => { if (!disabled) { setIsOpen(!isOpen); } }; const handleOptionClick = (option) => { if (!option.disabled) { onChange?.(option.value); setIsOpen(false); } }; const handleKeyDown = (event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); handleTriggerClick(); } }; return (_jsxs(SelectContainer, { ref: containerRef, fullWidth: fullWidth, className: className, ...props, children: [_jsxs(SelectTrigger, { type: "button", variant: variant, size: size, disabled: disabled, isOpen: isOpen, onClick: handleTriggerClick, onKeyDown: handleKeyDown, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": placeholder, children: [_jsx("span", { children: selectedOption ? (selectedOption.label) : (_jsx(Placeholder, { children: placeholder })) }), _jsx(ArrowIcon, { isOpen: isOpen })] }), _jsx(SelectDropdown, { isOpen: isOpen, role: "listbox", children: options.map((option) => (_jsx(SelectOption, { isSelected: option.value === value, disabled: option.disabled || false, onClick: () => handleOptionClick(option), role: "option", "aria-selected": option.value === value, children: option.label }, option.value))) })] })); }; Select.displayName = 'Select';