@j2-health/design-system 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +15 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +9 -2
- package/dist/index2.js +9 -2
- package/dist/src/components/alert/Alert.cjs +4 -2
- package/dist/src/components/alert/Alert.cjs.map +1 -1
- package/dist/src/components/alert/Alert.d.ts +2 -2
- package/dist/src/components/alert/Alert.js +3 -2
- package/dist/src/components/alert/Alert.js.map +1 -1
- package/dist/src/components/button/Button.cjs +7 -2
- package/dist/src/components/button/Button.cjs.map +1 -1
- package/dist/src/components/button/Button.d.ts +10 -2
- package/dist/src/components/button/Button.js +5 -2
- package/dist/src/components/button/Button.js.map +1 -1
- package/dist/src/components/card/Card.cjs +16 -2
- package/dist/src/components/card/Card.cjs.map +1 -1
- package/dist/src/components/card/Card.d.ts +7 -1
- package/dist/src/components/card/Card.js +16 -2
- package/dist/src/components/card/Card.js.map +1 -1
- package/dist/src/components/changeChip/ChangeChip.cjs +52 -0
- package/dist/src/components/changeChip/ChangeChip.cjs.map +1 -0
- package/dist/src/components/changeChip/ChangeChip.d.ts +40 -0
- package/dist/src/components/changeChip/ChangeChip.js +49 -0
- package/dist/src/components/changeChip/ChangeChip.js.map +1 -0
- package/dist/src/components/changeChip/index.d.ts +1 -0
- package/dist/src/components/collapse/Collapse.cjs +9 -2
- package/dist/src/components/collapse/Collapse.cjs.map +1 -1
- package/dist/src/components/collapse/Collapse.d.ts +7 -1
- package/dist/src/components/collapse/Collapse.js +9 -2
- package/dist/src/components/collapse/Collapse.js.map +1 -1
- package/dist/src/components/collapse/Collapse.module.css.cjs +7 -4
- package/dist/src/components/collapse/Collapse.module.css.cjs.map +1 -1
- package/dist/src/components/collapse/Collapse.module.css.js +7 -5
- package/dist/src/components/collapse/Collapse.module.css.js.map +1 -1
- package/dist/src/components/dropdown/Dropdown.cjs +6 -1
- package/dist/src/components/dropdown/Dropdown.cjs.map +1 -1
- package/dist/src/components/dropdown/Dropdown.d.ts +8 -1
- package/dist/src/components/dropdown/Dropdown.js +6 -1
- package/dist/src/components/dropdown/Dropdown.js.map +1 -1
- package/dist/src/components/emptyState/EmptyState.cjs +39 -0
- package/dist/src/components/emptyState/EmptyState.cjs.map +1 -0
- package/dist/src/components/emptyState/EmptyState.d.ts +20 -0
- package/dist/src/components/emptyState/EmptyState.js +37 -0
- package/dist/src/components/emptyState/EmptyState.js.map +1 -0
- package/dist/src/components/emptyState/index.d.ts +1 -0
- package/dist/src/components/input/AntdInput.d.ts +1 -1
- package/dist/src/components/input/AntdSearchInput.d.ts +1 -1
- package/dist/src/components/listRow/ListRow.cjs +65 -0
- package/dist/src/components/listRow/ListRow.cjs.map +1 -0
- package/dist/src/components/listRow/ListRow.d.ts +41 -0
- package/dist/src/components/listRow/ListRow.js +63 -0
- package/dist/src/components/listRow/ListRow.js.map +1 -0
- package/dist/src/components/listRow/index.d.ts +1 -0
- package/dist/src/components/modal/Modal.cjs +9 -3
- package/dist/src/components/modal/Modal.cjs.map +1 -1
- package/dist/src/components/modal/Modal.d.ts +3 -1
- package/dist/src/components/modal/Modal.js +10 -4
- package/dist/src/components/modal/Modal.js.map +1 -1
- package/dist/src/components/navMenu/NavMenu.cjs +2 -2
- package/dist/src/components/navMenu/NavMenu.cjs.map +1 -1
- package/dist/src/components/navMenu/NavMenu.d.ts +3 -1
- package/dist/src/components/navMenu/NavMenu.js +2 -2
- package/dist/src/components/navMenu/NavMenu.js.map +1 -1
- package/dist/src/components/popover/Popover.cjs.map +1 -1
- package/dist/src/components/popover/Popover.d.ts +1 -1
- package/dist/src/components/popover/Popover.js.map +1 -1
- package/dist/src/components/popover/Popover.module.css.cjs +12 -9
- package/dist/src/components/popover/Popover.module.css.cjs.map +1 -1
- package/dist/src/components/popover/Popover.module.css.js +12 -10
- package/dist/src/components/popover/Popover.module.css.js.map +1 -1
- package/dist/src/components/select/SummarizedSelect.cjs +16 -12
- package/dist/src/components/select/SummarizedSelect.cjs.map +1 -1
- package/dist/src/components/select/SummarizedSelect.d.ts +15 -3
- package/dist/src/components/select/SummarizedSelect.js +16 -12
- package/dist/src/components/select/SummarizedSelect.js.map +1 -1
- package/dist/src/components/select/SummarizedSelect.module.css.cjs +15 -9
- package/dist/src/components/select/SummarizedSelect.module.css.cjs.map +1 -1
- package/dist/src/components/select/SummarizedSelect.module.css.js +14 -10
- package/dist/src/components/select/SummarizedSelect.module.css.js.map +1 -1
- package/dist/src/components/statusPill/StatusPill.cjs +47 -0
- package/dist/src/components/statusPill/StatusPill.cjs.map +1 -0
- package/dist/src/components/statusPill/StatusPill.d.ts +28 -0
- package/dist/src/components/statusPill/StatusPill.js +45 -0
- package/dist/src/components/statusPill/StatusPill.js.map +1 -0
- package/dist/src/components/statusPill/StatusPill.module.css.cjs +20 -0
- package/dist/src/components/statusPill/StatusPill.module.css.cjs.map +1 -0
- package/dist/src/components/statusPill/StatusPill.module.css.js +16 -0
- package/dist/src/components/statusPill/StatusPill.module.css.js.map +1 -0
- package/dist/src/components/statusPill/index.d.ts +1 -0
- package/dist/src/components/swatch/Swatch.cjs +50 -0
- package/dist/src/components/swatch/Swatch.cjs.map +1 -0
- package/dist/src/components/swatch/Swatch.d.ts +24 -0
- package/dist/src/components/swatch/Swatch.js +48 -0
- package/dist/src/components/swatch/Swatch.js.map +1 -0
- package/dist/src/components/swatch/index.d.ts +1 -0
- package/dist/src/components/swatchStrip/SwatchStrip.cjs +50 -0
- package/dist/src/components/swatchStrip/SwatchStrip.cjs.map +1 -0
- package/dist/src/components/swatchStrip/SwatchStrip.d.ts +25 -0
- package/dist/src/components/swatchStrip/SwatchStrip.js +50 -0
- package/dist/src/components/swatchStrip/SwatchStrip.js.map +1 -0
- package/dist/src/components/swatchStrip/index.d.ts +1 -0
- package/dist/src/components/switch/Switch.cjs +7 -3
- package/dist/src/components/switch/Switch.cjs.map +1 -1
- package/dist/src/components/switch/Switch.d.ts +1 -1
- package/dist/src/components/switch/Switch.js +5 -3
- package/dist/src/components/switch/Switch.js.map +1 -1
- package/dist/src/components/tabs/Tabs.cjs +6 -1
- package/dist/src/components/tabs/Tabs.cjs.map +1 -1
- package/dist/src/components/tabs/Tabs.d.ts +10 -2
- package/dist/src/components/tabs/Tabs.js +4 -1
- package/dist/src/components/tabs/Tabs.js.map +1 -1
- package/dist/src/components/tabs/Tabs.module.css.cjs +13 -0
- package/dist/src/components/tabs/Tabs.module.css.cjs.map +1 -0
- package/dist/src/components/tabs/Tabs.module.css.js +11 -0
- package/dist/src/components/tabs/Tabs.module.css.js.map +1 -0
- package/dist/src/components/tag/Tag.cjs +13 -6
- package/dist/src/components/tag/Tag.cjs.map +1 -1
- package/dist/src/components/tag/Tag.d.ts +13 -2
- package/dist/src/components/tag/Tag.js +13 -6
- package/dist/src/components/tag/Tag.js.map +1 -1
- package/dist/src/components/thresholdBar/ThresholdBar.cjs +128 -0
- package/dist/src/components/thresholdBar/ThresholdBar.cjs.map +1 -0
- package/dist/src/components/thresholdBar/ThresholdBar.d.ts +36 -0
- package/dist/src/components/thresholdBar/ThresholdBar.js +125 -0
- package/dist/src/components/thresholdBar/ThresholdBar.js.map +1 -0
- package/dist/src/components/thresholdBar/ThresholdBar.module.css.cjs +19 -0
- package/dist/src/components/thresholdBar/ThresholdBar.module.css.cjs.map +1 -0
- package/dist/src/components/thresholdBar/ThresholdBar.module.css.js +15 -0
- package/dist/src/components/thresholdBar/ThresholdBar.module.css.js.map +1 -0
- package/dist/src/components/thresholdBar/index.d.ts +1 -0
- package/dist/src/index.d.ts +0 -13
- package/dist/style.css +346 -41
- package/dist/tailwind.cjs +56 -0
- package/dist/tailwind.cjs.map +1 -1
- package/dist/tailwind.config.d.ts +112 -0
- package/dist/tailwind.js +56 -0
- package/dist/tailwind.js.map +1 -1
- package/package.json +2 -2
- package/src/stylesheets/Colors.stories.tsx +163 -0
- package/src/stylesheets/base.css +110 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.cjs","names":["useState","useRef","useMemo","Input","MagnifyingGlassIcon","Tag","cx","styles","Fragment","Spin","LoadingOutlined","CaretDownIcon","AntdDropdown","Typography","_Fragment","Select"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant = SelectProps['variant'] | 'headlined'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a `Typography.Link` target (label + caret).\n * Ignores `variant` — the trigger is always a link.\n */\n trigger?: SummarizedSelectTrigger\n defaultOpen?: boolean\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n defaultOpen = false,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const antVariant = isHeadline ? 'borderless' : variant\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n inputRef.current?.focus({ cursor: 'end' })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n return filterOptions(options, searchValue)\n }, [searchValue, options])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n autoFocus\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search so antd rebuilds its option list per\n keystroke. Focusing the search input blurs the Select, antd\n starts a close, cancels it because focus stayed in the popup,\n and never clears its `lockOptions` flag -- a locked list keeps\n showing the options it had when the popup opened. */}\n <Fragment key={searchValue}>{menu}</Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary)] text-white hover:bg-[var(--j2-color-primary)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div className=\"bg-white rounded-lg shadow-md p-2 min-w-[240px]\">\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n autoFocus\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"regular\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx('inline-flex', rootClassName)}\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n open={isOpen}\n showSearch={false}\n style={{ width: measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]:\n variant !== 'underlined' && variant !== 'headlined',\n [styles.isActive]:\n multiple &&\n value.length > 0 &&\n variant !== 'underlined' &&\n variant !== 'headlined',\n [styles.headlinedSelect]: isHeadline,\n }),\n popup: { root: popupClassName },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.cjs","names":["useState","useRef","useMemo","Input","MagnifyingGlassIcon","Tag","cx","styles","Fragment","Spin","LoadingOutlined","CaretDownIcon","AntdDropdown","Typography","_Fragment","Select"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant =\n SelectProps['variant'] | 'headlined' | 'field'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n /**\n * Look of the `'select'` trigger.\n * - antd's own variants (`'outlined'`, `'borderless'`, ...): the filter-chip\n * look. It sizes to its label and turns into a filled pill once a\n * multiple select has values.\n * - `'headlined'`: a page-title select.\n * - `'field'`: a plain form field. It fills its container and keeps the\n * same look whatever is selected, so it lines up with the inputs and\n * selects around it in a form row.\n */\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a text target (label + caret), for\n * breadcrumbs and inline switchers. Semibold primary text with a duotone\n * caret; a consumer class such as `font-normal` still wins on weight.\n * Ignores `variant`.\n */\n trigger?: SummarizedSelectTrigger\n defaultOpen?: boolean\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n defaultOpen = false,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const isField = variant === 'field'\n const antVariant = isHeadline ? 'borderless' : isField ? 'outlined' : variant\n const isChip = !isField && variant !== 'underlined' && !isHeadline\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n // `preventScroll`: on first open the popup is still at its initial\n // spot when this runs, and a plain focus scrolls the page to it.\n inputRef.current?.focus({ cursor: 'end', preventScroll: true })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n return filterOptions(options, searchValue)\n }, [searchValue, options])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search so antd rebuilds its option list per\n keystroke. Focusing the search input blurs the Select, antd\n starts a close, cancels it because focus stayed in the popup,\n and never clears its `lockOptions` flag -- a locked list keeps\n showing the options it had when the popup opened. */}\n <Fragment key={searchValue}>{menu}</Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div className=\"bg-white rounded-lg shadow-md p-2 min-w-[240px]\">\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1.5\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"duotone\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx('inline-flex', styles.dropdownTrigger, rootClassName)}\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n open={isOpen}\n showSearch={false}\n style={{ width: isField ? '100%' : measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]: isChip,\n [styles.isActive]: isChip && multiple && value.length > 0,\n [styles.headlinedSelect]: isHeadline,\n [styles.fieldSelect]: isField,\n }),\n popup: { root: popupClassName },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -9,19 +9,31 @@ type GroupOption = {
|
|
|
9
9
|
options: Option[];
|
|
10
10
|
};
|
|
11
11
|
export type SelectOption = Option | GroupOption | OptionWithLogo;
|
|
12
|
-
export type SummarizedSelectVariant = SelectProps['variant'] | 'headlined';
|
|
12
|
+
export type SummarizedSelectVariant = SelectProps['variant'] | 'headlined' | 'field';
|
|
13
13
|
export type SummarizedSelectTrigger = 'select' | 'dropdown';
|
|
14
14
|
type BaseProps = Omit<SelectProps<string | string[], SelectOption>, 'mode' | 'value' | 'onChange' | 'variant'> & {
|
|
15
15
|
searchPlaceholder?: string;
|
|
16
16
|
formControlPlaceholder?: string;
|
|
17
17
|
rootClassName?: string;
|
|
18
18
|
popupClassName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Look of the `'select'` trigger.
|
|
21
|
+
* - antd's own variants (`'outlined'`, `'borderless'`, ...): the filter-chip
|
|
22
|
+
* look. It sizes to its label and turns into a filled pill once a
|
|
23
|
+
* multiple select has values.
|
|
24
|
+
* - `'headlined'`: a page-title select.
|
|
25
|
+
* - `'field'`: a plain form field. It fills its container and keeps the
|
|
26
|
+
* same look whatever is selected, so it lines up with the inputs and
|
|
27
|
+
* selects around it in a form row.
|
|
28
|
+
*/
|
|
19
29
|
variant?: SummarizedSelectVariant;
|
|
20
30
|
/**
|
|
21
31
|
* Shape of the control that opens the popup.
|
|
22
32
|
* - `'select'` (default): antd Select, styled by `variant`.
|
|
23
|
-
* - `'dropdown'`: antd Dropdown with a
|
|
24
|
-
*
|
|
33
|
+
* - `'dropdown'`: antd Dropdown with a text target (label + caret), for
|
|
34
|
+
* breadcrumbs and inline switchers. Semibold primary text with a duotone
|
|
35
|
+
* caret; a consumer class such as `font-normal` still wins on weight.
|
|
36
|
+
* Ignores `variant`.
|
|
25
37
|
*/
|
|
26
38
|
trigger?: SummarizedSelectTrigger;
|
|
27
39
|
defaultOpen?: boolean;
|
|
@@ -29,7 +29,9 @@ var filterOptions = (options, searchValue) => {
|
|
|
29
29
|
};
|
|
30
30
|
function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading, multiple, value, onChange, options, renderLabel, rootClassName, popupClassName, variant, trigger = "select", defaultOpen = false, ...props }) {
|
|
31
31
|
const isHeadline = variant === "headlined";
|
|
32
|
-
const
|
|
32
|
+
const isField = variant === "field";
|
|
33
|
+
const antVariant = isHeadline ? "borderless" : isField ? "outlined" : variant;
|
|
34
|
+
const isChip = !isField && variant !== "underlined" && !isHeadline;
|
|
33
35
|
const [searchValue, setSearchValue] = useState("");
|
|
34
36
|
const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0);
|
|
35
37
|
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
@@ -58,7 +60,10 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
58
60
|
if (focusTrigger > 0) requestAnimationFrame(() => {
|
|
59
61
|
requestAnimationFrame(() => {
|
|
60
62
|
setTimeout(() => {
|
|
61
|
-
inputRef.current?.focus({
|
|
63
|
+
inputRef.current?.focus({
|
|
64
|
+
cursor: "end",
|
|
65
|
+
preventScroll: true
|
|
66
|
+
});
|
|
62
67
|
}, 100);
|
|
63
68
|
});
|
|
64
69
|
});
|
|
@@ -146,7 +151,6 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
146
151
|
className: "mb-2 px-2 pb-2 border-b -mx-1 mt-1",
|
|
147
152
|
children: /* @__PURE__ */ jsx(Input, {
|
|
148
153
|
ref: inputRef,
|
|
149
|
-
autoFocus: true,
|
|
150
154
|
placeholder: searchPlaceholder || "Search...",
|
|
151
155
|
value: searchValue,
|
|
152
156
|
onChange: (e) => {
|
|
@@ -218,7 +222,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
218
222
|
role: "option",
|
|
219
223
|
"aria-selected": isSelected,
|
|
220
224
|
onClick: () => handleOptionClick(optionValue),
|
|
221
|
-
className: cx("px-3 py-1.5 rounded cursor-pointer text-sm", isSelected ? "bg-[var(--j2-color-primary)] text-
|
|
225
|
+
className: cx("px-3 py-1.5 rounded cursor-pointer text-sm", isSelected ? "bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]" : "hover:bg-[var(--j2-color-bg-hover)]"),
|
|
222
226
|
children: hasLogo ? /* @__PURE__ */ jsxs("div", {
|
|
223
227
|
className: "flex items-center gap-2",
|
|
224
228
|
children: [/* @__PURE__ */ jsx("div", {
|
|
@@ -243,7 +247,6 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
243
247
|
className: "pb-2 border-b border-j2-border-secondary",
|
|
244
248
|
children: /* @__PURE__ */ jsx(Input, {
|
|
245
249
|
ref: inputRef,
|
|
246
|
-
autoFocus: true,
|
|
247
250
|
placeholder: searchPlaceholder || "Search...",
|
|
248
251
|
value: searchValue,
|
|
249
252
|
onChange: (e) => {
|
|
@@ -308,13 +311,13 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
308
311
|
if (trigger === "dropdown") {
|
|
309
312
|
const hasSelection = multiple ? value.length > 0 : Boolean(value);
|
|
310
313
|
const triggerContent = /* @__PURE__ */ jsxs("span", {
|
|
311
|
-
className: "inline-flex items-center gap-1",
|
|
314
|
+
className: "inline-flex items-center gap-1.5",
|
|
312
315
|
children: [hasSelection ? displayText : formControlPlaceholder ?? "Select", loading ? /* @__PURE__ */ jsx(Spin, {
|
|
313
316
|
indicator: /* @__PURE__ */ jsx(LoadingOutlined, { spin: true }),
|
|
314
317
|
size: "small",
|
|
315
318
|
"data-testid": "loading-spinner"
|
|
316
319
|
}) : /* @__PURE__ */ jsx(CaretDownIcon, {
|
|
317
|
-
weight: "
|
|
320
|
+
weight: "duotone",
|
|
318
321
|
"data-testid": "caret-down"
|
|
319
322
|
})]
|
|
320
323
|
});
|
|
@@ -326,7 +329,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
326
329
|
popupRender: dropdownPopupRender,
|
|
327
330
|
children: /* @__PURE__ */ jsx(Typography.Link, {
|
|
328
331
|
disabled: props.disabled,
|
|
329
|
-
className: cx("inline-flex", rootClassName),
|
|
332
|
+
className: cx("inline-flex", SummarizedSelect_module_default.dropdownTrigger, rootClassName),
|
|
330
333
|
children: triggerContent
|
|
331
334
|
})
|
|
332
335
|
});
|
|
@@ -344,7 +347,7 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
344
347
|
}), /* @__PURE__ */ jsx(Select, {
|
|
345
348
|
open: isOpen,
|
|
346
349
|
showSearch: false,
|
|
347
|
-
style: { width: measuredWidth },
|
|
350
|
+
style: { width: isField ? "100%" : measuredWidth },
|
|
348
351
|
suffixIcon: loading ? /* @__PURE__ */ jsx(Spin, {
|
|
349
352
|
indicator: /* @__PURE__ */ jsx(LoadingOutlined, { spin: true }),
|
|
350
353
|
size: "small",
|
|
@@ -371,9 +374,10 @@ function SummarizedSelect({ searchPlaceholder, formControlPlaceholder, loading,
|
|
|
371
374
|
onOpenChange: handleOpenChange,
|
|
372
375
|
classNames: {
|
|
373
376
|
root: cx(rootClassName, SummarizedSelect_module_default.summarizedSelect, {
|
|
374
|
-
[SummarizedSelect_module_default.hemisphericSelect]:
|
|
375
|
-
[SummarizedSelect_module_default.isActive]: multiple && value.length > 0
|
|
376
|
-
[SummarizedSelect_module_default.headlinedSelect]: isHeadline
|
|
377
|
+
[SummarizedSelect_module_default.hemisphericSelect]: isChip,
|
|
378
|
+
[SummarizedSelect_module_default.isActive]: isChip && multiple && value.length > 0,
|
|
379
|
+
[SummarizedSelect_module_default.headlinedSelect]: isHeadline,
|
|
380
|
+
[SummarizedSelect_module_default.fieldSelect]: isField
|
|
377
381
|
}),
|
|
378
382
|
popup: { root: popupClassName }
|
|
379
383
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.js","names":["Tag","styles","AntdDropdown","_Fragment"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant = SelectProps['variant'] | 'headlined'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a `Typography.Link` target (label + caret).\n * Ignores `variant` — the trigger is always a link.\n */\n trigger?: SummarizedSelectTrigger\n defaultOpen?: boolean\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n defaultOpen = false,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const antVariant = isHeadline ? 'borderless' : variant\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n inputRef.current?.focus({ cursor: 'end' })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n return filterOptions(options, searchValue)\n }, [searchValue, options])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n autoFocus\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search so antd rebuilds its option list per\n keystroke. Focusing the search input blurs the Select, antd\n starts a close, cancels it because focus stayed in the popup,\n and never clears its `lockOptions` flag -- a locked list keeps\n showing the options it had when the popup opened. */}\n <Fragment key={searchValue}>{menu}</Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary)] text-white hover:bg-[var(--j2-color-primary)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div className=\"bg-white rounded-lg shadow-md p-2 min-w-[240px]\">\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n autoFocus\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"regular\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx('inline-flex', rootClassName)}\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n open={isOpen}\n showSearch={false}\n style={{ width: measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]:\n variant !== 'underlined' && variant !== 'headlined',\n [styles.isActive]:\n multiple &&\n value.length > 0 &&\n variant !== 'underlined' &&\n variant !== 'headlined',\n [styles.headlinedSelect]: isHeadline,\n }),\n popup: { root: popupClassName },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.js","names":["Tag","styles","AntdDropdown","_Fragment"],"sources":["../../../../src/components/select/SummarizedSelect.tsx"],"sourcesContent":["import {\n Dropdown as AntdDropdown,\n Select,\n Spin,\n Input,\n SelectProps,\n InputRef,\n Typography,\n} from 'antd'\nimport { DefaultOptionType } from 'antd/es/select'\nimport { Fragment, useState, useMemo, useRef, useEffect } from 'react'\nimport { LoadingOutlined } from '@ant-design/icons'\nimport { CaretDownIcon, MagnifyingGlassIcon } from '@phosphor-icons/react'\nimport { Tag } from '../tag'\nimport cx from 'classnames'\n\nimport styles from './SummarizedSelect.module.css'\n\ntype Option = DefaultOptionType\ntype OptionWithLogo = Option & {\n logo: React.ReactNode\n}\n\ntype GroupOption = {\n label: string\n options: Option[]\n}\n\nexport type SelectOption = Option | GroupOption | OptionWithLogo\n\nexport type SummarizedSelectVariant =\n SelectProps['variant'] | 'headlined' | 'field'\n\nexport type SummarizedSelectTrigger = 'select' | 'dropdown'\n\ntype BaseProps = Omit<\n SelectProps<string | string[], SelectOption>,\n 'mode' | 'value' | 'onChange' | 'variant'\n> & {\n searchPlaceholder?: string\n formControlPlaceholder?: string\n rootClassName?: string\n popupClassName?: string\n /**\n * Look of the `'select'` trigger.\n * - antd's own variants (`'outlined'`, `'borderless'`, ...): the filter-chip\n * look. It sizes to its label and turns into a filled pill once a\n * multiple select has values.\n * - `'headlined'`: a page-title select.\n * - `'field'`: a plain form field. It fills its container and keeps the\n * same look whatever is selected, so it lines up with the inputs and\n * selects around it in a form row.\n */\n variant?: SummarizedSelectVariant\n /**\n * Shape of the control that opens the popup.\n * - `'select'` (default): antd Select, styled by `variant`.\n * - `'dropdown'`: antd Dropdown with a text target (label + caret), for\n * breadcrumbs and inline switchers. Semibold primary text with a duotone\n * caret; a consumer class such as `font-normal` still wins on weight.\n * Ignores `variant`.\n */\n trigger?: SummarizedSelectTrigger\n defaultOpen?: boolean\n\n loading?: boolean\n}\n\ntype SingleProps = {\n multiple?: false\n renderLabel?: undefined\n value: string | undefined\n onChange: (newValue: string) => void\n}\n\ntype MultiProps = {\n multiple: true\n renderLabel: (count: number) => string\n value: string[]\n onChange: (newValue: string[]) => void\n}\n\nexport type Props = BaseProps & (SingleProps | MultiProps)\n\nconst isGroupOption = (option: SelectOption): option is GroupOption => {\n return 'options' in option\n}\n\nconst getAllOptions = (options: SelectOption[] | undefined): Option[] => {\n if (!options) return []\n\n return options.flatMap((option) =>\n isGroupOption(option) ? option.options : [option]\n )\n}\n\nconst filterOptions = (\n options: SelectOption[] | undefined,\n searchValue: string\n): SelectOption[] => {\n if (!options) return []\n if (!searchValue) return options\n\n return options\n .map((option) => {\n if (isGroupOption(option)) {\n const filteredSubOptions = option.options.filter((subOption) =>\n subOption.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n return filteredSubOptions.length > 0\n ? { ...option, options: filteredSubOptions }\n : null\n } else {\n return option.label\n ?.toString()\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n ? option\n : null\n }\n })\n .filter((option): option is SelectOption => option !== null)\n}\n\nexport function SummarizedSelect({\n searchPlaceholder,\n formControlPlaceholder,\n loading,\n multiple,\n value,\n onChange,\n options,\n renderLabel,\n rootClassName,\n popupClassName,\n variant,\n trigger = 'select',\n defaultOpen = false,\n ...props\n}: Props) {\n const isHeadline = variant === 'headlined'\n const isField = variant === 'field'\n const antVariant = isHeadline ? 'borderless' : isField ? 'outlined' : variant\n const isChip = !isField && variant !== 'underlined' && !isHeadline\n const [searchValue, setSearchValue] = useState('')\n const [focusTrigger, setFocusTrigger] = useState(defaultOpen ? 1 : 0)\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const inputRef = useRef<InputRef>(null)\n const measureSpanRef = useRef<HTMLSpanElement>(null)\n const [measuredWidth, setMeasuredWidth] = useState<number>()\n\n const displayText = useMemo(() => {\n if (multiple && value.length > 0) {\n return renderLabel(value.length)\n }\n if (!multiple && value) {\n const option = getAllOptions(options).find((opt) => opt.value === value)\n return option ? String(option.label) : String(value)\n }\n return formControlPlaceholder ?? ''\n }, [multiple, value, options, renderLabel, formControlPlaceholder])\n\n useEffect(() => {\n if (!measureSpanRef.current) return\n // padding (22px = 11px each side) + arrow (18px) + border (6px)\n setMeasuredWidth(Math.ceil(measureSpanRef.current.offsetWidth) + 46)\n }, [displayText])\n\n useEffect(() => {\n if (focusTrigger > 0) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setTimeout(() => {\n // `preventScroll`: on first open the popup is still at its initial\n // spot when this runs, and a plain focus scrolls the page to it.\n inputRef.current?.focus({ cursor: 'end', preventScroll: true })\n }, 100)\n })\n })\n }\n }, [focusTrigger])\n\n const filteredOptions = useMemo(() => {\n return filterOptions(options, searchValue)\n }, [searchValue, options])\n\n const flatFilteredOptions = useMemo(() => {\n return getAllOptions(filteredOptions)\n }, [filteredOptions])\n\n const allFlatOptions = useMemo(() => {\n return getAllOptions(options)\n }, [options])\n\n const handleTagClose = (removedValue: string) => {\n if (!multiple) return\n\n onChange(value.filter((x) => x !== removedValue))\n }\n\n const handleToggleAll = () => {\n if (!multiple) return\n\n const allFilteredValues = getAllOptions(filteredOptions).map(\n (opt) => opt.value as string\n )\n const someSelected = allFilteredValues.some((val) => value.includes(val))\n\n if (someSelected) {\n onChange(value.filter((val) => !allFilteredValues.includes(val)))\n }\n }\n\n const handleSelectFirstOption = () => {\n if (flatFilteredOptions.length === 0) return\n\n const firstOption = flatFilteredOptions[0]\n if (!firstOption) return\n\n const optionValue = firstOption.value as string\n\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleOptionClick = (optionValue: string) => {\n if (multiple) {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue))\n } else {\n onChange([...value, optionValue])\n }\n } else {\n onChange(optionValue)\n handleOpenChange(false)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n // Allow these navigation keys to bubble up to Select's native keyboard handler\n const navigationKeys = ['ArrowUp', 'ArrowDown']\n\n // Handle Enter - select first filtered option (custom behavior)\n if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n handleSelectFirstOption()\n return\n }\n\n // Handle Escape - close dropdown (custom behavior)\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n handleOpenChange(false)\n return\n }\n\n // For arrow keys, prevent cursor movement but allow propagation to Select\n if (navigationKeys.includes(e.key)) {\n e.preventDefault() // Prevents cursor from moving to start/end of input text\n // Do NOT call stopPropagation() - let event bubble to Select component\n return\n }\n\n // For all other keys (including Backspace), stop propagation\n // This prevents backspace from removing tags in multiple mode\n e.stopPropagation()\n }\n\n const optionRender: NonNullable<\n SelectProps<string | string[], SelectOption>['optionRender']\n > = (option) => {\n if ('logo' in option.data && option.data.logo) {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">{option.data.logo}</div>\n <span className=\"overflow-ellipsis overflow-hidden\">\n {option.label}\n </span>\n </div>\n )\n }\n return <div>{option.label}</div>\n }\n\n const popupRender = (menu: React.ReactElement) => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div>\n <div className=\"mb-2 px-2 pb-2 border-b -mx-1 mt-1\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n e.preventDefault()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 ? (\n <div className=\"px-2 pb-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((value) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={value}\n status=\"default\"\n closable\n onClose={() => handleTagClose(value)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(value)}\n >\n {valueToLabel(value)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n ) : null}\n <div\n className={cx(styles.menuContainer, 'rounded-lg', {\n [styles.headlinedMenuContainer]: isHeadline,\n [styles.menuContainerMultiple]: multiple,\n })}\n >\n {/* Keyed on the search so antd rebuilds its option list per\n keystroke. Focusing the search input blurs the Select, antd\n starts a close, cancels it because focus stayed in the popup,\n and never clears its `lockOptions` flag -- a locked list keeps\n showing the options it had when the popup opened. */}\n <Fragment key={searchValue}>{menu}</Fragment>\n </div>\n <div className=\"flex justify-between items-center\">\n {multiple && (\n <div className=\"w-full mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n aria-selected=\"false\"\n className={cx(\n 'ant-select-item ant-select-item-option w-full',\n styles.clearAllButton\n )}\n title=\"Clear all\"\n onClick={handleToggleAll}\n >\n <div className=\"ant-select-item-option-content text-center font-semibold\">\n Clear all\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n }\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open)\n if (open) {\n // Trigger focus by updating the counter\n setFocusTrigger((prev) => prev + 1)\n } else {\n setSearchValue('')\n }\n }\n\n const renderDropdownOptionRow = (option: Option) => {\n const optionValue = option.value as string\n const isSelected = multiple\n ? value.includes(optionValue)\n : value === optionValue\n const hasLogo = 'logo' in option && (option as OptionWithLogo).logo\n return (\n <div\n key={optionValue}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleOptionClick(optionValue)}\n className={cx(\n 'px-3 py-1.5 rounded cursor-pointer text-sm',\n isSelected\n ? 'bg-[var(--j2-color-primary-bg-hover)] font-semibold text-[var(--j2-color-primary)] hover:bg-[var(--j2-color-primary-bg-hover)]'\n : 'hover:bg-[var(--j2-color-bg-hover)]'\n )}\n >\n {hasLogo ? (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-4 shrink-0\">\n {(option as OptionWithLogo).logo}\n </div>\n <span className=\"overflow-hidden overflow-ellipsis\">\n {option.label}\n </span>\n </div>\n ) : (\n option.label\n )}\n </div>\n )\n }\n\n const dropdownPopupRender = () => {\n const valueToLabel = (val: string) => {\n const option = allFlatOptions.find((opt) => opt.value === val)\n return option ? (option.label as string) : val\n }\n\n return (\n <div className=\"bg-white rounded-lg shadow-md p-2 min-w-[240px]\">\n <div className=\"pb-2 border-b border-j2-border-secondary\">\n <Input\n ref={inputRef}\n key={focusTrigger}\n placeholder={searchPlaceholder || 'Search...'}\n value={searchValue}\n onChange={(e) => {\n setSearchValue(e.target.value)\n e.stopPropagation()\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n prefix={\n <MagnifyingGlassIcon\n size={16}\n className=\"text-j2-text-placeholder\"\n />\n }\n allowClear\n />\n </div>\n {multiple && value.length > 0 && (\n <div className=\"px-1 pt-2\">\n <div className=\"flex flex-wrap gap-y-1\">\n {(value as string[]).map((v) => (\n <Tag\n className=\"opacity-100 z-10 flex max-w-full\"\n key={v}\n status=\"default\"\n closable\n onClose={() => handleTagClose(v)}\n >\n <span\n className=\"overflow-ellipsis overflow-hidden\"\n title={valueToLabel(v)}\n >\n {valueToLabel(v)}\n </span>\n </Tag>\n ))}\n </div>\n </div>\n )}\n <div\n className=\"max-h-72 overflow-y-auto py-1\"\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n >\n {filteredOptions.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-[var(--j2-color-text-secondary)]\">\n No options found\n </div>\n ) : (\n filteredOptions.map((opt) => {\n if (isGroupOption(opt)) {\n return (\n <div key={`group-${opt.label}`}>\n <div className=\"px-3 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-[var(--j2-color-text-tertiary)]\">\n {opt.label}\n </div>\n {opt.options.map(renderDropdownOptionRow)}\n </div>\n )\n }\n return renderDropdownOptionRow(opt)\n })\n )}\n </div>\n {multiple && value.length > 0 && (\n <div className=\"mt-1 pt-1 border-t border-j2-border-secondary\">\n <div\n role=\"button\"\n aria-label=\"Clear all\"\n title=\"Clear all\"\n onClick={handleToggleAll}\n className={cx(\n 'text-center font-semibold text-sm py-1.5 rounded cursor-pointer',\n styles.clearAllButton\n )}\n >\n Clear all\n </div>\n </div>\n )}\n </div>\n )\n }\n\n if (trigger === 'dropdown') {\n const hasSelection = multiple ? value.length > 0 : Boolean(value)\n const triggerContent = (\n <span className=\"inline-flex items-center gap-1.5\">\n {hasSelection ? displayText : (formControlPlaceholder ?? 'Select')}\n {loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon weight=\"duotone\" data-testid=\"caret-down\" />\n )}\n </span>\n )\n\n return (\n <AntdDropdown\n open={isOpen}\n onOpenChange={handleOpenChange}\n trigger={['click']}\n disabled={props.disabled}\n popupRender={dropdownPopupRender}\n >\n <Typography.Link\n disabled={props.disabled}\n className={cx('inline-flex', styles.dropdownTrigger, rootClassName)}\n >\n {triggerContent}\n </Typography.Link>\n </AntdDropdown>\n )\n }\n\n return (\n <>\n <span\n ref={measureSpanRef}\n aria-hidden\n style={{\n position: 'absolute',\n visibility: 'hidden',\n whiteSpace: 'nowrap',\n fontSize: 'inherit',\n }}\n >\n {displayText}\n </span>\n <Select<string | string[], SelectOption>\n open={isOpen}\n showSearch={false}\n style={{ width: isField ? '100%' : measuredWidth }}\n suffixIcon={\n loading ? (\n <Spin\n indicator={<LoadingOutlined spin />}\n size=\"small\"\n data-testid=\"loading-spinner\"\n />\n ) : (\n <CaretDownIcon size={14} data-testid=\"caret-down\" />\n )\n }\n placeholder={formControlPlaceholder}\n mode={multiple ? 'multiple' : undefined}\n value={value}\n maxTagCount={0}\n maxTagPlaceholder={multiple ? () => renderLabel(value.length) : value}\n options={filteredOptions}\n onChange={(val) => {\n if (multiple) {\n if (Array.isArray(val)) {\n onChange(val)\n } else {\n throw new Error('Value should be an array in multiple mode')\n }\n } else {\n if (typeof val === 'string') {\n onChange(val)\n } else {\n throw new Error(\n 'Value should be a string in single selection mode'\n )\n }\n }\n }}\n popupRender={popupRender}\n optionRender={optionRender}\n onOpenChange={handleOpenChange}\n classNames={{\n root: cx(rootClassName, styles.summarizedSelect, {\n [styles.hemisphericSelect]: isChip,\n [styles.isActive]: isChip && multiple && value.length > 0,\n [styles.headlinedSelect]: isHeadline,\n [styles.fieldSelect]: isField,\n }),\n popup: { root: popupClassName },\n }}\n variant={antVariant}\n {...props}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
//#region src/components/select/SummarizedSelect.module.css
|
|
2
|
-
var hemisphericSelect = "
|
|
3
|
-
var summarizedSelect = "
|
|
4
|
-
var isActive = "
|
|
5
|
-
var menuContainer = "
|
|
6
|
-
var menuContainerMultiple = "
|
|
7
|
-
var headlinedSelect = "
|
|
8
|
-
var headlinedMenuContainer = "
|
|
9
|
-
var clearAllButton = "
|
|
2
|
+
var hemisphericSelect = "_hemisphericSelect_1jnt4_1";
|
|
3
|
+
var summarizedSelect = "_summarizedSelect_1jnt4_9";
|
|
4
|
+
var isActive = "_isActive_1jnt4_46";
|
|
5
|
+
var menuContainer = "_menuContainer_1jnt4_58";
|
|
6
|
+
var menuContainerMultiple = "_menuContainerMultiple_1jnt4_68";
|
|
7
|
+
var headlinedSelect = "_headlinedSelect_1jnt4_83";
|
|
8
|
+
var headlinedMenuContainer = "_headlinedMenuContainer_1jnt4_135";
|
|
9
|
+
var clearAllButton = "_clearAllButton_1jnt4_146";
|
|
10
|
+
var dropdownTrigger = "_dropdownTrigger_1jnt4_164";
|
|
11
|
+
var fieldSelect = "_fieldSelect_1jnt4_190";
|
|
10
12
|
var SummarizedSelect_module_default = {
|
|
11
13
|
hemisphericSelect,
|
|
12
14
|
summarizedSelect,
|
|
@@ -15,11 +17,15 @@ var SummarizedSelect_module_default = {
|
|
|
15
17
|
menuContainerMultiple,
|
|
16
18
|
headlinedSelect,
|
|
17
19
|
headlinedMenuContainer,
|
|
18
|
-
clearAllButton
|
|
20
|
+
clearAllButton,
|
|
21
|
+
dropdownTrigger,
|
|
22
|
+
fieldSelect
|
|
19
23
|
};
|
|
20
24
|
//#endregion
|
|
21
25
|
exports.clearAllButton = clearAllButton;
|
|
22
26
|
exports.default = SummarizedSelect_module_default;
|
|
27
|
+
exports.dropdownTrigger = dropdownTrigger;
|
|
28
|
+
exports.fieldSelect = fieldSelect;
|
|
23
29
|
exports.headlinedMenuContainer = headlinedMenuContainer;
|
|
24
30
|
exports.headlinedSelect = headlinedSelect;
|
|
25
31
|
exports.hemisphericSelect = hemisphericSelect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.module.css.cjs","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.module.css.cjs","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n\n/*\n * Dropdown trigger (`trigger=\"dropdown\"`)\n * Reads as emphasized text with an affordance, not as a link: semibold\n * primary text, no underline, and a fade on hover instead of a color shift.\n * Weight sits in the `components` layer so a consumer utility such as\n * `font-normal` on `rootClassName` still wins: Tailwind 4 emits utilities in\n * a later native layer, and Tailwind 3's are unlayered, which beats any layer.\n * Color stays unlayered, with `.ant-typography`, to beat antd's link color.\n */\n@layer components {\n .dropdownTrigger {\n font-weight: 600;\n }\n}\n\n.dropdownTrigger:global(.ant-typography),\n.dropdownTrigger:global(.ant-typography):hover,\n.dropdownTrigger:global(.ant-typography):focus {\n color: var(--j2-color-primary);\n text-decoration: none;\n}\n\n.dropdownTrigger:global(.ant-typography):hover {\n opacity: 0.7;\n}\n\n.dropdownTrigger:global(.ant-typography-disabled),\n.dropdownTrigger:global(.ant-typography-disabled):hover {\n color: var(--j2-color-text-disabled);\n opacity: 1;\n}\n\n/*\n * Field variant (`variant=\"field\"`)\n * A form field: full width, the field's own text color, a muted caret.\n */\n.fieldSelect :global(.ant-select-suffix) {\n color: var(--j2-color-text-secondary);\n}\n"],"mappings":""}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
//#region src/components/select/SummarizedSelect.module.css
|
|
2
|
-
var hemisphericSelect = "
|
|
3
|
-
var summarizedSelect = "
|
|
4
|
-
var isActive = "
|
|
5
|
-
var menuContainer = "
|
|
6
|
-
var menuContainerMultiple = "
|
|
7
|
-
var headlinedSelect = "
|
|
8
|
-
var headlinedMenuContainer = "
|
|
9
|
-
var clearAllButton = "
|
|
2
|
+
var hemisphericSelect = "_hemisphericSelect_1jnt4_1";
|
|
3
|
+
var summarizedSelect = "_summarizedSelect_1jnt4_9";
|
|
4
|
+
var isActive = "_isActive_1jnt4_46";
|
|
5
|
+
var menuContainer = "_menuContainer_1jnt4_58";
|
|
6
|
+
var menuContainerMultiple = "_menuContainerMultiple_1jnt4_68";
|
|
7
|
+
var headlinedSelect = "_headlinedSelect_1jnt4_83";
|
|
8
|
+
var headlinedMenuContainer = "_headlinedMenuContainer_1jnt4_135";
|
|
9
|
+
var clearAllButton = "_clearAllButton_1jnt4_146";
|
|
10
|
+
var dropdownTrigger = "_dropdownTrigger_1jnt4_164";
|
|
11
|
+
var fieldSelect = "_fieldSelect_1jnt4_190";
|
|
10
12
|
var SummarizedSelect_module_default = {
|
|
11
13
|
hemisphericSelect,
|
|
12
14
|
summarizedSelect,
|
|
@@ -15,9 +17,11 @@ var SummarizedSelect_module_default = {
|
|
|
15
17
|
menuContainerMultiple,
|
|
16
18
|
headlinedSelect,
|
|
17
19
|
headlinedMenuContainer,
|
|
18
|
-
clearAllButton
|
|
20
|
+
clearAllButton,
|
|
21
|
+
dropdownTrigger,
|
|
22
|
+
fieldSelect
|
|
19
23
|
};
|
|
20
24
|
//#endregion
|
|
21
|
-
export { clearAllButton, SummarizedSelect_module_default as default, headlinedMenuContainer, headlinedSelect, hemisphericSelect, isActive, menuContainer, menuContainerMultiple, summarizedSelect };
|
|
25
|
+
export { clearAllButton, SummarizedSelect_module_default as default, dropdownTrigger, fieldSelect, headlinedMenuContainer, headlinedSelect, hemisphericSelect, isActive, menuContainer, menuContainerMultiple, summarizedSelect };
|
|
22
26
|
|
|
23
27
|
//# sourceMappingURL=SummarizedSelect.module.css.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummarizedSelect.module.css.js","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"SummarizedSelect.module.css.js","names":[],"sources":["../../../../src/components/select/SummarizedSelect.module.css"],"sourcesContent":[".hemisphericSelect {\n border-radius: 9999px !important;\n\n :global(.ant-select-placeholder) {\n color: var(--j2-color-primary) !important;\n }\n}\n\n.summarizedSelect {\n :global(.ant-select-suffix) {\n color: var(--j2-color-primary);\n }\n\n :global(.ant-select-selection-item) {\n background: none !important;\n border: none !important;\n padding-inline-end: 0 !important;\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-selection-item-content) {\n margin-inline-end: 0 !important;\n }\n\n :global(.ant-select-content-item-rest) {\n max-width: 100%;\n }\n\n :global(.ant-select-content-item-suffix) {\n position: absolute;\n width: 1px;\n }\n\n /* antd 6 sizes a multiple select from its in-flow items. With the suffix\n (search input) and the placeholder both absolute, an empty select\n collapses to the font size (18px tall). Hold the row at one item's\n height, which the search input supplied before it was taken out of flow. */\n &:global(.ant-select-multiple) :global(.ant-select-content) {\n min-height: calc(\n var(--ant-select-multi-item-height, 24px) +\n var(--ant-select-internal_fixed_item_margin, 2px) * 2\n );\n }\n}\n\n.isActive {\n background: var(--j2-color-primary) !important;\n\n :global(.ant-select-selection-item-content) {\n color: white !important;\n }\n\n :global(.ant-select-suffix) {\n color: white !important;\n }\n}\n\n.menuContainer :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.menuContainerMultiple :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary-bg-hover) !important;\n}\n\n.menuContainerMultiple\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: inherit;\n}\n\n/*\n * Headlined variant styles\n * The select root owns its border and background in Ant Design 6.\n */\n\n.headlinedSelect:global(.ant-select):global(.ant-select-single) {\n font-size: var(--j2-font-size-heading-2);\n height: 40px;\n width: fit-content !important;\n}\n\n.headlinedSelect:global(.ant-select) {\n background: transparent;\n padding-left: 0;\n padding-right: 4px;\n font-size: var(--j2-font-size-heading-2);\n border-bottom: 1px solid transparent;\n border-radius: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-suffix) {\n height: 16px;\n width: 16px;\n right: 0;\n}\n\n.headlinedSelect:global(.ant-select) :global(.ant-select-content) {\n font-weight: 600;\n line-height: 1.3;\n}\n\n/* antd 6 outlines a focused borderless select through\n `:has(input:focus-visible)`, which a text input matches on a mouse click\n too, so every click boxed the headline. The underline below already marks\n focus. `!important` because antd's status variants of that rule reach\n (0,5,1) specificity. */\n.headlinedSelect:global(.ant-select) {\n outline: none !important;\n}\n\n/* Hover state - show underline */\n.headlinedSelect:global(.ant-select):hover {\n border-bottom-color: var(--j2-color-primary);\n}\n\n/* Open/focused state - keep underline and text color */\n.headlinedSelect:global(.ant-select-open),\n.headlinedSelect:global(.ant-select-focused) {\n border-bottom-color: var(--j2-color-primary);\n}\n\n.headlinedSelect:global(.ant-select-open) :global(.ant-select-content),\n.headlinedSelect:global(.ant-select-focused) :global(.ant-select-content) {\n color: inherit;\n}\n\n/* Headline dropdown styles - needs !important to override .menuContainer */\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected) {\n background: var(--j2-color-primary) !important;\n}\n\n.menuContainer.headlinedMenuContainer\n :global(.ant-select-item-option-selected)\n :global(.ant-select-item-option-content) {\n color: white;\n}\n\n.clearAllButton {\n color: var(--j2-color-primary);\n}\n\n.clearAllButton:hover {\n background-color: var(--j2-color-primary-bg-hover);\n}\n\n/*\n * Dropdown trigger (`trigger=\"dropdown\"`)\n * Reads as emphasized text with an affordance, not as a link: semibold\n * primary text, no underline, and a fade on hover instead of a color shift.\n * Weight sits in the `components` layer so a consumer utility such as\n * `font-normal` on `rootClassName` still wins: Tailwind 4 emits utilities in\n * a later native layer, and Tailwind 3's are unlayered, which beats any layer.\n * Color stays unlayered, with `.ant-typography`, to beat antd's link color.\n */\n@layer components {\n .dropdownTrigger {\n font-weight: 600;\n }\n}\n\n.dropdownTrigger:global(.ant-typography),\n.dropdownTrigger:global(.ant-typography):hover,\n.dropdownTrigger:global(.ant-typography):focus {\n color: var(--j2-color-primary);\n text-decoration: none;\n}\n\n.dropdownTrigger:global(.ant-typography):hover {\n opacity: 0.7;\n}\n\n.dropdownTrigger:global(.ant-typography-disabled),\n.dropdownTrigger:global(.ant-typography-disabled):hover {\n color: var(--j2-color-text-disabled);\n opacity: 1;\n}\n\n/*\n * Field variant (`variant=\"field\"`)\n * A form field: full width, the field's own text color, a muted caret.\n */\n.fieldSelect :global(.ant-select-suffix) {\n color: var(--j2-color-text-secondary);\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const require_runtime = require("../../../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_Dropdown = require("../dropdown/Dropdown.cjs");
|
|
3
|
+
const require_StatusPill_module = require("./StatusPill.module.css.cjs");
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
let classnames = require("classnames");
|
|
6
|
+
classnames = require_runtime.__toESM(classnames, 1);
|
|
7
|
+
//#region src/components/statusPill/StatusPill.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A small pill reporting a state, with an optional action at the end. Sits
|
|
10
|
+
* at button height (small), so it lines up with the buttons beside it.
|
|
11
|
+
*/
|
|
12
|
+
var StatusPill = ({ label, detail, tone = "default", onClick, menu, labelAriaLabel, trailing, disabled = false, className }) => {
|
|
13
|
+
const text = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [label, detail !== void 0 && detail !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
14
|
+
className: "font-semibold tabular-nums",
|
|
15
|
+
children: detail
|
|
16
|
+
})] });
|
|
17
|
+
const interactive = !disabled && (onClick || menu);
|
|
18
|
+
const labelButton = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
19
|
+
type: "button",
|
|
20
|
+
onClick: menu ? void 0 : onClick,
|
|
21
|
+
"aria-label": labelAriaLabel,
|
|
22
|
+
disabled,
|
|
23
|
+
className: require_StatusPill_module.default.label,
|
|
24
|
+
children: text
|
|
25
|
+
});
|
|
26
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
27
|
+
className: (0, classnames.default)(require_StatusPill_module.default.pill, tone === "warning" && require_StatusPill_module.default.warning, disabled && require_StatusPill_module.default.disabled, className),
|
|
28
|
+
children: [interactive ? menu ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Dropdown.Dropdown, {
|
|
29
|
+
menu,
|
|
30
|
+
trigger: ["click"],
|
|
31
|
+
children: labelButton
|
|
32
|
+
}) : labelButton : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33
|
+
className: require_StatusPill_module.default.static,
|
|
34
|
+
children: text
|
|
35
|
+
}), trailing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
36
|
+
className: "inline-flex items-center",
|
|
37
|
+
ref: (el) => {
|
|
38
|
+
el?.toggleAttribute("inert", disabled);
|
|
39
|
+
},
|
|
40
|
+
children: trailing
|
|
41
|
+
})]
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
exports.StatusPill = StatusPill;
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=StatusPill.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusPill.cjs","names":["_Fragment","styles","cx","Dropdown"],"sources":["../../../../src/components/statusPill/StatusPill.tsx"],"sourcesContent":["import cx from 'classnames'\nimport type { MenuProps } from 'antd'\n\nimport { Dropdown } from '../dropdown'\nimport styles from './StatusPill.module.css'\n\nexport type StatusPillProps = {\n /** What the pill reports, e.g. \"Draft saved\". */\n label: React.ReactNode\n /** Emphasized detail after the label, e.g. counts. */\n detail?: React.ReactNode\n /** `'warning'` tints the pill for something that needs attention. */\n tone?: 'default' | 'warning'\n /** Makes the label a button. */\n onClick?: () => void\n /** Makes the label open this menu instead. */\n menu?: MenuProps\n /** Accessible name for the label's button or menu trigger. */\n labelAriaLabel?: string\n /**\n * A control at the end: a small `Button` or a `Switch`. It sits beside\n * the label, not inside it, so its clicks never trigger the label.\n */\n trailing?: React.ReactNode\n /** Mutes the pill and makes it inert. */\n disabled?: boolean\n className?: string\n}\n\n/**\n * A small pill reporting a state, with an optional action at the end. Sits\n * at button height (small), so it lines up with the buttons beside it.\n */\nexport const StatusPill = ({\n label,\n detail,\n tone = 'default',\n onClick,\n menu,\n labelAriaLabel,\n trailing,\n disabled = false,\n className,\n}: StatusPillProps) => {\n const text = (\n <>\n {label}\n {detail !== undefined && detail !== null && (\n <span className=\"font-semibold tabular-nums\">{detail}</span>\n )}\n </>\n )\n\n const interactive = !disabled && (onClick || menu)\n const labelButton = (\n <button\n type=\"button\"\n onClick={menu ? undefined : onClick}\n aria-label={labelAriaLabel}\n disabled={disabled}\n className={styles.label}\n >\n {text}\n </button>\n )\n\n return (\n <span\n className={cx(\n styles.pill,\n tone === 'warning' && styles.warning,\n disabled && styles.disabled,\n className\n )}\n >\n {interactive ? (\n menu ? (\n <Dropdown menu={menu} trigger={['click']}>\n {labelButton}\n </Dropdown>\n ) : (\n labelButton\n )\n ) : (\n <span className={styles.static}>{text}</span>\n )}\n {trailing && (\n <span\n className=\"inline-flex items-center\"\n // `pointer-events: none` stops the mouse but not the keyboard; inert\n // takes a disabled pill's control out of focus and the a11y tree.\n // Set as an attribute so it works on React 18 and 19 alike.\n ref={(el) => {\n el?.toggleAttribute('inert', disabled)\n }}\n >\n {trailing}\n </span>\n )}\n </span>\n )\n}\n"],"mappings":";;;;;;;;;;;AAiCA,IAAa,cAAc,EACzB,OACA,QACA,OAAO,WACP,SACA,MACA,gBACA,UACA,WAAW,OACX,gBACqB;CACrB,MAAM,OACJ,iBAAA,GAAA,kBAAA,KAAA,CAAAA,kBAAAA,UAAA,EAAA,UAAA,CACG,OACA,WAAW,KAAA,KAAa,WAAW,QAClC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;EAAM,WAAU;EAA8B,UAAA;CAAa,CAAA,CAE7D,EAAA,CAAA;CAGJ,MAAM,cAAc,CAAC,aAAa,WAAW;CAC7C,MAAM,cACJ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;EACE,MAAK;EACL,SAAS,OAAO,KAAA,IAAY;EAC5B,cAAY;EACF;EACV,WAAWC,0BAAAA,QAAO;EAEjB,UAAA;CACK,CAAA;CAGV,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;EACE,YAAA,GAAWC,WAAAA,QAAAA,CACTD,0BAAAA,QAAO,MACP,SAAS,aAAaA,0BAAAA,QAAO,SAC7B,YAAYA,0BAAAA,QAAO,UACnB,SACF;EANF,UAAA,CAQG,cACC,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACE,iBAAAA,UAAD;GAAgB;GAAM,SAAS,CAAC,OAAO;GACpC,UAAA;EACO,CAAA,IAEV,cAGF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,WAAWF,0BAAAA,QAAO;GAAS,UAAA;EAAW,CAAA,GAE7C,YACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GACE,WAAU;GAIV,MAAM,OAAO;IACX,IAAI,gBAAgB,SAAS,QAAQ;GACvC;GAEC,UAAA;EACG,CAAA,CAEJ;;AAEV"}
|