@brycks/core-front 0.3.4 → 0.3.6
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/List/List.cjs +1 -1
- package/dist/components/data/List/List.cjs.map +1 -1
- package/dist/components/data/List/List.js +1 -1
- package/dist/components/data/List/List.js.map +1 -1
- 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 +141 -124
- package/dist/components/data/Table/Table.js.map +1 -1
- package/dist/components/data/TreeView/TreeView.cjs +1 -1
- package/dist/components/data/TreeView/TreeView.cjs.map +1 -1
- package/dist/components/data/TreeView/TreeView.js +1 -1
- package/dist/components/data/TreeView/TreeView.js.map +1 -1
- package/dist/components/feedback/Alert/Alert.cjs +1 -1
- package/dist/components/feedback/Alert/Alert.cjs.map +1 -1
- package/dist/components/feedback/Alert/Alert.js +20 -19
- package/dist/components/feedback/Alert/Alert.js.map +1 -1
- package/dist/components/feedback/Drawer/Drawer.cjs +2 -2
- package/dist/components/feedback/Drawer/Drawer.cjs.map +1 -1
- package/dist/components/feedback/Drawer/Drawer.js +58 -57
- package/dist/components/feedback/Drawer/Drawer.js.map +1 -1
- 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 +63 -61
- 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 +88 -79
- package/dist/components/feedback/Popover/Popover.js.map +1 -1
- package/dist/components/feedback/Toast/Toast.cjs +2 -2
- package/dist/components/feedback/Toast/Toast.cjs.map +1 -1
- package/dist/components/feedback/Toast/Toast.js +102 -93
- package/dist/components/feedback/Toast/Toast.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 +139 -139
- package/dist/components/form/Combobox/Combobox.js.map +1 -1
- package/dist/components/form/DateInput/DateInput.cjs +1 -1
- package/dist/components/form/DateInput/DateInput.cjs.map +1 -1
- package/dist/components/form/DateInput/DateInput.js +2 -2
- package/dist/components/form/DateInput/DateInput.js.map +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs.map +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.js +34 -34
- package/dist/components/form/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/form/DropZone/DropZone.cjs +1 -1
- package/dist/components/form/DropZone/DropZone.cjs.map +1 -1
- package/dist/components/form/DropZone/DropZone.js +10 -10
- package/dist/components/form/DropZone/DropZone.js.map +1 -1
- package/dist/components/form/FileInput/FileInput.cjs +1 -1
- package/dist/components/form/FileInput/FileInput.cjs.map +1 -1
- package/dist/components/form/FileInput/FileInput.js +1 -1
- package/dist/components/form/FileInput/FileInput.js.map +1 -1
- package/dist/components/form/FormCard/FormCard.cjs +1 -1
- package/dist/components/form/FormCard/FormCard.cjs.map +1 -1
- package/dist/components/form/FormCard/FormCard.js +9 -9
- package/dist/components/form/FormCard/FormCard.js.map +1 -1
- package/dist/components/form/FormField/FormField.cjs +1 -1
- package/dist/components/form/FormField/FormField.cjs.map +1 -1
- package/dist/components/form/FormField/FormField.js +67 -55
- package/dist/components/form/FormField/FormField.js.map +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.cjs +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.cjs.map +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.js +2 -3
- package/dist/components/form/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/components/form/Radio/Radio.cjs +1 -1
- package/dist/components/form/Radio/Radio.cjs.map +1 -1
- package/dist/components/form/Radio/Radio.js +20 -20
- package/dist/components/form/Radio/Radio.js.map +1 -1
- package/dist/components/form/TagInput/TagInput.cjs +1 -1
- package/dist/components/form/TagInput/TagInput.cjs.map +1 -1
- package/dist/components/form/TagInput/TagInput.js +104 -102
- package/dist/components/form/TagInput/TagInput.js.map +1 -1
- package/dist/components/form/TimePicker/TimePicker.cjs +1 -1
- package/dist/components/form/TimePicker/TimePicker.cjs.map +1 -1
- package/dist/components/form/TimePicker/TimePicker.js +29 -30
- package/dist/components/form/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/layout/Collapse/Collapse.cjs.map +1 -1
- package/dist/components/layout/Collapse/Collapse.js.map +1 -1
- package/dist/components/media/Image/Image.cjs +1 -1
- package/dist/components/media/Image/Image.cjs.map +1 -1
- package/dist/components/media/Image/Image.js +9 -9
- package/dist/components/media/Image/Image.js.map +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.cjs +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.cjs.map +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.js +6 -6
- package/dist/components/media/ImageThumbnail/ImageThumbnail.js.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.cjs +1 -1
- package/dist/components/navigation/Accordion/Accordion.cjs.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.js +0 -1
- package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
- package/dist/components/navigation/Menu/Menu.cjs +1 -1
- package/dist/components/navigation/Menu/Menu.cjs.map +1 -1
- package/dist/components/navigation/Menu/Menu.js +87 -86
- package/dist/components/navigation/Menu/Menu.js.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.js +107 -99
- package/dist/components/navigation/Pagination/Pagination.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 +10 -10
- package/dist/components/utility/Avatar/Avatar.js.map +1 -1
- 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 +10 -10
- package/dist/components/utility/Logo/Logo.js.map +1 -1
- package/dist/design-system/themes/ThemeProvider.cjs +1 -1
- package/dist/design-system/themes/ThemeProvider.cjs.map +1 -1
- package/dist/design-system/themes/ThemeProvider.js +46 -46
- package/dist/design-system/themes/ThemeProvider.js.map +1 -1
- package/dist/design-system/tokens/zIndex.cjs +1 -1
- package/dist/design-system/tokens/zIndex.cjs.map +1 -1
- package/dist/design-system/tokens/zIndex.js +2 -0
- package/dist/design-system/tokens/zIndex.js.map +1 -1
- package/dist/feedback.d.ts +8 -0
- package/dist/form.d.ts +10 -0
- package/dist/index.d.ts +29 -0
- package/dist/navigation.d.ts +19 -0
- package/dist/styles.css +1 -1
- package/dist/tokens.d.ts +2 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TagInput.cjs","sources":["../../../../src/components/form/TagInput/TagInput.tsx"],"sourcesContent":["/**\n * TagInput Component\n *\n * An input field for managing tags/chips with keyboard support.\n * Supports suggestions, validation, and custom tag rendering.\n *\n * @module components/form/TagInput\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n type CSSProperties,\n type ReactNode,\n type KeyboardEvent,\n type ChangeEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport { componentHeights, componentPaddingX, componentGap } from '../../../design-system/primitives'\n\nexport type TagInputSize = 'sm' | 'md' | 'lg'\n\nexport interface TagItem {\n /** Unique identifier */\n id: string\n /** Display label */\n label: string\n /** Optional color */\n color?: string\n}\n\nexport interface TagInputProps {\n /** Current tags */\n value?: TagItem[]\n /** Default tags (uncontrolled) */\n defaultValue?: TagItem[]\n /** Callback when tags change */\n onChange?: (tags: TagItem[]) => void\n /** Placeholder text */\n placeholder?: string\n /** Component size */\n size?: TagInputSize\n /** Maximum number of tags */\n maxTags?: number\n /** Whether to allow duplicates */\n allowDuplicates?: boolean\n /** Delimiter keys to create tag (default: Enter, comma) */\n delimiters?: string[]\n /** Whether the input is disabled */\n disabled?: boolean\n /** Whether the input is invalid */\n isInvalid?: boolean\n /** Whether the input is read-only */\n readOnly?: boolean\n /** Validation function for new tags */\n validateTag?: (value: string) => boolean | string\n /** Transform function for new tag value */\n transformTag?: (value: string) => string\n /** Suggested tags for autocomplete */\n suggestions?: TagItem[]\n /** Custom tag renderer */\n renderTag?: (tag: TagItem, onRemove: () => void) => ReactNode\n /** Label for accessibility */\n 'aria-label'?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeConfig: Record<TagInputSize, { height: number; fontSize: number; tagHeight: number; padding: number; gap: number }> = {\n sm: { height: componentHeights.sm, fontSize: fontSizes.base - 1, tagHeight: spacing[5], padding: componentPaddingX.xs, gap: spacing[1] },\n md: { height: componentHeights.md, fontSize: fontSizes.base, tagHeight: spacing[6], padding: componentPaddingX.sm, gap: spacing[1.5] },\n lg: { height: componentHeights.lg, fontSize: fontSizes.md, tagHeight: spacing[7], padding: componentPaddingX.sm, gap: spacing[2] },\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const TagInput = forwardRef<HTMLInputElement, TagInputProps>(function TagInput(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n placeholder = 'Add tags...',\n size = 'md',\n maxTags,\n allowDuplicates = false,\n delimiters = ['Enter', ','],\n disabled = false,\n isInvalid = false,\n readOnly = false,\n validateTag,\n transformTag = (v) => v.trim(),\n suggestions,\n renderTag,\n 'aria-label': ariaLabel = 'Tag input',\n className,\n testId,\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState<TagItem[]>(defaultValue)\n const [inputValue, setInputValue] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [showSuggestions, setShowSuggestions] = useState(false)\n const [activeSuggestion, setActiveSuggestion] = useState(-1)\n\n const inputRef = useRef<HTMLInputElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const tags = controlledValue !== undefined ? controlledValue : internalValue\n const config = sizeConfig[size]\n\n const isInteractive = !disabled && !readOnly\n\n // Filter suggestions\n const filteredSuggestions = suggestions?.filter(\n (s) =>\n s.label.toLowerCase().includes(inputValue.toLowerCase()) &&\n !tags.some((t) => t.id === s.id)\n ) || []\n\n const updateTags = useCallback(\n (newTags: TagItem[]) => {\n if (controlledValue === undefined) {\n setInternalValue(newTags)\n }\n onChange?.(newTags)\n },\n [controlledValue, onChange]\n )\n\n const addTag = useCallback(\n (value: string) => {\n const trimmed = transformTag(value)\n if (!trimmed) return false\n\n // Check max tags\n if (maxTags && tags.length >= maxTags) {\n setError(`Maximum ${maxTags} tags allowed`)\n return false\n }\n\n // Check duplicates\n if (!allowDuplicates && tags.some((t) => t.label.toLowerCase() === trimmed.toLowerCase())) {\n setError('Tag already exists')\n return false\n }\n\n // Validate\n if (validateTag) {\n const result = validateTag(trimmed)\n if (result !== true) {\n setError(typeof result === 'string' ? result : 'Invalid tag')\n return false\n }\n }\n\n const newTag: TagItem = {\n id: `tag-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n label: trimmed,\n }\n\n updateTags([...tags, newTag])\n setInputValue('')\n setError(null)\n return true\n },\n [tags, maxTags, allowDuplicates, validateTag, transformTag, updateTags]\n )\n\n const removeTag = useCallback(\n (tagId: string) => {\n if (!isInteractive) return\n updateTags(tags.filter((t) => t.id !== tagId))\n },\n [isInteractive, tags, updateTags]\n )\n\n const handleInputChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n\n // Check for delimiter in the value\n if (value.includes(',')) {\n const parts = value.split(',')\n parts.forEach((part, index) => {\n if (index < parts.length - 1 && part.trim()) {\n addTag(part)\n }\n })\n setInputValue(parts[parts.length - 1])\n } else {\n setInputValue(value)\n }\n\n setError(null)\n setShowSuggestions(true)\n setActiveSuggestion(-1)\n }, [addTag])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (!isInteractive) return\n\n // Handle suggestions navigation\n if (showSuggestions && filteredSuggestions.length > 0) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.max(prev - 1, 0))\n return\n }\n if ((e.key === 'Enter' || e.key === 'Tab') && activeSuggestion >= 0) {\n e.preventDefault()\n const selected = filteredSuggestions[activeSuggestion]\n if (selected) {\n updateTags([...tags, selected])\n setInputValue('')\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n return\n }\n }\n\n // Create tag on delimiter\n if (delimiters.includes(e.key) && inputValue) {\n e.preventDefault()\n addTag(inputValue)\n setShowSuggestions(false)\n return\n }\n\n // Remove last tag on backspace\n if (e.key === 'Backspace' && !inputValue && tags.length > 0) {\n removeTag(tags[tags.length - 1].id)\n return\n }\n\n // Close suggestions on escape\n if (e.key === 'Escape') {\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n },\n [isInteractive, showSuggestions, filteredSuggestions, activeSuggestion, delimiters, inputValue, tags, addTag, removeTag, updateTags]\n )\n\n // Close suggestions on outside click\n useEffect(() => {\n if (!showSuggestions) return\n\n const handleClick = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) {\n setShowSuggestions(false)\n }\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [showSuggestions])\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: '100%',\n }\n\n const wrapperStyle: CSSProperties = {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: config.gap,\n minHeight: config.height,\n padding: `${spacing[1]}px ${config.padding}px`,\n backgroundColor: disabled ? 'var(--brycks-background-muted)' : 'var(--brycks-background-default)',\n border: `1px solid ${\n isInvalid || error\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 tagStyle = (tag: TagItem): CSSProperties => ({\n display: 'inline-flex',\n alignItems: 'center',\n gap: spacing[1],\n height: config.tagHeight,\n padding: `0 ${spacing[2]}px`,\n fontSize: config.fontSize - 1,\n fontWeight: 500,\n color: tag.color ? 'white' : 'var(--brycks-foreground-default)',\n backgroundColor: tag.color || 'var(--brycks-background-muted)',\n borderRadius: 'var(--brycks-radius-full)',\n whiteSpace: 'nowrap',\n })\n\n const removeButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: spacing[4],\n height: spacing[4],\n marginLeft: spacing[0.5],\n marginRight: -spacing[1],\n color: 'inherit',\n opacity: 0.7,\n cursor: 'pointer',\n borderRadius: 'var(--brycks-radius-full)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n }\n\n const inputStyle: CSSProperties = {\n flex: 1,\n minWidth: 100,\n height: config.tagHeight,\n padding: 0,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n }\n\n const suggestionsStyle: CSSProperties = {\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: spacing[1],\n maxHeight: 200,\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 }\n\n const suggestionStyle = (isActive: boolean): CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.md,\n padding: `${spacing[2]}px ${spacing[3]}px`,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: isActive ? 'var(--brycks-background-muted)' : 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n })\n\n const errorStyle: CSSProperties = {\n marginTop: spacing[1],\n fontSize: fontSizes.sm,\n color: 'var(--brycks-error-default)',\n }\n\n const defaultRenderTag = (tag: TagItem, onRemove: () => void) => (\n <span key={tag.id} style={tagStyle(tag)}>\n {tag.label}\n {isInteractive && (\n <button\n type=\"button\"\n aria-label={`Remove ${tag.label}`}\n style={removeButtonStyle}\n onClick={(e) => {\n e.stopPropagation()\n onRemove()\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.opacity = '1'\n e.currentTarget.style.backgroundColor = 'rgba(0,0,0,0.1)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.opacity = '0.7'\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n >\n <CloseIcon />\n </button>\n )}\n </span>\n )\n\n return (\n <div\n ref={containerRef}\n className={cx('brycks-tag-input', `brycks-tag-input--${size}`, className)}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n style={wrapperStyle}\n onClick={() => !disabled && inputRef.current?.focus()}\n >\n {tags.map((tag) =>\n renderTag ? renderTag(tag, () => removeTag(tag.id)) : defaultRenderTag(tag, () => removeTag(tag.id))\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-label={ariaLabel}\n aria-expanded={showSuggestions && filteredSuggestions.length > 0}\n aria-autocomplete=\"list\"\n aria-invalid={isInvalid || !!error}\n value={inputValue}\n placeholder={tags.length === 0 ? placeholder : ''}\n disabled={disabled}\n readOnly={readOnly}\n style={inputStyle}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setIsFocused(true)\n setShowSuggestions(true)\n }}\n onBlur={() => setIsFocused(false)}\n />\n </div>\n\n {showSuggestions && filteredSuggestions.length > 0 && (\n <ul role=\"listbox\" style={suggestionsStyle}>\n {filteredSuggestions.map((suggestion, index) => (\n <li\n key={suggestion.id}\n role=\"option\"\n aria-selected={index === activeSuggestion}\n style={suggestionStyle(index === activeSuggestion)}\n onClick={() => {\n updateTags([...tags, suggestion])\n setInputValue('')\n setShowSuggestions(false)\n inputRef.current?.focus()\n }}\n onMouseEnter={() => setActiveSuggestion(index)}\n >\n {suggestion.label}\n </li>\n ))}\n </ul>\n )}\n\n {error && <div style={errorStyle}>{error}</div>}\n </div>\n )\n})\n\nTagInput.displayName = 'TagInput'\n"],"names":["sizeConfig","componentHeights","fontSizes","spacing","componentPaddingX","CloseIcon","jsx","TagInput","forwardRef","controlledValue","defaultValue","onChange","placeholder","size","maxTags","allowDuplicates","delimiters","disabled","isInvalid","readOnly","validateTag","transformTag","v","suggestions","renderTag","ariaLabel","className","testId","ref","internalValue","setInternalValue","useState","inputValue","setInputValue","isFocused","setIsFocused","error","setError","showSuggestions","setShowSuggestions","activeSuggestion","setActiveSuggestion","inputRef","useRef","containerRef","tags","config","isInteractive","filteredSuggestions","s","updateTags","useCallback","newTags","addTag","value","trimmed","t","result","newTag","removeTag","tagId","handleInputChange","parts","part","index","handleKeyDown","prev","selected","useEffect","handleClick","e","containerStyle","wrapperStyle","durations","easings","tagStyle","tag","removeButtonStyle","inputStyle","suggestionsStyle","suggestionStyle","isActive","componentGap","errorStyle","defaultRenderTag","onRemove","jsxs","cx","node","suggestion"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TagInput.cjs","sources":["../../../../src/components/form/TagInput/TagInput.tsx"],"sourcesContent":["/**\n * TagInput Component\n *\n * An input field for managing tags/chips with keyboard support.\n * Supports suggestions, validation, and custom tag rendering.\n *\n * @module components/form/TagInput\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n type CSSProperties,\n type ReactNode,\n type KeyboardEvent,\n type ChangeEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport { componentHeights, componentPaddingX, componentGap } from '../../../design-system/primitives'\n\nexport type TagInputSize = 'sm' | 'md' | 'lg'\n\nexport interface TagItem {\n /** Unique identifier */\n id: string\n /** Display label */\n label: string\n /** Optional color */\n color?: string\n}\n\nexport interface TagInputProps {\n /** Current tags */\n value?: TagItem[]\n /** Default tags (uncontrolled) */\n defaultValue?: TagItem[]\n /** Callback when tags change */\n onChange?: (tags: TagItem[]) => void\n /** Placeholder text */\n placeholder?: string\n /** Component size */\n size?: TagInputSize\n /** Maximum number of tags */\n maxTags?: number\n /** Whether to allow duplicates */\n allowDuplicates?: boolean\n /** Delimiter keys to create tag (default: Enter, comma) */\n delimiters?: string[]\n /** Whether the input is disabled */\n disabled?: boolean\n /** Whether the input is invalid */\n isInvalid?: boolean\n /** Whether the input is read-only */\n readOnly?: boolean\n /** Validation function for new tags */\n validateTag?: (value: string) => boolean | string\n /** Transform function for new tag value */\n transformTag?: (value: string) => string\n /** Suggested tags for autocomplete */\n suggestions?: TagItem[]\n /** Custom tag renderer */\n renderTag?: (tag: TagItem, onRemove: () => void) => ReactNode\n /** Message shown when the tag limit is reached */\n maxTagsMessage?: (maxTags: number) => string\n /** Message shown when a duplicate tag is rejected */\n duplicateMessage?: string\n /** Label for accessibility */\n 'aria-label'?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeConfig: Record<TagInputSize, { height: number; fontSize: number; tagHeight: number; padding: number; gap: number }> = {\n sm: { height: componentHeights.sm, fontSize: fontSizes.base - 1, tagHeight: spacing[5], padding: componentPaddingX.xs, gap: spacing[1] },\n md: { height: componentHeights.md, fontSize: fontSizes.base, tagHeight: spacing[6], padding: componentPaddingX.sm, gap: spacing[1.5] },\n lg: { height: componentHeights.lg, fontSize: fontSizes.md, tagHeight: spacing[7], padding: componentPaddingX.sm, gap: spacing[2] },\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const TagInput = forwardRef<HTMLInputElement, TagInputProps>(function TagInput(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n placeholder = 'Add tags...',\n size = 'md',\n maxTags,\n allowDuplicates = false,\n delimiters = ['Enter', ','],\n disabled = false,\n isInvalid = false,\n readOnly = false,\n validateTag,\n transformTag = (v) => v.trim(),\n suggestions,\n renderTag,\n maxTagsMessage = (max) => `Maximum ${max} tags allowed`,\n duplicateMessage = 'Tag already exists',\n 'aria-label': ariaLabel = 'Tag input',\n className,\n testId,\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState<TagItem[]>(defaultValue)\n const [inputValue, setInputValue] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [showSuggestions, setShowSuggestions] = useState(false)\n const [activeSuggestion, setActiveSuggestion] = useState(-1)\n\n const inputRef = useRef<HTMLInputElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const tags = controlledValue !== undefined ? controlledValue : internalValue\n const config = sizeConfig[size]\n\n const isInteractive = !disabled && !readOnly\n\n // Filter suggestions\n const filteredSuggestions = suggestions?.filter(\n (s) =>\n s.label.toLowerCase().includes(inputValue.toLowerCase()) &&\n !tags.some((t) => t.id === s.id)\n ) || []\n\n const updateTags = useCallback(\n (newTags: TagItem[]) => {\n if (controlledValue === undefined) {\n setInternalValue(newTags)\n }\n onChange?.(newTags)\n },\n [controlledValue, onChange]\n )\n\n const addTag = useCallback(\n (value: string) => {\n const trimmed = transformTag(value)\n if (!trimmed) return false\n\n // Check max tags\n if (maxTags && tags.length >= maxTags) {\n setError(maxTagsMessage(maxTags))\n return false\n }\n\n // Check duplicates\n if (!allowDuplicates && tags.some((t) => t.label.toLowerCase() === trimmed.toLowerCase())) {\n setError(duplicateMessage)\n return false\n }\n\n // Validate\n if (validateTag) {\n const result = validateTag(trimmed)\n if (result !== true) {\n setError(typeof result === 'string' ? result : 'Invalid tag')\n return false\n }\n }\n\n const newTag: TagItem = {\n id: `tag-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n label: trimmed,\n }\n\n updateTags([...tags, newTag])\n setInputValue('')\n setError(null)\n return true\n },\n [tags, maxTags, allowDuplicates, validateTag, transformTag, updateTags, maxTagsMessage, duplicateMessage]\n )\n\n const removeTag = useCallback(\n (tagId: string) => {\n if (!isInteractive) return\n updateTags(tags.filter((t) => t.id !== tagId))\n },\n [isInteractive, tags, updateTags]\n )\n\n const handleInputChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n\n // Check for delimiter in the value\n if (value.includes(',')) {\n const parts = value.split(',')\n parts.forEach((part, index) => {\n if (index < parts.length - 1 && part.trim()) {\n addTag(part)\n }\n })\n setInputValue(parts[parts.length - 1])\n } else {\n setInputValue(value)\n }\n\n setError(null)\n setShowSuggestions(true)\n setActiveSuggestion(-1)\n }, [addTag])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (!isInteractive) return\n\n // Handle suggestions navigation\n if (showSuggestions && filteredSuggestions.length > 0) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.max(prev - 1, 0))\n return\n }\n if ((e.key === 'Enter' || e.key === 'Tab') && activeSuggestion >= 0) {\n e.preventDefault()\n const selected = filteredSuggestions[activeSuggestion]\n if (selected) {\n updateTags([...tags, selected])\n setInputValue('')\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n return\n }\n }\n\n // Create tag on delimiter\n if (delimiters.includes(e.key) && inputValue) {\n e.preventDefault()\n addTag(inputValue)\n setShowSuggestions(false)\n return\n }\n\n // Remove last tag on backspace\n if (e.key === 'Backspace' && !inputValue && tags.length > 0) {\n removeTag(tags[tags.length - 1].id)\n return\n }\n\n // Close suggestions on escape\n if (e.key === 'Escape') {\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n },\n [isInteractive, showSuggestions, filteredSuggestions, activeSuggestion, delimiters, inputValue, tags, addTag, removeTag, updateTags]\n )\n\n // Close suggestions on outside click\n useEffect(() => {\n if (!showSuggestions) return\n\n const handleClick = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) {\n setShowSuggestions(false)\n }\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [showSuggestions])\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: '100%',\n }\n\n const wrapperStyle: CSSProperties = {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: config.gap,\n minHeight: config.height,\n padding: `${spacing[1]}px ${config.padding}px`,\n backgroundColor: disabled ? 'var(--brycks-background-muted)' : 'var(--brycks-background-default)',\n border: `1px solid ${\n isInvalid || error\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 tagStyle = (tag: TagItem): CSSProperties => ({\n display: 'inline-flex',\n alignItems: 'center',\n gap: spacing[1],\n height: config.tagHeight,\n padding: `0 ${spacing[2]}px`,\n fontSize: config.fontSize - 1,\n fontWeight: 500,\n color: tag.color ? 'white' : 'var(--brycks-foreground-default)',\n backgroundColor: tag.color || 'var(--brycks-background-muted)',\n borderRadius: 'var(--brycks-radius-full)',\n whiteSpace: 'nowrap',\n })\n\n const removeButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: spacing[4],\n height: spacing[4],\n marginLeft: spacing[0.5],\n marginRight: -spacing[1],\n color: 'inherit',\n opacity: 0.7,\n cursor: 'pointer',\n borderRadius: 'var(--brycks-radius-full)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n }\n\n const inputStyle: CSSProperties = {\n flex: 1,\n minWidth: 100,\n height: config.tagHeight,\n padding: 0,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n }\n\n const suggestionsStyle: CSSProperties = {\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: spacing[1],\n maxHeight: 200,\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 }\n\n const suggestionStyle = (isActive: boolean): CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.md,\n padding: `${spacing[2]}px ${spacing[3]}px`,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: isActive ? 'var(--brycks-background-muted)' : 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n })\n\n const errorStyle: CSSProperties = {\n marginTop: spacing[1],\n fontSize: fontSizes.sm,\n color: 'var(--brycks-error-default)',\n }\n\n const defaultRenderTag = (tag: TagItem, onRemove: () => void) => (\n <span key={tag.id} style={tagStyle(tag)}>\n {tag.label}\n {isInteractive && (\n <button\n type=\"button\"\n aria-label={`Remove ${tag.label}`}\n style={removeButtonStyle}\n onClick={(e) => {\n e.stopPropagation()\n onRemove()\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.opacity = '1'\n e.currentTarget.style.backgroundColor = 'rgba(0,0,0,0.1)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.opacity = '0.7'\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n >\n <CloseIcon />\n </button>\n )}\n </span>\n )\n\n return (\n <div\n ref={containerRef}\n className={cx('brycks-tag-input', `brycks-tag-input--${size}`, className)}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n style={wrapperStyle}\n onClick={() => !disabled && inputRef.current?.focus()}\n >\n {tags.map((tag) =>\n renderTag ? renderTag(tag, () => removeTag(tag.id)) : defaultRenderTag(tag, () => removeTag(tag.id))\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-label={ariaLabel}\n aria-expanded={showSuggestions && filteredSuggestions.length > 0}\n aria-autocomplete=\"list\"\n aria-invalid={isInvalid || !!error}\n value={inputValue}\n placeholder={tags.length === 0 ? placeholder : ''}\n disabled={disabled}\n readOnly={readOnly}\n style={inputStyle}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setIsFocused(true)\n setShowSuggestions(true)\n }}\n onBlur={() => setIsFocused(false)}\n />\n </div>\n\n {showSuggestions && filteredSuggestions.length > 0 && (\n <ul role=\"listbox\" style={suggestionsStyle}>\n {filteredSuggestions.map((suggestion, index) => (\n <li\n key={suggestion.id}\n role=\"option\"\n aria-selected={index === activeSuggestion}\n style={suggestionStyle(index === activeSuggestion)}\n onClick={() => {\n updateTags([...tags, suggestion])\n setInputValue('')\n setShowSuggestions(false)\n inputRef.current?.focus()\n }}\n onMouseEnter={() => setActiveSuggestion(index)}\n >\n {suggestion.label}\n </li>\n ))}\n </ul>\n )}\n\n {error && <div style={errorStyle}>{error}</div>}\n </div>\n )\n})\n\nTagInput.displayName = 'TagInput'\n"],"names":["sizeConfig","componentHeights","fontSizes","spacing","componentPaddingX","CloseIcon","jsx","TagInput","forwardRef","controlledValue","defaultValue","onChange","placeholder","size","maxTags","allowDuplicates","delimiters","disabled","isInvalid","readOnly","validateTag","transformTag","v","suggestions","renderTag","maxTagsMessage","max","duplicateMessage","ariaLabel","className","testId","ref","internalValue","setInternalValue","useState","inputValue","setInputValue","isFocused","setIsFocused","error","setError","showSuggestions","setShowSuggestions","activeSuggestion","setActiveSuggestion","inputRef","useRef","containerRef","tags","config","isInteractive","filteredSuggestions","s","updateTags","useCallback","newTags","addTag","value","trimmed","t","result","newTag","removeTag","tagId","handleInputChange","parts","part","index","handleKeyDown","prev","selected","useEffect","handleClick","e","containerStyle","wrapperStyle","durations","easings","tagStyle","tag","removeButtonStyle","inputStyle","suggestionsStyle","suggestionStyle","isActive","componentGap","errorStyle","defaultRenderTag","onRemove","jsxs","cx","node","suggestion"],"mappings":"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"}
|
|
@@ -1,83 +1,85 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { forwardRef as
|
|
3
|
-
import { cx as
|
|
4
|
-
import { durations as T, easings as
|
|
1
|
+
import { jsxs as H, jsx as s } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as he, useState as p, useRef as q, useCallback as w, useEffect as me } from "react";
|
|
3
|
+
import { cx as ye } from "../../../utils/styles.js";
|
|
4
|
+
import { durations as T, easings as D } from "../../../design-system/tokens/motion.js";
|
|
5
5
|
import { spacing as r } from "../../../design-system/tokens/spacing.js";
|
|
6
|
-
import { componentPaddingX as
|
|
7
|
-
import { fontSizes as
|
|
8
|
-
const
|
|
9
|
-
sm: { height: A.sm, fontSize:
|
|
10
|
-
md: { height: A.md, fontSize:
|
|
11
|
-
lg: { height: A.lg, fontSize:
|
|
6
|
+
import { componentPaddingX as M, componentHeights as A, componentGap as be } from "../../../design-system/primitives/sizing.js";
|
|
7
|
+
import { fontSizes as R } from "../../../design-system/tokens/typography.js";
|
|
8
|
+
const ke = {
|
|
9
|
+
sm: { height: A.sm, fontSize: R.base - 1, tagHeight: r[5], padding: M.xs, gap: r[1] },
|
|
10
|
+
md: { height: A.md, fontSize: R.base, tagHeight: r[6], padding: M.sm, gap: r[1.5] },
|
|
11
|
+
lg: { height: A.lg, fontSize: R.md, tagHeight: r[7], padding: M.sm, gap: r[2] }
|
|
12
12
|
};
|
|
13
|
-
function
|
|
14
|
-
return /* @__PURE__ */
|
|
13
|
+
function ve() {
|
|
14
|
+
return /* @__PURE__ */ s("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ s("path", { d: "M3 3l6 6M9 3l-6 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
|
|
15
15
|
}
|
|
16
|
-
const
|
|
17
|
-
value:
|
|
18
|
-
defaultValue:
|
|
16
|
+
const we = he(function({
|
|
17
|
+
value: S,
|
|
18
|
+
defaultValue: J = [],
|
|
19
19
|
onChange: B,
|
|
20
|
-
placeholder:
|
|
20
|
+
placeholder: Q = "Add tags...",
|
|
21
21
|
size: W = "md",
|
|
22
|
-
maxTags:
|
|
22
|
+
maxTags: x,
|
|
23
23
|
allowDuplicates: j = !1,
|
|
24
24
|
delimiters: F = ["Enter", ","],
|
|
25
25
|
disabled: h = !1,
|
|
26
26
|
isInvalid: K = !1,
|
|
27
27
|
readOnly: N = !1,
|
|
28
|
-
validateTag:
|
|
29
|
-
transformTag: O = (
|
|
30
|
-
suggestions:
|
|
28
|
+
validateTag: E,
|
|
29
|
+
transformTag: O = (m) => m.trim(),
|
|
30
|
+
suggestions: Z,
|
|
31
31
|
renderTag: P,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
maxTagsMessage: G = (m) => `Maximum ${m} tags allowed`,
|
|
33
|
+
duplicateMessage: U = "Tag already exists",
|
|
34
|
+
"aria-label": _ = "Tag input",
|
|
35
|
+
className: ee,
|
|
36
|
+
testId: te
|
|
37
|
+
}, C) {
|
|
38
|
+
const [m, re] = p(J), [d, y] = p(""), [V, X] = p(!1), [$, b] = p(null), [f, l] = p(!1), [k, g] = p(-1), L = q(null), Y = q(null), n = S !== void 0 ? S : m, a = ke[W], v = !h && !N, c = Z?.filter(
|
|
37
39
|
(e) => e.label.toLowerCase().includes(d.toLowerCase()) && !n.some((t) => t.id === e.id)
|
|
38
|
-
) || [], u =
|
|
40
|
+
) || [], u = w(
|
|
39
41
|
(e) => {
|
|
40
|
-
|
|
42
|
+
S === void 0 && re(e), B?.(e);
|
|
41
43
|
},
|
|
42
|
-
[
|
|
43
|
-
),
|
|
44
|
+
[S, B]
|
|
45
|
+
), I = w(
|
|
44
46
|
(e) => {
|
|
45
47
|
const t = O(e);
|
|
46
48
|
if (!t) return !1;
|
|
47
|
-
if (
|
|
48
|
-
return
|
|
49
|
-
if (!j && n.some((
|
|
50
|
-
return
|
|
51
|
-
if (
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
return
|
|
49
|
+
if (x && n.length >= x)
|
|
50
|
+
return b(G(x)), !1;
|
|
51
|
+
if (!j && n.some((i) => i.label.toLowerCase() === t.toLowerCase()))
|
|
52
|
+
return b(U), !1;
|
|
53
|
+
if (E) {
|
|
54
|
+
const i = E(t);
|
|
55
|
+
if (i !== !0)
|
|
56
|
+
return b(typeof i == "string" ? i : "Invalid tag"), !1;
|
|
55
57
|
}
|
|
56
58
|
const o = {
|
|
57
59
|
id: `tag-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
58
60
|
label: t
|
|
59
61
|
};
|
|
60
|
-
return u([...n, o]),
|
|
62
|
+
return u([...n, o]), y(""), b(null), !0;
|
|
61
63
|
},
|
|
62
|
-
[n,
|
|
63
|
-
),
|
|
64
|
+
[n, x, j, E, O, u, G, U]
|
|
65
|
+
), z = w(
|
|
64
66
|
(e) => {
|
|
65
|
-
|
|
67
|
+
v && u(n.filter((t) => t.id !== e));
|
|
66
68
|
},
|
|
67
|
-
[
|
|
68
|
-
),
|
|
69
|
+
[v, n, u]
|
|
70
|
+
), ne = w((e) => {
|
|
69
71
|
const t = e.target.value;
|
|
70
72
|
if (t.includes(",")) {
|
|
71
73
|
const o = t.split(",");
|
|
72
|
-
o.forEach((
|
|
73
|
-
|
|
74
|
-
}),
|
|
74
|
+
o.forEach((i, pe) => {
|
|
75
|
+
pe < o.length - 1 && i.trim() && I(i);
|
|
76
|
+
}), y(o[o.length - 1]);
|
|
75
77
|
} else
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}, [
|
|
78
|
+
y(t);
|
|
79
|
+
b(null), l(!0), g(-1);
|
|
80
|
+
}, [I]), oe = w(
|
|
79
81
|
(e) => {
|
|
80
|
-
if (
|
|
82
|
+
if (v) {
|
|
81
83
|
if (f && c.length > 0) {
|
|
82
84
|
if (e.key === "ArrowDown") {
|
|
83
85
|
e.preventDefault(), g((t) => Math.min(t + 1, c.length - 1));
|
|
@@ -87,37 +89,37 @@ const ke = ge(function({
|
|
|
87
89
|
e.preventDefault(), g((t) => Math.max(t - 1, 0));
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
|
-
if ((e.key === "Enter" || e.key === "Tab") &&
|
|
92
|
+
if ((e.key === "Enter" || e.key === "Tab") && k >= 0) {
|
|
91
93
|
e.preventDefault();
|
|
92
|
-
const t = c[
|
|
93
|
-
t && (u([...n, t]),
|
|
94
|
+
const t = c[k];
|
|
95
|
+
t && (u([...n, t]), y(""), l(!1), g(-1));
|
|
94
96
|
return;
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
if (F.includes(e.key) && d) {
|
|
98
|
-
e.preventDefault(),
|
|
100
|
+
e.preventDefault(), I(d), l(!1);
|
|
99
101
|
return;
|
|
100
102
|
}
|
|
101
103
|
if (e.key === "Backspace" && !d && n.length > 0) {
|
|
102
|
-
|
|
104
|
+
z(n[n.length - 1].id);
|
|
103
105
|
return;
|
|
104
106
|
}
|
|
105
107
|
e.key === "Escape" && (l(!1), g(-1));
|
|
106
108
|
}
|
|
107
109
|
},
|
|
108
|
-
[
|
|
110
|
+
[v, f, c, k, F, d, n, I, z, u]
|
|
109
111
|
);
|
|
110
|
-
|
|
112
|
+
me(() => {
|
|
111
113
|
if (!f) return;
|
|
112
114
|
const e = (t) => {
|
|
113
|
-
|
|
115
|
+
Y.current?.contains(t.target) || l(!1);
|
|
114
116
|
};
|
|
115
117
|
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
116
118
|
}, [f]);
|
|
117
|
-
const
|
|
119
|
+
const ae = {
|
|
118
120
|
position: "relative",
|
|
119
121
|
width: "100%"
|
|
120
|
-
},
|
|
122
|
+
}, ie = {
|
|
121
123
|
display: "flex",
|
|
122
124
|
flexWrap: "wrap",
|
|
123
125
|
alignItems: "center",
|
|
@@ -125,12 +127,12 @@ const ke = ge(function({
|
|
|
125
127
|
minHeight: a.height,
|
|
126
128
|
padding: `${r[1]}px ${a.padding}px`,
|
|
127
129
|
backgroundColor: h ? "var(--brycks-background-muted)" : "var(--brycks-background-default)",
|
|
128
|
-
border: `1px solid ${K ||
|
|
130
|
+
border: `1px solid ${K || $ ? "var(--brycks-error-default)" : V ? "var(--brycks-primary-default)" : "var(--brycks-border-default)"}`,
|
|
129
131
|
borderRadius: "var(--brycks-radius-md)",
|
|
130
|
-
transition: `all ${T.fast}ms ${
|
|
132
|
+
transition: `all ${T.fast}ms ${D.easeOut}`,
|
|
131
133
|
cursor: h ? "not-allowed" : "text",
|
|
132
|
-
boxShadow:
|
|
133
|
-
},
|
|
134
|
+
boxShadow: V ? "var(--brycks-focus-ring)" : void 0
|
|
135
|
+
}, se = (e) => ({
|
|
134
136
|
display: "inline-flex",
|
|
135
137
|
alignItems: "center",
|
|
136
138
|
gap: r[1],
|
|
@@ -142,7 +144,7 @@ const ke = ge(function({
|
|
|
142
144
|
backgroundColor: e.color || "var(--brycks-background-muted)",
|
|
143
145
|
borderRadius: "var(--brycks-radius-full)",
|
|
144
146
|
whiteSpace: "nowrap"
|
|
145
|
-
}),
|
|
147
|
+
}), le = {
|
|
146
148
|
display: "flex",
|
|
147
149
|
alignItems: "center",
|
|
148
150
|
justifyContent: "center",
|
|
@@ -154,8 +156,8 @@ const ke = ge(function({
|
|
|
154
156
|
opacity: 0.7,
|
|
155
157
|
cursor: "pointer",
|
|
156
158
|
borderRadius: "var(--brycks-radius-full)",
|
|
157
|
-
transition: `all ${T.fast}ms ${
|
|
158
|
-
},
|
|
159
|
+
transition: `all ${T.fast}ms ${D.easeOut}`
|
|
160
|
+
}, ce = {
|
|
159
161
|
flex: 1,
|
|
160
162
|
minWidth: 100,
|
|
161
163
|
height: a.tagHeight,
|
|
@@ -165,7 +167,7 @@ const ke = ge(function({
|
|
|
165
167
|
backgroundColor: "transparent",
|
|
166
168
|
border: "none",
|
|
167
169
|
outline: "none"
|
|
168
|
-
},
|
|
170
|
+
}, ue = {
|
|
169
171
|
position: "absolute",
|
|
170
172
|
top: "100%",
|
|
171
173
|
left: 0,
|
|
@@ -179,29 +181,29 @@ const ke = ge(function({
|
|
|
179
181
|
boxShadow: "var(--brycks-shadow-lg)",
|
|
180
182
|
zIndex: "var(--brycks-z-dropdown)",
|
|
181
183
|
padding: r[1]
|
|
182
|
-
},
|
|
184
|
+
}, de = (e) => ({
|
|
183
185
|
display: "flex",
|
|
184
186
|
alignItems: "center",
|
|
185
|
-
gap:
|
|
187
|
+
gap: be.md,
|
|
186
188
|
padding: `${r[2]}px ${r[3]}px`,
|
|
187
189
|
fontSize: a.fontSize,
|
|
188
190
|
color: "var(--brycks-foreground-default)",
|
|
189
191
|
backgroundColor: e ? "var(--brycks-background-muted)" : "transparent",
|
|
190
192
|
borderRadius: "var(--brycks-radius-md)",
|
|
191
193
|
cursor: "pointer",
|
|
192
|
-
transition: `background-color ${T.fast}ms ${
|
|
193
|
-
}),
|
|
194
|
+
transition: `background-color ${T.fast}ms ${D.easeOut}`
|
|
195
|
+
}), fe = {
|
|
194
196
|
marginTop: r[1],
|
|
195
|
-
fontSize:
|
|
197
|
+
fontSize: R.sm,
|
|
196
198
|
color: "var(--brycks-error-default)"
|
|
197
|
-
},
|
|
199
|
+
}, ge = (e, t) => /* @__PURE__ */ H("span", { style: se(e), children: [
|
|
198
200
|
e.label,
|
|
199
|
-
|
|
201
|
+
v && /* @__PURE__ */ s(
|
|
200
202
|
"button",
|
|
201
203
|
{
|
|
202
204
|
type: "button",
|
|
203
205
|
"aria-label": `Remove ${e.label}`,
|
|
204
|
-
style:
|
|
206
|
+
style: le,
|
|
205
207
|
onClick: (o) => {
|
|
206
208
|
o.stopPropagation(), t();
|
|
207
209
|
},
|
|
@@ -211,76 +213,76 @@ const ke = ge(function({
|
|
|
211
213
|
onMouseLeave: (o) => {
|
|
212
214
|
o.currentTarget.style.opacity = "0.7", o.currentTarget.style.backgroundColor = "transparent";
|
|
213
215
|
},
|
|
214
|
-
children: /* @__PURE__ */
|
|
216
|
+
children: /* @__PURE__ */ s(ve, {})
|
|
215
217
|
}
|
|
216
218
|
)
|
|
217
219
|
] }, e.id);
|
|
218
|
-
return /* @__PURE__ */
|
|
220
|
+
return /* @__PURE__ */ H(
|
|
219
221
|
"div",
|
|
220
222
|
{
|
|
221
|
-
ref:
|
|
222
|
-
className:
|
|
223
|
-
style:
|
|
224
|
-
"data-testid":
|
|
223
|
+
ref: Y,
|
|
224
|
+
className: ye("brycks-tag-input", `brycks-tag-input--${W}`, ee),
|
|
225
|
+
style: ae,
|
|
226
|
+
"data-testid": te,
|
|
225
227
|
children: [
|
|
226
|
-
/* @__PURE__ */
|
|
228
|
+
/* @__PURE__ */ H(
|
|
227
229
|
"div",
|
|
228
230
|
{
|
|
229
|
-
style:
|
|
231
|
+
style: ie,
|
|
230
232
|
onClick: () => !h && L.current?.focus(),
|
|
231
233
|
children: [
|
|
232
234
|
n.map(
|
|
233
|
-
(e) => P ? P(e, () =>
|
|
235
|
+
(e) => P ? P(e, () => z(e.id)) : ge(e, () => z(e.id))
|
|
234
236
|
),
|
|
235
|
-
/* @__PURE__ */
|
|
237
|
+
/* @__PURE__ */ s(
|
|
236
238
|
"input",
|
|
237
239
|
{
|
|
238
240
|
ref: (e) => {
|
|
239
|
-
L.current = e, typeof
|
|
241
|
+
L.current = e, typeof C == "function" ? C(e) : C && (C.current = e);
|
|
240
242
|
},
|
|
241
243
|
type: "text",
|
|
242
244
|
role: "combobox",
|
|
243
|
-
"aria-label":
|
|
245
|
+
"aria-label": _,
|
|
244
246
|
"aria-expanded": f && c.length > 0,
|
|
245
247
|
"aria-autocomplete": "list",
|
|
246
|
-
"aria-invalid": K ||
|
|
248
|
+
"aria-invalid": K || !!$,
|
|
247
249
|
value: d,
|
|
248
|
-
placeholder: n.length === 0 ?
|
|
250
|
+
placeholder: n.length === 0 ? Q : "",
|
|
249
251
|
disabled: h,
|
|
250
252
|
readOnly: N,
|
|
251
|
-
style:
|
|
252
|
-
onChange:
|
|
253
|
-
onKeyDown:
|
|
253
|
+
style: ce,
|
|
254
|
+
onChange: ne,
|
|
255
|
+
onKeyDown: oe,
|
|
254
256
|
onFocus: () => {
|
|
255
|
-
|
|
257
|
+
X(!0), l(!0);
|
|
256
258
|
},
|
|
257
|
-
onBlur: () =>
|
|
259
|
+
onBlur: () => X(!1)
|
|
258
260
|
}
|
|
259
261
|
)
|
|
260
262
|
]
|
|
261
263
|
}
|
|
262
264
|
),
|
|
263
|
-
f && c.length > 0 && /* @__PURE__ */
|
|
265
|
+
f && c.length > 0 && /* @__PURE__ */ s("ul", { role: "listbox", style: ue, children: c.map((e, t) => /* @__PURE__ */ s(
|
|
264
266
|
"li",
|
|
265
267
|
{
|
|
266
268
|
role: "option",
|
|
267
|
-
"aria-selected": t ===
|
|
268
|
-
style:
|
|
269
|
+
"aria-selected": t === k,
|
|
270
|
+
style: de(t === k),
|
|
269
271
|
onClick: () => {
|
|
270
|
-
u([...n, e]),
|
|
272
|
+
u([...n, e]), y(""), l(!1), L.current?.focus();
|
|
271
273
|
},
|
|
272
274
|
onMouseEnter: () => g(t),
|
|
273
275
|
children: e.label
|
|
274
276
|
},
|
|
275
277
|
e.id
|
|
276
278
|
)) }),
|
|
277
|
-
|
|
279
|
+
$ && /* @__PURE__ */ s("div", { style: fe, children: $ })
|
|
278
280
|
]
|
|
279
281
|
}
|
|
280
282
|
);
|
|
281
283
|
});
|
|
282
|
-
|
|
284
|
+
we.displayName = "TagInput";
|
|
283
285
|
export {
|
|
284
|
-
|
|
286
|
+
we as TagInput
|
|
285
287
|
};
|
|
286
288
|
//# sourceMappingURL=TagInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TagInput.js","sources":["../../../../src/components/form/TagInput/TagInput.tsx"],"sourcesContent":["/**\n * TagInput Component\n *\n * An input field for managing tags/chips with keyboard support.\n * Supports suggestions, validation, and custom tag rendering.\n *\n * @module components/form/TagInput\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n type CSSProperties,\n type ReactNode,\n type KeyboardEvent,\n type ChangeEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport { componentHeights, componentPaddingX, componentGap } from '../../../design-system/primitives'\n\nexport type TagInputSize = 'sm' | 'md' | 'lg'\n\nexport interface TagItem {\n /** Unique identifier */\n id: string\n /** Display label */\n label: string\n /** Optional color */\n color?: string\n}\n\nexport interface TagInputProps {\n /** Current tags */\n value?: TagItem[]\n /** Default tags (uncontrolled) */\n defaultValue?: TagItem[]\n /** Callback when tags change */\n onChange?: (tags: TagItem[]) => void\n /** Placeholder text */\n placeholder?: string\n /** Component size */\n size?: TagInputSize\n /** Maximum number of tags */\n maxTags?: number\n /** Whether to allow duplicates */\n allowDuplicates?: boolean\n /** Delimiter keys to create tag (default: Enter, comma) */\n delimiters?: string[]\n /** Whether the input is disabled */\n disabled?: boolean\n /** Whether the input is invalid */\n isInvalid?: boolean\n /** Whether the input is read-only */\n readOnly?: boolean\n /** Validation function for new tags */\n validateTag?: (value: string) => boolean | string\n /** Transform function for new tag value */\n transformTag?: (value: string) => string\n /** Suggested tags for autocomplete */\n suggestions?: TagItem[]\n /** Custom tag renderer */\n renderTag?: (tag: TagItem, onRemove: () => void) => ReactNode\n /** Label for accessibility */\n 'aria-label'?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeConfig: Record<TagInputSize, { height: number; fontSize: number; tagHeight: number; padding: number; gap: number }> = {\n sm: { height: componentHeights.sm, fontSize: fontSizes.base - 1, tagHeight: spacing[5], padding: componentPaddingX.xs, gap: spacing[1] },\n md: { height: componentHeights.md, fontSize: fontSizes.base, tagHeight: spacing[6], padding: componentPaddingX.sm, gap: spacing[1.5] },\n lg: { height: componentHeights.lg, fontSize: fontSizes.md, tagHeight: spacing[7], padding: componentPaddingX.sm, gap: spacing[2] },\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const TagInput = forwardRef<HTMLInputElement, TagInputProps>(function TagInput(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n placeholder = 'Add tags...',\n size = 'md',\n maxTags,\n allowDuplicates = false,\n delimiters = ['Enter', ','],\n disabled = false,\n isInvalid = false,\n readOnly = false,\n validateTag,\n transformTag = (v) => v.trim(),\n suggestions,\n renderTag,\n 'aria-label': ariaLabel = 'Tag input',\n className,\n testId,\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState<TagItem[]>(defaultValue)\n const [inputValue, setInputValue] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [showSuggestions, setShowSuggestions] = useState(false)\n const [activeSuggestion, setActiveSuggestion] = useState(-1)\n\n const inputRef = useRef<HTMLInputElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const tags = controlledValue !== undefined ? controlledValue : internalValue\n const config = sizeConfig[size]\n\n const isInteractive = !disabled && !readOnly\n\n // Filter suggestions\n const filteredSuggestions = suggestions?.filter(\n (s) =>\n s.label.toLowerCase().includes(inputValue.toLowerCase()) &&\n !tags.some((t) => t.id === s.id)\n ) || []\n\n const updateTags = useCallback(\n (newTags: TagItem[]) => {\n if (controlledValue === undefined) {\n setInternalValue(newTags)\n }\n onChange?.(newTags)\n },\n [controlledValue, onChange]\n )\n\n const addTag = useCallback(\n (value: string) => {\n const trimmed = transformTag(value)\n if (!trimmed) return false\n\n // Check max tags\n if (maxTags && tags.length >= maxTags) {\n setError(`Maximum ${maxTags} tags allowed`)\n return false\n }\n\n // Check duplicates\n if (!allowDuplicates && tags.some((t) => t.label.toLowerCase() === trimmed.toLowerCase())) {\n setError('Tag already exists')\n return false\n }\n\n // Validate\n if (validateTag) {\n const result = validateTag(trimmed)\n if (result !== true) {\n setError(typeof result === 'string' ? result : 'Invalid tag')\n return false\n }\n }\n\n const newTag: TagItem = {\n id: `tag-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n label: trimmed,\n }\n\n updateTags([...tags, newTag])\n setInputValue('')\n setError(null)\n return true\n },\n [tags, maxTags, allowDuplicates, validateTag, transformTag, updateTags]\n )\n\n const removeTag = useCallback(\n (tagId: string) => {\n if (!isInteractive) return\n updateTags(tags.filter((t) => t.id !== tagId))\n },\n [isInteractive, tags, updateTags]\n )\n\n const handleInputChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n\n // Check for delimiter in the value\n if (value.includes(',')) {\n const parts = value.split(',')\n parts.forEach((part, index) => {\n if (index < parts.length - 1 && part.trim()) {\n addTag(part)\n }\n })\n setInputValue(parts[parts.length - 1])\n } else {\n setInputValue(value)\n }\n\n setError(null)\n setShowSuggestions(true)\n setActiveSuggestion(-1)\n }, [addTag])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (!isInteractive) return\n\n // Handle suggestions navigation\n if (showSuggestions && filteredSuggestions.length > 0) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.max(prev - 1, 0))\n return\n }\n if ((e.key === 'Enter' || e.key === 'Tab') && activeSuggestion >= 0) {\n e.preventDefault()\n const selected = filteredSuggestions[activeSuggestion]\n if (selected) {\n updateTags([...tags, selected])\n setInputValue('')\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n return\n }\n }\n\n // Create tag on delimiter\n if (delimiters.includes(e.key) && inputValue) {\n e.preventDefault()\n addTag(inputValue)\n setShowSuggestions(false)\n return\n }\n\n // Remove last tag on backspace\n if (e.key === 'Backspace' && !inputValue && tags.length > 0) {\n removeTag(tags[tags.length - 1].id)\n return\n }\n\n // Close suggestions on escape\n if (e.key === 'Escape') {\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n },\n [isInteractive, showSuggestions, filteredSuggestions, activeSuggestion, delimiters, inputValue, tags, addTag, removeTag, updateTags]\n )\n\n // Close suggestions on outside click\n useEffect(() => {\n if (!showSuggestions) return\n\n const handleClick = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) {\n setShowSuggestions(false)\n }\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [showSuggestions])\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: '100%',\n }\n\n const wrapperStyle: CSSProperties = {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: config.gap,\n minHeight: config.height,\n padding: `${spacing[1]}px ${config.padding}px`,\n backgroundColor: disabled ? 'var(--brycks-background-muted)' : 'var(--brycks-background-default)',\n border: `1px solid ${\n isInvalid || error\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 tagStyle = (tag: TagItem): CSSProperties => ({\n display: 'inline-flex',\n alignItems: 'center',\n gap: spacing[1],\n height: config.tagHeight,\n padding: `0 ${spacing[2]}px`,\n fontSize: config.fontSize - 1,\n fontWeight: 500,\n color: tag.color ? 'white' : 'var(--brycks-foreground-default)',\n backgroundColor: tag.color || 'var(--brycks-background-muted)',\n borderRadius: 'var(--brycks-radius-full)',\n whiteSpace: 'nowrap',\n })\n\n const removeButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: spacing[4],\n height: spacing[4],\n marginLeft: spacing[0.5],\n marginRight: -spacing[1],\n color: 'inherit',\n opacity: 0.7,\n cursor: 'pointer',\n borderRadius: 'var(--brycks-radius-full)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n }\n\n const inputStyle: CSSProperties = {\n flex: 1,\n minWidth: 100,\n height: config.tagHeight,\n padding: 0,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n }\n\n const suggestionsStyle: CSSProperties = {\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: spacing[1],\n maxHeight: 200,\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 }\n\n const suggestionStyle = (isActive: boolean): CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.md,\n padding: `${spacing[2]}px ${spacing[3]}px`,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: isActive ? 'var(--brycks-background-muted)' : 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n })\n\n const errorStyle: CSSProperties = {\n marginTop: spacing[1],\n fontSize: fontSizes.sm,\n color: 'var(--brycks-error-default)',\n }\n\n const defaultRenderTag = (tag: TagItem, onRemove: () => void) => (\n <span key={tag.id} style={tagStyle(tag)}>\n {tag.label}\n {isInteractive && (\n <button\n type=\"button\"\n aria-label={`Remove ${tag.label}`}\n style={removeButtonStyle}\n onClick={(e) => {\n e.stopPropagation()\n onRemove()\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.opacity = '1'\n e.currentTarget.style.backgroundColor = 'rgba(0,0,0,0.1)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.opacity = '0.7'\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n >\n <CloseIcon />\n </button>\n )}\n </span>\n )\n\n return (\n <div\n ref={containerRef}\n className={cx('brycks-tag-input', `brycks-tag-input--${size}`, className)}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n style={wrapperStyle}\n onClick={() => !disabled && inputRef.current?.focus()}\n >\n {tags.map((tag) =>\n renderTag ? renderTag(tag, () => removeTag(tag.id)) : defaultRenderTag(tag, () => removeTag(tag.id))\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-label={ariaLabel}\n aria-expanded={showSuggestions && filteredSuggestions.length > 0}\n aria-autocomplete=\"list\"\n aria-invalid={isInvalid || !!error}\n value={inputValue}\n placeholder={tags.length === 0 ? placeholder : ''}\n disabled={disabled}\n readOnly={readOnly}\n style={inputStyle}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setIsFocused(true)\n setShowSuggestions(true)\n }}\n onBlur={() => setIsFocused(false)}\n />\n </div>\n\n {showSuggestions && filteredSuggestions.length > 0 && (\n <ul role=\"listbox\" style={suggestionsStyle}>\n {filteredSuggestions.map((suggestion, index) => (\n <li\n key={suggestion.id}\n role=\"option\"\n aria-selected={index === activeSuggestion}\n style={suggestionStyle(index === activeSuggestion)}\n onClick={() => {\n updateTags([...tags, suggestion])\n setInputValue('')\n setShowSuggestions(false)\n inputRef.current?.focus()\n }}\n onMouseEnter={() => setActiveSuggestion(index)}\n >\n {suggestion.label}\n </li>\n ))}\n </ul>\n )}\n\n {error && <div style={errorStyle}>{error}</div>}\n </div>\n )\n})\n\nTagInput.displayName = 'TagInput'\n"],"names":["sizeConfig","componentHeights","fontSizes","spacing","componentPaddingX","CloseIcon","jsx","TagInput","forwardRef","controlledValue","defaultValue","onChange","placeholder","size","maxTags","allowDuplicates","delimiters","disabled","isInvalid","readOnly","validateTag","transformTag","v","suggestions","renderTag","ariaLabel","className","testId","ref","internalValue","setInternalValue","useState","inputValue","setInputValue","isFocused","setIsFocused","error","setError","showSuggestions","setShowSuggestions","activeSuggestion","setActiveSuggestion","inputRef","useRef","containerRef","tags","config","isInteractive","filteredSuggestions","s","updateTags","useCallback","newTags","addTag","value","trimmed","t","result","newTag","removeTag","tagId","handleInputChange","parts","part","index","handleKeyDown","prev","selected","useEffect","handleClick","e","containerStyle","wrapperStyle","durations","easings","tagStyle","tag","removeButtonStyle","inputStyle","suggestionsStyle","suggestionStyle","isActive","componentGap","errorStyle","defaultRenderTag","onRemove","jsxs","cx","node","suggestion"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TagInput.js","sources":["../../../../src/components/form/TagInput/TagInput.tsx"],"sourcesContent":["/**\n * TagInput Component\n *\n * An input field for managing tags/chips with keyboard support.\n * Supports suggestions, validation, and custom tag rendering.\n *\n * @module components/form/TagInput\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n type CSSProperties,\n type ReactNode,\n type KeyboardEvent,\n type ChangeEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport { componentHeights, componentPaddingX, componentGap } from '../../../design-system/primitives'\n\nexport type TagInputSize = 'sm' | 'md' | 'lg'\n\nexport interface TagItem {\n /** Unique identifier */\n id: string\n /** Display label */\n label: string\n /** Optional color */\n color?: string\n}\n\nexport interface TagInputProps {\n /** Current tags */\n value?: TagItem[]\n /** Default tags (uncontrolled) */\n defaultValue?: TagItem[]\n /** Callback when tags change */\n onChange?: (tags: TagItem[]) => void\n /** Placeholder text */\n placeholder?: string\n /** Component size */\n size?: TagInputSize\n /** Maximum number of tags */\n maxTags?: number\n /** Whether to allow duplicates */\n allowDuplicates?: boolean\n /** Delimiter keys to create tag (default: Enter, comma) */\n delimiters?: string[]\n /** Whether the input is disabled */\n disabled?: boolean\n /** Whether the input is invalid */\n isInvalid?: boolean\n /** Whether the input is read-only */\n readOnly?: boolean\n /** Validation function for new tags */\n validateTag?: (value: string) => boolean | string\n /** Transform function for new tag value */\n transformTag?: (value: string) => string\n /** Suggested tags for autocomplete */\n suggestions?: TagItem[]\n /** Custom tag renderer */\n renderTag?: (tag: TagItem, onRemove: () => void) => ReactNode\n /** Message shown when the tag limit is reached */\n maxTagsMessage?: (maxTags: number) => string\n /** Message shown when a duplicate tag is rejected */\n duplicateMessage?: string\n /** Label for accessibility */\n 'aria-label'?: string\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeConfig: Record<TagInputSize, { height: number; fontSize: number; tagHeight: number; padding: number; gap: number }> = {\n sm: { height: componentHeights.sm, fontSize: fontSizes.base - 1, tagHeight: spacing[5], padding: componentPaddingX.xs, gap: spacing[1] },\n md: { height: componentHeights.md, fontSize: fontSizes.base, tagHeight: spacing[6], padding: componentPaddingX.sm, gap: spacing[1.5] },\n lg: { height: componentHeights.lg, fontSize: fontSizes.md, tagHeight: spacing[7], padding: componentPaddingX.sm, gap: spacing[2] },\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const TagInput = forwardRef<HTMLInputElement, TagInputProps>(function TagInput(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n placeholder = 'Add tags...',\n size = 'md',\n maxTags,\n allowDuplicates = false,\n delimiters = ['Enter', ','],\n disabled = false,\n isInvalid = false,\n readOnly = false,\n validateTag,\n transformTag = (v) => v.trim(),\n suggestions,\n renderTag,\n maxTagsMessage = (max) => `Maximum ${max} tags allowed`,\n duplicateMessage = 'Tag already exists',\n 'aria-label': ariaLabel = 'Tag input',\n className,\n testId,\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState<TagItem[]>(defaultValue)\n const [inputValue, setInputValue] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [showSuggestions, setShowSuggestions] = useState(false)\n const [activeSuggestion, setActiveSuggestion] = useState(-1)\n\n const inputRef = useRef<HTMLInputElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const tags = controlledValue !== undefined ? controlledValue : internalValue\n const config = sizeConfig[size]\n\n const isInteractive = !disabled && !readOnly\n\n // Filter suggestions\n const filteredSuggestions = suggestions?.filter(\n (s) =>\n s.label.toLowerCase().includes(inputValue.toLowerCase()) &&\n !tags.some((t) => t.id === s.id)\n ) || []\n\n const updateTags = useCallback(\n (newTags: TagItem[]) => {\n if (controlledValue === undefined) {\n setInternalValue(newTags)\n }\n onChange?.(newTags)\n },\n [controlledValue, onChange]\n )\n\n const addTag = useCallback(\n (value: string) => {\n const trimmed = transformTag(value)\n if (!trimmed) return false\n\n // Check max tags\n if (maxTags && tags.length >= maxTags) {\n setError(maxTagsMessage(maxTags))\n return false\n }\n\n // Check duplicates\n if (!allowDuplicates && tags.some((t) => t.label.toLowerCase() === trimmed.toLowerCase())) {\n setError(duplicateMessage)\n return false\n }\n\n // Validate\n if (validateTag) {\n const result = validateTag(trimmed)\n if (result !== true) {\n setError(typeof result === 'string' ? result : 'Invalid tag')\n return false\n }\n }\n\n const newTag: TagItem = {\n id: `tag-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n label: trimmed,\n }\n\n updateTags([...tags, newTag])\n setInputValue('')\n setError(null)\n return true\n },\n [tags, maxTags, allowDuplicates, validateTag, transformTag, updateTags, maxTagsMessage, duplicateMessage]\n )\n\n const removeTag = useCallback(\n (tagId: string) => {\n if (!isInteractive) return\n updateTags(tags.filter((t) => t.id !== tagId))\n },\n [isInteractive, tags, updateTags]\n )\n\n const handleInputChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n\n // Check for delimiter in the value\n if (value.includes(',')) {\n const parts = value.split(',')\n parts.forEach((part, index) => {\n if (index < parts.length - 1 && part.trim()) {\n addTag(part)\n }\n })\n setInputValue(parts[parts.length - 1])\n } else {\n setInputValue(value)\n }\n\n setError(null)\n setShowSuggestions(true)\n setActiveSuggestion(-1)\n }, [addTag])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (!isInteractive) return\n\n // Handle suggestions navigation\n if (showSuggestions && filteredSuggestions.length > 0) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setActiveSuggestion((prev) => Math.max(prev - 1, 0))\n return\n }\n if ((e.key === 'Enter' || e.key === 'Tab') && activeSuggestion >= 0) {\n e.preventDefault()\n const selected = filteredSuggestions[activeSuggestion]\n if (selected) {\n updateTags([...tags, selected])\n setInputValue('')\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n return\n }\n }\n\n // Create tag on delimiter\n if (delimiters.includes(e.key) && inputValue) {\n e.preventDefault()\n addTag(inputValue)\n setShowSuggestions(false)\n return\n }\n\n // Remove last tag on backspace\n if (e.key === 'Backspace' && !inputValue && tags.length > 0) {\n removeTag(tags[tags.length - 1].id)\n return\n }\n\n // Close suggestions on escape\n if (e.key === 'Escape') {\n setShowSuggestions(false)\n setActiveSuggestion(-1)\n }\n },\n [isInteractive, showSuggestions, filteredSuggestions, activeSuggestion, delimiters, inputValue, tags, addTag, removeTag, updateTags]\n )\n\n // Close suggestions on outside click\n useEffect(() => {\n if (!showSuggestions) return\n\n const handleClick = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) {\n setShowSuggestions(false)\n }\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [showSuggestions])\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: '100%',\n }\n\n const wrapperStyle: CSSProperties = {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: config.gap,\n minHeight: config.height,\n padding: `${spacing[1]}px ${config.padding}px`,\n backgroundColor: disabled ? 'var(--brycks-background-muted)' : 'var(--brycks-background-default)',\n border: `1px solid ${\n isInvalid || error\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 tagStyle = (tag: TagItem): CSSProperties => ({\n display: 'inline-flex',\n alignItems: 'center',\n gap: spacing[1],\n height: config.tagHeight,\n padding: `0 ${spacing[2]}px`,\n fontSize: config.fontSize - 1,\n fontWeight: 500,\n color: tag.color ? 'white' : 'var(--brycks-foreground-default)',\n backgroundColor: tag.color || 'var(--brycks-background-muted)',\n borderRadius: 'var(--brycks-radius-full)',\n whiteSpace: 'nowrap',\n })\n\n const removeButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: spacing[4],\n height: spacing[4],\n marginLeft: spacing[0.5],\n marginRight: -spacing[1],\n color: 'inherit',\n opacity: 0.7,\n cursor: 'pointer',\n borderRadius: 'var(--brycks-radius-full)',\n transition: `all ${durations.fast}ms ${easings.easeOut}`,\n }\n\n const inputStyle: CSSProperties = {\n flex: 1,\n minWidth: 100,\n height: config.tagHeight,\n padding: 0,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n }\n\n const suggestionsStyle: CSSProperties = {\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: spacing[1],\n maxHeight: 200,\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 }\n\n const suggestionStyle = (isActive: boolean): CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.md,\n padding: `${spacing[2]}px ${spacing[3]}px`,\n fontSize: config.fontSize,\n color: 'var(--brycks-foreground-default)',\n backgroundColor: isActive ? 'var(--brycks-background-muted)' : 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n })\n\n const errorStyle: CSSProperties = {\n marginTop: spacing[1],\n fontSize: fontSizes.sm,\n color: 'var(--brycks-error-default)',\n }\n\n const defaultRenderTag = (tag: TagItem, onRemove: () => void) => (\n <span key={tag.id} style={tagStyle(tag)}>\n {tag.label}\n {isInteractive && (\n <button\n type=\"button\"\n aria-label={`Remove ${tag.label}`}\n style={removeButtonStyle}\n onClick={(e) => {\n e.stopPropagation()\n onRemove()\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.opacity = '1'\n e.currentTarget.style.backgroundColor = 'rgba(0,0,0,0.1)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.opacity = '0.7'\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n >\n <CloseIcon />\n </button>\n )}\n </span>\n )\n\n return (\n <div\n ref={containerRef}\n className={cx('brycks-tag-input', `brycks-tag-input--${size}`, className)}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n style={wrapperStyle}\n onClick={() => !disabled && inputRef.current?.focus()}\n >\n {tags.map((tag) =>\n renderTag ? renderTag(tag, () => removeTag(tag.id)) : defaultRenderTag(tag, () => removeTag(tag.id))\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-label={ariaLabel}\n aria-expanded={showSuggestions && filteredSuggestions.length > 0}\n aria-autocomplete=\"list\"\n aria-invalid={isInvalid || !!error}\n value={inputValue}\n placeholder={tags.length === 0 ? placeholder : ''}\n disabled={disabled}\n readOnly={readOnly}\n style={inputStyle}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setIsFocused(true)\n setShowSuggestions(true)\n }}\n onBlur={() => setIsFocused(false)}\n />\n </div>\n\n {showSuggestions && filteredSuggestions.length > 0 && (\n <ul role=\"listbox\" style={suggestionsStyle}>\n {filteredSuggestions.map((suggestion, index) => (\n <li\n key={suggestion.id}\n role=\"option\"\n aria-selected={index === activeSuggestion}\n style={suggestionStyle(index === activeSuggestion)}\n onClick={() => {\n updateTags([...tags, suggestion])\n setInputValue('')\n setShowSuggestions(false)\n inputRef.current?.focus()\n }}\n onMouseEnter={() => setActiveSuggestion(index)}\n >\n {suggestion.label}\n </li>\n ))}\n </ul>\n )}\n\n {error && <div style={errorStyle}>{error}</div>}\n </div>\n )\n})\n\nTagInput.displayName = 'TagInput'\n"],"names":["sizeConfig","componentHeights","fontSizes","spacing","componentPaddingX","CloseIcon","jsx","TagInput","forwardRef","controlledValue","defaultValue","onChange","placeholder","size","maxTags","allowDuplicates","delimiters","disabled","isInvalid","readOnly","validateTag","transformTag","v","suggestions","renderTag","maxTagsMessage","max","duplicateMessage","ariaLabel","className","testId","ref","internalValue","setInternalValue","useState","inputValue","setInputValue","isFocused","setIsFocused","error","setError","showSuggestions","setShowSuggestions","activeSuggestion","setActiveSuggestion","inputRef","useRef","containerRef","tags","config","isInteractive","filteredSuggestions","s","updateTags","useCallback","newTags","addTag","value","trimmed","t","result","newTag","removeTag","tagId","handleInputChange","parts","part","index","handleKeyDown","prev","selected","useEffect","handleClick","e","containerStyle","wrapperStyle","durations","easings","tagStyle","tag","removeButtonStyle","inputStyle","suggestionsStyle","suggestionStyle","isActive","componentGap","errorStyle","defaultRenderTag","onRemove","jsxs","cx","node","suggestion"],"mappings":"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"}
|