@stackone/malachite 2.47.2 → 2.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +1 -0
- package/dist/components/Button.js +64 -87
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Dropdown.js +283 -282
- package/dist/components/Dropdown.js.map +1 -1
- package/dist/components/IconIndicator.js +27 -0
- package/dist/components/IconIndicator.js.map +1 -0
- package/dist/components/buttonSizing.js +30 -0
- package/dist/components/buttonSizing.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.js +351 -349
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sources":["../../src/components/Dropdown.tsx"],"sourcesContent":["import React, {\n useId,\n useState,\n useRef,\n useEffect,\n useInsertionEffect,\n useLayoutEffect,\n useCallback,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { Control, FieldPath, FieldValues } from 'react-hook-form';\nimport BaseFormComponent, {\n type RequiredIndicator,\n type RightSideContent,\n useFormFieldIds,\n} from './BaseFormComponent';\nimport CaretDownIcon from './CustomIcons/CaretDownIcon';\nimport CloseIcon from './CustomIcons/CloseIcon';\nimport FieldMessage from './FieldMessage';\nimport LoadingInput from './LoadingInput';\nimport Spinner from './Spinner';\nimport Tag from './Tag';\nimport Tooltip from './Tooltip';\nimport MarkdownBlock from './Typography/MarkdownBlock';\nimport { inlineMarkdownText } from './Typography/inlineMarkdown';\nimport { getDeepActiveElement } from './activeElement';\nimport { CONTROL_TEXT_SIZE, CONTROL_TEXT_SIZE_CLASS } from './controlTextSize';\nimport { controlWidthStyle } from './controlWidth';\nimport { DROPDOWN_TRIGGER_ATTR, type DropdownTone, getTriggerVisual } from './dropdownTriggerStyle';\nimport { pushEscapeLayer } from './escapeLayers';\nimport {\n MENU_MAX_HEIGHT_PX,\n MENU_SPECS,\n type MenuGeometry,\n isTriggerOffscreen,\n measureMenuGeometry,\n rectSignature,\n} from './floatingMenuGeometry';\nimport { FOCUS_RING } from './focusRing';\nimport { hasBadge } from './hasBadge';\nimport { ensureDropdownPanelStyles } from './optionRowStyles';\nimport { usePopupLayer } from './overlayLayers';\nimport { useTopLayer } from './topLayer';\nimport { isCut, tooltipLines } from './truncatedLines';\n\n// The menu portals into document.body, outside any shadow root, so a Tailwind-styled badge (a Tag)\n// needs a shadow host of its own; loaded only when a badge is passed.\nconst BadgeHost = React.lazy(() => import('./ActionMenuTagHost'));\n\nconst TriggerTag = ({ id, text, disabled }: { id: string; text: string; disabled?: boolean }) => (\n <span\n id={id}\n className={`flex min-w-0 max-w-[40%] [flex-shrink:3] ${disabled ? 'opacity-60' : ''}`}\n >\n <Tag value={text} paddingSize=\"compact\" fontSize=\"xsmall\" textTransform=\"none\" />\n </span>\n);\n\nexport type { DropdownTone };\n\nexport interface DropdownItem {\n id: string;\n label: string;\n icon?: React.ReactNode;\n /** Alternate label shown in the closed trigger when selected (falls back to `label`). */\n triggerLabel?: string;\n /** Short tag shown at the right of the closed trigger while this item is selected. */\n triggerTag?: string;\n /** Items sharing a `group` render under a section header, in first-seen order. */\n group?: string;\n subtitle?: string;\n rightSideText?: string;\n rightSideTextVariant?: 'muted' | 'primary';\n rightSideTextAlignment?: 'left' | 'right';\n /** Right-aligned badge shown in the open menu only (not in the trigger or the search input). */\n badge?: React.ReactNode;\n}\n\ninterface DropdownBaseProps {\n label?: string;\n hint?: string;\n rightSideContent?: RightSideContent;\n tooltip?: string;\n name: FieldPath<FieldValues> | string;\n loading?: boolean;\n menuLoading?: boolean;\n items: DropdownItem[];\n onItemSelected?: (id?: string) => void;\n defaultValue?: string;\n /** Controlled selection. When set, the trigger always reflects this id and the component\n * keeps no selection state of its own. Pass it with `onItemSelected`. */\n value?: string;\n disabled?: boolean;\n error?: boolean;\n /** `pending` marks a value the user still has to supply. Outranks open and selection. */\n tone?: DropdownTone;\n className?: string;\n formControl?: Control<FieldValues, unknown>;\n description?: string;\n required?: boolean;\n requiredIndicator?: RequiredIndicator;\n helperText?: React.ReactNode;\n placeholder?: string;\n subtitleLayout?: SubtitleLayout;\n /** Adds a clear control to the trigger, reported as `onItemSelected(undefined)`. */\n clearable?: boolean;\n /** 'large' (42px) for form inputs; 'medium' (32px) for toolbar chips; 'small' (28px) beside a title. */\n size?: DropdownSize;\n fullWidth?: boolean;\n width?: string | number;\n /**\n * Raises the open menu's floor above the shared 160px one, without widening the trigger.\n * For a control pinned narrow by its column — a role picker in a 160px cell, a member\n * picker in a 200px slot — whose options carry a subtitle the trigger never has to show.\n */\n minWidth?: number;\n /**\n * Which trigger edge a menu wider than its trigger lines up with. `end` grows it leftwards,\n * for a control at the right of its container. Either flips when the viewport has no room.\n */\n menuAlign?: 'start' | 'end';\n /** Names the trigger from the light DOM, where `htmlFor` cannot reach into the shadow root. */\n id?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n/**\n * The search trigger is a single-line text input with nowhere for a second line, so\n * `showSubtitleInTrigger` is rejected alongside `search` rather than silently ignored.\n */\ntype DropdownTriggerModeProps =\n | {\n search?: false;\n /** Promotes the selected item's `subtitle` into the closed trigger, beneath the value. */\n showSubtitleInTrigger?: boolean;\n }\n | { search: true; showSubtitleInTrigger?: never };\n\nexport type DropdownProps = DropdownBaseProps & DropdownTriggerModeProps;\n\n/**\n * Matches Button and the Figma component library: 28 / 32 / 42px. These names moved up a\n * tier in 0.71 — what was `xsmall`/`small`/`medium` is now `small`/`medium`/`large`.\n */\nexport type DropdownSize = 'small' | 'medium' | 'large';\n\nexport type SubtitleLayout = 'inline' | 'stacked';\n\n// Text without these renders the same parsed or not, so it skips the parser.\nconst INLINE_MARKDOWN_SYNTAX = /[*`[<&\\\\]/;\n\n// Inert links: a <button> takes no interactive content.\nconst ItemSubtitle = ({ text }: { text: string }) =>\n INLINE_MARKDOWN_SYNTAX.test(text) ? (\n <MarkdownBlock\n text={text}\n variant=\"inline\"\n color=\"inherit\"\n size=\"inherit\"\n links=\"inert\"\n omitMargin\n />\n ) : (\n text\n );\n\nconst PANEL_MESSAGE_STYLE: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: '24px 16px',\n color: 'var(--malachite-text-dimmed, rgb(161, 161, 161))',\n};\n\n// Figma pins the option's inline annotation at 11px on every tier — unlike the label,\n// it does not ride the ladder (Item Large 68:2617, Item Medium 2343:2134).\nconst ANNOTATION_FONT_SIZE = 'var(--malachite-font-size-xsmall, 11px)';\n\nconst OPTION_SELECTOR = '[data-dropdown-option]';\n\nconst panelOptions = (panel: HTMLElement | null): HTMLElement[] =>\n Array.from(panel?.querySelectorAll<HTMLElement>(OPTION_SELECTOR) ?? []);\n\n// Search what the subtitle shows: link and image text, not their destinations or markers.\nconst subtitleSearchText = (subtitle: string) =>\n INLINE_MARKDOWN_SYNTAX.test(subtitle)\n ? inlineMarkdownText(subtitle)\n : subtitle.replace(/\\s+/g, ' ');\n\nconst matchesSearch = (item: DropdownItem, query: string) => {\n const q = query.toLowerCase();\n const labelMatches = item.label.toLowerCase().includes(q);\n const subtitleMatches = item.subtitle\n ? subtitleSearchText(item.subtitle).toLowerCase().includes(q)\n : false;\n const rightSideTextMatches = item.rightSideText\n ? item.rightSideText.toLowerCase().includes(q)\n : false;\n return labelMatches || subtitleMatches || rightSideTextMatches;\n};\n\nconst TRIGGER_SIZE_HEIGHT: Record<DropdownSize, string> = {\n small: 'h-[var(--malachite-control-height-small,28px)]',\n medium: 'h-[var(--malachite-control-height-medium,32px)]',\n large: 'h-[var(--malachite-control-height-large,42px)]',\n};\n\nconst TRIGGER_SIZE_CLASSES: Record<DropdownSize, string> = {\n small: `${TRIGGER_SIZE_HEIGHT.small} px-2.5 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.small}`,\n medium: `${TRIGGER_SIZE_HEIGHT.medium} px-3 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.medium}`,\n large: `${TRIGGER_SIZE_HEIGHT.large} px-4 py-2.5 ${CONTROL_TEXT_SIZE_CLASS.large}`,\n};\n\nconst TRIGGER_SIZE_STACKED_CLASSES: Record<DropdownSize, string> = {\n small: `min-h-[var(--malachite-control-height-small,28px)] px-2.5 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.small}`,\n medium: `min-h-[var(--malachite-control-height-medium,32px)] px-3 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.medium}`,\n large: `min-h-[var(--malachite-control-height-large,42px)] px-4 py-2.5 ${CONTROL_TEXT_SIZE_CLASS.large}`,\n};\n\nconst CLEAR_OFFSET_CLASSES: Record<DropdownSize, string> = {\n small: 'right-[26px] size-4',\n medium: 'right-[30px] size-4',\n large: 'right-[38px] size-4',\n};\n\nconst CLEAR_STACKED_TOP_CLASSES: Record<DropdownSize, string> = {\n small: 'top-[calc(var(--malachite-control-height-small,28px)/2)] -translate-y-1/2',\n medium: 'top-[calc(var(--malachite-control-height-medium,32px)/2)] -translate-y-1/2',\n large: 'top-[calc(var(--malachite-control-height-large,42px)/2)] -translate-y-1/2',\n};\n\n// Radius tracks the tier in Figma: 10 / 12 / 14. Only 12 has a --malachite-radius-* rung.\nconst TRIGGER_SIZE_RADIUS: Record<DropdownSize, string> = {\n small: 'rounded-[var(--malachite-radius-10,10px)]',\n medium: 'rounded-xl',\n large: 'rounded-[var(--malachite-radius-xxl,14px)]',\n};\n\nconst NEVER = () => false;\n\nconst ValueRow: React.FC<{ wrap: boolean; id?: string; children: React.ReactNode }> = ({\n wrap,\n id,\n children,\n}) =>\n wrap ? (\n <span id={id} className=\"min-w-0 flex items-center gap-2\">\n {children}\n </span>\n ) : (\n <>{children}</>\n );\n\nconst LabelRow: React.FC<{ row: boolean; children: React.ReactNode }> = ({ row, children }) =>\n row ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>\n {children}\n </span>\n ) : (\n <>{children}</>\n );\n\ninterface DropdownTriggerProps {\n isOpen: boolean;\n onClick: (fromKeyboard?: boolean) => void;\n selectedItem: DropdownItem | undefined;\n hasClear?: boolean;\n onClear?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n clearLabel?: string;\n disabled?: boolean;\n error?: boolean;\n tone?: DropdownTone;\n placeholder?: string;\n search?: boolean;\n showSubtitleInTrigger?: boolean;\n searchQuery?: string;\n onSearchChange?: (value: string) => void;\n onFocusOpen?: () => void;\n /** ArrowDown on the trigger: opens the menu, or steps into it if already open. */\n onArrowDown?: () => void;\n /** Tab off the trigger: dismisses the panel, which is portaled and would outlive the focus. */\n onTabAway?: () => void;\n size?: DropdownSize;\n controlId: string;\n labelId?: string;\n describedBy?: string;\n required?: boolean;\n ariaLabel?: string;\n ariaLabelledBy?: string;\n /** A caller-supplied id means an external `<label for>` may be naming the control. */\n hasCallerId?: boolean;\n}\n\nconst DropdownTrigger = React.forwardRef<HTMLElement, DropdownTriggerProps>(\n (\n {\n isOpen,\n onClick,\n selectedItem,\n disabled = false,\n error = false,\n tone,\n placeholder,\n search = false,\n showSubtitleInTrigger = false,\n searchQuery = '',\n onSearchChange,\n onFocusOpen,\n onArrowDown,\n onTabAway,\n size = 'large',\n hasClear = false,\n onClear,\n clearLabel,\n controlId,\n labelId,\n describedBy,\n required = false,\n ariaLabel,\n ariaLabelledBy,\n hasCallerId = false,\n },\n forwardedRef,\n ) => {\n const stacked = showSubtitleInTrigger && !search && !!selectedItem?.subtitle;\n const sizeClasses = stacked\n ? TRIGGER_SIZE_STACKED_CLASSES[size]\n : TRIGGER_SIZE_CLASSES[size];\n const sizeRadius = TRIGGER_SIZE_RADIUS[size];\n const valueId = `${controlId}-value`;\n const subtitleId = `${controlId}-subtitle`;\n // aria-labelledby outranks aria-label in the accessible-name algorithm, so the\n // generated label+value pair has to be dropped for a caller's aria-label to apply.\n // Named off nothing, the button takes its name from every descendant — the subtitle\n // included, which `aria-describedby` then repeats. Naming it off the value alone fixes\n // that, but only where nothing else already names the control.\n const tagId = `${controlId}-tag`;\n const rendersButton = !search || disabled;\n const hasTag = rendersButton && !!selectedItem?.triggerTag;\n const showsSearchTag = !rendersButton && !isOpen && !!selectedItem?.triggerTag;\n const valueIds = hasTag ? `${valueId} ${tagId}` : valueId;\n const namesItself = !labelId && !ariaLabel && !hasCallerId && (stacked || hasTag);\n const labelledBy =\n ariaLabelledBy ??\n (labelId && !ariaLabel ? `${labelId} ${valueIds}` : undefined) ??\n (namesItself ? valueIds : undefined);\n const tagOutsideName = hasTag && !labelledBy?.split(' ').includes(tagId);\n\n const handleTriggerKeyDown = (event: React.KeyboardEvent): void => {\n // Not prevented: Tab carries on to the next control. In search mode the trigger keeps\n // focus on open, so this is the panel's only Tab dismissal.\n if (event.key === 'Tab') {\n onTabAway?.();\n return;\n }\n if (event.key !== 'ArrowDown') {\n return;\n }\n event.preventDefault();\n onArrowDown?.();\n };\n\n const valueTextRef = useRef<HTMLSpanElement>(null);\n const subtitleTextRef = useRef<HTMLSpanElement>(null);\n const triggerVisual = getTriggerVisual({ disabled, error, tone, open: isOpen });\n const showValueLabel = !isOpen && !!selectedItem;\n const valueText = selectedItem?.triggerLabel ?? selectedItem?.label;\n const triggerSubtitle = stacked ? selectedItem?.subtitle : undefined;\n const isValueTruncated = () => isCut(valueTextRef.current);\n\n // A tooltip reads its text at render, but which line is cut off is only knowable on\n // hover — so the one measurement pass that decides whether to show also records what\n // to say. The initial value never shows: untruncated, the tooltip refuses to open.\n const [cutLines, setCutLines] = useState({ value: false, subtitle: true });\n const measureTruncatedLines = () => {\n const value = isValueTruncated();\n const subtitle = isCut(subtitleTextRef.current);\n if (!value && !subtitle) {\n return false;\n }\n setCutLines({ value, subtitle });\n return true;\n };\n\n if (search && !disabled) {\n return (\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n className={`\n relative w-full ${sizeClasses} ${sizeRadius}\n border border-solid\n transition-all duration-200\n flex items-center\n `}\n style={triggerVisual}\n {...{ [DROPDOWN_TRIGGER_ATTR]: '' }}\n data-open={isOpen || undefined}\n onClick={(e) => e.stopPropagation()}\n >\n {selectedItem?.icon && (\n <span className=\"flex shrink-0 items-center justify-center pr-2\">\n {selectedItem.icon}\n </span>\n )}\n <Tooltip text={valueText} shouldShow={isValueTruncated} isShrinkable fill>\n <div className=\"relative flex-1 flex items-center min-w-0\">\n {showValueLabel && (\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-0 flex items-center pointer-events-none\"\n >\n <span\n ref={valueTextRef}\n className=\"min-w-0 block truncate text-[length:inherit]\n text-[var(--malachite-text-primary)]\"\n >\n {valueText}\n </span>\n </span>\n )}\n <input\n id={controlId}\n type=\"text\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-invalid={error || undefined}\n aria-required={required || undefined}\n aria-describedby={\n [describedBy, showsSearchTag ? tagId : undefined]\n .filter(Boolean)\n .join(' ') || undefined\n }\n value={isOpen ? searchQuery : (selectedItem?.label ?? '')}\n onChange={(e) => {\n e.stopPropagation();\n onSearchChange?.(e.target.value);\n if (!isOpen) {\n onClick();\n }\n }}\n onFocus={() => {\n onFocusOpen?.();\n }}\n onKeyDown={handleTriggerKeyDown}\n placeholder={placeholder ?? 'Select Field'}\n className={`flex-1 min-w-0 bg-transparent outline-none\n text-[length:inherit] font-normal\n placeholder:text-[var(--malachite-text-dimmed)] ${\n showValueLabel\n ? 'text-transparent'\n : 'text-[var(--malachite-text-primary)]'\n }`}\n />\n </div>\n </Tooltip>\n {showsSearchTag && selectedItem?.triggerTag && (\n <>\n <span aria-hidden=\"true\" className=\"w-2 shrink-0\" />\n <TriggerTag id={tagId} text={selectedItem.triggerTag} />\n </>\n )}\n {hasClear && (\n <button\n type=\"button\"\n aria-label={clearLabel}\n onClick={onClear}\n className=\"flex shrink-0 items-center justify-center pl-2 cursor-pointer\n bg-transparent border-none p-0 text-[var(--malachite-text-placeholder)]\n hover:text-[var(--malachite-text-primary)] transition-colors\n rounded-full focus-visible:[outline:2px_solid_var(--malachite-text-primary)] focus-visible:outline-offset-2\"\n >\n <CloseIcon size={13} />\n </button>\n )}\n <div className=\"flex items-center justify-center pl-2\">\n {/* Mouse-only affordance: the input beside it already opens the menu on\n click and focus, so this stays out of the tab order to avoid a\n duplicate stop — but it must still be a button, not a click-handling\n span, so it is exposed and activatable rather than invisible. */}\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={isOpen ? 'Close options' : 'Open options'}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n className=\"flex items-center justify-center cursor-pointer bg-transparent border-none p-0\"\n >\n <CaretDownIcon\n size={13}\n style={{\n color: isOpen\n ? 'var(--malachite-text-primary, rgb(10, 10, 10))'\n : 'var(--malachite-text-placeholder, rgb(187, 187, 187))',\n transition: 'transform 0.2s ease, color 0.2s ease',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n />\n </button>\n </div>\n </div>\n );\n }\n\n const trigger = (\n <button\n ref={forwardedRef as React.Ref<HTMLButtonElement>}\n id={controlId}\n type=\"button\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n aria-invalid={error || undefined}\n aria-required={required || undefined}\n aria-describedby={\n [\n describedBy,\n triggerSubtitle ? subtitleId : undefined,\n tagOutsideName ? tagId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n onClick={(e) => {\n e.stopPropagation();\n onClick(e.detail === 0);\n }}\n onKeyDown={handleTriggerKeyDown}\n disabled={disabled}\n style={triggerVisual}\n {...{ [DROPDOWN_TRIGGER_ATTR]: '' }}\n className={`\n relative w-full ${sizeClasses} ${sizeRadius}\n border border-solid\n transition-all duration-200\n flex ${stacked ? 'items-start' : 'items-center'} gap-3\n cursor-pointer\n disabled:cursor-not-allowed ${FOCUS_RING}\n `}\n >\n {/* Spans: <button> takes phrasing content only. */}\n <span\n id={triggerSubtitle ? undefined : valueId}\n className={`text-left ${hasTag ? 'flex-[1_1_auto]' : 'flex-1'} min-w-0 flex ${\n triggerSubtitle ? 'flex-col gap-1' : 'items-center gap-2'\n }`}\n >\n {selectedItem ? (\n <>\n <ValueRow wrap={!!triggerSubtitle} id={valueId}>\n {selectedItem.icon && (\n <span className=\"flex items-center justify-center shrink-0\">\n {selectedItem.icon}\n </span>\n )}\n <Tooltip\n text={valueText}\n shouldShow={triggerSubtitle ? NEVER : isValueTruncated}\n triggerAs=\"span\"\n isShrinkable\n >\n <span\n ref={valueTextRef}\n className={`min-w-0 block truncate text-[length:inherit] ${\n disabled\n ? 'text-[var(--malachite-text-placeholder)]'\n : 'text-[var(--malachite-text-primary)]'\n }`}\n >\n {valueText}\n </span>\n </Tooltip>\n </ValueRow>\n {triggerSubtitle && (\n <span\n id={subtitleId}\n ref={subtitleTextRef}\n className=\"min-w-0 block truncate text-[length:var(--malachite-font-size-xsmall,11px)] text-[var(--malachite-text-secondary,rgb(123,123,123))] leading-normal\"\n >\n <ItemSubtitle text={triggerSubtitle} />\n </span>\n )}\n </>\n ) : (\n <span\n className={`flex-1 min-w-0 truncate text-[length:inherit] ${\n disabled\n ? 'text-[var(--malachite-text-placeholder)]'\n : 'text-[var(--malachite-text-dimmed)]'\n }`}\n >\n {placeholder ?? 'Select Field'}\n </span>\n )}\n </span>\n {selectedItem?.triggerTag && (\n <TriggerTag id={tagId} text={selectedItem.triggerTag} disabled={disabled} />\n )}\n {hasClear && <span aria-hidden=\"true\" className=\"shrink-0 w-4\" />}\n <span className=\"flex items-center justify-center shrink-0\">\n <CaretDownIcon\n size={13}\n style={{\n color: isOpen\n ? 'var(--malachite-text-primary, rgb(10, 10, 10))'\n : 'var(--malachite-text-placeholder, rgb(187, 187, 187))',\n transition: 'transform 0.2s ease, color 0.2s ease',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n />\n </span>\n </button>\n );\n\n // The button is what takes focus, so the tooltip wraps it rather than a line inside:\n // mounted on a line it could only ever open with a pointer, and nested tooltips opened\n // together on hover. Its text is already in the trigger's name and description, so it\n // repeats it visually only. `fill`, not `isShrinkable`, whose `overflow: hidden` would\n // clip the error ring the button paints outside its border box.\n // Gated on the prop, not on there being a subtitle to show: keyed off the selection the\n // wrapper would appear on the first choice, remounting the button `focusTrigger` has\n // just handed focus back to and dropping the keyboard user at <body>.\n return showSubtitleInTrigger && !search ? (\n <Tooltip\n text={tooltipLines([\n ['value', cutLines.value && valueText],\n [\n 'subtitle',\n cutLines.subtitle && triggerSubtitle && (\n <ItemSubtitle text={triggerSubtitle} />\n ),\n ],\n ])}\n shouldShow={triggerSubtitle ? measureTruncatedLines : NEVER}\n fill\n describesTrigger={false}\n >\n {trigger}\n </Tooltip>\n ) : (\n trigger\n );\n },\n);\nDropdownTrigger.displayName = 'DropdownTrigger';\n\ninterface DropdownItemComponentProps {\n item: DropdownItem;\n selected: boolean;\n showTooltipOnFocus: boolean;\n subtitleLayout: SubtitleLayout;\n onItemSelected: (item: DropdownItem) => void;\n}\n\nconst DropdownItemComponent = ({\n item,\n selected,\n showTooltipOnFocus,\n subtitleLayout,\n onItemSelected,\n}: DropdownItemComponentProps) => {\n const textColor = selected\n ? 'var(--malachite-accent-foreground, rgb(2, 122, 66))'\n : 'var(--malachite-text-primary, rgb(10, 10, 10))';\n const stacked = subtitleLayout === 'stacked' && !!item.subtitle;\n const optionId = `mal-${useId().replace(/[^a-zA-Z0-9_-]/g, '')}`;\n const optionLabelId = `${optionId}-label`;\n const optionSubtitleId = `${optionId}-subtitle`;\n const optionBadgeId = `${optionId}-badge`;\n const labelRef = useRef<HTMLSpanElement>(null);\n const subtitleRef = useRef<HTMLSpanElement>(null);\n const rightSideRef = useRef<HTMLSpanElement>(null);\n\n // Seeded all-cut: `Tooltip` skips `shouldShow` when its text is empty.\n const [cutLines, setCutLines] = useState({ label: true, subtitle: true, rightSide: true });\n const measureOptionLines = () => {\n const label = isCut(labelRef.current);\n const subtitle = isCut(subtitleRef.current);\n const rightSide = isCut(rightSideRef.current);\n if (!label && !subtitle && !rightSide) {\n return false;\n }\n setCutLines({ label, subtitle, rightSide });\n return true;\n };\n\n // Default to muted so right-side metadata (e.g. category tags) de-emphasises\n // against the primary item label. Consumers can opt back in with 'primary'.\n const rightSideTextColor =\n item.rightSideTextVariant === 'primary'\n ? 'var(--malachite-text-right-side-text-primary, rgb(10, 10, 10))'\n : 'var(--malachite-text-right-side-text-muted, rgb(123, 123, 123))';\n\n const rightSideJustify = item.rightSideTextAlignment === 'left' ? 'flex-start' : 'flex-end';\n\n const option = (\n // `role=\"option\"` would be invalid — nothing here declares a `listbox`, and an\n // orphaned option is dropped from the a11y tree. `aria-current`, not\n // `aria-pressed`: these are one-of-many choices, not toggles. tabIndex={-1}\n // because the portaled panel is outside the trigger's tab order; DropdownPanel\n // focuses an option on open and arrow keys move between them.\n <button\n type=\"button\"\n data-dropdown-option=\"\"\n data-selected={selected}\n aria-current={selected || undefined}\n // Unnamed, the option takes its name from everything inside it — a sentence-length\n // subtitle or a badge included.\n aria-labelledby={item.subtitle || hasBadge(item.badge) ? optionLabelId : undefined}\n // The id sits on the light-DOM wrapper: one inside the badge's shadow root is unreachable.\n aria-describedby={\n [\n item.subtitle ? optionSubtitleId : undefined,\n hasBadge(item.badge) ? optionBadgeId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n tabIndex={-1}\n onClick={(e) => {\n e.stopPropagation();\n onItemSelected(item);\n }}\n className=\"malachite-dropdown-option\"\n style={{\n minHeight: 38,\n borderRadius: 8,\n display: 'flex',\n alignItems: 'center',\n padding: 10,\n gap: 12,\n cursor: 'pointer',\n transition: 'background-color 120ms ease',\n // Reset the UA button chrome. Background is deliberately absent — see PANEL_RULES.\n width: '100%',\n border: 'none',\n textAlign: 'left',\n font: 'inherit',\n color: 'inherit',\n }}\n >\n {/* Spans: <button> takes phrasing content only. */}\n <span\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n minWidth: 0,\n }}\n >\n <span style={{ flex: '1 1 auto', display: 'block', minWidth: 0 }}>\n <span\n style={\n stacked\n ? { display: 'flex', flexDirection: 'column', gap: 2 }\n : { display: 'flex', alignItems: 'center', gap: 8 }\n }\n >\n <LabelRow row={stacked && !!item.icon}>\n {item.icon && (\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n {item.icon}\n </span>\n )}\n <span\n id={\n item.subtitle || hasBadge(item.badge)\n ? optionLabelId\n : undefined\n }\n ref={labelRef}\n style={{\n fontWeight: 400,\n color: textColor,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n }}\n >\n {item.label}\n </span>\n </LabelRow>\n {item.subtitle &&\n (stacked ? (\n <span\n id={optionSubtitleId}\n ref={subtitleRef}\n style={{\n fontSize: ANNOTATION_FONT_SIZE,\n fontWeight: 400,\n lineHeight: 1.4,\n color: selected\n ? textColor\n : 'var(--malachite-text-dimmed, rgb(161, 161, 161))',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n <ItemSubtitle text={item.subtitle} />\n </span>\n ) : (\n <span\n style={{\n // Zero basis: the subtitle gives way before the label.\n flexGrow: 1,\n flexBasis: 0,\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n minWidth: 0,\n overflow: 'hidden',\n }}\n >\n <span\n style={{\n fontSize: ANNOTATION_FONT_SIZE,\n fontWeight: 400,\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n flexShrink: 0,\n }}\n >\n |\n </span>\n <span\n id={optionSubtitleId}\n ref={subtitleRef}\n style={{\n fontSize: ANNOTATION_FONT_SIZE,\n fontWeight: 400,\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n }}\n >\n <ItemSubtitle text={item.subtitle} />\n </span>\n </span>\n ))}\n </span>\n </span>\n <span\n style={{\n // Reserved only when there is something to put there: an empty slot\n // still holding its width truncates the label and subtitle early.\n minWidth: item.rightSideText\n ? 'var(--malachite-text-right-side-text-min-width, 80px)'\n : 0,\n flexShrink: 1,\n display: 'flex',\n justifyContent: rightSideJustify,\n }}\n >\n {item.rightSideText && (\n <span\n ref={rightSideRef}\n style={{\n fontSize: 'var(--malachite-text-right-side-text-font-size, 12px)',\n fontWeight: 400,\n color: rightSideTextColor,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n }}\n >\n {item.rightSideText}\n </span>\n )}\n </span>\n {hasBadge(item.badge) && (\n <span id={optionBadgeId} style={{ flexShrink: 0, display: 'flex' }}>\n <React.Suspense fallback={null}>\n <BadgeHost>{item.badge}</BadgeHost>\n </React.Suspense>\n </span>\n )}\n </span>\n </button>\n );\n\n // Focus lands on the option itself, and focusin does not reach a descendant, so a keyboard\n // user could never open a tooltip mounted inside it.\n return (\n <Tooltip\n text={tooltipLines([\n ['label', cutLines.label && item.label],\n [\n 'subtitle',\n cutLines.subtitle && item.subtitle && <ItemSubtitle text={item.subtitle} />,\n ],\n ['rightSide', cutLines.rightSide && item.rightSideText],\n ])}\n shouldShow={measureOptionLines}\n showOnFocus={showTooltipOnFocus}\n isShrinkable\n describesTrigger={false}\n >\n {option}\n </Tooltip>\n );\n};\n\ninterface DropdownPanelProps {\n items: DropdownItem[];\n onItemSelected: (item?: DropdownItem) => void;\n selectedItem: DropdownItem | undefined;\n menuLoading?: boolean;\n emptyMessage: string;\n /** Focus an option on open. False in search mode, where the input keeps focus. */\n autoFocus: boolean;\n /** Panel has been measured. It renders `visibility: hidden` until then, and a\n * hidden element cannot take focus, so open-time focus has to wait for this. */\n positioned: boolean;\n /** Close the panel and hand focus back to the trigger. */\n onDismiss: () => void;\n keyboardNavigation: boolean;\n onKeyboardNavigation: () => void;\n subtitleLayout: SubtitleLayout;\n size: DropdownSize;\n}\n\nconst DropdownPanel = React.forwardRef<\n HTMLDivElement,\n DropdownPanelProps & { style?: React.CSSProperties }\n>((props, ref) => {\n const {\n items,\n onItemSelected,\n selectedItem,\n menuLoading,\n emptyMessage,\n autoFocus,\n positioned,\n onDismiss,\n keyboardNavigation,\n onKeyboardNavigation,\n subtitleLayout,\n size,\n style,\n } = props;\n const panelRef = useRef<HTMLDivElement | null>(null);\n const popupIdentity = usePopupLayer('dropdown', true, panelRef);\n\n // The panel only mounts while open, so no condition. useInsertionEffect, not layout:\n // it runs before the DOM mutation, so the rules are in place before the rows are inserted.\n useInsertionEffect(() => {\n ensureDropdownPanelStyles();\n }, []);\n\n useTopLayer(panelRef, true);\n\n // Start on the selected option so Enter re-confirms the current value. Not keyed on\n // `items`: re-running as the filtered list changes would yank focus back to the top.\n useEffect(() => {\n if (!autoFocus || !positioned) {\n return;\n }\n const options = panelOptions(panelRef.current);\n const selected = options.find((option) => option.dataset.selected === 'true');\n // Falls back to the panel: with no options nothing else can hold focus, and Tab-dismiss\n // only fires from inside it.\n (selected ?? options[0] ?? panelRef.current)?.focus();\n }, [autoFocus, positioned]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {\n // The panel is portaled to document.body, so the browser's next tab stop bears no\n // relation to the trigger. Dismissing restores trigger focus so Tab resumes there.\n if (event.key === 'Tab') {\n onDismiss();\n return;\n }\n const options = panelOptions(panelRef.current);\n if (options.length === 0) {\n return;\n }\n const current = options.indexOf(document.activeElement as HTMLElement);\n const target = {\n ArrowDown: current + 1,\n ArrowUp: current - 1,\n Home: 0,\n End: options.length - 1,\n }[event.key];\n if (target === undefined) {\n return;\n }\n event.preventDefault();\n onKeyboardNavigation();\n options[Math.min(Math.max(target, 0), options.length - 1)]?.focus();\n };\n\n // Inline styles, not Tailwind: this portals into document.body, outside the\n // Shadow DOM the malachite stylesheet is adopted into.\n return (\n <div\n ref={(node) => {\n panelRef.current = node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n }}\n {...popupIdentity}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n style={{\n background: MENU_SPECS.standard.background,\n border: MENU_SPECS.standard.border,\n borderRadius: MENU_SPECS.standard.radius,\n boxShadow: MENU_SPECS.standard.shadow,\n maxHeight: MENU_MAX_HEIGHT_PX,\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n fontSize: CONTROL_TEXT_SIZE[size],\n ...style,\n }}\n >\n {menuLoading ? (\n <div style={PANEL_MESSAGE_STYLE}>\n <Spinner size=\"xxxsmall\" />\n <span>Loading…</span>\n </div>\n ) : items.length === 0 ? (\n <div style={PANEL_MESSAGE_STYLE}>{emptyMessage}</div>\n ) : (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n padding: MENU_SPECS.standard.padding,\n overflowY: 'auto',\n scrollbarWidth: 'thin',\n scrollbarColor:\n 'var(--malachite-text-placeholder, rgb(187, 187, 187)) transparent',\n }}\n >\n {items.map((item, index) => {\n const prev = items[index - 1];\n const showGroupHeader =\n !!item.group && (!prev || prev.group !== item.group);\n return (\n <div key={item.id} style={{ flexShrink: 0 }}>\n {showGroupHeader && (\n <div\n style={{\n padding: '6px 10px 4px',\n fontSize: 12,\n fontWeight: 500,\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n textTransform: 'none',\n userSelect: 'none',\n }}\n >\n {item.group}\n </div>\n )}\n <DropdownItemComponent\n item={item}\n onItemSelected={onItemSelected}\n subtitleLayout={subtitleLayout}\n selected={item.id === selectedItem?.id || false}\n showTooltipOnFocus={keyboardNavigation}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n});\nDropdownPanel.displayName = 'DropdownPanel';\n\nexport const Dropdown = ({\n items,\n onItemSelected,\n defaultValue,\n value,\n disabled = false,\n error,\n tone,\n label,\n hint,\n rightSideContent,\n tooltip,\n name,\n required = false,\n requiredIndicator,\n loading,\n menuLoading,\n formControl,\n description,\n helperText,\n placeholder,\n search = false,\n showSubtitleInTrigger = false,\n subtitleLayout = 'inline',\n clearable = false,\n size = 'large',\n fullWidth = false,\n width,\n minWidth,\n menuAlign = 'start',\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n}: DropdownProps) => {\n const { controlId, labelId, descriptionId, hintId, helperTextId } = useFormFieldIds({\n id,\n label,\n description,\n hint,\n helperText: true,\n });\n const [isOpen, setIsOpen] = useState(false);\n // The id, never the resolved item: a cached object goes stale when `items` is rebuilt.\n const [ownValue, setOwnValue] = useState(defaultValue);\n const selectedId = value ?? ownValue;\n const selectedItem = items.find((item) => item.id === selectedId);\n const showClear = clearable && selectedId !== undefined && selectedId !== '' && !disabled;\n const triggerIsStacked = showSubtitleInTrigger && !search && !!selectedItem?.subtitle;\n const clearLabel = `Clear ${label ?? placeholder ?? 'selection'}`;\n\n // `defaultValue` only seeds the state, so a later change has to be pushed in.\n const lastDefaultValueRef = useRef(defaultValue);\n useEffect(() => {\n if (lastDefaultValueRef.current === defaultValue) {\n return;\n }\n lastDefaultValueRef.current = defaultValue;\n setOwnValue(defaultValue);\n }, [defaultValue]);\n const [searchQuery, setSearchQuery] = useState('');\n // Search mode only: set when the panel is opened by ArrowDown, so focus follows the\n // user into the list on mount instead of staying in the input.\n const [focusPanelOnOpen, setFocusPanelOnOpen] = useState(false);\n const [keyboardNavigation, setKeyboardNavigation] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const [panelPosition, setPanelPosition] = useState<MenuGeometry | null>(null);\n\n const reopenOnFocusRef = useRef(true);\n\n // In search mode the trigger is a wrapper div; the focusable part is the input.\n const focusTrigger = useCallback(() => {\n const trigger = triggerRef.current;\n const target =\n trigger instanceof HTMLButtonElement\n ? trigger\n : (trigger?.querySelector<HTMLElement>('input') ?? null);\n // A `.focus()` that fires no focus event — an already-focused element, or one that never\n // lands (disabled, hidden, unfocused window) — leaves the latch to eat the next real focus.\n if (!target || target === getDeepActiveElement()) {\n return;\n }\n if (!search) {\n target.focus();\n return;\n }\n reopenOnFocusRef.current = false;\n target.focus();\n if (getDeepActiveElement() !== target) {\n reopenOnFocusRef.current = true;\n }\n }, [search]);\n\n const handleClear = useCallback(\n (event: React.MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n setOwnValue(undefined);\n // The resolver is told the empty this form started the field at; the public\n // callback keeps reporting `undefined` whatever shape that is.\n reportSelectionRef.current?.(reportEmptyRef.current);\n onItemSelected?.(undefined);\n focusTrigger();\n },\n [onItemSelected, focusTrigger],\n );\n\n const updatePanelPosition = useCallback(() => {\n const trigger = triggerRef.current;\n if (!trigger) return;\n\n setPanelPosition(\n measureMenuGeometry(panelRef.current, {\n triggerRect: trigger.getBoundingClientRect(),\n preset: 'standard',\n minWidth,\n align: menuAlign === 'end' ? 'right' : 'left',\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n }),\n );\n }, [minWidth, menuAlign]);\n\n useEffect(() => {\n if (!isOpen) {\n setPanelPosition(null);\n setFocusPanelOnOpen(false);\n return;\n }\n updatePanelPosition();\n const handleClickOutside = (event: MouseEvent) => {\n const path = event.composedPath();\n const trigger = dropdownRef.current;\n const panel = panelRef.current;\n const inTrigger = !!trigger && path.includes(trigger);\n const inPanel = !!panel && path.includes(panel);\n if (!inTrigger && !inPanel) {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n if (panelRef.current?.contains(getDeepActiveElement())) {\n focusTrigger();\n }\n // Closing unmounts the option holding focus, so no focusout reaches the wrapper\n // below; when the trigger holds it one does, and reporting here too validates twice.\n if (!dropdownRef.current?.contains(getDeepActiveElement())) {\n reportBlurRef.current?.();\n }\n }\n };\n // ESC via the shared layer stack: closes only the topmost overlay. Focus is\n // restored explicitly — unmounting the option it sits on would drop it to <body>.\n const popEscapeLayer = pushEscapeLayer(() => {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n focusTrigger();\n });\n const handleScrollOrResize = () => updatePanelPosition();\n\n // `scroll` is not composed: a window listener never hears a scroller inside a\n // consumer's shadow root, so the trigger's rect is tracked instead.\n let frame = 0;\n let lastRect = '';\n const followTrigger = () => {\n const trigger = triggerRef.current;\n if (trigger) {\n const rect = trigger.getBoundingClientRect();\n\n if (isTriggerOffscreen(rect, window.innerWidth, window.innerHeight)) {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n return;\n }\n\n const signature = rectSignature(rect);\n if (signature !== lastRect) {\n lastRect = signature;\n updatePanelPosition();\n }\n }\n frame = requestAnimationFrame(followTrigger);\n };\n frame = requestAnimationFrame(followTrigger);\n\n document.addEventListener('mousedown', handleClickOutside);\n window.addEventListener('scroll', handleScrollOrResize, true);\n window.addEventListener('resize', handleScrollOrResize);\n return () => {\n cancelAnimationFrame(frame);\n document.removeEventListener('mousedown', handleClickOutside);\n popEscapeLayer();\n window.removeEventListener('scroll', handleScrollOrResize, true);\n window.removeEventListener('resize', handleScrollOrResize);\n };\n }, [isOpen, search, updatePanelPosition, focusTrigger]);\n\n useLayoutEffect(() => {\n if (!isOpen) {\n return;\n }\n updatePanelPosition();\n\n const panel = panelRef.current;\n if (!panel || typeof ResizeObserver === 'undefined') {\n return;\n }\n const observer = new ResizeObserver(() => updatePanelPosition());\n observer.observe(panel);\n return () => observer.disconnect();\n }, [isOpen, updatePanelPosition]);\n\n const reportSelectionRef = useRef<((value: unknown) => void) | undefined>(undefined);\n const reportBlurRef = useRef<(() => void) | undefined>(undefined);\n const reportEmptyRef = useRef<unknown>('');\n\n const handleItemSelected = (item?: DropdownItem) => {\n setOwnValue(item?.id);\n reportSelectionRef.current?.(item?.id ?? reportEmptyRef.current);\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n onItemSelected?.(item?.id);\n focusTrigger();\n };\n\n const dismissPanel = () => {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n focusTrigger();\n };\n\n // ArrowDown is the \"take me into the list\" gesture. When it also opens the panel the\n // intent carries over to the mount, so it doesn't cost a second press in search mode.\n const enterPanel = () => {\n setKeyboardNavigation(true);\n const first = panelOptions(panelRef.current)[0];\n if (first) {\n first.focus();\n return;\n }\n setFocusPanelOnOpen(true);\n setIsOpen(true);\n };\n\n const visibleItems =\n search && searchQuery ? items.filter((item) => matchesSearch(item, searchQuery)) : items;\n\n return (\n <BaseFormComponent\n fullWidth={fullWidth}\n label={label}\n hint={hint}\n rightSideContent={rightSideContent}\n tooltip={tooltip}\n name={name}\n required={required}\n requiredIndicator={requiredIndicator}\n loading={loading}\n formControl={formControl}\n description={description}\n controlId={controlId}\n labelId={labelId}\n descriptionId={descriptionId}\n hintId={hintId}\n loadingComponent={\n width === undefined ? (\n <LoadingInput\n heightClass={TRIGGER_SIZE_HEIGHT[size]}\n helperText={!!helperText}\n helperTextMarginTop\n />\n ) : (\n <div style={controlWidthStyle(width)}>\n <LoadingInput\n heightClass={TRIGGER_SIZE_HEIGHT[size]}\n helperText={!!helperText}\n helperTextMarginTop\n />\n </div>\n )\n }\n >\n {({ error: fieldError, message, onFieldChange, onFieldBlur, emptyValue }) => {\n reportSelectionRef.current = onFieldChange;\n reportBlurRef.current = onFieldBlur;\n reportEmptyRef.current = emptyValue;\n const isError = error ?? fieldError;\n // `error={false}` opts out of the resolver entirely, message included: a screen\n // that has dealt with the rejection its own way would otherwise keep reporting it.\n // The message is its own line rather than a replacement for the helper text,\n // matching Input and TextArea: a field that explains what it wants still has to\n // say why what was chosen was rejected.\n const errorMessage = error === false ? undefined : message;\n const errorMessageId = `${helperTextId}-error`;\n const describedBy =\n [\n descriptionId,\n hintId,\n helperText ? helperTextId : undefined,\n errorMessage ? errorMessageId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <>\n <div\n ref={dropdownRef}\n className={`relative w-full`}\n style={controlWidthStyle(width)}\n // Only leaving the field altogether is a blur `mode: 'onBlur'` should\n // hear. The panel is portaled to the body, so containment has to be\n // asked of it separately — otherwise opening the menu reads as\n // leaving, and the form validates before anything has been chosen.\n onBlur={(event) => {\n const next = event.relatedTarget as Node | null;\n const staysInField =\n event.currentTarget.contains(next) ||\n panelRef.current?.contains(next) === true;\n\n if (!staysInField) {\n reportBlurRef.current?.();\n }\n }}\n >\n {showClear && !search && (\n <button\n type=\"button\"\n onClick={handleClear}\n aria-label={clearLabel}\n className={`absolute ${\n triggerIsStacked\n ? CLEAR_STACKED_TOP_CLASSES[size]\n : 'top-1/2 -translate-y-1/2'\n } z-10 flex items-center\n justify-center rounded-full text-[var(--malachite-text-placeholder)]\n hover:text-[var(--malachite-text-primary)] transition-colors\n focus-visible:[outline:2px_solid_var(--malachite-text-primary)] focus-visible:outline-offset-2 ${CLEAR_OFFSET_CLASSES[size]}`}\n >\n <CloseIcon size={13} />\n </button>\n )}\n <DropdownTrigger\n hasClear={showClear}\n onClear={handleClear}\n clearLabel={clearLabel}\n ref={triggerRef as React.Ref<HTMLElement>}\n isOpen={isOpen}\n onClick={(fromKeyboard) => {\n if (disabled) {\n return;\n }\n setKeyboardNavigation(!!fromKeyboard);\n setIsOpen(!isOpen);\n }}\n selectedItem={selectedItem}\n disabled={disabled}\n error={isError}\n tone={tone}\n placeholder={placeholder}\n search={search}\n showSubtitleInTrigger={showSubtitleInTrigger}\n searchQuery={searchQuery}\n onSearchChange={setSearchQuery}\n onFocusOpen={() => {\n if (!reopenOnFocusRef.current) {\n reopenOnFocusRef.current = true;\n return;\n }\n setIsOpen(true);\n }}\n onArrowDown={() => {\n if (!disabled) {\n enterPanel();\n }\n }}\n onTabAway={() => {\n if (isOpen) {\n dismissPanel();\n }\n }}\n size={size}\n controlId={controlId}\n hasCallerId={!!id}\n labelId={labelId}\n describedBy={describedBy}\n required={required}\n ariaLabel={ariaLabel}\n ariaLabelledBy={ariaLabelledBy}\n />\n {isOpen &&\n createPortal(\n <DropdownPanel\n ref={panelRef}\n style={{\n position: 'fixed',\n top: panelPosition?.top ?? 0,\n left: panelPosition?.left ?? 0,\n width: panelPosition?.width,\n maxHeight: panelPosition?.maxHeight,\n visibility: panelPosition ? 'visible' : 'hidden',\n opacity: panelPosition ? 1 : 0,\n }}\n items={visibleItems}\n onItemSelected={handleItemSelected}\n selectedItem={selectedItem}\n menuLoading={menuLoading}\n emptyMessage={\n items.length === 0\n ? 'No options available'\n : 'No results found'\n }\n subtitleLayout={subtitleLayout}\n size={size}\n autoFocus={!search || focusPanelOnOpen}\n positioned={panelPosition !== null}\n onDismiss={dismissPanel}\n keyboardNavigation={keyboardNavigation}\n onKeyboardNavigation={() => setKeyboardNavigation(true)}\n />,\n document.body,\n )}\n </div>\n {helperText && (\n <div\n id={helperTextId}\n className=\"mt-1 text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-text-dimmed,rgb(161,161,161))]\"\n >\n {helperText}\n </div>\n )}\n <FieldMessage id={errorMessageId} message={errorMessage} spaced />\n </>\n );\n }}\n </BaseFormComponent>\n );\n};\n\nexport default Dropdown;\n"],"names":["BadgeHost","React","TriggerTag","id","text","disabled","jsx","Tag","INLINE_MARKDOWN_SYNTAX","ItemSubtitle","MarkdownBlock","PANEL_MESSAGE_STYLE","ANNOTATION_FONT_SIZE","OPTION_SELECTOR","panelOptions","panel","subtitleSearchText","subtitle","inlineMarkdownText","matchesSearch","item","query","q","labelMatches","subtitleMatches","rightSideTextMatches","TRIGGER_SIZE_HEIGHT","TRIGGER_SIZE_CLASSES","CONTROL_TEXT_SIZE_CLASS","TRIGGER_SIZE_STACKED_CLASSES","CLEAR_OFFSET_CLASSES","CLEAR_STACKED_TOP_CLASSES","TRIGGER_SIZE_RADIUS","NEVER","ValueRow","wrap","children","Fragment","LabelRow","row","DropdownTrigger","isOpen","onClick","selectedItem","error","tone","placeholder","search","showSubtitleInTrigger","searchQuery","onSearchChange","onFocusOpen","onArrowDown","onTabAway","size","hasClear","onClear","clearLabel","controlId","labelId","describedBy","required","ariaLabel","ariaLabelledBy","hasCallerId","forwardedRef","stacked","sizeClasses","sizeRadius","valueId","subtitleId","tagId","rendersButton","hasTag","showsSearchTag","valueIds","namesItself","labelledBy","tagOutsideName","handleTriggerKeyDown","event","valueTextRef","useRef","subtitleTextRef","triggerVisual","getTriggerVisual","showValueLabel","valueText","triggerSubtitle","isValueTruncated","isCut","cutLines","setCutLines","useState","measureTruncatedLines","value","jsxs","DROPDOWN_TRIGGER_ATTR","e","Tooltip","CloseIcon","CaretDownIcon","trigger","FOCUS_RING","tooltipLines","DropdownItemComponent","selected","showTooltipOnFocus","subtitleLayout","onItemSelected","textColor","optionId","useId","optionLabelId","optionSubtitleId","optionBadgeId","labelRef","subtitleRef","rightSideRef","measureOptionLines","label","rightSide","rightSideTextColor","rightSideJustify","option","hasBadge","DropdownPanel","props","ref","items","menuLoading","emptyMessage","autoFocus","positioned","onDismiss","keyboardNavigation","onKeyboardNavigation","style","panelRef","popupIdentity","usePopupLayer","useInsertionEffect","ensureDropdownPanelStyles","useTopLayer","useEffect","options","_a","node","current","target","MENU_SPECS","MENU_MAX_HEIGHT_PX","CONTROL_TEXT_SIZE","Spinner","index","prev","showGroupHeader","Dropdown","defaultValue","hint","rightSideContent","tooltip","name","requiredIndicator","loading","formControl","description","helperText","clearable","fullWidth","width","minWidth","menuAlign","descriptionId","hintId","helperTextId","useFormFieldIds","setIsOpen","ownValue","setOwnValue","selectedId","showClear","triggerIsStacked","lastDefaultValueRef","setSearchQuery","focusPanelOnOpen","setFocusPanelOnOpen","setKeyboardNavigation","dropdownRef","triggerRef","panelPosition","setPanelPosition","reopenOnFocusRef","focusTrigger","useCallback","getDeepActiveElement","handleClear","reportSelectionRef","reportEmptyRef","updatePanelPosition","measureMenuGeometry","handleClickOutside","path","inTrigger","inPanel","_b","_c","reportBlurRef","popEscapeLayer","pushEscapeLayer","handleScrollOrResize","frame","lastRect","followTrigger","rect","isTriggerOffscreen","signature","rectSignature","useLayoutEffect","observer","handleItemSelected","dismissPanel","enterPanel","first","visibleItems","BaseFormComponent","LoadingInput","controlWidthStyle","fieldError","message","onFieldChange","onFieldBlur","emptyValue","isError","errorMessage","errorMessageId","next","fromKeyboard","createPortal","FieldMessage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sources":["../../src/components/Dropdown.tsx"],"sourcesContent":["import React, {\n useId,\n useState,\n useRef,\n useEffect,\n useInsertionEffect,\n useLayoutEffect,\n useCallback,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { Control, FieldPath, FieldValues } from 'react-hook-form';\nimport BaseFormComponent, {\n type RequiredIndicator,\n type RightSideContent,\n useFormFieldIds,\n} from './BaseFormComponent';\nimport CaretDownIcon from './CustomIcons/CaretDownIcon';\nimport CloseIcon from './CustomIcons/CloseIcon';\nimport FieldMessage from './FieldMessage';\nimport LoadingInput from './LoadingInput';\nimport Spinner from './Spinner';\nimport Tag from './Tag';\nimport Tooltip from './Tooltip';\nimport MarkdownBlock from './Typography/MarkdownBlock';\nimport { inlineMarkdownText } from './Typography/inlineMarkdown';\nimport { getDeepActiveElement } from './activeElement';\nimport { CONTROL_TEXT_SIZE, CONTROL_TEXT_SIZE_CLASS } from './controlTextSize';\nimport { controlWidthStyle } from './controlWidth';\nimport { DROPDOWN_TRIGGER_ATTR, type DropdownTone, getTriggerVisual } from './dropdownTriggerStyle';\nimport { pushEscapeLayer } from './escapeLayers';\nimport {\n MENU_MAX_HEIGHT_PX,\n MENU_SPECS,\n type MenuGeometry,\n isTriggerOffscreen,\n measureMenuGeometry,\n rectSignature,\n} from './floatingMenuGeometry';\nimport { FOCUS_RING } from './focusRing';\nimport { hasBadge } from './hasBadge';\nimport { ensureDropdownPanelStyles } from './optionRowStyles';\nimport { usePopupLayer } from './overlayLayers';\nimport { useTopLayer } from './topLayer';\nimport { isCut, tooltipLines } from './truncatedLines';\n\n// The menu portals into document.body, outside any shadow root, so a Tailwind-styled badge (a Tag)\n// needs a shadow host of its own; loaded only when a badge is passed.\nconst BadgeHost = React.lazy(() => import('./ActionMenuTagHost'));\n\nconst TriggerTag = ({ id, text, disabled }: { id: string; text: string; disabled?: boolean }) => (\n <span\n id={id}\n className={`flex min-w-0 max-w-[40%] [flex-shrink:3] ${disabled ? 'opacity-60' : ''}`}\n >\n <Tag value={text} paddingSize=\"compact\" fontSize=\"xsmall\" textTransform=\"none\" />\n </span>\n);\n\nexport type { DropdownTone };\n\nexport interface DropdownItem {\n id: string;\n label: string;\n icon?: React.ReactNode;\n /** Alternate label shown in the closed trigger when selected (falls back to `label`). */\n triggerLabel?: string;\n /** Short tag shown at the right of the closed trigger while this item is selected. */\n triggerTag?: string;\n /** Items sharing a `group` render under a section header, in first-seen order. */\n group?: string;\n subtitle?: string;\n rightSideText?: string;\n rightSideTextVariant?: 'muted' | 'primary';\n rightSideTextAlignment?: 'left' | 'right';\n /** Badge shown in the open menu only (not in the trigger or the search input). */\n badge?: React.ReactNode;\n /** Where the badge sits: the option's right end (default), or right after its label. */\n badgePlacement?: 'end' | 'label';\n}\n\ninterface DropdownBaseProps {\n label?: string;\n hint?: string;\n rightSideContent?: RightSideContent;\n tooltip?: string;\n name: FieldPath<FieldValues> | string;\n loading?: boolean;\n menuLoading?: boolean;\n items: DropdownItem[];\n onItemSelected?: (id?: string) => void;\n defaultValue?: string;\n /** Controlled selection. When set, the trigger always reflects this id and the component\n * keeps no selection state of its own. Pass it with `onItemSelected`. */\n value?: string;\n disabled?: boolean;\n error?: boolean;\n /** `pending` marks a value the user still has to supply. Outranks open and selection. */\n tone?: DropdownTone;\n className?: string;\n formControl?: Control<FieldValues, unknown>;\n description?: string;\n required?: boolean;\n requiredIndicator?: RequiredIndicator;\n helperText?: React.ReactNode;\n placeholder?: string;\n subtitleLayout?: SubtitleLayout;\n /** Adds a clear control to the trigger, reported as `onItemSelected(undefined)`. */\n clearable?: boolean;\n /** 'large' (42px) for form inputs; 'medium' (32px) for toolbar chips; 'small' (28px) beside a title. */\n size?: DropdownSize;\n fullWidth?: boolean;\n width?: string | number;\n /**\n * Raises the open menu's floor above the shared 160px one, without widening the trigger.\n * For a control pinned narrow by its column — a role picker in a 160px cell, a member\n * picker in a 200px slot — whose options carry a subtitle the trigger never has to show.\n */\n minWidth?: number;\n /**\n * Which trigger edge a menu wider than its trigger lines up with. `end` grows it leftwards,\n * for a control at the right of its container. Either flips when the viewport has no room.\n */\n menuAlign?: 'start' | 'end';\n /** Names the trigger from the light DOM, where `htmlFor` cannot reach into the shadow root. */\n id?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n/**\n * The search trigger is a single-line text input with nowhere for a second line, so\n * `showSubtitleInTrigger` is rejected alongside `search` rather than silently ignored.\n */\ntype DropdownTriggerModeProps =\n | {\n search?: false;\n /** Promotes the selected item's `subtitle` into the closed trigger, beneath the value. */\n showSubtitleInTrigger?: boolean;\n }\n | { search: true; showSubtitleInTrigger?: never };\n\nexport type DropdownProps = DropdownBaseProps & DropdownTriggerModeProps;\n\n/**\n * Matches Button and the Figma component library: 28 / 32 / 42px. These names moved up a\n * tier in 0.71 — what was `xsmall`/`small`/`medium` is now `small`/`medium`/`large`.\n */\nexport type DropdownSize = 'small' | 'medium' | 'large';\n\nexport type SubtitleLayout = 'inline' | 'stacked';\n\n// Text without these renders the same parsed or not, so it skips the parser.\nconst INLINE_MARKDOWN_SYNTAX = /[*`[<&\\\\]/;\n\n// Inert links: a <button> takes no interactive content.\nconst ItemSubtitle = ({ text }: { text: string }) =>\n INLINE_MARKDOWN_SYNTAX.test(text) ? (\n <MarkdownBlock\n text={text}\n variant=\"inline\"\n color=\"inherit\"\n size=\"inherit\"\n links=\"inert\"\n omitMargin\n />\n ) : (\n text\n );\n\nconst PANEL_MESSAGE_STYLE: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: '24px 16px',\n color: 'var(--malachite-text-dimmed, rgb(161, 161, 161))',\n};\n\n// Figma pins the option's inline annotation at 11px on every tier — unlike the label,\n// it does not ride the ladder (Item Large 68:2617, Item Medium 2343:2134).\nconst ANNOTATION_FONT_SIZE = 'var(--malachite-font-size-xsmall, 11px)';\n\nconst OPTION_SELECTOR = '[data-dropdown-option]';\n\nconst panelOptions = (panel: HTMLElement | null): HTMLElement[] =>\n Array.from(panel?.querySelectorAll<HTMLElement>(OPTION_SELECTOR) ?? []);\n\n// Search what the subtitle shows: link and image text, not their destinations or markers.\nconst subtitleSearchText = (subtitle: string) =>\n INLINE_MARKDOWN_SYNTAX.test(subtitle)\n ? inlineMarkdownText(subtitle)\n : subtitle.replace(/\\s+/g, ' ');\n\nconst matchesSearch = (item: DropdownItem, query: string) => {\n const q = query.toLowerCase();\n const labelMatches = item.label.toLowerCase().includes(q);\n const subtitleMatches = item.subtitle\n ? subtitleSearchText(item.subtitle).toLowerCase().includes(q)\n : false;\n const rightSideTextMatches = item.rightSideText\n ? item.rightSideText.toLowerCase().includes(q)\n : false;\n return labelMatches || subtitleMatches || rightSideTextMatches;\n};\n\nconst TRIGGER_SIZE_HEIGHT: Record<DropdownSize, string> = {\n small: 'h-[var(--malachite-control-height-small,28px)]',\n medium: 'h-[var(--malachite-control-height-medium,32px)]',\n large: 'h-[var(--malachite-control-height-large,42px)]',\n};\n\nconst TRIGGER_SIZE_CLASSES: Record<DropdownSize, string> = {\n small: `${TRIGGER_SIZE_HEIGHT.small} px-2.5 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.small}`,\n medium: `${TRIGGER_SIZE_HEIGHT.medium} px-3 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.medium}`,\n large: `${TRIGGER_SIZE_HEIGHT.large} px-4 py-2.5 ${CONTROL_TEXT_SIZE_CLASS.large}`,\n};\n\nconst TRIGGER_SIZE_STACKED_CLASSES: Record<DropdownSize, string> = {\n small: `min-h-[var(--malachite-control-height-small,28px)] px-2.5 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.small}`,\n medium: `min-h-[var(--malachite-control-height-medium,32px)] px-3 py-1.5 ${CONTROL_TEXT_SIZE_CLASS.medium}`,\n large: `min-h-[var(--malachite-control-height-large,42px)] px-4 py-2.5 ${CONTROL_TEXT_SIZE_CLASS.large}`,\n};\n\nconst CLEAR_OFFSET_CLASSES: Record<DropdownSize, string> = {\n small: 'right-[26px] size-4',\n medium: 'right-[30px] size-4',\n large: 'right-[38px] size-4',\n};\n\nconst CLEAR_STACKED_TOP_CLASSES: Record<DropdownSize, string> = {\n small: 'top-[calc(var(--malachite-control-height-small,28px)/2)] -translate-y-1/2',\n medium: 'top-[calc(var(--malachite-control-height-medium,32px)/2)] -translate-y-1/2',\n large: 'top-[calc(var(--malachite-control-height-large,42px)/2)] -translate-y-1/2',\n};\n\n// Radius tracks the tier in Figma: 10 / 12 / 14. Only 12 has a --malachite-radius-* rung.\nconst TRIGGER_SIZE_RADIUS: Record<DropdownSize, string> = {\n small: 'rounded-[var(--malachite-radius-10,10px)]',\n medium: 'rounded-xl',\n large: 'rounded-[var(--malachite-radius-xxl,14px)]',\n};\n\nconst NEVER = () => false;\n\nconst ValueRow: React.FC<{ wrap: boolean; id?: string; children: React.ReactNode }> = ({\n wrap,\n id,\n children,\n}) =>\n wrap ? (\n <span id={id} className=\"min-w-0 flex items-center gap-2\">\n {children}\n </span>\n ) : (\n <>{children}</>\n );\n\nconst LabelRow: React.FC<{ row: boolean; children: React.ReactNode }> = ({ row, children }) =>\n row ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>\n {children}\n </span>\n ) : (\n <>{children}</>\n );\n\ninterface DropdownTriggerProps {\n isOpen: boolean;\n onClick: (fromKeyboard?: boolean) => void;\n selectedItem: DropdownItem | undefined;\n hasClear?: boolean;\n onClear?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n clearLabel?: string;\n disabled?: boolean;\n error?: boolean;\n tone?: DropdownTone;\n placeholder?: string;\n search?: boolean;\n showSubtitleInTrigger?: boolean;\n searchQuery?: string;\n onSearchChange?: (value: string) => void;\n onFocusOpen?: () => void;\n /** ArrowDown on the trigger: opens the menu, or steps into it if already open. */\n onArrowDown?: () => void;\n /** Tab off the trigger: dismisses the panel, which is portaled and would outlive the focus. */\n onTabAway?: () => void;\n size?: DropdownSize;\n controlId: string;\n labelId?: string;\n describedBy?: string;\n required?: boolean;\n ariaLabel?: string;\n ariaLabelledBy?: string;\n /** A caller-supplied id means an external `<label for>` may be naming the control. */\n hasCallerId?: boolean;\n}\n\nconst DropdownTrigger = React.forwardRef<HTMLElement, DropdownTriggerProps>(\n (\n {\n isOpen,\n onClick,\n selectedItem,\n disabled = false,\n error = false,\n tone,\n placeholder,\n search = false,\n showSubtitleInTrigger = false,\n searchQuery = '',\n onSearchChange,\n onFocusOpen,\n onArrowDown,\n onTabAway,\n size = 'large',\n hasClear = false,\n onClear,\n clearLabel,\n controlId,\n labelId,\n describedBy,\n required = false,\n ariaLabel,\n ariaLabelledBy,\n hasCallerId = false,\n },\n forwardedRef,\n ) => {\n const stacked = showSubtitleInTrigger && !search && !!selectedItem?.subtitle;\n const sizeClasses = stacked\n ? TRIGGER_SIZE_STACKED_CLASSES[size]\n : TRIGGER_SIZE_CLASSES[size];\n const sizeRadius = TRIGGER_SIZE_RADIUS[size];\n const valueId = `${controlId}-value`;\n const subtitleId = `${controlId}-subtitle`;\n // aria-labelledby outranks aria-label in the accessible-name algorithm, so the\n // generated label+value pair has to be dropped for a caller's aria-label to apply.\n // Named off nothing, the button takes its name from every descendant — the subtitle\n // included, which `aria-describedby` then repeats. Naming it off the value alone fixes\n // that, but only where nothing else already names the control.\n const tagId = `${controlId}-tag`;\n const rendersButton = !search || disabled;\n const hasTag = rendersButton && !!selectedItem?.triggerTag;\n const showsSearchTag = !rendersButton && !isOpen && !!selectedItem?.triggerTag;\n const valueIds = hasTag ? `${valueId} ${tagId}` : valueId;\n const namesItself = !labelId && !ariaLabel && !hasCallerId && (stacked || hasTag);\n const labelledBy =\n ariaLabelledBy ??\n (labelId && !ariaLabel ? `${labelId} ${valueIds}` : undefined) ??\n (namesItself ? valueIds : undefined);\n const tagOutsideName = hasTag && !labelledBy?.split(' ').includes(tagId);\n\n const handleTriggerKeyDown = (event: React.KeyboardEvent): void => {\n // Not prevented: Tab carries on to the next control. In search mode the trigger keeps\n // focus on open, so this is the panel's only Tab dismissal.\n if (event.key === 'Tab') {\n onTabAway?.();\n return;\n }\n if (event.key !== 'ArrowDown') {\n return;\n }\n event.preventDefault();\n onArrowDown?.();\n };\n\n const valueTextRef = useRef<HTMLSpanElement>(null);\n const subtitleTextRef = useRef<HTMLSpanElement>(null);\n const triggerVisual = getTriggerVisual({ disabled, error, tone, open: isOpen });\n const showValueLabel = !isOpen && !!selectedItem;\n const valueText = selectedItem?.triggerLabel ?? selectedItem?.label;\n const triggerSubtitle = stacked ? selectedItem?.subtitle : undefined;\n const isValueTruncated = () => isCut(valueTextRef.current);\n\n // A tooltip reads its text at render, but which line is cut off is only knowable on\n // hover — so the one measurement pass that decides whether to show also records what\n // to say. The initial value never shows: untruncated, the tooltip refuses to open.\n const [cutLines, setCutLines] = useState({ value: false, subtitle: true });\n const measureTruncatedLines = () => {\n const value = isValueTruncated();\n const subtitle = isCut(subtitleTextRef.current);\n if (!value && !subtitle) {\n return false;\n }\n setCutLines({ value, subtitle });\n return true;\n };\n\n if (search && !disabled) {\n return (\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n className={`\n relative w-full ${sizeClasses} ${sizeRadius}\n border border-solid\n transition-all duration-200\n flex items-center\n `}\n style={triggerVisual}\n {...{ [DROPDOWN_TRIGGER_ATTR]: '' }}\n data-open={isOpen || undefined}\n onClick={(e) => e.stopPropagation()}\n >\n {selectedItem?.icon && (\n <span className=\"flex shrink-0 items-center justify-center pr-2\">\n {selectedItem.icon}\n </span>\n )}\n <Tooltip text={valueText} shouldShow={isValueTruncated} isShrinkable fill>\n <div className=\"relative flex-1 flex items-center min-w-0\">\n {showValueLabel && (\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-0 flex items-center pointer-events-none\"\n >\n <span\n ref={valueTextRef}\n className=\"min-w-0 block truncate text-[length:inherit]\n text-[var(--malachite-text-primary)]\"\n >\n {valueText}\n </span>\n </span>\n )}\n <input\n id={controlId}\n type=\"text\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-invalid={error || undefined}\n aria-required={required || undefined}\n aria-describedby={\n [describedBy, showsSearchTag ? tagId : undefined]\n .filter(Boolean)\n .join(' ') || undefined\n }\n value={isOpen ? searchQuery : (selectedItem?.label ?? '')}\n onChange={(e) => {\n e.stopPropagation();\n onSearchChange?.(e.target.value);\n if (!isOpen) {\n onClick();\n }\n }}\n onFocus={() => {\n onFocusOpen?.();\n }}\n onKeyDown={handleTriggerKeyDown}\n placeholder={placeholder ?? 'Select Field'}\n className={`flex-1 min-w-0 bg-transparent outline-none\n text-[length:inherit] font-normal\n placeholder:text-[var(--malachite-text-dimmed)] ${\n showValueLabel\n ? 'text-transparent'\n : 'text-[var(--malachite-text-primary)]'\n }`}\n />\n </div>\n </Tooltip>\n {showsSearchTag && selectedItem?.triggerTag && (\n <>\n <span aria-hidden=\"true\" className=\"w-2 shrink-0\" />\n <TriggerTag id={tagId} text={selectedItem.triggerTag} />\n </>\n )}\n {hasClear && (\n <button\n type=\"button\"\n aria-label={clearLabel}\n onClick={onClear}\n className=\"flex shrink-0 items-center justify-center pl-2 cursor-pointer\n bg-transparent border-none p-0 text-[var(--malachite-text-placeholder)]\n hover:text-[var(--malachite-text-primary)] transition-colors\n rounded-full focus-visible:[outline:2px_solid_var(--malachite-text-primary)] focus-visible:outline-offset-2\"\n >\n <CloseIcon size={13} />\n </button>\n )}\n <div className=\"flex items-center justify-center pl-2\">\n {/* Mouse-only affordance: the input beside it already opens the menu on\n click and focus, so this stays out of the tab order to avoid a\n duplicate stop — but it must still be a button, not a click-handling\n span, so it is exposed and activatable rather than invisible. */}\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={isOpen ? 'Close options' : 'Open options'}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n className=\"flex items-center justify-center cursor-pointer bg-transparent border-none p-0\"\n >\n <CaretDownIcon\n size={13}\n style={{\n color: isOpen\n ? 'var(--malachite-text-primary, rgb(10, 10, 10))'\n : 'var(--malachite-text-placeholder, rgb(187, 187, 187))',\n transition: 'transform 0.2s ease, color 0.2s ease',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n />\n </button>\n </div>\n </div>\n );\n }\n\n const trigger = (\n <button\n ref={forwardedRef as React.Ref<HTMLButtonElement>}\n id={controlId}\n type=\"button\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n aria-invalid={error || undefined}\n aria-required={required || undefined}\n aria-describedby={\n [\n describedBy,\n triggerSubtitle ? subtitleId : undefined,\n tagOutsideName ? tagId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n onClick={(e) => {\n e.stopPropagation();\n onClick(e.detail === 0);\n }}\n onKeyDown={handleTriggerKeyDown}\n disabled={disabled}\n style={triggerVisual}\n {...{ [DROPDOWN_TRIGGER_ATTR]: '' }}\n className={`\n relative w-full ${sizeClasses} ${sizeRadius}\n border border-solid\n transition-all duration-200\n flex ${stacked ? 'items-start' : 'items-center'} gap-3\n cursor-pointer\n disabled:cursor-not-allowed ${FOCUS_RING}\n `}\n >\n {/* Spans: <button> takes phrasing content only. */}\n <span\n id={triggerSubtitle ? undefined : valueId}\n className={`text-left ${hasTag ? 'flex-[1_1_auto]' : 'flex-1'} min-w-0 flex ${\n triggerSubtitle ? 'flex-col gap-1' : 'items-center gap-2'\n }`}\n >\n {selectedItem ? (\n <>\n <ValueRow wrap={!!triggerSubtitle} id={valueId}>\n {selectedItem.icon && (\n <span className=\"flex items-center justify-center shrink-0\">\n {selectedItem.icon}\n </span>\n )}\n <Tooltip\n text={valueText}\n shouldShow={triggerSubtitle ? NEVER : isValueTruncated}\n triggerAs=\"span\"\n isShrinkable\n >\n <span\n ref={valueTextRef}\n className={`min-w-0 block truncate text-[length:inherit] ${\n disabled\n ? 'text-[var(--malachite-text-placeholder)]'\n : 'text-[var(--malachite-text-primary)]'\n }`}\n >\n {valueText}\n </span>\n </Tooltip>\n </ValueRow>\n {triggerSubtitle && (\n <span\n id={subtitleId}\n ref={subtitleTextRef}\n className=\"min-w-0 block truncate text-[length:var(--malachite-font-size-xsmall,11px)] text-[var(--malachite-text-secondary,rgb(123,123,123))] leading-normal\"\n >\n <ItemSubtitle text={triggerSubtitle} />\n </span>\n )}\n </>\n ) : (\n <span\n className={`flex-1 min-w-0 truncate text-[length:inherit] ${\n disabled\n ? 'text-[var(--malachite-text-placeholder)]'\n : 'text-[var(--malachite-text-dimmed)]'\n }`}\n >\n {placeholder ?? 'Select Field'}\n </span>\n )}\n </span>\n {selectedItem?.triggerTag && (\n <TriggerTag id={tagId} text={selectedItem.triggerTag} disabled={disabled} />\n )}\n {hasClear && <span aria-hidden=\"true\" className=\"shrink-0 w-4\" />}\n <span className=\"flex items-center justify-center shrink-0\">\n <CaretDownIcon\n size={13}\n style={{\n color: isOpen\n ? 'var(--malachite-text-primary, rgb(10, 10, 10))'\n : 'var(--malachite-text-placeholder, rgb(187, 187, 187))',\n transition: 'transform 0.2s ease, color 0.2s ease',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n />\n </span>\n </button>\n );\n\n // The button is what takes focus, so the tooltip wraps it rather than a line inside:\n // mounted on a line it could only ever open with a pointer, and nested tooltips opened\n // together on hover. Its text is already in the trigger's name and description, so it\n // repeats it visually only. `fill`, not `isShrinkable`, whose `overflow: hidden` would\n // clip the error ring the button paints outside its border box.\n // Gated on the prop, not on there being a subtitle to show: keyed off the selection the\n // wrapper would appear on the first choice, remounting the button `focusTrigger` has\n // just handed focus back to and dropping the keyboard user at <body>.\n return showSubtitleInTrigger && !search ? (\n <Tooltip\n text={tooltipLines([\n ['value', cutLines.value && valueText],\n [\n 'subtitle',\n cutLines.subtitle && triggerSubtitle && (\n <ItemSubtitle text={triggerSubtitle} />\n ),\n ],\n ])}\n shouldShow={triggerSubtitle ? measureTruncatedLines : NEVER}\n fill\n describesTrigger={false}\n >\n {trigger}\n </Tooltip>\n ) : (\n trigger\n );\n },\n);\nDropdownTrigger.displayName = 'DropdownTrigger';\n\ninterface DropdownItemComponentProps {\n item: DropdownItem;\n selected: boolean;\n showTooltipOnFocus: boolean;\n subtitleLayout: SubtitleLayout;\n onItemSelected: (item: DropdownItem) => void;\n}\n\nconst DropdownItemComponent = ({\n item,\n selected,\n showTooltipOnFocus,\n subtitleLayout,\n onItemSelected,\n}: DropdownItemComponentProps) => {\n const textColor = selected\n ? 'var(--malachite-accent-foreground, rgb(2, 122, 66))'\n : 'var(--malachite-text-primary, rgb(10, 10, 10))';\n const stacked = subtitleLayout === 'stacked' && !!item.subtitle;\n const optionId = `mal-${useId().replace(/[^a-zA-Z0-9_-]/g, '')}`;\n const optionLabelId = `${optionId}-label`;\n const optionSubtitleId = `${optionId}-subtitle`;\n const optionBadgeId = `${optionId}-badge`;\n const badgeBesideLabel = item.badgePlacement === 'label';\n const badge = hasBadge(item.badge) ? (\n <span id={optionBadgeId} style={{ flexShrink: 0, display: 'flex' }}>\n <React.Suspense fallback={null}>\n <BadgeHost>{item.badge}</BadgeHost>\n </React.Suspense>\n </span>\n ) : null;\n const labelRef = useRef<HTMLSpanElement>(null);\n const subtitleRef = useRef<HTMLSpanElement>(null);\n const rightSideRef = useRef<HTMLSpanElement>(null);\n\n // Seeded all-cut: `Tooltip` skips `shouldShow` when its text is empty.\n const [cutLines, setCutLines] = useState({ label: true, subtitle: true, rightSide: true });\n const measureOptionLines = () => {\n const label = isCut(labelRef.current);\n const subtitle = isCut(subtitleRef.current);\n const rightSide = isCut(rightSideRef.current);\n if (!label && !subtitle && !rightSide) {\n return false;\n }\n setCutLines({ label, subtitle, rightSide });\n return true;\n };\n\n // Default to muted so right-side metadata (e.g. category tags) de-emphasises\n // against the primary item label. Consumers can opt back in with 'primary'.\n const rightSideTextColor =\n item.rightSideTextVariant === 'primary'\n ? 'var(--malachite-text-right-side-text-primary, rgb(10, 10, 10))'\n : 'var(--malachite-text-right-side-text-muted, rgb(123, 123, 123))';\n\n const rightSideJustify = item.rightSideTextAlignment === 'left' ? 'flex-start' : 'flex-end';\n\n const option = (\n // `role=\"option\"` would be invalid — nothing here declares a `listbox`, and an\n // orphaned option is dropped from the a11y tree. `aria-current`, not\n // `aria-pressed`: these are one-of-many choices, not toggles. tabIndex={-1}\n // because the portaled panel is outside the trigger's tab order; DropdownPanel\n // focuses an option on open and arrow keys move between them.\n <button\n type=\"button\"\n data-dropdown-option=\"\"\n data-selected={selected}\n aria-current={selected || undefined}\n // Unnamed, the option takes its name from everything inside it — a sentence-length\n // subtitle or a badge included.\n aria-labelledby={item.subtitle || hasBadge(item.badge) ? optionLabelId : undefined}\n // The id sits on the light-DOM wrapper: one inside the badge's shadow root is unreachable.\n aria-describedby={\n [\n item.subtitle ? optionSubtitleId : undefined,\n hasBadge(item.badge) ? optionBadgeId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n tabIndex={-1}\n onClick={(e) => {\n e.stopPropagation();\n onItemSelected(item);\n }}\n className=\"malachite-dropdown-option\"\n style={{\n minHeight: 38,\n borderRadius: 8,\n display: 'flex',\n alignItems: 'center',\n padding: 10,\n gap: 12,\n cursor: 'pointer',\n transition: 'background-color 120ms ease',\n // Reset the UA button chrome. Background is deliberately absent — see PANEL_RULES.\n width: '100%',\n border: 'none',\n textAlign: 'left',\n font: 'inherit',\n color: 'inherit',\n }}\n >\n {/* Spans: <button> takes phrasing content only. */}\n <span\n style={{\n flex: 1,\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n minWidth: 0,\n }}\n >\n <span style={{ flex: '1 1 auto', display: 'block', minWidth: 0 }}>\n <span\n style={\n stacked\n ? { display: 'flex', flexDirection: 'column', gap: 2 }\n : { display: 'flex', alignItems: 'center', gap: 8 }\n }\n >\n <LabelRow row={stacked && (!!item.icon || (badgeBesideLabel && !!badge))}>\n {item.icon && (\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n {item.icon}\n </span>\n )}\n <span\n id={\n item.subtitle || hasBadge(item.badge)\n ? optionLabelId\n : undefined\n }\n ref={labelRef}\n style={{\n fontWeight: 400,\n color: textColor,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n }}\n >\n {item.label}\n </span>\n {badgeBesideLabel && badge}\n </LabelRow>\n {item.subtitle &&\n (stacked ? (\n <span\n id={optionSubtitleId}\n ref={subtitleRef}\n style={{\n fontSize: ANNOTATION_FONT_SIZE,\n fontWeight: 400,\n lineHeight: 1.4,\n color: selected\n ? textColor\n : 'var(--malachite-text-dimmed, rgb(161, 161, 161))',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n <ItemSubtitle text={item.subtitle} />\n </span>\n ) : (\n <span\n style={{\n // Zero basis: the subtitle gives way before the label.\n flexGrow: 1,\n flexBasis: 0,\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n minWidth: 0,\n overflow: 'hidden',\n }}\n >\n <span\n style={{\n fontSize: ANNOTATION_FONT_SIZE,\n fontWeight: 400,\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n flexShrink: 0,\n }}\n >\n |\n </span>\n <span\n id={optionSubtitleId}\n ref={subtitleRef}\n style={{\n fontSize: ANNOTATION_FONT_SIZE,\n fontWeight: 400,\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n }}\n >\n <ItemSubtitle text={item.subtitle} />\n </span>\n </span>\n ))}\n </span>\n </span>\n <span\n style={{\n // Reserved only when there is something to put there: an empty slot\n // still holding its width truncates the label and subtitle early.\n minWidth: item.rightSideText\n ? 'var(--malachite-text-right-side-text-min-width, 80px)'\n : 0,\n flexShrink: 1,\n display: 'flex',\n justifyContent: rightSideJustify,\n }}\n >\n {item.rightSideText && (\n <span\n ref={rightSideRef}\n style={{\n fontSize: 'var(--malachite-text-right-side-text-font-size, 12px)',\n fontWeight: 400,\n color: rightSideTextColor,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n }}\n >\n {item.rightSideText}\n </span>\n )}\n </span>\n {!badgeBesideLabel && badge}\n </span>\n </button>\n );\n\n // Focus lands on the option itself, and focusin does not reach a descendant, so a keyboard\n // user could never open a tooltip mounted inside it.\n return (\n <Tooltip\n text={tooltipLines([\n ['label', cutLines.label && item.label],\n [\n 'subtitle',\n cutLines.subtitle && item.subtitle && <ItemSubtitle text={item.subtitle} />,\n ],\n ['rightSide', cutLines.rightSide && item.rightSideText],\n ])}\n shouldShow={measureOptionLines}\n showOnFocus={showTooltipOnFocus}\n isShrinkable\n describesTrigger={false}\n >\n {option}\n </Tooltip>\n );\n};\n\ninterface DropdownPanelProps {\n items: DropdownItem[];\n onItemSelected: (item?: DropdownItem) => void;\n selectedItem: DropdownItem | undefined;\n menuLoading?: boolean;\n emptyMessage: string;\n /** Focus an option on open. False in search mode, where the input keeps focus. */\n autoFocus: boolean;\n /** Panel has been measured. It renders `visibility: hidden` until then, and a\n * hidden element cannot take focus, so open-time focus has to wait for this. */\n positioned: boolean;\n /** Close the panel and hand focus back to the trigger. */\n onDismiss: () => void;\n keyboardNavigation: boolean;\n onKeyboardNavigation: () => void;\n subtitleLayout: SubtitleLayout;\n size: DropdownSize;\n}\n\nconst DropdownPanel = React.forwardRef<\n HTMLDivElement,\n DropdownPanelProps & { style?: React.CSSProperties }\n>((props, ref) => {\n const {\n items,\n onItemSelected,\n selectedItem,\n menuLoading,\n emptyMessage,\n autoFocus,\n positioned,\n onDismiss,\n keyboardNavigation,\n onKeyboardNavigation,\n subtitleLayout,\n size,\n style,\n } = props;\n const panelRef = useRef<HTMLDivElement | null>(null);\n const popupIdentity = usePopupLayer('dropdown', true, panelRef);\n\n // The panel only mounts while open, so no condition. useInsertionEffect, not layout:\n // it runs before the DOM mutation, so the rules are in place before the rows are inserted.\n useInsertionEffect(() => {\n ensureDropdownPanelStyles();\n }, []);\n\n useTopLayer(panelRef, true);\n\n // Start on the selected option so Enter re-confirms the current value. Not keyed on\n // `items`: re-running as the filtered list changes would yank focus back to the top.\n useEffect(() => {\n if (!autoFocus || !positioned) {\n return;\n }\n const options = panelOptions(panelRef.current);\n const selected = options.find((option) => option.dataset.selected === 'true');\n // Falls back to the panel: with no options nothing else can hold focus, and Tab-dismiss\n // only fires from inside it.\n (selected ?? options[0] ?? panelRef.current)?.focus();\n }, [autoFocus, positioned]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {\n // The panel is portaled to document.body, so the browser's next tab stop bears no\n // relation to the trigger. Dismissing restores trigger focus so Tab resumes there.\n if (event.key === 'Tab') {\n onDismiss();\n return;\n }\n const options = panelOptions(panelRef.current);\n if (options.length === 0) {\n return;\n }\n const current = options.indexOf(document.activeElement as HTMLElement);\n const target = {\n ArrowDown: current + 1,\n ArrowUp: current - 1,\n Home: 0,\n End: options.length - 1,\n }[event.key];\n if (target === undefined) {\n return;\n }\n event.preventDefault();\n onKeyboardNavigation();\n options[Math.min(Math.max(target, 0), options.length - 1)]?.focus();\n };\n\n // Inline styles, not Tailwind: this portals into document.body, outside the\n // Shadow DOM the malachite stylesheet is adopted into.\n return (\n <div\n ref={(node) => {\n panelRef.current = node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n }}\n {...popupIdentity}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n style={{\n background: MENU_SPECS.standard.background,\n border: MENU_SPECS.standard.border,\n borderRadius: MENU_SPECS.standard.radius,\n boxShadow: MENU_SPECS.standard.shadow,\n maxHeight: MENU_MAX_HEIGHT_PX,\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n fontSize: CONTROL_TEXT_SIZE[size],\n ...style,\n }}\n >\n {menuLoading ? (\n <div style={PANEL_MESSAGE_STYLE}>\n <Spinner size=\"xxxsmall\" />\n <span>Loading…</span>\n </div>\n ) : items.length === 0 ? (\n <div style={PANEL_MESSAGE_STYLE}>{emptyMessage}</div>\n ) : (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n padding: MENU_SPECS.standard.padding,\n overflowY: 'auto',\n scrollbarWidth: 'thin',\n scrollbarColor:\n 'var(--malachite-text-placeholder, rgb(187, 187, 187)) transparent',\n }}\n >\n {items.map((item, index) => {\n const prev = items[index - 1];\n const showGroupHeader =\n !!item.group && (!prev || prev.group !== item.group);\n return (\n <div key={item.id} style={{ flexShrink: 0 }}>\n {showGroupHeader && (\n <div\n style={{\n padding: '6px 10px 4px',\n fontSize: 12,\n fontWeight: 500,\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n textTransform: 'none',\n userSelect: 'none',\n }}\n >\n {item.group}\n </div>\n )}\n <DropdownItemComponent\n item={item}\n onItemSelected={onItemSelected}\n subtitleLayout={subtitleLayout}\n selected={item.id === selectedItem?.id || false}\n showTooltipOnFocus={keyboardNavigation}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n});\nDropdownPanel.displayName = 'DropdownPanel';\n\nexport const Dropdown = ({\n items,\n onItemSelected,\n defaultValue,\n value,\n disabled = false,\n error,\n tone,\n label,\n hint,\n rightSideContent,\n tooltip,\n name,\n required = false,\n requiredIndicator,\n loading,\n menuLoading,\n formControl,\n description,\n helperText,\n placeholder,\n search = false,\n showSubtitleInTrigger = false,\n subtitleLayout = 'inline',\n clearable = false,\n size = 'large',\n fullWidth = false,\n width,\n minWidth,\n menuAlign = 'start',\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n}: DropdownProps) => {\n const { controlId, labelId, descriptionId, hintId, helperTextId } = useFormFieldIds({\n id,\n label,\n description,\n hint,\n helperText: true,\n });\n const [isOpen, setIsOpen] = useState(false);\n // The id, never the resolved item: a cached object goes stale when `items` is rebuilt.\n const [ownValue, setOwnValue] = useState(defaultValue);\n const selectedId = value ?? ownValue;\n const selectedItem = items.find((item) => item.id === selectedId);\n const showClear = clearable && selectedId !== undefined && selectedId !== '' && !disabled;\n const triggerIsStacked = showSubtitleInTrigger && !search && !!selectedItem?.subtitle;\n const clearLabel = `Clear ${label ?? placeholder ?? 'selection'}`;\n\n // `defaultValue` only seeds the state, so a later change has to be pushed in.\n const lastDefaultValueRef = useRef(defaultValue);\n useEffect(() => {\n if (lastDefaultValueRef.current === defaultValue) {\n return;\n }\n lastDefaultValueRef.current = defaultValue;\n setOwnValue(defaultValue);\n }, [defaultValue]);\n const [searchQuery, setSearchQuery] = useState('');\n // Search mode only: set when the panel is opened by ArrowDown, so focus follows the\n // user into the list on mount instead of staying in the input.\n const [focusPanelOnOpen, setFocusPanelOnOpen] = useState(false);\n const [keyboardNavigation, setKeyboardNavigation] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const [panelPosition, setPanelPosition] = useState<MenuGeometry | null>(null);\n\n const reopenOnFocusRef = useRef(true);\n\n // In search mode the trigger is a wrapper div; the focusable part is the input.\n const focusTrigger = useCallback(() => {\n const trigger = triggerRef.current;\n const target =\n trigger instanceof HTMLButtonElement\n ? trigger\n : (trigger?.querySelector<HTMLElement>('input') ?? null);\n // A `.focus()` that fires no focus event — an already-focused element, or one that never\n // lands (disabled, hidden, unfocused window) — leaves the latch to eat the next real focus.\n if (!target || target === getDeepActiveElement()) {\n return;\n }\n if (!search) {\n target.focus();\n return;\n }\n reopenOnFocusRef.current = false;\n target.focus();\n if (getDeepActiveElement() !== target) {\n reopenOnFocusRef.current = true;\n }\n }, [search]);\n\n const handleClear = useCallback(\n (event: React.MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n setOwnValue(undefined);\n // The resolver is told the empty this form started the field at; the public\n // callback keeps reporting `undefined` whatever shape that is.\n reportSelectionRef.current?.(reportEmptyRef.current);\n onItemSelected?.(undefined);\n focusTrigger();\n },\n [onItemSelected, focusTrigger],\n );\n\n const updatePanelPosition = useCallback(() => {\n const trigger = triggerRef.current;\n if (!trigger) return;\n\n setPanelPosition(\n measureMenuGeometry(panelRef.current, {\n triggerRect: trigger.getBoundingClientRect(),\n preset: 'standard',\n minWidth,\n align: menuAlign === 'end' ? 'right' : 'left',\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n }),\n );\n }, [minWidth, menuAlign]);\n\n useEffect(() => {\n if (!isOpen) {\n setPanelPosition(null);\n setFocusPanelOnOpen(false);\n return;\n }\n updatePanelPosition();\n const handleClickOutside = (event: MouseEvent) => {\n const path = event.composedPath();\n const trigger = dropdownRef.current;\n const panel = panelRef.current;\n const inTrigger = !!trigger && path.includes(trigger);\n const inPanel = !!panel && path.includes(panel);\n if (!inTrigger && !inPanel) {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n if (panelRef.current?.contains(getDeepActiveElement())) {\n focusTrigger();\n }\n // Closing unmounts the option holding focus, so no focusout reaches the wrapper\n // below; when the trigger holds it one does, and reporting here too validates twice.\n if (!dropdownRef.current?.contains(getDeepActiveElement())) {\n reportBlurRef.current?.();\n }\n }\n };\n // ESC via the shared layer stack: closes only the topmost overlay. Focus is\n // restored explicitly — unmounting the option it sits on would drop it to <body>.\n const popEscapeLayer = pushEscapeLayer(() => {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n focusTrigger();\n });\n const handleScrollOrResize = () => updatePanelPosition();\n\n // `scroll` is not composed: a window listener never hears a scroller inside a\n // consumer's shadow root, so the trigger's rect is tracked instead.\n let frame = 0;\n let lastRect = '';\n const followTrigger = () => {\n const trigger = triggerRef.current;\n if (trigger) {\n const rect = trigger.getBoundingClientRect();\n\n if (isTriggerOffscreen(rect, window.innerWidth, window.innerHeight)) {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n return;\n }\n\n const signature = rectSignature(rect);\n if (signature !== lastRect) {\n lastRect = signature;\n updatePanelPosition();\n }\n }\n frame = requestAnimationFrame(followTrigger);\n };\n frame = requestAnimationFrame(followTrigger);\n\n document.addEventListener('mousedown', handleClickOutside);\n window.addEventListener('scroll', handleScrollOrResize, true);\n window.addEventListener('resize', handleScrollOrResize);\n return () => {\n cancelAnimationFrame(frame);\n document.removeEventListener('mousedown', handleClickOutside);\n popEscapeLayer();\n window.removeEventListener('scroll', handleScrollOrResize, true);\n window.removeEventListener('resize', handleScrollOrResize);\n };\n }, [isOpen, search, updatePanelPosition, focusTrigger]);\n\n useLayoutEffect(() => {\n if (!isOpen) {\n return;\n }\n updatePanelPosition();\n\n const panel = panelRef.current;\n if (!panel || typeof ResizeObserver === 'undefined') {\n return;\n }\n const observer = new ResizeObserver(() => updatePanelPosition());\n observer.observe(panel);\n return () => observer.disconnect();\n }, [isOpen, updatePanelPosition]);\n\n const reportSelectionRef = useRef<((value: unknown) => void) | undefined>(undefined);\n const reportBlurRef = useRef<(() => void) | undefined>(undefined);\n const reportEmptyRef = useRef<unknown>('');\n\n const handleItemSelected = (item?: DropdownItem) => {\n setOwnValue(item?.id);\n reportSelectionRef.current?.(item?.id ?? reportEmptyRef.current);\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n onItemSelected?.(item?.id);\n focusTrigger();\n };\n\n const dismissPanel = () => {\n setIsOpen(false);\n if (search) {\n setSearchQuery('');\n }\n focusTrigger();\n };\n\n // ArrowDown is the \"take me into the list\" gesture. When it also opens the panel the\n // intent carries over to the mount, so it doesn't cost a second press in search mode.\n const enterPanel = () => {\n setKeyboardNavigation(true);\n const first = panelOptions(panelRef.current)[0];\n if (first) {\n first.focus();\n return;\n }\n setFocusPanelOnOpen(true);\n setIsOpen(true);\n };\n\n const visibleItems =\n search && searchQuery ? items.filter((item) => matchesSearch(item, searchQuery)) : items;\n\n return (\n <BaseFormComponent\n fullWidth={fullWidth}\n label={label}\n hint={hint}\n rightSideContent={rightSideContent}\n tooltip={tooltip}\n name={name}\n required={required}\n requiredIndicator={requiredIndicator}\n loading={loading}\n formControl={formControl}\n description={description}\n controlId={controlId}\n labelId={labelId}\n descriptionId={descriptionId}\n hintId={hintId}\n loadingComponent={\n width === undefined ? (\n <LoadingInput\n heightClass={TRIGGER_SIZE_HEIGHT[size]}\n helperText={!!helperText}\n helperTextMarginTop\n />\n ) : (\n <div style={controlWidthStyle(width)}>\n <LoadingInput\n heightClass={TRIGGER_SIZE_HEIGHT[size]}\n helperText={!!helperText}\n helperTextMarginTop\n />\n </div>\n )\n }\n >\n {({ error: fieldError, message, onFieldChange, onFieldBlur, emptyValue }) => {\n reportSelectionRef.current = onFieldChange;\n reportBlurRef.current = onFieldBlur;\n reportEmptyRef.current = emptyValue;\n const isError = error ?? fieldError;\n // `error={false}` opts out of the resolver entirely, message included: a screen\n // that has dealt with the rejection its own way would otherwise keep reporting it.\n // The message is its own line rather than a replacement for the helper text,\n // matching Input and TextArea: a field that explains what it wants still has to\n // say why what was chosen was rejected.\n const errorMessage = error === false ? undefined : message;\n const errorMessageId = `${helperTextId}-error`;\n const describedBy =\n [\n descriptionId,\n hintId,\n helperText ? helperTextId : undefined,\n errorMessage ? errorMessageId : undefined,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <>\n <div\n ref={dropdownRef}\n className={`relative w-full`}\n style={controlWidthStyle(width)}\n // Only leaving the field altogether is a blur `mode: 'onBlur'` should\n // hear. The panel is portaled to the body, so containment has to be\n // asked of it separately — otherwise opening the menu reads as\n // leaving, and the form validates before anything has been chosen.\n onBlur={(event) => {\n const next = event.relatedTarget as Node | null;\n const staysInField =\n event.currentTarget.contains(next) ||\n panelRef.current?.contains(next) === true;\n\n if (!staysInField) {\n reportBlurRef.current?.();\n }\n }}\n >\n {showClear && !search && (\n <button\n type=\"button\"\n onClick={handleClear}\n aria-label={clearLabel}\n className={`absolute ${\n triggerIsStacked\n ? CLEAR_STACKED_TOP_CLASSES[size]\n : 'top-1/2 -translate-y-1/2'\n } z-10 flex items-center\n justify-center rounded-full text-[var(--malachite-text-placeholder)]\n hover:text-[var(--malachite-text-primary)] transition-colors\n focus-visible:[outline:2px_solid_var(--malachite-text-primary)] focus-visible:outline-offset-2 ${CLEAR_OFFSET_CLASSES[size]}`}\n >\n <CloseIcon size={13} />\n </button>\n )}\n <DropdownTrigger\n hasClear={showClear}\n onClear={handleClear}\n clearLabel={clearLabel}\n ref={triggerRef as React.Ref<HTMLElement>}\n isOpen={isOpen}\n onClick={(fromKeyboard) => {\n if (disabled) {\n return;\n }\n setKeyboardNavigation(!!fromKeyboard);\n setIsOpen(!isOpen);\n }}\n selectedItem={selectedItem}\n disabled={disabled}\n error={isError}\n tone={tone}\n placeholder={placeholder}\n search={search}\n showSubtitleInTrigger={showSubtitleInTrigger}\n searchQuery={searchQuery}\n onSearchChange={setSearchQuery}\n onFocusOpen={() => {\n if (!reopenOnFocusRef.current) {\n reopenOnFocusRef.current = true;\n return;\n }\n setIsOpen(true);\n }}\n onArrowDown={() => {\n if (!disabled) {\n enterPanel();\n }\n }}\n onTabAway={() => {\n if (isOpen) {\n dismissPanel();\n }\n }}\n size={size}\n controlId={controlId}\n hasCallerId={!!id}\n labelId={labelId}\n describedBy={describedBy}\n required={required}\n ariaLabel={ariaLabel}\n ariaLabelledBy={ariaLabelledBy}\n />\n {isOpen &&\n createPortal(\n <DropdownPanel\n ref={panelRef}\n style={{\n position: 'fixed',\n top: panelPosition?.top ?? 0,\n left: panelPosition?.left ?? 0,\n width: panelPosition?.width,\n maxHeight: panelPosition?.maxHeight,\n visibility: panelPosition ? 'visible' : 'hidden',\n opacity: panelPosition ? 1 : 0,\n }}\n items={visibleItems}\n onItemSelected={handleItemSelected}\n selectedItem={selectedItem}\n menuLoading={menuLoading}\n emptyMessage={\n items.length === 0\n ? 'No options available'\n : 'No results found'\n }\n subtitleLayout={subtitleLayout}\n size={size}\n autoFocus={!search || focusPanelOnOpen}\n positioned={panelPosition !== null}\n onDismiss={dismissPanel}\n keyboardNavigation={keyboardNavigation}\n onKeyboardNavigation={() => setKeyboardNavigation(true)}\n />,\n document.body,\n )}\n </div>\n {helperText && (\n <div\n id={helperTextId}\n className=\"mt-1 text-[length:var(--malachite-font-size-small,13px)] text-left pl-2 text-[var(--malachite-text-dimmed,rgb(161,161,161))]\"\n >\n {helperText}\n </div>\n )}\n <FieldMessage id={errorMessageId} message={errorMessage} spaced />\n </>\n );\n }}\n </BaseFormComponent>\n );\n};\n\nexport default Dropdown;\n"],"names":["BadgeHost","React","TriggerTag","id","text","disabled","jsx","Tag","INLINE_MARKDOWN_SYNTAX","ItemSubtitle","MarkdownBlock","PANEL_MESSAGE_STYLE","ANNOTATION_FONT_SIZE","OPTION_SELECTOR","panelOptions","panel","subtitleSearchText","subtitle","inlineMarkdownText","matchesSearch","item","query","q","labelMatches","subtitleMatches","rightSideTextMatches","TRIGGER_SIZE_HEIGHT","TRIGGER_SIZE_CLASSES","CONTROL_TEXT_SIZE_CLASS","TRIGGER_SIZE_STACKED_CLASSES","CLEAR_OFFSET_CLASSES","CLEAR_STACKED_TOP_CLASSES","TRIGGER_SIZE_RADIUS","NEVER","ValueRow","wrap","children","Fragment","LabelRow","row","DropdownTrigger","isOpen","onClick","selectedItem","error","tone","placeholder","search","showSubtitleInTrigger","searchQuery","onSearchChange","onFocusOpen","onArrowDown","onTabAway","size","hasClear","onClear","clearLabel","controlId","labelId","describedBy","required","ariaLabel","ariaLabelledBy","hasCallerId","forwardedRef","stacked","sizeClasses","sizeRadius","valueId","subtitleId","tagId","rendersButton","hasTag","showsSearchTag","valueIds","namesItself","labelledBy","tagOutsideName","handleTriggerKeyDown","event","valueTextRef","useRef","subtitleTextRef","triggerVisual","getTriggerVisual","showValueLabel","valueText","triggerSubtitle","isValueTruncated","isCut","cutLines","setCutLines","useState","measureTruncatedLines","value","jsxs","DROPDOWN_TRIGGER_ATTR","e","Tooltip","CloseIcon","CaretDownIcon","trigger","FOCUS_RING","tooltipLines","DropdownItemComponent","selected","showTooltipOnFocus","subtitleLayout","onItemSelected","textColor","optionId","useId","optionLabelId","optionSubtitleId","optionBadgeId","badgeBesideLabel","badge","hasBadge","labelRef","subtitleRef","rightSideRef","measureOptionLines","label","rightSide","rightSideTextColor","rightSideJustify","option","DropdownPanel","props","ref","items","menuLoading","emptyMessage","autoFocus","positioned","onDismiss","keyboardNavigation","onKeyboardNavigation","style","panelRef","popupIdentity","usePopupLayer","useInsertionEffect","ensureDropdownPanelStyles","useTopLayer","useEffect","options","_a","node","current","target","MENU_SPECS","MENU_MAX_HEIGHT_PX","CONTROL_TEXT_SIZE","Spinner","index","prev","showGroupHeader","Dropdown","defaultValue","hint","rightSideContent","tooltip","name","requiredIndicator","loading","formControl","description","helperText","clearable","fullWidth","width","minWidth","menuAlign","descriptionId","hintId","helperTextId","useFormFieldIds","setIsOpen","ownValue","setOwnValue","selectedId","showClear","triggerIsStacked","lastDefaultValueRef","setSearchQuery","focusPanelOnOpen","setFocusPanelOnOpen","setKeyboardNavigation","dropdownRef","triggerRef","panelPosition","setPanelPosition","reopenOnFocusRef","focusTrigger","useCallback","getDeepActiveElement","handleClear","reportSelectionRef","reportEmptyRef","updatePanelPosition","measureMenuGeometry","handleClickOutside","path","inTrigger","inPanel","_b","_c","reportBlurRef","popEscapeLayer","pushEscapeLayer","handleScrollOrResize","frame","lastRect","followTrigger","rect","isTriggerOffscreen","signature","rectSignature","useLayoutEffect","observer","handleItemSelected","dismissPanel","enterPanel","first","visibleItems","BaseFormComponent","LoadingInput","controlWidthStyle","fieldError","message","onFieldChange","onFieldBlur","emptyValue","isError","errorMessage","errorMessageId","next","fromKeyboard","createPortal","FieldMessage"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import l from "./Tooltip.js";
|
|
3
|
+
import { getIconOnlySizeClasses as m, getIconSizeClass as c } from "./buttonSizing.js";
|
|
4
|
+
import { FOCUS_RING as s } from "./focusRing.js";
|
|
5
|
+
const x = ({
|
|
6
|
+
icon: i,
|
|
7
|
+
"aria-label": n,
|
|
8
|
+
tooltip: e,
|
|
9
|
+
size: r = "small",
|
|
10
|
+
className: o = ""
|
|
11
|
+
}) => {
|
|
12
|
+
const a = /* @__PURE__ */ t(
|
|
13
|
+
"span",
|
|
14
|
+
{
|
|
15
|
+
role: "img",
|
|
16
|
+
"aria-label": n,
|
|
17
|
+
tabIndex: e ? 0 : void 0,
|
|
18
|
+
className: `inline-flex items-center justify-center rounded-[var(--malachite-radius-10,10px)] text-[var(--malachite-primary-foreground)] ${m(r)} ${c(r)} ${e ? s : ""} ${o}`.trim(),
|
|
19
|
+
children: i
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
return e ? /* @__PURE__ */ t(l, { text: e, placement: "bottom", inline: !0, children: a }) : a;
|
|
23
|
+
};
|
|
24
|
+
export {
|
|
25
|
+
x as default
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=IconIndicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconIndicator.js","sources":["../../src/components/IconIndicator.tsx"],"sourcesContent":["import type React from 'react';\nimport type { ButtonSize } from './Button';\nimport Tooltip from './Tooltip';\nimport { getIconOnlySizeClasses, getIconSizeClass } from './buttonSizing';\nimport { FOCUS_RING } from './focusRing';\n\nexport interface IconIndicatorProps {\n icon: React.ReactNode;\n /** The indicator's only text for assistive tech; it renders as `role=\"img\"`. */\n 'aria-label': string;\n tooltip?: string;\n /** Matches `Button`'s `iconOnly` square, so an indicator lines up with icon buttons beside it. */\n size?: ButtonSize;\n className?: string;\n}\n\n/** A non-interactive icon carrying a meaning, for where an icon button would offer nothing to do. */\nconst IconIndicator: React.FC<IconIndicatorProps> = ({\n icon,\n 'aria-label': ariaLabel,\n tooltip,\n size = 'small',\n className = '',\n}) => {\n // Focusable only with a tooltip, so a keyboard user can reach what it says.\n const indicator = (\n <span\n role=\"img\"\n aria-label={ariaLabel}\n tabIndex={tooltip ? 0 : undefined}\n className={`inline-flex items-center justify-center rounded-[var(--malachite-radius-10,10px)] text-[var(--malachite-primary-foreground)] ${getIconOnlySizeClasses(size)} ${getIconSizeClass(size)} ${tooltip ? FOCUS_RING : ''} ${className}`.trim()}\n >\n {icon}\n </span>\n );\n\n if (!tooltip) {\n return indicator;\n }\n\n return (\n <Tooltip text={tooltip} placement=\"bottom\" inline>\n {indicator}\n </Tooltip>\n );\n};\n\nexport default IconIndicator;\n"],"names":["IconIndicator","icon","ariaLabel","tooltip","size","className","indicator","jsx","getIconOnlySizeClasses","getIconSizeClass","FOCUS_RING","Tooltip"],"mappings":";;;;AAiBA,MAAMA,IAA8C,CAAC;AAAA,EACjD,MAAAC;AAAA,EACA,cAAcC;AAAA,EACd,SAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,WAAAC,IAAY;AAChB,MAAM;AAEF,QAAMC,IACF,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,MAAK;AAAA,MACL,cAAYL;AAAA,MACZ,UAAUC,IAAU,IAAI;AAAA,MACxB,WAAW,gIAAgIK,EAAuBJ,CAAI,CAAC,IAAIK,EAAiBL,CAAI,CAAC,IAAID,IAAUO,IAAa,EAAE,IAAIL,CAAS,GAAG,KAAA;AAAA,MAE7O,UAAAJ;AAAA,IAAA;AAAA,EAAA;AAIT,SAAKE,IAKD,gBAAAI,EAACI,KAAQ,MAAMR,GAAS,WAAU,UAAS,QAAM,IAC5C,UAAAG,EAAA,CACL,IANOA;AAQf;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const s = (e) => {
|
|
2
|
+
switch (e) {
|
|
3
|
+
case "xsmall":
|
|
4
|
+
return "size-[20px] shrink-0";
|
|
5
|
+
case "small":
|
|
6
|
+
return "size-[28px] shrink-0";
|
|
7
|
+
case "medium":
|
|
8
|
+
return "size-[32px] shrink-0";
|
|
9
|
+
default:
|
|
10
|
+
return "size-[42px] shrink-0";
|
|
11
|
+
}
|
|
12
|
+
}, a = (e) => {
|
|
13
|
+
switch (e) {
|
|
14
|
+
case "xsmall":
|
|
15
|
+
return "[&_svg]:size-[var(--malachite-icon-size-xsmall)]!";
|
|
16
|
+
case "small":
|
|
17
|
+
return "[&_svg]:size-[var(--malachite-icon-size-small)]!";
|
|
18
|
+
case "medium":
|
|
19
|
+
return "[&_svg]:size-[var(--malachite-icon-size-medium)]!";
|
|
20
|
+
case "large":
|
|
21
|
+
return "[&_svg]:size-[var(--malachite-icon-size-large)]!";
|
|
22
|
+
default:
|
|
23
|
+
return "[&_svg]:size-[var(--malachite-icon-size-large)]!";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
export {
|
|
27
|
+
s as getIconOnlySizeClasses,
|
|
28
|
+
a as getIconSizeClass
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=buttonSizing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buttonSizing.js","sources":["../../src/components/buttonSizing.ts"],"sourcesContent":["import type { ButtonSize } from './Button';\n\n/** An icon-only button is a square on the control ladder; without this it collapses to the\n * glyph plus its border. */\nexport const getIconOnlySizeClasses = (size: ButtonSize): string => {\n switch (size) {\n case 'xsmall':\n return 'size-[20px] shrink-0';\n case 'small':\n return 'size-[28px] shrink-0';\n case 'medium':\n return 'size-[32px] shrink-0';\n default:\n return 'size-[42px] shrink-0';\n }\n};\n\nexport const getIconSizeClass = (size: ButtonSize): string => {\n switch (size) {\n case 'xsmall':\n return '[&_svg]:size-[var(--malachite-icon-size-xsmall)]!';\n case 'small':\n return '[&_svg]:size-[var(--malachite-icon-size-small)]!';\n case 'medium':\n return '[&_svg]:size-[var(--malachite-icon-size-medium)]!';\n case 'large':\n return '[&_svg]:size-[var(--malachite-icon-size-large)]!';\n default:\n return '[&_svg]:size-[var(--malachite-icon-size-large)]!';\n }\n};\n"],"names":["getIconOnlySizeClasses","size","getIconSizeClass"],"mappings":"AAIO,MAAMA,IAAyB,CAACC,MAA6B;AAChE,UAAQA,GAAA;AAAA,IACJ,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EAAA;AAEnB,GAEaC,IAAmB,CAACD,MAA6B;AAC1D,UAAQA,GAAA;AAAA,IACJ,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EAAA;AAEnB;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1420,8 +1420,10 @@ export declare interface DropdownItem {
|
|
|
1420
1420
|
rightSideText?: string;
|
|
1421
1421
|
rightSideTextVariant?: 'muted' | 'primary';
|
|
1422
1422
|
rightSideTextAlignment?: 'left' | 'right';
|
|
1423
|
-
/**
|
|
1423
|
+
/** Badge shown in the open menu only (not in the trigger or the search input). */
|
|
1424
1424
|
badge?: default_2.ReactNode;
|
|
1425
|
+
/** Where the badge sits: the option's right end (default), or right after its label. */
|
|
1426
|
+
badgePlacement?: 'end' | 'label';
|
|
1425
1427
|
}
|
|
1426
1428
|
|
|
1427
1429
|
export declare type DropdownProps = DropdownBaseProps & DropdownTriggerModeProps;
|
|
@@ -1720,6 +1722,19 @@ export declare function getCurrentThemeMode(): 'light' | 'dark';
|
|
|
1720
1722
|
|
|
1721
1723
|
export declare const GlobeIcon: React.FC<IconProps_56>;
|
|
1722
1724
|
|
|
1725
|
+
/** A non-interactive icon carrying a meaning, for where an icon button would offer nothing to do. */
|
|
1726
|
+
export declare const IconIndicator: default_2.FC<IconIndicatorProps>;
|
|
1727
|
+
|
|
1728
|
+
export declare interface IconIndicatorProps {
|
|
1729
|
+
icon: default_2.ReactNode;
|
|
1730
|
+
/** The indicator's only text for assistive tech; it renders as `role="img"`. */
|
|
1731
|
+
'aria-label': string;
|
|
1732
|
+
tooltip?: string;
|
|
1733
|
+
/** Matches `Button`'s `iconOnly` square, so an indicator lines up with icon buttons beside it. */
|
|
1734
|
+
size?: ButtonSize;
|
|
1735
|
+
className?: string;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1723
1738
|
declare interface IconProps {
|
|
1724
1739
|
size?: number | string;
|
|
1725
1740
|
className?: string;
|