@keboola/design 11.4.0 → 11.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/AGENTS.md +198 -7
- package/CHANGELOG.md +383 -0
- package/COMPONENT-API.md +73 -52
- package/dist/{AIKit-DDg5DBCG.js → AIKit-BExvt9pt.js} +390 -70
- package/dist/AIKit-BExvt9pt.js.map +1 -0
- package/dist/{Alert-DHJFrWnS.js → Alert-Ba5b2YPq.js} +2 -2
- package/dist/{Alert-DHJFrWnS.js.map → Alert-Ba5b2YPq.js.map} +1 -1
- package/dist/{Badge-Ch26CXoP.js → Badge-D0pXdekt.js} +2 -2
- package/dist/Badge-D0pXdekt.js.map +1 -0
- package/dist/{BrandEditor-Go7w8Zj2.js → BrandEditor-CSANsxUz.js} +6 -6
- package/dist/{BrandEditor-Go7w8Zj2.js.map → BrandEditor-CSANsxUz.js.map} +1 -1
- package/dist/{BrandLogo-Dmi7jo21.js → BrandLogo-CoKBk4MI.js} +4 -4
- package/dist/BrandLogo-CoKBk4MI.js.map +1 -0
- package/dist/{Breadcrumb-uEkM6adI.js → Breadcrumb-g_xn_-Nf.js} +2 -2
- package/dist/{Breadcrumb-uEkM6adI.js.map → Breadcrumb-g_xn_-Nf.js.map} +1 -1
- package/dist/{Checkbox-fC0BuO2B.js → Checkbox-CUIn2jap.js} +2 -2
- package/dist/{Checkbox-fC0BuO2B.js.map → Checkbox-CUIn2jap.js.map} +1 -1
- package/dist/{Clipboard-ChPdiUy3.js → Clipboard-BTW6C-b_.js} +2 -2
- package/dist/{Clipboard-ChPdiUy3.js.map → Clipboard-BTW6C-b_.js.map} +1 -1
- package/dist/{ClipboardButton-D9pDjgkB.js → ClipboardButton-CwZJdRaz.js} +2 -2
- package/dist/{ClipboardButton-D9pDjgkB.js.map → ClipboardButton-CwZJdRaz.js.map} +1 -1
- package/dist/{CodeEditor-Cxy3HnKH.js → CodeEditor-C9zy7PxK.js} +6 -6
- package/dist/{CodeEditor-Cxy3HnKH.js.map → CodeEditor-C9zy7PxK.js.map} +1 -1
- package/dist/{ColorInput-Bxj-1eLT.js → ColorInput-BZV-u_94.js} +3 -3
- package/dist/{ColorInput-Bxj-1eLT.js.map → ColorInput-BZV-u_94.js.map} +1 -1
- package/dist/{Combobox-Cs_1pj2q.js → Combobox-BfIfaVMA.js} +273 -104
- package/dist/Combobox-BfIfaVMA.js.map +1 -0
- package/dist/{Command-B7ML9YMv.js → Command-Bfa1kpbt.js} +2 -2
- package/dist/{Command-B7ML9YMv.js.map → Command-Bfa1kpbt.js.map} +1 -1
- package/dist/{CopyField-BO_sh-HO.js → CopyField-DpT0Ngz1.js} +2 -2
- package/dist/{CopyField-BO_sh-HO.js.map → CopyField-DpT0Ngz1.js.map} +1 -1
- package/dist/{DateInput-ZdaMQo5i.js → DateInput-DiEd5uCL.js} +3 -3
- package/dist/{DateInput-ZdaMQo5i.js.map → DateInput-DiEd5uCL.js.map} +1 -1
- package/dist/{DateRangeInput-DkvNh_sT.js → DateRangeInput-DPfVYchl.js} +3 -3
- package/dist/{DateRangeInput-DkvNh_sT.js.map → DateRangeInput-DPfVYchl.js.map} +1 -1
- package/dist/DiagramSource-C5_d8Gdj.js +11 -0
- package/dist/DiagramSource-C5_d8Gdj.js.map +1 -0
- package/dist/{FieldItem-CCd9-xnp.js → FieldItem-B7XMmZSz.js} +3 -3
- package/dist/{FieldItem-CCd9-xnp.js.map → FieldItem-B7XMmZSz.js.map} +1 -1
- package/dist/{Form-k6PH-em3.js → Form-CsttTHn4.js} +7 -7
- package/dist/Form-CsttTHn4.js.map +1 -0
- package/dist/{FormGroup-DbcDtrgU.js → FormGroup-DHvTFdno.js} +3 -3
- package/dist/{FormGroup-DbcDtrgU.js.map → FormGroup-DHvTFdno.js.map} +1 -1
- package/dist/{FullScreenModal-BvPuYibe.js → FullScreenModal-CN9nAs72.js} +50 -2
- package/dist/FullScreenModal-CN9nAs72.js.map +1 -0
- package/dist/{InputGroup-BnLHY0eq.js → InputGroup-DcZRlVnN.js} +22 -14
- package/dist/InputGroup-DcZRlVnN.js.map +1 -0
- package/dist/{Kbd-CvSM3D3-.js → Kbd-Cvvt91Q8.js} +14 -4
- package/dist/Kbd-Cvvt91Q8.js.map +1 -0
- package/dist/{MermaidDiagram-WkonYErO.js → MermaidDiagram-DSI7xMu2.js} +21 -19
- package/dist/MermaidDiagram-DSI7xMu2.js.map +1 -0
- package/dist/{MultiActionButtonGroup-CxWH7yWK.js → MultiActionButtonGroup-DokHbPgM.js} +2 -2
- package/dist/{MultiActionButtonGroup-CxWH7yWK.js.map → MultiActionButtonGroup-DokHbPgM.js.map} +1 -1
- package/dist/{Navbar-B2UsolVU.js → Navbar-Liy1TPI7.js} +6 -6
- package/dist/{Navbar-B2UsolVU.js.map → Navbar-Liy1TPI7.js.map} +1 -1
- package/dist/PageHeader-Q3IpCnQd.js.map +1 -1
- package/dist/{PageToolbar-DnbFt14Q.js → PageToolbar-DExqEYGl.js} +2 -2
- package/dist/{PageToolbar-DnbFt14Q.js.map → PageToolbar-DExqEYGl.js.map} +1 -1
- package/dist/{Popconfirm-CILjmzKI.js → Popconfirm-5pBzT_HQ.js} +10 -11
- package/dist/{Popconfirm-CILjmzKI.js.map → Popconfirm-5pBzT_HQ.js.map} +1 -1
- package/dist/{RadioGroup-XFzFd1ti.js → RadioGroup-DXPbSj8P.js} +2 -2
- package/dist/{RadioGroup-XFzFd1ti.js.map → RadioGroup-DXPbSj8P.js.map} +1 -1
- package/dist/{Search-4Bxtt8hS.js → Search-5uQAiNIP.js} +2 -2
- package/dist/{Search-4Bxtt8hS.js.map → Search-5uQAiNIP.js.map} +1 -1
- package/dist/{SearchInput-f_oY9T4Z.js → SearchInput-D4UgAXJK.js} +3 -3
- package/dist/{SearchInput-f_oY9T4Z.js.map → SearchInput-D4UgAXJK.js.map} +1 -1
- package/dist/{SectionNav-BpJlisbT.js → SectionNav-OkKCjSA-.js} +3 -3
- package/dist/{SectionNav-BpJlisbT.js.map → SectionNav-OkKCjSA-.js.map} +1 -1
- package/dist/{Select-DpcgKqKB.js → Select-DV3Hak_l.js} +3 -4
- package/dist/Select-DV3Hak_l.js.map +1 -0
- package/dist/{Sidebar-Cm6I4dE1.js → Sidebar-D3cY1kha.js} +44 -20
- package/dist/Sidebar-D3cY1kha.js.map +1 -0
- package/dist/{Slider-pPC_3gz9.js → Slider-CRf-bB4y.js} +2 -2
- package/dist/{Slider-pPC_3gz9.js.map → Slider-CRf-bB4y.js.map} +1 -1
- package/dist/{Switch-ChfPKcTE.js → Switch-B0WdGSjz.js} +7 -7
- package/dist/{Switch-ChfPKcTE.js.map → Switch-B0WdGSjz.js.map} +1 -1
- package/dist/{TextInput-DHM6dHmn.js → TextInput-DH5SkbsE.js} +3 -3
- package/dist/{TextInput-DHM6dHmn.js.map → TextInput-DH5SkbsE.js.map} +1 -1
- package/dist/{ThemeProvider-DrQJtzpd.js → ThemeProvider-2RMdVGxO.js} +17 -12
- package/dist/{ThemeProvider-DrQJtzpd.js.map → ThemeProvider-2RMdVGxO.js.map} +1 -1
- package/dist/{Timeline-6btyJl4D.js → Timeline-BG5Xogxh.js} +11 -11
- package/dist/{Timeline-6btyJl4D.js.map → Timeline-BG5Xogxh.js.map} +1 -1
- package/dist/{Workbench-BzE-Vvd9.js → Workbench-UR2FBC7I.js} +3 -1
- package/dist/Workbench-UR2FBC7I.js.map +1 -0
- package/dist/{ZoomableSvg-BWnDkR61.js → ZoomableSvg-pooPb1Cu.js} +3 -3
- package/dist/{ZoomableSvg-BWnDkR61.js.map → ZoomableSvg-pooPb1Cu.js.map} +1 -1
- package/dist/editors.js +4 -4
- package/dist/flint.js +136 -9
- package/dist/flint.js.map +1 -1
- package/dist/index.d.ts +801 -324
- package/dist/index.js +41 -40
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/AuthLayout.js +118 -0
- package/dist/internal/blocks/AuthLayout.js.map +1 -0
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.js +1 -1
- package/dist/internal/blocks/Command.js +1 -1
- package/dist/internal/blocks/CopyField.js +1 -1
- package/dist/internal/blocks/DateInput.js +1 -1
- package/dist/internal/blocks/DateRangeInput.js +1 -1
- package/dist/internal/blocks/ExportMenu.js +1 -1
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
- package/dist/internal/blocks/Form.js +1 -1
- package/dist/internal/blocks/FormGroup.js +1 -1
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
- package/dist/internal/blocks/MultiCombobox.js +107 -48
- package/dist/internal/blocks/MultiCombobox.js.map +1 -1
- package/dist/internal/blocks/NumberInput.js +1 -1
- package/dist/internal/blocks/PageToolbar.js +1 -1
- package/dist/internal/blocks/PasswordInput.js +2 -2
- package/dist/internal/blocks/SearchInput.js +1 -1
- package/dist/internal/blocks/SearchInputWithNavigation.js +2 -2
- package/dist/internal/blocks/SectionNav.js +1 -1
- package/dist/internal/blocks/TextInput.js +1 -1
- package/dist/internal/blocks/Textarea.js +1 -1
- package/dist/internal/blocks/TimeInput.js +2 -2
- package/dist/internal/components/Alert.js +1 -1
- package/dist/internal/components/Avatar.js +1 -1
- package/dist/internal/components/Badge.js +1 -1
- package/dist/internal/components/BrandLogo.js +1 -1
- package/dist/internal/components/Breadcrumb.js +1 -1
- package/dist/internal/components/Checkbox.js +1 -1
- package/dist/internal/components/Clipboard.js +1 -1
- package/dist/internal/components/CollapsiblePanel.js +1 -1
- package/dist/internal/components/Combobox.js +2 -2
- package/dist/internal/components/FullScreenModal.js +1 -1
- package/dist/internal/components/InputGroup.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/Navbar.js +1 -1
- package/dist/internal/components/Popconfirm.js +1 -1
- package/dist/internal/components/Progress.js +3 -1
- package/dist/internal/components/Progress.js.map +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Select.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/Switch.js +1 -1
- package/dist/internal/components/ThemeProvider.js +1 -1
- package/dist/internal/components/Timeline.js +1 -1
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +1 -1
- package/dist/internal/components/Workbench.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/utils.js +2 -2
- package/dist/markdown-editor.js +29 -23
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +22 -23
- package/dist/rjsf.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/{svgTransforms-C9njt92h.js → svgTransforms-CJAYPk7o.js} +2 -10
- package/dist/svgTransforms-CJAYPk7o.js.map +1 -0
- package/dist/testing.js +1 -1
- package/dist/{useColorSchemeState-klihG9-i.js → themeScopeContext-D7fSyb06.js} +16 -3
- package/dist/themeScopeContext-D7fSyb06.js.map +1 -0
- package/dist/{themeTokens-D70HeNVF.js → themeTokens-qP1-55O7.js} +37 -10
- package/dist/themeTokens-qP1-55O7.js.map +1 -0
- package/dist/{utils-B5Z52hYs.js → utils-DSvrhU8E.js} +6 -2
- package/dist/{utils-B5Z52hYs.js.map → utils-DSvrhU8E.js.map} +1 -1
- package/dist/vega.d.ts +1 -1
- package/dist/vega.js +3 -3
- package/dist/vega.js.map +1 -1
- package/dist/{vegaTheme-DfoEQhOy.js → vegaTheme-CSvFEMBl.js} +6 -6
- package/dist/vegaTheme-CSvFEMBl.js.map +1 -0
- package/package.json +11 -9
- package/src/styles.css +3 -0
- package/dist/AIKit-DDg5DBCG.js.map +0 -1
- package/dist/Badge-Ch26CXoP.js.map +0 -1
- package/dist/BrandLogo-Dmi7jo21.js.map +0 -1
- package/dist/Combobox-Cs_1pj2q.js.map +0 -1
- package/dist/Form-k6PH-em3.js.map +0 -1
- package/dist/FullScreenModal-BvPuYibe.js.map +0 -1
- package/dist/InputGroup-BnLHY0eq.js.map +0 -1
- package/dist/Kbd-CvSM3D3-.js.map +0 -1
- package/dist/MermaidDiagram-WkonYErO.js.map +0 -1
- package/dist/Select-DpcgKqKB.js.map +0 -1
- package/dist/Sidebar-Cm6I4dE1.js.map +0 -1
- package/dist/Workbench-BzE-Vvd9.js.map +0 -1
- package/dist/svgTransforms-C9njt92h.js.map +0 -1
- package/dist/themeTokens-D70HeNVF.js.map +0 -1
- package/dist/useColorSchemeState-klihG9-i.js.map +0 -1
- package/dist/vegaTheme-DfoEQhOy.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Search-4Bxtt8hS.js","names":["SearchIcon"],"sources":["../src/components/Search/ClearButton.tsx","../src/components/Search/styles.ts","../src/components/Search/utils.ts","../src/components/Search/Search.tsx","../src/components/Search/SearchForm.tsx"],"sourcesContent":["import type { MouseEventHandler } from 'react';\n\nimport { X } from '../../icons';\nimport { cn } from '../../utils';\n\ntype Props = {\n onClick: MouseEventHandler<HTMLButtonElement>;\n testId?: string;\n};\n\nexport const ClearButton = ({ onClick, testId }: Props) => {\n // Prevent default, as we do not want to lose input focus.\n const handleMouseDown: MouseEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n tabIndex={-1} // clear button should not be focusable\n onMouseDown={handleMouseDown}\n className={cn(\n // reset\n 'tw:border-none',\n 'tw:bg-transparent',\n 'tw:p-0',\n\n // positioning\n 'tw:flex',\n 'tw:items-center',\n\n 'tw:cursor-pointer',\n 'tw:text-muted-foreground',\n 'tw:hover:text-foreground',\n )}\n data-testid={testId}\n >\n <X className=\"tw:size-4\" />\n </button>\n );\n};\n","import { cva } from 'class-variance-authority';\n\nexport const searchWrapperVariants = cva(\n [\n // positioning\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2.5',\n\n // base\n 'tw:text-card-foreground',\n 'tw:transition-all',\n 'tw:font-sans',\n\n // readonly — `secondary` over `muted`, which is too close to the `card` fill to\n // read as non-editable in either scheme\n 'tw:has-[input[readonly]]:bg-secondary',\n 'tw:has-[input[readonly]]:focus-within:ring-0',\n 'tw:has-[input[readonly]]:outline-0',\n\n // disabled\n 'tw:disabled:opacity-40',\n\n // default input padding (was sizing.default)\n 'tw:[&>input]:py-[15px]',\n ],\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: [\n 'tw:rounded-lg',\n 'tw:px-5',\n 'tw:bg-card',\n 'tw:shadow-raised',\n // outline\n 'tw:outline',\n 'tw:outline-1',\n 'tw:outline-transparent',\n // focus\n 'tw:has-[input:focus]:outline-1',\n 'tw:has-[input:focus]:ring-4',\n 'tw:has-[input:focus]:outline-ring',\n 'tw:has-[input:focus]:ring-ring/30',\n ],\n ai: [\n 'tailwindcss-preflight',\n 'tw:relative',\n 'tw:rounded-card',\n 'tw:px-4',\n 'tw:cursor-text',\n 'tw:border-2',\n 'tw:border-transparent',\n 'tw:bg-gradient-to-br',\n 'tw:from-secondary-600',\n 'tw:to-purple-600',\n 'tw:bg-origin-border',\n // Floods the interior so the gradient shows only in the 2px border box.\n 'tw:shadow-[inset_0_100vw_rgb(var(--card))]',\n // focus\n 'tw:has-[input:focus]:ring-4',\n 'tw:has-[input:focus]:ring-ring/30',\n ],\n },\n },\n },\n);\n\nexport const searchInputClassnames = [\n // reset\n 'tw:border-none',\n 'tw:bg-transparent',\n 'tw:outline-hidden',\n 'tw:w-full',\n 'tw:p-0',\n\n // base\n 'tw:text-base',\n 'tw:leading-6',\n 'tw:font-normal',\n 'tw:font-sans',\n\n // placeholder\n 'tw:placeholder:text-muted-foreground',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n].join(' ');\n","import { createPrefixedString } from '../../utils';\n\nexport const genSearchTestId = (prefix: string = '') => {\n const ps = createPrefixedString(prefix);\n return {\n toString: () => prefix,\n wrapper: ps`search-wrapper`,\n input: ps`search-input`,\n clearButton: ps`search-clear-button`,\n };\n};\n","import { useEffect, useMemo, useState } from 'react';\nimport type {\n ChangeEvent,\n ChangeEventHandler,\n ComponentProps,\n FocusEvent,\n FocusEventHandler,\n MouseEvent,\n MouseEventHandler,\n ReactNode,\n} from 'react';\n\nimport { Search as SearchIcon, Sparkles } from '../../icons';\nimport { cn, debounce, noop } from '../../utils';\n\nimport { ClearButton } from './ClearButton';\nimport { searchInputClassnames, searchWrapperVariants } from './styles';\nimport { genSearchTestId } from './utils';\n\ntype SearchChangeEventHandler = (\n value: string,\n event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLButtonElement>,\n) => void;\n\ntype SearchBlurEventHandler = (value: string, event: FocusEvent<HTMLInputElement, Element>) => void;\n\ntype Props = {\n suffix?: ReactNode;\n disableDebounce?: boolean;\n debounceDelay?: number;\n onChange?: SearchChangeEventHandler;\n onBlur?: SearchBlurEventHandler;\n value?: string | null;\n defaultValue?: string | null;\n testId?: string;\n onClear?: () => void;\n variant?: 'default' | 'ai';\n} & Omit<\n ComponentProps<'input'>,\n 'type' | 'onBlur' | 'onChange' | 'value' | 'defaultValue' | 'prefix' | 'suffix'\n>;\n\n/**\n * @deprecated Use `SearchInput` instead. `Search` is kept only for the legacy (non-sidebar) layout.\n */\nexport const Search = ({\n ref,\n suffix,\n className,\n onBlur,\n onChange = noop,\n disabled = false,\n readOnly = false,\n disableDebounce = false,\n debounceDelay = 300,\n value: externalValue,\n defaultValue,\n testId: prefixTestId = '',\n placeholder = 'Search',\n onClear,\n variant = 'default',\n ...rest\n}: Props) => {\n const [internalValue, setInternalValue] = useState(() =>\n externalValue != null ? externalValue : defaultValue,\n );\n const hasValue = internalValue !== '';\n\n const isClearButtonVisible = hasValue && !disabled && !readOnly;\n const testId = genSearchTestId(prefixTestId);\n\n const debouncedOnChange = useMemo(\n () => (disableDebounce ? onChange : debounce(onChange, debounceDelay)),\n [disableDebounce, debounceDelay, onChange],\n );\n\n useEffect(() => {\n if (externalValue == null) return; // uncontrolled state\n // oxlint-disable-next-line react-x/set-state-in-effect\n setInternalValue(externalValue);\n }, [externalValue]);\n\n const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n const currentValue = event.target.value;\n setInternalValue(currentValue);\n debouncedOnChange(currentValue, event);\n };\n\n const handleBlur: FocusEventHandler<HTMLInputElement> = (event) => {\n const currentValue = event.target.value;\n setInternalValue(currentValue);\n onBlur?.(currentValue, event);\n };\n\n const handleClear: MouseEventHandler<HTMLButtonElement> = (event) => {\n setInternalValue('');\n onChange?.('', event);\n onClear?.();\n };\n\n // Clicking anywhere in the field that isn't an interactive control (the leading icon,\n // the empty chrome) focuses the input — the whole pill acts as one click target.\n const handleWrapperMouseDown: MouseEventHandler<HTMLDivElement> = (event) => {\n if (disabled || readOnly) return;\n if ((event.target as HTMLElement).closest('button, a, input, textarea, [role=\"button\"]')) {\n return;\n }\n event.preventDefault();\n event.currentTarget.querySelector('input')?.focus();\n };\n\n return (\n // Mouse-only convenience: clicking the chrome focuses the input. The input itself is the\n // real interactive/focusable target, so no extra role or key handler is needed here.\n // oxlint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n className={cn(\n searchWrapperVariants({ variant }),\n {\n 'tw:cursor-not-allowed tw:opacity-40': disabled,\n },\n className,\n )}\n data-testid={testId.wrapper}\n onMouseDown={handleWrapperMouseDown}\n >\n {variant === 'ai' ? (\n <Sparkles className=\"tw:size-4 tw:shrink-0 tw:[&_*]:stroke-aigradient-600\" />\n ) : (\n <SearchIcon className=\"tw:size-4 tw:shrink-0 tw:text-neutral-400\" />\n )}\n\n <input\n {...rest}\n ref={ref}\n placeholder={placeholder}\n data-testid={testId.input}\n type=\"text\"\n value={internalValue ?? ''}\n onChange={handleChange}\n onBlur={handleBlur}\n className={searchInputClassnames}\n disabled={disabled}\n readOnly={readOnly}\n />\n\n {isClearButtonVisible && <ClearButton onClick={handleClear} testId={testId.clearButton} />}\n\n {suffix}\n </div>\n );\n};\n","import type { ComponentProps, FormEventHandler } from 'react';\n\nimport { Search } from './Search';\n\ntype Props = {\n onSubmit: (value: string) => void;\n} & Omit<ComponentProps<typeof Search>, 'onClear' | 'onBlur' | 'onSubmit'>;\n\nexport const SearchForm = ({ ref, onSubmit, name = 'search-field', ...props }: Props) => {\n const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {\n event.preventDefault();\n const searchEl = event.currentTarget.elements.namedItem(name) as HTMLInputElement;\n onSubmit(searchEl.value);\n };\n\n const onClear = () => {\n onSubmit('');\n };\n\n return (\n <form onSubmit={handleSubmit}>\n <Search\n {...props}\n ref={ref}\n onClear={onClear}\n name={name}\n // Debounce has no meaning when we use submit, which is triggered by pressing enter.\n disableDebounce\n />\n </form>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Search-5uQAiNIP.js","names":["SearchIcon"],"sources":["../src/components/Search/ClearButton.tsx","../src/components/Search/styles.ts","../src/components/Search/utils.ts","../src/components/Search/Search.tsx","../src/components/Search/SearchForm.tsx"],"sourcesContent":["import type { MouseEventHandler } from 'react';\n\nimport { X } from '../../icons';\nimport { cn } from '../../utils';\n\ntype Props = {\n onClick: MouseEventHandler<HTMLButtonElement>;\n testId?: string;\n};\n\nexport const ClearButton = ({ onClick, testId }: Props) => {\n // Prevent default, as we do not want to lose input focus.\n const handleMouseDown: MouseEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n tabIndex={-1} // clear button should not be focusable\n onMouseDown={handleMouseDown}\n className={cn(\n // reset\n 'tw:border-none',\n 'tw:bg-transparent',\n 'tw:p-0',\n\n // positioning\n 'tw:flex',\n 'tw:items-center',\n\n 'tw:cursor-pointer',\n 'tw:text-muted-foreground',\n 'tw:hover:text-foreground',\n )}\n data-testid={testId}\n >\n <X className=\"tw:size-4\" />\n </button>\n );\n};\n","import { cva } from 'class-variance-authority';\n\nexport const searchWrapperVariants = cva(\n [\n // positioning\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2.5',\n\n // base\n 'tw:text-card-foreground',\n 'tw:transition-all',\n 'tw:font-sans',\n\n // readonly — `secondary` over `muted`, which is too close to the `card` fill to\n // read as non-editable in either scheme\n 'tw:has-[input[readonly]]:bg-secondary',\n 'tw:has-[input[readonly]]:focus-within:ring-0',\n 'tw:has-[input[readonly]]:outline-0',\n\n // disabled\n 'tw:disabled:opacity-40',\n\n // default input padding (was sizing.default)\n 'tw:[&>input]:py-[15px]',\n ],\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: [\n 'tw:rounded-lg',\n 'tw:px-5',\n 'tw:bg-card',\n 'tw:shadow-raised',\n // outline\n 'tw:outline',\n 'tw:outline-1',\n 'tw:outline-transparent',\n // focus\n 'tw:has-[input:focus]:outline-1',\n 'tw:has-[input:focus]:ring-4',\n 'tw:has-[input:focus]:outline-ring',\n 'tw:has-[input:focus]:ring-ring/30',\n ],\n ai: [\n 'tailwindcss-preflight',\n 'tw:relative',\n 'tw:rounded-card',\n 'tw:px-4',\n 'tw:cursor-text',\n 'tw:border-2',\n 'tw:border-transparent',\n 'tw:bg-gradient-to-br',\n 'tw:from-secondary-600',\n 'tw:to-purple-600',\n 'tw:bg-origin-border',\n // Floods the interior so the gradient shows only in the 2px border box.\n 'tw:shadow-[inset_0_100vw_rgb(var(--card))]',\n // focus\n 'tw:has-[input:focus]:ring-4',\n 'tw:has-[input:focus]:ring-ring/30',\n ],\n },\n },\n },\n);\n\nexport const searchInputClassnames = [\n // reset\n 'tw:border-none',\n 'tw:bg-transparent',\n 'tw:outline-hidden',\n 'tw:w-full',\n 'tw:p-0',\n\n // base\n 'tw:text-base',\n 'tw:leading-6',\n 'tw:font-normal',\n 'tw:font-sans',\n\n // placeholder\n 'tw:placeholder:text-muted-foreground',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n].join(' ');\n","import { createPrefixedString } from '../../utils';\n\nexport const genSearchTestId = (prefix: string = '') => {\n const ps = createPrefixedString(prefix);\n return {\n toString: () => prefix,\n wrapper: ps`search-wrapper`,\n input: ps`search-input`,\n clearButton: ps`search-clear-button`,\n };\n};\n","import { useEffect, useMemo, useState } from 'react';\nimport type {\n ChangeEvent,\n ChangeEventHandler,\n ComponentProps,\n FocusEvent,\n FocusEventHandler,\n MouseEvent,\n MouseEventHandler,\n ReactNode,\n} from 'react';\n\nimport { Search as SearchIcon, Sparkles } from '../../icons';\nimport { cn, debounce, noop } from '../../utils';\n\nimport { ClearButton } from './ClearButton';\nimport { searchInputClassnames, searchWrapperVariants } from './styles';\nimport { genSearchTestId } from './utils';\n\ntype SearchChangeEventHandler = (\n value: string,\n event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLButtonElement>,\n) => void;\n\ntype SearchBlurEventHandler = (value: string, event: FocusEvent<HTMLInputElement, Element>) => void;\n\ntype Props = {\n suffix?: ReactNode;\n disableDebounce?: boolean;\n debounceDelay?: number;\n onChange?: SearchChangeEventHandler;\n onBlur?: SearchBlurEventHandler;\n value?: string | null;\n defaultValue?: string | null;\n testId?: string;\n onClear?: () => void;\n variant?: 'default' | 'ai';\n} & Omit<\n ComponentProps<'input'>,\n 'type' | 'onBlur' | 'onChange' | 'value' | 'defaultValue' | 'prefix' | 'suffix'\n>;\n\n/**\n * @deprecated Use `SearchInput` instead. `Search` is kept only for the legacy (non-sidebar) layout.\n */\nexport const Search = ({\n ref,\n suffix,\n className,\n onBlur,\n onChange = noop,\n disabled = false,\n readOnly = false,\n disableDebounce = false,\n debounceDelay = 300,\n value: externalValue,\n defaultValue,\n testId: prefixTestId = '',\n placeholder = 'Search',\n onClear,\n variant = 'default',\n ...rest\n}: Props) => {\n const [internalValue, setInternalValue] = useState(() =>\n externalValue != null ? externalValue : defaultValue,\n );\n const hasValue = internalValue !== '';\n\n const isClearButtonVisible = hasValue && !disabled && !readOnly;\n const testId = genSearchTestId(prefixTestId);\n\n const debouncedOnChange = useMemo(\n () => (disableDebounce ? onChange : debounce(onChange, debounceDelay)),\n [disableDebounce, debounceDelay, onChange],\n );\n\n useEffect(() => {\n if (externalValue == null) return; // uncontrolled state\n // oxlint-disable-next-line react-x/set-state-in-effect\n setInternalValue(externalValue);\n }, [externalValue]);\n\n const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n const currentValue = event.target.value;\n setInternalValue(currentValue);\n debouncedOnChange(currentValue, event);\n };\n\n const handleBlur: FocusEventHandler<HTMLInputElement> = (event) => {\n const currentValue = event.target.value;\n setInternalValue(currentValue);\n onBlur?.(currentValue, event);\n };\n\n const handleClear: MouseEventHandler<HTMLButtonElement> = (event) => {\n setInternalValue('');\n onChange?.('', event);\n onClear?.();\n };\n\n // Clicking anywhere in the field that isn't an interactive control (the leading icon,\n // the empty chrome) focuses the input — the whole pill acts as one click target.\n const handleWrapperMouseDown: MouseEventHandler<HTMLDivElement> = (event) => {\n if (disabled || readOnly) return;\n if ((event.target as HTMLElement).closest('button, a, input, textarea, [role=\"button\"]')) {\n return;\n }\n event.preventDefault();\n event.currentTarget.querySelector('input')?.focus();\n };\n\n return (\n // Mouse-only convenience: clicking the chrome focuses the input. The input itself is the\n // real interactive/focusable target, so no extra role or key handler is needed here.\n // oxlint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n className={cn(\n searchWrapperVariants({ variant }),\n {\n 'tw:cursor-not-allowed tw:opacity-40': disabled,\n },\n className,\n )}\n data-testid={testId.wrapper}\n onMouseDown={handleWrapperMouseDown}\n >\n {variant === 'ai' ? (\n <Sparkles className=\"tw:size-4 tw:shrink-0 tw:[&_*]:stroke-aigradient-600\" />\n ) : (\n <SearchIcon className=\"tw:size-4 tw:shrink-0 tw:text-neutral-400\" />\n )}\n\n <input\n {...rest}\n ref={ref}\n placeholder={placeholder}\n data-testid={testId.input}\n type=\"text\"\n value={internalValue ?? ''}\n onChange={handleChange}\n onBlur={handleBlur}\n className={searchInputClassnames}\n disabled={disabled}\n readOnly={readOnly}\n />\n\n {isClearButtonVisible && <ClearButton onClick={handleClear} testId={testId.clearButton} />}\n\n {suffix}\n </div>\n );\n};\n","import type { ComponentProps, FormEventHandler } from 'react';\n\nimport { Search } from './Search';\n\ntype Props = {\n onSubmit: (value: string) => void;\n} & Omit<ComponentProps<typeof Search>, 'onClear' | 'onBlur' | 'onSubmit'>;\n\nexport const SearchForm = ({ ref, onSubmit, name = 'search-field', ...props }: Props) => {\n const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {\n event.preventDefault();\n const searchEl = event.currentTarget.elements.namedItem(name) as HTMLInputElement;\n onSubmit(searchEl.value);\n };\n\n const onClear = () => {\n onSubmit('');\n };\n\n return (\n <form onSubmit={handleSubmit}>\n <Search\n {...props}\n ref={ref}\n onClear={onClear}\n name={name}\n // Debounce has no meaning when we use submit, which is triggered by pressing enter.\n disableDebounce\n />\n </form>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { debounce } from "./utils-
|
|
1
|
+
import { debounce } from "./utils-DSvrhU8E.js";
|
|
2
2
|
import { Search, X } from "./icons-Cek151jC.js";
|
|
3
|
-
import { InputGroup } from "./InputGroup-
|
|
3
|
+
import { InputGroup } from "./InputGroup-DcZRlVnN.js";
|
|
4
4
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/blocks/SearchInput/SearchInput.tsx
|
|
@@ -99,4 +99,4 @@ const SearchInput = ({ ref, state, variant, focusVariant, sizing, className, val
|
|
|
99
99
|
//#endregion
|
|
100
100
|
export { SearchInput };
|
|
101
101
|
|
|
102
|
-
//# sourceMappingURL=SearchInput-
|
|
102
|
+
//# sourceMappingURL=SearchInput-D4UgAXJK.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput-
|
|
1
|
+
{"version":3,"file":"SearchInput-D4UgAXJK.js","names":[],"sources":["../src/blocks/SearchInput/SearchInput.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport type { ChangeEventHandler, ComponentProps, FocusEventHandler } from 'react';\n\nimport { InputGroup } from '../../components/InputGroup';\nimport { Search, X } from '../../icons';\nimport { debounce } from '../../utils';\n\ntype InputGroupProps = Pick<\n ComponentProps<typeof InputGroup>,\n 'variant' | 'focusVariant' | 'state' | 'sizing'\n>;\n\ntype InputGroupInputProps = Omit<ComponentProps<typeof InputGroup.Input>, 'value' | 'defaultValue'>;\n\n/**\n * Props for `SearchInput`. `onValueChange` is debounced by default (300ms) so callers can wire it directly\n * to expensive filter / fetch operations without `useMemo` plumbing. `value={null}` / `value={undefined}`\n * is treated as \"not provided\" — the component falls back to `defaultValue` (or, if absent, internal\n * state initialized to empty). `value={\"\"}` is controlled-empty.\n */\ntype Props = InputGroupProps &\n InputGroupInputProps & {\n value?: string | null;\n defaultValue?: string | null;\n /** Called with the latest string value after the debounce window (default 300ms). Fires synchronously on clear and when `disableDebounce` is set. For sync echo of every keystroke use `onChange`. */\n onValueChange?: (value: string) => void;\n /** Called with the string value on blur. */\n onValueBlur?: (value: string) => void;\n /** Called when the user clicks the clear button. Receives no arguments — the value is reset to \"\". */\n onClear?: () => void;\n /** Render the trailing clear (x) button when there's a non-empty value. */\n allowClear?: boolean;\n /** Bypass the debounce — `onValueChange` fires synchronously on every keystroke. */\n disableDebounce?: boolean;\n /** Debounce window in ms. Default 300. Ignored when `disableDebounce` is set. */\n debounceDelay?: number;\n };\n\n/**\n * Debounced search input with a leading magnifying-glass icon and optional clear button.\n *\n * **When to use:** the search field inside `PageToolbar.Search`, list / table search, combobox-less\n * free-text filters. `onValueChange` is debounced so callers can wire it directly to fetches without\n * `useMemo` plumbing.\n * **When NOT to use:** for a plain string input use `TextInput`; for selecting from a known enumerated\n * list use `Combobox` (which has its own search built in).\n * **Composition:** typically rendered in `PageToolbar.Search` next to `MultiCombobox` filter pills. Use\n * `allowClear` for the canonical x-to-reset affordance.\n *\n * @see RECIPES.md#filter-toolbar — for the search + filter chips toolbar pattern\n */\nexport const SearchInput = ({\n ref,\n\n // group props\n state,\n variant,\n focusVariant,\n sizing,\n className,\n\n // own props\n value: valueProp,\n defaultValue,\n onValueChange,\n onValueBlur,\n onChange,\n onBlur,\n onClear,\n allowClear = false,\n disableDebounce = false,\n debounceDelay = 300,\n\n // input props\n disabled,\n readOnly,\n ...restInputProps\n}: Props) => {\n const [internalValue, setInternalValue] = useState<string>(\n valueProp != null ? valueProp : (defaultValue ?? ''),\n );\n\n // Tracks whether a debounced call is pending so the controlled-value sync\n // effect doesn't overwrite characters the user typed during the debounce window.\n const debounceInFlightRef = useRef(false);\n const cancelRef = useRef<() => void>(() => {});\n\n const debouncedOnValueChange = useMemo(() => {\n if (!onValueChange || disableDebounce) {\n cancelRef.current = () => {};\n return onValueChange;\n }\n const d = debounce((val: string) => {\n debounceInFlightRef.current = false;\n onValueChange(val);\n }, debounceDelay);\n cancelRef.current = d.cancel;\n return d;\n }, [onValueChange, disableDebounce, debounceDelay]);\n\n // Cancel any pending debounced call when the debounced fn changes or on unmount.\n useEffect(() => {\n return () => cancelRef.current();\n }, [debouncedOnValueChange]);\n\n // Sync controlled value — but skip while a debounced call is in flight to\n // avoid snapping the input back to the old value mid-typing.\n useEffect(() => {\n if (valueProp == null) return;\n if (debounceInFlightRef.current) return;\n setInternalValue(valueProp);\n }, [valueProp]);\n\n const canClear = allowClear && !!internalValue && !disabled && !readOnly;\n\n const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n const val = event.target.value;\n setInternalValue(val);\n if (!disableDebounce && debouncedOnValueChange) debounceInFlightRef.current = true;\n debouncedOnValueChange?.(val);\n onChange?.(event);\n };\n\n const handleBlur: FocusEventHandler<HTMLInputElement> = (event) => {\n onValueBlur?.(event.target.value);\n onBlur?.(event);\n };\n\n const handleClear = () => {\n cancelRef.current();\n debounceInFlightRef.current = false;\n setInternalValue('');\n onValueChange?.('');\n onClear?.();\n };\n\n return (\n <InputGroup\n state={state}\n variant={variant}\n sizing={sizing}\n focusVariant={focusVariant}\n className={className}\n >\n <InputGroup.Addon align=\"inline-start\">\n <Search className=\"tw:size-4 tw:shrink-0 tw:text-muted-foreground\" />\n </InputGroup.Addon>\n\n <InputGroup.Input\n {...restInputProps}\n ref={ref}\n value={internalValue}\n onChange={handleChange}\n onBlur={handleBlur}\n disabled={disabled}\n readOnly={readOnly}\n />\n\n {canClear && (\n <InputGroup.Addon align=\"inline-end\">\n <InputGroup.Button\n aria-label=\"Clear search\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={handleClear}\n >\n <X className=\"tw:size-4\" />\n </InputGroup.Button>\n </InputGroup.Addon>\n )}\n </InputGroup>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmDA,MAAa,eAAe,EAC1B,KAGA,OACA,SACA,cACA,QACA,WAGA,OAAO,WACP,cACA,eACA,aACA,UACA,QACA,SACA,aAAa,OACb,kBAAkB,OAClB,gBAAgB,KAGhB,UACA,UACA,GAAG,qBACQ;CACX,MAAM,CAAC,eAAe,oBAAoB,SACxC,aAAa,OAAO,YAAa,gBAAgB,EACnD;CAIA,MAAM,sBAAsB,OAAO,KAAK;CACxC,MAAM,YAAY,aAAyB,CAAC,CAAC;CAE7C,MAAM,yBAAyB,cAAc;EAC3C,IAAI,CAAC,iBAAiB,iBAAiB;GACrC,UAAU,gBAAgB,CAAC;GAC3B,OAAO;EACT;EACA,MAAM,IAAI,UAAU,QAAgB;GAClC,oBAAoB,UAAU;GAC9B,cAAc,GAAG;EACnB,GAAG,aAAa;EAChB,UAAU,UAAU,EAAE;EACtB,OAAO;CACT,GAAG;EAAC;EAAe;EAAiB;CAAa,CAAC;CAGlD,gBAAgB;EACd,aAAa,UAAU,QAAQ;CACjC,GAAG,CAAC,sBAAsB,CAAC;CAI3B,gBAAgB;EACd,IAAI,aAAa,MAAM;EACvB,IAAI,oBAAoB,SAAS;EACjC,iBAAiB,SAAS;CAC5B,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,WAAW,cAAc,CAAC,CAAC,iBAAiB,CAAC,YAAY,CAAC;CAEhE,MAAM,gBAAsD,UAAU;EACpE,MAAM,MAAM,MAAM,OAAO;EACzB,iBAAiB,GAAG;EACpB,IAAI,CAAC,mBAAmB,wBAAwB,oBAAoB,UAAU;EAC9E,yBAAyB,GAAG;EAC5B,WAAW,KAAK;CAClB;CAEA,MAAM,cAAmD,UAAU;EACjE,cAAc,MAAM,OAAO,KAAK;EAChC,SAAS,KAAK;CAChB;CAEA,MAAM,oBAAoB;EACxB,UAAU,QAAQ;EAClB,oBAAoB,UAAU;EAC9B,iBAAiB,EAAE;EACnB,gBAAgB,EAAE;EAClB,UAAU;CACZ;CAEA,OACE,qBAAC,YAAD;EACS;EACE;EACD;EACM;EACH;EALb,UAAA;GAOE,oBAAC,WAAW,OAAZ;IAAkB,OAAM;IACtB,UAAA,oBAAC,QAAD,EAAQ,WAAU,iDAAkD,CAAA;GACpD,CAAA;GAElB,oBAAC,WAAW,OAAZ;IACE,GAAI;IACC;IACL,OAAO;IACP,UAAU;IACV,QAAQ;IACE;IACA;GACX,CAAA;GAEA,YACC,oBAAC,WAAW,OAAZ;IAAkB,OAAM;IACtB,UAAA,oBAAC,WAAW,QAAZ;KACE,cAAW;KACX,cAAc,UAAU,MAAM,eAAe;KAC7C,SAAS;KAET,UAAA,oBAAC,GAAD,EAAG,WAAU,YAAa,CAAA;IACT,CAAA;GACH,CAAA;EAEV;;AAEhB"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { noop } from "./utils-
|
|
2
|
+
import { noop } from "./utils-DSvrhU8E.js";
|
|
3
3
|
import { ChevronDown } from "./icons-Cek151jC.js";
|
|
4
4
|
import { Button } from "./Button-DsRrU5F1.js";
|
|
5
5
|
import { DropdownMenu } from "./DropdownMenu-CASr-jgl.js";
|
|
6
|
-
import { Badge } from "./Badge-
|
|
6
|
+
import { Badge } from "./Badge-D0pXdekt.js";
|
|
7
7
|
import { Collapsible } from "./Collapsible-BQXWEOBC.js";
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -273,4 +273,4 @@ const SectionNav = ({ groups, activeId, renderItem, showDescriptions = false, la
|
|
|
273
273
|
//#endregion
|
|
274
274
|
export { SectionNav };
|
|
275
275
|
|
|
276
|
-
//# sourceMappingURL=SectionNav-
|
|
276
|
+
//# sourceMappingURL=SectionNav-OkKCjSA-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SectionNav-BpJlisbT.js","names":[],"sources":["../src/blocks/SectionNav/SectionNavItemContent.tsx","../src/blocks/SectionNav/SectionNavGroupRow.tsx","../src/blocks/SectionNav/SectionNav.tsx"],"sourcesContent":["import { Badge } from '../../components/Badge';\nimport { ChevronDown } from '../../icons';\nimport { cn } from '../../utils';\n\nimport type { SectionNavItem } from './types';\n\ntype Props = {\n item: SectionNavItem;\n /** Tints the title. */\n active: boolean;\n showDescription?: boolean;\n /** Group rows only — renders the chevron, pointing the way the list is about to move. */\n expanded?: boolean;\n /**\n * Sub-section rows pass `false`. A group's icon stands for the group, and repeating a glyph on\n * each indented child turns a short list into a column of competing marks: the indent and the\n * rule already say these belong to the row above. An item may still carry an `icon` for surfaces\n * that flatten the tree, such as a tab row, where every destination is top level.\n */\n showIcon?: boolean;\n};\n\n/**\n * One row's body, rendered identically in the tree and in the collapsed dropdown — same title, same\n * badge, same description. Shared rather than written twice so the two cannot drift.\n */\nexport const SectionNavItemContent = ({\n item,\n active,\n showDescription = false,\n expanded,\n showIcon = true,\n}: Props) => {\n const Icon = item.icon;\n\n return (\n <span className=\"tw:flex tw:min-w-0 tw:flex-1 tw:flex-col tw:gap-0.5\">\n <span className=\"tw:flex tw:items-center tw:gap-2\">\n {showIcon && Icon && <Icon className=\"tw:size-4 tw:shrink-0\" />}\n <span\n className={cn(\n 'tw:flex-1 tw:truncate tw:text-sm',\n active ? 'tw:font-medium tw:text-accent-foreground' : 'tw:text-foreground',\n )}\n >\n {item.title}\n </span>\n {item.isNew && (\n <Badge\n color=\"blue-inverse\"\n className=\"tw:min-h-0 tw:text-[10px]\"\n labelClassName=\"tw:px-1.5 tw:py-0\"\n >\n New\n </Badge>\n )}\n {expanded !== undefined && (\n <ChevronDown\n className={cn(\n 'tw:size-4 tw:shrink-0 tw:text-muted-foreground tw:transition-transform tw:duration-200',\n expanded && 'tw:rotate-180',\n )}\n />\n )}\n </span>\n {/* Descriptions wrap rather than truncate — they are the second line, not the label. A token\n with no break opportunity would still paint straight out of the 256px column, so break it. */}\n {showDescription && item.description && (\n <span className=\"tw:text-xs tw:break-words tw:text-muted-foreground\">\n {item.description}\n </span>\n )}\n </span>\n );\n};\n","import { useState } from 'react';\nimport type { MouseEvent, ReactNode } from 'react';\n\nimport { Collapsible } from '../../components/Collapsible';\nimport { cn, noop } from '../../utils';\n\nimport { SectionNavItemContent } from './SectionNavItemContent';\nimport type { SectionNavGroup, SectionNavItemRenderProps } from './types';\n\ntype Props = {\n group: SectionNavGroup;\n activeId: string | undefined;\n renderItem: (props: SectionNavItemRenderProps) => ReactNode;\n showDescriptions: boolean;\n};\n\n/**\n * The ring is **inset**, not an outline. A row is exactly as wide as the nav column, and\n * `PageLayout.Content nav` makes that column a scroll container (`overflow-y-auto`, which forces\n * `overflow-x` to `auto` too) — so there is 0px of slack for anything painted outside the border\n * box, and the browser's default `outline-offset: 1px` ring gets clipped on both edges. Painting\n * inside the box cannot be clipped, at any column width, by any ancestor.\n */\nconst FOCUS_RING =\n 'tw:focus-visible:outline-hidden tw:focus-visible:ring-2 tw:focus-visible:ring-inset tw:focus-visible:ring-ring';\n\nconst rowClass = (active: boolean) =>\n cn(\n 'tw:flex tw:w-full tw:cursor-pointer tw:items-center tw:gap-2 tw:rounded-md tw:border-none tw:px-3 tw:py-2 tw:text-left tw:text-sm tw:no-underline tw:transition-colors',\n FOCUS_RING,\n active\n ? 'tw:bg-accent tw:font-medium tw:text-accent-foreground'\n : 'tw:bg-transparent tw:text-foreground tw:hover:bg-muted',\n );\n\nconst childRowClass = (active: boolean) =>\n cn(\n 'tw:flex tw:w-full tw:cursor-pointer tw:rounded-md tw:border-none tw:px-3 tw:py-1.5 tw:text-left tw:no-underline tw:transition-colors',\n FOCUS_RING,\n active ? 'tw:bg-accent' : 'tw:bg-transparent tw:hover:bg-muted',\n );\n\n/**\n * One group row and its sub-sections. The row is a single control: it opens the group **and** goes to\n * its first section, and only collapses once you are already there — so the chevron never becomes a\n * separate thing to aim at, and one click always makes progress.\n */\nexport const SectionNavGroupRow = ({ group, activeId, renderItem, showDescriptions }: Props) => {\n // Open on arrival: the nav is short enough that hiding any of it costs more than it saves.\n const [open, setOpen] = useState(true);\n\n const hasChildren = group.children.length > 0;\n const targetId = group.children[0]?.id ?? group.id;\n const isCurrent = group.id === activeId;\n const holdsCurrent = isCurrent || group.children.some((child) => child.id === activeId);\n\n const onClick = (event: MouseEvent<HTMLElement>) => {\n if (!hasChildren) return;\n\n // Already on the row's target, so navigating would be a no-op and the only thing left for the\n // click to do is toggle. `preventDefault` is what tells the caller's link not to navigate.\n if (activeId === targetId) {\n event.preventDefault();\n setOpen((isOpen) => !isOpen);\n\n return;\n }\n\n setOpen(true);\n };\n\n return (\n <Collapsible open={open} onOpenChange={setOpen} className=\"tw:flex tw:flex-col tw:gap-0.5\">\n {renderItem({\n targetId,\n isActive: isCurrent,\n children: (\n <SectionNavItemContent\n item={group}\n active={holdsCurrent}\n expanded={hasChildren ? open : undefined}\n />\n ),\n itemProps: {\n className: rowClass(holdsCurrent),\n 'aria-current': isCurrent ? 'page' : undefined,\n 'aria-expanded': hasChildren ? open : undefined,\n 'data-active': holdsCurrent && !isCurrent ? true : undefined,\n onClick,\n },\n })}\n\n {hasChildren && (\n <Collapsible.Content>\n {/* `pl-1` keeps each row's background box off the group's rule — without it an active\n row's `bg-accent` sits flush against the line. 4px is also what lines the child titles\n (20 + 1 + 4 + 12 = 37px) up with the parent's, which its icon puts at 12 + 16 + 8 = 36px. */}\n {/* `my-0 mr-0` and not `m-0`: a host app emits its own `.tw\\:m-0` from its own source, and\n its stylesheet is the later one — shorthand and longhand at equal specificity means the\n app's `m-0` would land after this `ml-5` and flatten the indent. Longhands only, so\n nothing here can be overridden by a copy of a class this block also uses. */}\n <ul className=\"tw:my-0 tw:mr-0 tw:ml-5 tw:flex tw:list-none tw:flex-col tw:gap-0.5 tw:border-l tw:border-border tw:py-0.5 tw:pl-1\">\n {group.children.map((child) => {\n const active = child.id === activeId;\n\n return (\n <li key={child.id}>\n {renderItem({\n targetId: child.id,\n isActive: active,\n children: (\n <SectionNavItemContent\n item={child}\n active={active}\n showDescription={showDescriptions}\n showIcon={false}\n />\n ),\n itemProps: {\n className: childRowClass(active),\n 'aria-current': active ? 'page' : undefined,\n 'aria-expanded': undefined,\n 'data-active': undefined,\n onClick: noop,\n },\n })}\n </li>\n );\n })}\n {group.note && (\n <li className=\"tw:py-1 tw:pl-3 tw:text-xs tw:text-muted-foreground\">{group.note}</li>\n )}\n </ul>\n </Collapsible.Content>\n )}\n </Collapsible>\n );\n};\n","import type { ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { DropdownMenu } from '../../components/DropdownMenu';\nimport { ChevronDown } from '../../icons';\nimport { cn, noop } from '../../utils';\n\nimport { SectionNavGroupRow } from './SectionNavGroupRow';\nimport { SectionNavItemContent } from './SectionNavItemContent';\nimport type { SectionNavGroup, SectionNavItemRenderProps } from './types';\n\ntype Props = {\n /**\n * The sections to show, already filtered. Visibility, permissions and feature flags stay in the\n * app — this block renders exactly what it is handed, in order.\n */\n groups: SectionNavGroup[];\n /** `id` of the current section: a child's, or a childless group's. */\n activeId?: string;\n /**\n * Renders the clickable element for one row, so routing never enters the design system. Return a\n * `NavLink` / TanStack `Link` / `<a>` pointing at `targetId` and spread `itemProps` onto it.\n */\n renderItem: (props: SectionNavItemRenderProps) => ReactNode;\n /** Print each section's `description` under its title. Off — the tree stays scannable without it. */\n showDescriptions?: boolean;\n /** Accessible name for the tree's `<nav>`, and the collapsed label with nothing active. */\n label?: string;\n /** Applied to the tree's `<nav>`. The column's own geometry belongs to `PageLayout.Content nav`. */\n className?: string;\n};\n\n/**\n * In-page grouped navigation for one page's sections: a tree above the container's breakpoint, a\n * single dropdown below it. Both are rendered and CSS picks one, and both draw their rows through\n * the same renderer, so the two can never drift apart.\n *\n * **This is not `Sidebar`.** `Sidebar` is the app-level left rail — `SidebarProvider`, icon-collapse,\n * one per app shell, outside `PageLayout`. `SectionNav` is scoped to a single page's sections, lives\n * inside `PageLayout.Content`, and owns no global state. See `AGENTS.md`.\n *\n * **Router-agnostic:** `renderItem` is the seam. Pass it whatever your router calls a link.\n *\n * ```tsx\n * <PageLayout.Content nav={\n * <SectionNav\n * groups={groups}\n * activeId={activeId}\n * renderItem={({ targetId, children, itemProps }) => (\n * <Link to={targetId} {...itemProps}>{children}</Link>\n * )}\n * />\n * }>\n * {page}\n * </PageLayout.Content>\n * ```\n *\n * The tree↔dropdown switch is a **container** query on the content area's width, never the viewport\n * — a product sidebar or a chat panel narrows the page without the window resizing.\n * `PageLayout.Content nav={…}` names that container; standalone, put `tw:@container/section-nav` on\n * an ancestor yourself.\n *\n * @see RECIPES.md#section-nav\n */\nexport const SectionNav = ({\n groups,\n activeId,\n renderItem,\n showDescriptions = false,\n label = 'Sections',\n className,\n}: Props) => {\n /**\n * What the collapsed trigger names. A sub-section carries its group with it — \"Developer settings /\n * CLI agents\" — so the trigger says where you are, not just what page this is.\n */\n const activeChild = groups\n .flatMap((group) => group.children.map((child) => ({ group, child })))\n .find(({ child }) => child.id === activeId);\n const activeGroup = groups.find((group) => group.id === activeId);\n const current = activeChild\n ? {\n icon: activeChild.group.icon,\n title: activeChild.child.title,\n parent: activeChild.group.title,\n }\n : { icon: activeGroup?.icon, title: activeGroup?.title ?? label, parent: undefined };\n const CurrentIcon = current.icon;\n /** A group whose subtree holds the active section: tinted like the tree's row, but not `aria-current`. */\n const holdsActive = (group: SectionNavGroup) =>\n group.id === activeId || group.children.some((child) => child.id === activeId);\n\n return (\n <>\n {/* The reset is scoped (`.tailwindcss-preflight`, see `styles.css`), and the rows are\n caller-owned elements — `renderItem` returns the app's own `<a>`, which never inherits a\n scope this block does not open. Without it those rows are `content-box`, so the `w-full`\n + `px-3` in `rowClass` measures 24px wider than the 256px column and every row bleeds out\n of it. Opening the scope here covers the whole tree, rows included. */}\n {/* `display` is set by TWO container variants and never by a plain utility. A host app that\n emits `tw:flex` or `tw:hidden` from its own source ships an identical `.tw\\:flex` /\n `.tw\\:hidden` rule — same specificity, same layer, and its stylesheet is the later one, so\n whichever of the two this block wrote plainly would lose to the app's copy and the tree\n would be stuck visible or stuck hidden. Both variants are selectors only this block emits,\n and their queries are mutually exclusive, so nothing outside can outrank them. */}\n <nav\n aria-label={label}\n className={cn(\n 'tailwindcss-preflight',\n 'tw:w-full tw:flex-col tw:gap-0.5 tw:@[640px]/section-nav:flex tw:@max-[640px]/section-nav:hidden',\n className,\n )}\n >\n {groups.map((group) => (\n <SectionNavGroupRow\n key={group.id}\n group={group}\n activeId={activeId}\n renderItem={renderItem}\n showDescriptions={showDescriptions}\n />\n ))}\n </nav>\n\n <div className=\"tw:w-full tw:bg-background tw:@[640px]/section-nav:hidden tw:@max-[640px]/section-nav:block\">\n <DropdownMenu>\n <DropdownMenu.Trigger asChild>\n <Button variant=\"outline\" className=\"tw:w-full tw:justify-between\">\n <span className=\"tw:flex tw:min-w-0 tw:items-center tw:gap-2\">\n {CurrentIcon && <CurrentIcon className=\"tw:size-4 tw:shrink-0\" />}\n {current.parent && (\n <>\n <span className=\"tw:truncate tw:font-normal tw:text-muted-foreground\">\n {current.parent}\n </span>\n <span className=\"tw:text-border\">/</span>\n </>\n )}\n <span className=\"tw:truncate tw:font-medium tw:text-foreground\">\n {current.title}\n </span>\n </span>\n <ChevronDown className=\"tw:size-4 tw:shrink-0\" />\n </Button>\n </DropdownMenu.Trigger>\n\n <DropdownMenu.Content\n align=\"start\"\n className=\"tw:w-(--radix-dropdown-menu-trigger-width)\"\n >\n {groups.map((group) =>\n group.children.length > 0 ? (\n <DropdownMenu.Group key={group.id}>\n {/* A real item, not a label: it is a destination in the tree (it goes to the\n group's first section), so a menu that made it unclickable would be a different\n navigation, not a smaller one. Same row treatment as every other item. */}\n <DropdownMenu.Item asChild>\n {renderItem({\n targetId: group.children[0]?.id ?? group.id,\n isActive: false,\n children: <SectionNavItemContent item={group} active={holdsActive(group)} />,\n itemProps: {\n className: 'tw:no-underline',\n 'aria-current': undefined,\n 'aria-expanded': undefined,\n 'data-active': holdsActive(group) ? true : undefined,\n onClick: noop,\n },\n })}\n </DropdownMenu.Item>\n <div className=\"tw:ml-5 tw:border-l tw:border-border tw:py-0.5 tw:pl-1\">\n {group.children.map((child) => (\n <DropdownMenu.Item key={child.id} asChild>\n {renderItem({\n targetId: child.id,\n isActive: child.id === activeId,\n children: (\n <SectionNavItemContent\n item={child}\n active={child.id === activeId}\n showDescription={showDescriptions}\n showIcon={false}\n />\n ),\n itemProps: {\n className: 'tw:no-underline',\n 'aria-current': child.id === activeId ? 'page' : undefined,\n 'aria-expanded': undefined,\n 'data-active': undefined,\n onClick: noop,\n },\n })}\n </DropdownMenu.Item>\n ))}\n </div>\n </DropdownMenu.Group>\n ) : (\n <DropdownMenu.Item key={group.id} asChild>\n {renderItem({\n targetId: group.id,\n isActive: group.id === activeId,\n children: <SectionNavItemContent item={group} active={group.id === activeId} />,\n itemProps: {\n className: 'tw:no-underline',\n 'aria-current': group.id === activeId ? 'page' : undefined,\n 'aria-expanded': undefined,\n 'data-active': undefined,\n onClick: noop,\n },\n })}\n </DropdownMenu.Item>\n ),\n )}\n </DropdownMenu.Content>\n </DropdownMenu>\n </div>\n </>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SectionNav-OkKCjSA-.js","names":[],"sources":["../src/blocks/SectionNav/SectionNavItemContent.tsx","../src/blocks/SectionNav/SectionNavGroupRow.tsx","../src/blocks/SectionNav/SectionNav.tsx"],"sourcesContent":["import { Badge } from '../../components/Badge';\nimport { ChevronDown } from '../../icons';\nimport { cn } from '../../utils';\n\nimport type { SectionNavItem } from './types';\n\ntype Props = {\n item: SectionNavItem;\n /** Tints the title. */\n active: boolean;\n showDescription?: boolean;\n /** Group rows only — renders the chevron, pointing the way the list is about to move. */\n expanded?: boolean;\n /**\n * Sub-section rows pass `false`. A group's icon stands for the group, and repeating a glyph on\n * each indented child turns a short list into a column of competing marks: the indent and the\n * rule already say these belong to the row above. An item may still carry an `icon` for surfaces\n * that flatten the tree, such as a tab row, where every destination is top level.\n */\n showIcon?: boolean;\n};\n\n/**\n * One row's body, rendered identically in the tree and in the collapsed dropdown — same title, same\n * badge, same description. Shared rather than written twice so the two cannot drift.\n */\nexport const SectionNavItemContent = ({\n item,\n active,\n showDescription = false,\n expanded,\n showIcon = true,\n}: Props) => {\n const Icon = item.icon;\n\n return (\n <span className=\"tw:flex tw:min-w-0 tw:flex-1 tw:flex-col tw:gap-0.5\">\n <span className=\"tw:flex tw:items-center tw:gap-2\">\n {showIcon && Icon && <Icon className=\"tw:size-4 tw:shrink-0\" />}\n <span\n className={cn(\n 'tw:flex-1 tw:truncate tw:text-sm',\n active ? 'tw:font-medium tw:text-accent-foreground' : 'tw:text-foreground',\n )}\n >\n {item.title}\n </span>\n {item.isNew && (\n <Badge\n color=\"blue-inverse\"\n className=\"tw:min-h-0 tw:text-[10px]\"\n labelClassName=\"tw:px-1.5 tw:py-0\"\n >\n New\n </Badge>\n )}\n {expanded !== undefined && (\n <ChevronDown\n className={cn(\n 'tw:size-4 tw:shrink-0 tw:text-muted-foreground tw:transition-transform tw:duration-200',\n expanded && 'tw:rotate-180',\n )}\n />\n )}\n </span>\n {/* Descriptions wrap rather than truncate — they are the second line, not the label. A token\n with no break opportunity would still paint straight out of the 256px column, so break it. */}\n {showDescription && item.description && (\n <span className=\"tw:text-xs tw:break-words tw:text-muted-foreground\">\n {item.description}\n </span>\n )}\n </span>\n );\n};\n","import { useState } from 'react';\nimport type { MouseEvent, ReactNode } from 'react';\n\nimport { Collapsible } from '../../components/Collapsible';\nimport { cn, noop } from '../../utils';\n\nimport { SectionNavItemContent } from './SectionNavItemContent';\nimport type { SectionNavGroup, SectionNavItemRenderProps } from './types';\n\ntype Props = {\n group: SectionNavGroup;\n activeId: string | undefined;\n renderItem: (props: SectionNavItemRenderProps) => ReactNode;\n showDescriptions: boolean;\n};\n\n/**\n * The ring is **inset**, not an outline. A row is exactly as wide as the nav column, and\n * `PageLayout.Content nav` makes that column a scroll container (`overflow-y-auto`, which forces\n * `overflow-x` to `auto` too) — so there is 0px of slack for anything painted outside the border\n * box, and the browser's default `outline-offset: 1px` ring gets clipped on both edges. Painting\n * inside the box cannot be clipped, at any column width, by any ancestor.\n */\nconst FOCUS_RING =\n 'tw:focus-visible:outline-hidden tw:focus-visible:ring-2 tw:focus-visible:ring-inset tw:focus-visible:ring-ring';\n\nconst rowClass = (active: boolean) =>\n cn(\n 'tw:flex tw:w-full tw:cursor-pointer tw:items-center tw:gap-2 tw:rounded-md tw:border-none tw:px-3 tw:py-2 tw:text-left tw:text-sm tw:no-underline tw:transition-colors',\n FOCUS_RING,\n active\n ? 'tw:bg-accent tw:font-medium tw:text-accent-foreground'\n : 'tw:bg-transparent tw:text-foreground tw:hover:bg-muted',\n );\n\nconst childRowClass = (active: boolean) =>\n cn(\n 'tw:flex tw:w-full tw:cursor-pointer tw:rounded-md tw:border-none tw:px-3 tw:py-1.5 tw:text-left tw:no-underline tw:transition-colors',\n FOCUS_RING,\n active ? 'tw:bg-accent' : 'tw:bg-transparent tw:hover:bg-muted',\n );\n\n/**\n * One group row and its sub-sections. The row is a single control: it opens the group **and** goes to\n * its first section, and only collapses once you are already there — so the chevron never becomes a\n * separate thing to aim at, and one click always makes progress.\n */\nexport const SectionNavGroupRow = ({ group, activeId, renderItem, showDescriptions }: Props) => {\n // Open on arrival: the nav is short enough that hiding any of it costs more than it saves.\n const [open, setOpen] = useState(true);\n\n const hasChildren = group.children.length > 0;\n const targetId = group.children[0]?.id ?? group.id;\n const isCurrent = group.id === activeId;\n const holdsCurrent = isCurrent || group.children.some((child) => child.id === activeId);\n\n const onClick = (event: MouseEvent<HTMLElement>) => {\n if (!hasChildren) return;\n\n // Already on the row's target, so navigating would be a no-op and the only thing left for the\n // click to do is toggle. `preventDefault` is what tells the caller's link not to navigate.\n if (activeId === targetId) {\n event.preventDefault();\n setOpen((isOpen) => !isOpen);\n\n return;\n }\n\n setOpen(true);\n };\n\n return (\n <Collapsible open={open} onOpenChange={setOpen} className=\"tw:flex tw:flex-col tw:gap-0.5\">\n {renderItem({\n targetId,\n isActive: isCurrent,\n children: (\n <SectionNavItemContent\n item={group}\n active={holdsCurrent}\n expanded={hasChildren ? open : undefined}\n />\n ),\n itemProps: {\n className: rowClass(holdsCurrent),\n 'aria-current': isCurrent ? 'page' : undefined,\n 'aria-expanded': hasChildren ? open : undefined,\n 'data-active': holdsCurrent && !isCurrent ? true : undefined,\n onClick,\n },\n })}\n\n {hasChildren && (\n <Collapsible.Content>\n {/* `pl-1` keeps each row's background box off the group's rule — without it an active\n row's `bg-accent` sits flush against the line. 4px is also what lines the child titles\n (20 + 1 + 4 + 12 = 37px) up with the parent's, which its icon puts at 12 + 16 + 8 = 36px. */}\n {/* `my-0 mr-0` and not `m-0`: a host app emits its own `.tw\\:m-0` from its own source, and\n its stylesheet is the later one — shorthand and longhand at equal specificity means the\n app's `m-0` would land after this `ml-5` and flatten the indent. Longhands only, so\n nothing here can be overridden by a copy of a class this block also uses. */}\n <ul className=\"tw:my-0 tw:mr-0 tw:ml-5 tw:flex tw:list-none tw:flex-col tw:gap-0.5 tw:border-l tw:border-border tw:py-0.5 tw:pl-1\">\n {group.children.map((child) => {\n const active = child.id === activeId;\n\n return (\n <li key={child.id}>\n {renderItem({\n targetId: child.id,\n isActive: active,\n children: (\n <SectionNavItemContent\n item={child}\n active={active}\n showDescription={showDescriptions}\n showIcon={false}\n />\n ),\n itemProps: {\n className: childRowClass(active),\n 'aria-current': active ? 'page' : undefined,\n 'aria-expanded': undefined,\n 'data-active': undefined,\n onClick: noop,\n },\n })}\n </li>\n );\n })}\n {group.note && (\n <li className=\"tw:py-1 tw:pl-3 tw:text-xs tw:text-muted-foreground\">{group.note}</li>\n )}\n </ul>\n </Collapsible.Content>\n )}\n </Collapsible>\n );\n};\n","import type { ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { DropdownMenu } from '../../components/DropdownMenu';\nimport { ChevronDown } from '../../icons';\nimport { cn, noop } from '../../utils';\n\nimport { SectionNavGroupRow } from './SectionNavGroupRow';\nimport { SectionNavItemContent } from './SectionNavItemContent';\nimport type { SectionNavGroup, SectionNavItemRenderProps } from './types';\n\ntype Props = {\n /**\n * The sections to show, already filtered. Visibility, permissions and feature flags stay in the\n * app — this block renders exactly what it is handed, in order.\n */\n groups: SectionNavGroup[];\n /** `id` of the current section: a child's, or a childless group's. */\n activeId?: string;\n /**\n * Renders the clickable element for one row, so routing never enters the design system. Return a\n * `NavLink` / TanStack `Link` / `<a>` pointing at `targetId` and spread `itemProps` onto it.\n */\n renderItem: (props: SectionNavItemRenderProps) => ReactNode;\n /** Print each section's `description` under its title. Off — the tree stays scannable without it. */\n showDescriptions?: boolean;\n /** Accessible name for the tree's `<nav>`, and the collapsed label with nothing active. */\n label?: string;\n /** Applied to the tree's `<nav>`. The column's own geometry belongs to `PageLayout.Content nav`. */\n className?: string;\n};\n\n/**\n * In-page grouped navigation for one page's sections: a tree above the container's breakpoint, a\n * single dropdown below it. Both are rendered and CSS picks one, and both draw their rows through\n * the same renderer, so the two can never drift apart.\n *\n * **This is not `Sidebar`.** `Sidebar` is the app-level left rail — `SidebarProvider`, icon-collapse,\n * one per app shell, outside `PageLayout`. `SectionNav` is scoped to a single page's sections, lives\n * inside `PageLayout.Content`, and owns no global state. See `AGENTS.md`.\n *\n * **Router-agnostic:** `renderItem` is the seam. Pass it whatever your router calls a link.\n *\n * ```tsx\n * <PageLayout.Content nav={\n * <SectionNav\n * groups={groups}\n * activeId={activeId}\n * renderItem={({ targetId, children, itemProps }) => (\n * <Link to={targetId} {...itemProps}>{children}</Link>\n * )}\n * />\n * }>\n * {page}\n * </PageLayout.Content>\n * ```\n *\n * The tree↔dropdown switch is a **container** query on the content area's width, never the viewport\n * — a product sidebar or a chat panel narrows the page without the window resizing.\n * `PageLayout.Content nav={…}` names that container; standalone, put `tw:@container/section-nav` on\n * an ancestor yourself.\n *\n * @see RECIPES.md#section-nav\n */\nexport const SectionNav = ({\n groups,\n activeId,\n renderItem,\n showDescriptions = false,\n label = 'Sections',\n className,\n}: Props) => {\n /**\n * What the collapsed trigger names. A sub-section carries its group with it — \"Developer settings /\n * CLI agents\" — so the trigger says where you are, not just what page this is.\n */\n const activeChild = groups\n .flatMap((group) => group.children.map((child) => ({ group, child })))\n .find(({ child }) => child.id === activeId);\n const activeGroup = groups.find((group) => group.id === activeId);\n const current = activeChild\n ? {\n icon: activeChild.group.icon,\n title: activeChild.child.title,\n parent: activeChild.group.title,\n }\n : { icon: activeGroup?.icon, title: activeGroup?.title ?? label, parent: undefined };\n const CurrentIcon = current.icon;\n /** A group whose subtree holds the active section: tinted like the tree's row, but not `aria-current`. */\n const holdsActive = (group: SectionNavGroup) =>\n group.id === activeId || group.children.some((child) => child.id === activeId);\n\n return (\n <>\n {/* The reset is scoped (`.tailwindcss-preflight`, see `styles.css`), and the rows are\n caller-owned elements — `renderItem` returns the app's own `<a>`, which never inherits a\n scope this block does not open. Without it those rows are `content-box`, so the `w-full`\n + `px-3` in `rowClass` measures 24px wider than the 256px column and every row bleeds out\n of it. Opening the scope here covers the whole tree, rows included. */}\n {/* `display` is set by TWO container variants and never by a plain utility. A host app that\n emits `tw:flex` or `tw:hidden` from its own source ships an identical `.tw\\:flex` /\n `.tw\\:hidden` rule — same specificity, same layer, and its stylesheet is the later one, so\n whichever of the two this block wrote plainly would lose to the app's copy and the tree\n would be stuck visible or stuck hidden. Both variants are selectors only this block emits,\n and their queries are mutually exclusive, so nothing outside can outrank them. */}\n <nav\n aria-label={label}\n className={cn(\n 'tailwindcss-preflight',\n 'tw:w-full tw:flex-col tw:gap-0.5 tw:@[640px]/section-nav:flex tw:@max-[640px]/section-nav:hidden',\n className,\n )}\n >\n {groups.map((group) => (\n <SectionNavGroupRow\n key={group.id}\n group={group}\n activeId={activeId}\n renderItem={renderItem}\n showDescriptions={showDescriptions}\n />\n ))}\n </nav>\n\n <div className=\"tw:w-full tw:bg-background tw:@[640px]/section-nav:hidden tw:@max-[640px]/section-nav:block\">\n <DropdownMenu>\n <DropdownMenu.Trigger asChild>\n <Button variant=\"outline\" className=\"tw:w-full tw:justify-between\">\n <span className=\"tw:flex tw:min-w-0 tw:items-center tw:gap-2\">\n {CurrentIcon && <CurrentIcon className=\"tw:size-4 tw:shrink-0\" />}\n {current.parent && (\n <>\n <span className=\"tw:truncate tw:font-normal tw:text-muted-foreground\">\n {current.parent}\n </span>\n <span className=\"tw:text-border\">/</span>\n </>\n )}\n <span className=\"tw:truncate tw:font-medium tw:text-foreground\">\n {current.title}\n </span>\n </span>\n <ChevronDown className=\"tw:size-4 tw:shrink-0\" />\n </Button>\n </DropdownMenu.Trigger>\n\n <DropdownMenu.Content\n align=\"start\"\n className=\"tw:w-(--radix-dropdown-menu-trigger-width)\"\n >\n {groups.map((group) =>\n group.children.length > 0 ? (\n <DropdownMenu.Group key={group.id}>\n {/* A real item, not a label: it is a destination in the tree (it goes to the\n group's first section), so a menu that made it unclickable would be a different\n navigation, not a smaller one. Same row treatment as every other item. */}\n <DropdownMenu.Item asChild>\n {renderItem({\n targetId: group.children[0]?.id ?? group.id,\n isActive: false,\n children: <SectionNavItemContent item={group} active={holdsActive(group)} />,\n itemProps: {\n className: 'tw:no-underline',\n 'aria-current': undefined,\n 'aria-expanded': undefined,\n 'data-active': holdsActive(group) ? true : undefined,\n onClick: noop,\n },\n })}\n </DropdownMenu.Item>\n <div className=\"tw:ml-5 tw:border-l tw:border-border tw:py-0.5 tw:pl-1\">\n {group.children.map((child) => (\n <DropdownMenu.Item key={child.id} asChild>\n {renderItem({\n targetId: child.id,\n isActive: child.id === activeId,\n children: (\n <SectionNavItemContent\n item={child}\n active={child.id === activeId}\n showDescription={showDescriptions}\n showIcon={false}\n />\n ),\n itemProps: {\n className: 'tw:no-underline',\n 'aria-current': child.id === activeId ? 'page' : undefined,\n 'aria-expanded': undefined,\n 'data-active': undefined,\n onClick: noop,\n },\n })}\n </DropdownMenu.Item>\n ))}\n </div>\n </DropdownMenu.Group>\n ) : (\n <DropdownMenu.Item key={group.id} asChild>\n {renderItem({\n targetId: group.id,\n isActive: group.id === activeId,\n children: <SectionNavItemContent item={group} active={group.id === activeId} />,\n itemProps: {\n className: 'tw:no-underline',\n 'aria-current': group.id === activeId ? 'page' : undefined,\n 'aria-expanded': undefined,\n 'data-active': undefined,\n onClick: noop,\n },\n })}\n </DropdownMenu.Item>\n ),\n )}\n </DropdownMenu.Content>\n </DropdownMenu>\n </div>\n </>\n );\n};\n"],"mappings":"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"}
|
|
@@ -139,7 +139,7 @@ const isGroup = (itemOrGroup) => "items" in itemOrGroup;
|
|
|
139
139
|
* for forms with validation. Use the compound parts (`Select.Root`, `Select.Trigger`, `Select.Content`,
|
|
140
140
|
* `Select.Item`) for custom item layouts; the top-level `Select` covers the common cases.
|
|
141
141
|
*/
|
|
142
|
-
const Select = ({ value, defaultValue, onValueChange, disabled, name, required, open, defaultOpen, onOpenChange, dir, autoComplete, form, variant, state, sizing, placeholder,
|
|
142
|
+
const Select = ({ value, defaultValue, onValueChange, disabled, name, required, open, defaultOpen, onOpenChange, dir, autoComplete, form, variant, state, sizing, placeholder, className, onBlur, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, "aria-required": ariaRequired, items = [], ...accessibleName }) => {
|
|
143
143
|
const groupKeyId = useId();
|
|
144
144
|
const renderItem = (item) => /* @__PURE__ */ jsx(SelectItem, {
|
|
145
145
|
value: item.value,
|
|
@@ -162,14 +162,13 @@ const Select = ({ value, defaultValue, onValueChange, disabled, name, required,
|
|
|
162
162
|
autoComplete,
|
|
163
163
|
form,
|
|
164
164
|
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
165
|
+
...accessibleName,
|
|
165
166
|
variant,
|
|
166
167
|
state,
|
|
167
168
|
sizing,
|
|
168
169
|
placeholder,
|
|
169
|
-
id,
|
|
170
170
|
className,
|
|
171
171
|
onBlur,
|
|
172
|
-
"aria-label": ariaLabel,
|
|
173
172
|
"aria-describedby": ariaDescribedBy,
|
|
174
173
|
"aria-invalid": ariaInvalid,
|
|
175
174
|
"aria-required": ariaRequired
|
|
@@ -189,4 +188,4 @@ Select.Separator = SelectSeparator;
|
|
|
189
188
|
//#endregion
|
|
190
189
|
export { Select };
|
|
191
190
|
|
|
192
|
-
//# sourceMappingURL=Select-
|
|
191
|
+
//# sourceMappingURL=Select-DV3Hak_l.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select-DV3Hak_l.js","names":["SelectItemComponent"],"sources":["../src/components/Select/SelectContent.tsx","../src/components/Select/SelectGroup.tsx","../src/components/Select/SelectItem.tsx","../src/components/Select/SelectLabel.tsx","../src/components/Select/SelectRoot.tsx","../src/components/Select/SelectSeparator.tsx","../src/components/Select/SelectTrigger.tsx","../src/components/Select/Select.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\n\nimport { ChevronDown, ChevronUp } from '../../icons';\nimport { cn } from '../../utils';\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nconst scrollButtonStyles = cn(\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:rounded-sm',\n 'tw:p-1',\n 'tw:[&_svg:not([class*=\"tw:size-\"])]:size-5',\n);\n\ntype Variant = 'default' | 'argo';\n\n/**\n * Props for `Select.Content`. `container` portals the listbox into a custom element (useful inside modals).\n */\ntype Props = ComponentProps<typeof SelectPrimitive.Content> & {\n container?: HTMLElement | null;\n};\n\n/**\n * Listbox container for `Select`. Portals items into a popover sized to the trigger.\n * Normally rendered implicitly by `Select`; use directly only when composing custom item layouts via\n * the `Select.Root` / `Select.Trigger` / `Select.Content` compound parts.\n */\nexport const SelectContent = ({\n ref,\n className,\n children,\n container,\n position = 'popper',\n sideOffset = 4,\n ...props\n}: Props) => {\n const effectiveVariant: Variant = useArgoDesign() ? 'argo' : 'default';\n return (\n <SelectPrimitive.Portal container={container}>\n <SelectPrimitive.Content\n {...props}\n ref={ref}\n position={position}\n sideOffset={sideOffset}\n data-variant={effectiveVariant}\n className={cn(\n 'tailwindcss-preflight',\n 'tw:group/select-content',\n // Floating tier above Modal (1051): Tooltip 1060 / Combobox·Popover·Select 1055 / Modal 1051 / DropdownMenu.SubContent 1041 / FullScreenModal 1039\n 'tw:z-[1055]',\n\n // layout\n 'tw:flex tw:flex-col',\n 'tw:p-1',\n 'tw:data-[variant=default]:p-0',\n 'tw:overflow-hidden',\n 'tw:origin-(--radix-select-content-transform-origin)',\n\n // sizing\n 'tw:max-h-[var(--radix-select-content-available-height)]',\n 'tw:min-w-[var(--radix-select-trigger-width)]',\n\n // appearance\n 'tw:bg-popover',\n 'tw:text-popover-foreground',\n 'tw:shadow-md',\n 'tw:ring-1',\n 'tw:ring-foreground/10',\n 'tw:rounded-lg',\n 'tw:data-[variant=default]:rounded',\n\n // open animation\n 'tw:data-[state=open]:animate-in',\n 'tw:data-[state=open]:fade-in-0',\n 'tw:data-[state=open]:zoom-in-95',\n\n // closed animation\n 'tw:data-[state=closed]:animate-out',\n 'tw:data-[state=closed]:fade-out-0',\n 'tw:data-[state=closed]:zoom-out-95',\n\n // position animations\n 'tw:data-[side=bottom]:slide-in-from-top-2',\n 'tw:data-[side=left]:slide-in-from-right-2',\n 'tw:data-[side=right]:slide-in-from-left-2',\n 'tw:data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n >\n <SelectPrimitive.ScrollUpButton className={scrollButtonStyles}>\n <ChevronUp />\n </SelectPrimitive.ScrollUpButton>\n\n <SelectPrimitive.Viewport\n className={cn({\n 'tw:h-[var(--radix-select-trigger-height)] tw:w-full tw:min-w-[var(--radix-select-trigger-width)]':\n position === 'popper',\n })}\n >\n {children}\n </SelectPrimitive.Viewport>\n\n <SelectPrimitive.ScrollDownButton className={scrollButtonStyles}>\n <ChevronDown />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n );\n};\n","import type { ComponentProps } from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<typeof SelectPrimitive.Group>;\n\nexport const SelectGroup = ({ className, ...props }: Props) => (\n <SelectPrimitive.Group {...props} className={cn('tw:flex tw:flex-col tw:gap-0.5', className)} />\n);\n","import { useId } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\n\nimport { Check } from '../../icons';\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<typeof SelectPrimitive.Item> & {\n icon?: ReactNode;\n hint?: ReactNode;\n};\n\nexport const SelectItem = ({\n ref,\n className,\n children,\n icon,\n hint,\n 'aria-describedby': ariaDescribedBy,\n ...props\n}: Props) => {\n const hintId = useId();\n\n return (\n <SelectPrimitive.Item\n {...props}\n ref={ref}\n // Radix names the option from `ItemText` alone (`aria-labelledby`), so the hint is\n // described rather than named — it reaches a screen reader without joining the label.\n aria-describedby={\n [ariaDescribedBy, hint ? hintId : null].filter(Boolean).join(' ') || undefined\n }\n className={cn(\n 'tw:group/select-item',\n\n // layout\n 'tw:relative',\n 'tw:flex',\n 'tw:flex-1',\n 'tw:items-center',\n 'tw:gap-2',\n\n // spacing — default variant uses tighter radius and wider horizontal padding\n 'tw:py-2',\n 'tw:px-2',\n 'tw:group-data-[variant=default]/select-content:px-4',\n 'tw:rounded-lg',\n 'tw:group-data-[variant=default]/select-content:rounded-none',\n\n // typography\n 'tw:text-sm',\n 'tw:select-none',\n 'tw:cursor-default',\n 'tw:outline-hidden',\n\n // highlighted (keyboard / hover)\n 'tw:focus:outline-hidden',\n 'tw:data-[highlighted]:bg-accent',\n // The legacy highlight is a neutral step, not the argo accent.\n //\n // - `secondary` carries its own foreground, so fill and ink move together.\n // - `muted` is unusable: in dark it equals `popover`, so the band would disappear\n // into the listbox.\n 'tw:group-data-[variant=default]/select-content:data-[highlighted]:bg-secondary',\n 'tw:data-[highlighted]:text-accent-foreground',\n 'tw:group-data-[variant=default]/select-content:data-[highlighted]:text-secondary-foreground',\n\n // disabled\n 'tw:data-[disabled]:pointer-events-none',\n 'tw:data-[disabled]:opacity-50',\n\n // child svg defaults\n 'tw:[&_svg]:pointer-events-none',\n 'tw:[&_svg]:shrink-0',\n 'tw:[&_svg]:text-muted-foreground',\n \"tw:[&_svg:not([class*='tw:size-'])]:size-4\",\n className,\n )}\n >\n {icon}\n <span className=\"tw:flex-1 tw:truncate\">\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </span>\n {/* Outside `ItemText`, so the trigger shows the label alone once the option is picked. */}\n {hint && (\n <span id={hintId} className=\"tw:shrink-0 tw:text-xs tw:text-muted-foreground\">\n {hint}\n </span>\n )}\n <SelectPrimitive.ItemIndicator className=\"tw:pointer-events-none\">\n <Check className=\"tw:size-4\" />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n );\n};\n","import type { ComponentProps } from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<typeof SelectPrimitive.Label>;\n\nexport const SelectLabel = ({ className, ...props }: Props) => (\n <SelectPrimitive.Label\n {...props}\n className={cn(\n // Base (argo variant) — soft gray section label\n 'tw:px-2',\n 'tw:py-1.5',\n 'tw:text-xs',\n 'tw:font-medium',\n 'tw:leading-none',\n 'tw:text-muted-foreground',\n\n // Default variant — uppercase tracked label, matches Combobox default\n 'tw:group-data-[variant=default]/select-content:uppercase',\n 'tw:group-data-[variant=default]/select-content:font-semibold',\n 'tw:group-data-[variant=default]/select-content:tracking-wider',\n 'tw:group-data-[variant=default]/select-content:text-[11px]',\n 'tw:group-data-[variant=default]/select-content:text-black',\n 'tw:group-data-[variant=default]/select-content:pt-2',\n 'tw:group-data-[variant=default]/select-content:px-4',\n\n className,\n )}\n />\n);\n","import type { ReactNode } from 'react';\nimport { Root } from '@radix-ui/react-select';\n\n// Mirror Radix's `SelectProps` as an explicit list. We can't infer via\n// `ComponentProps<typeof Root>` or reuse Radix's `SelectProps` directly: both\n// transitively reference the un-exported `SelectSharedProps` interface, and\n// TS4023 fires when DTS emits anything that consumes it (e.g. `useAppForm`).\n// Keep this in sync with `@radix-ui/react-select`'s `SelectProps` shape.\nexport type SelectRootProps = {\n // SelectSharedProps\n children?: ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?(open: boolean): void;\n dir?: 'ltr' | 'rtl';\n name?: string;\n autoComplete?: string;\n disabled?: boolean;\n required?: boolean;\n form?: string;\n // SelectProps\n value?: string;\n defaultValue?: string;\n onValueChange?(value: string): void;\n};\n\nexport const SelectRoot = (props: SelectRootProps) => <Root {...props} />;\n","import type { ComponentProps } from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<typeof SelectPrimitive.Separator>;\n\nexport const SelectSeparator = ({ className, ...props }: Props) => (\n <SelectPrimitive.Separator\n {...props}\n className={cn('tw:mx-2 tw:my-1 tw:h-px tw:bg-border', className)}\n />\n);\n","import type { ComponentProps } from 'react';\nimport * as SelectPrimitive from '@radix-ui/react-select';\nimport { type VariantProps } from 'class-variance-authority';\n\nimport { ChevronDown } from '../../icons';\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\nimport { overlayTriggerVariants } from '../OverlayTrigger/styles';\nimport { useArgoDesign } from '../ThemeProvider/context';\n\ntype BaseProps = ComponentProps<typeof SelectPrimitive.Trigger> &\n Omit<VariantProps<typeof overlayTriggerVariants>, 'variant'> & {\n variant?: Exclude<VariantProps<typeof overlayTriggerVariants>['variant'], 'argo'> | 'inline';\n } & Pick<ComponentProps<typeof SelectPrimitive.Value>, 'placeholder'>;\n\n/**\n * The trigger needs an accessible name, so one of the three routes to one is required.\n *\n * - `role=\"combobox\"` is not a name-from-content role: neither the selected item's label nor the\n * `placeholder` names it.\n * - `id` counts only when a `<Label htmlFor>` points at it — the type cannot check that pair.\n * - Passing more than one is allowed; `aria-label` wins over a `<Label htmlFor>`.\n */\ntype SelectTriggerProps = BaseProps &\n (\n | Required<Pick<BaseProps, 'aria-label'>>\n | Required<Pick<BaseProps, 'aria-labelledby'>>\n | Required<Pick<BaseProps, 'id'>>\n );\n\nexport const SelectTrigger = ({\n ref,\n className,\n variant,\n state,\n sizing,\n placeholder,\n ...props\n}: SelectTriggerProps) => {\n const isArgoDesign = useArgoDesign();\n const effectiveVariant = (() => {\n if (variant === 'inline') return 'inline';\n if (isArgoDesign) return 'argo';\n return variant;\n })();\n const isInlineVariant = effectiveVariant === 'inline';\n\n if (isInlineVariant)\n return (\n <SelectPrimitive.Trigger {...props} ref={ref} className={cn(className)} asChild>\n <Button variant=\"inline\">\n <SelectPrimitive.Value placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <ChevronDown />\n </SelectPrimitive.Icon>\n </Button>\n </SelectPrimitive.Trigger>\n );\n\n return (\n <SelectPrimitive.Trigger\n {...props}\n ref={ref}\n className={cn(\n overlayTriggerVariants({ variant: effectiveVariant, state, sizing }),\n className,\n )}\n >\n <SelectPrimitive.Value placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <ChevronDown className=\"tw:size-4 tw:text-muted-foreground\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n};\n","import { useId } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\n\nimport { SelectContent } from './SelectContent';\nimport { SelectGroup } from './SelectGroup';\nimport { SelectItem as SelectItemComponent } from './SelectItem';\nimport { SelectLabel } from './SelectLabel';\nimport { SelectRoot, type SelectRootProps } from './SelectRoot';\nimport { SelectSeparator } from './SelectSeparator';\nimport { SelectTrigger } from './SelectTrigger';\n\nexport type SelectItem = {\n value: string;\n label: ReactNode;\n icon?: ReactNode;\n /** Trailing muted note shown in the listbox only — never in the trigger. */\n hint?: ReactNode;\n disabled?: boolean;\n};\n\nexport type SelectItemGroup = {\n label?: ReactNode;\n items: readonly SelectItem[];\n};\n\nconst isGroup = (itemOrGroup: SelectItem | SelectItemGroup): itemOrGroup is SelectItemGroup =>\n 'items' in itemOrGroup;\n\ntype TriggerProps = ComponentProps<typeof SelectTrigger>;\n\ntype BaseProps = Pick<\n SelectRootProps,\n | 'value'\n | 'defaultValue'\n | 'onValueChange'\n | 'disabled'\n | 'name'\n | 'required'\n | 'open'\n | 'defaultOpen'\n | 'onOpenChange'\n | 'dir'\n | 'autoComplete'\n | 'form'\n> &\n Pick<\n TriggerProps,\n | 'variant'\n | 'state'\n | 'sizing'\n | 'placeholder'\n | 'id'\n | 'className'\n | 'onBlur'\n | 'aria-label'\n | 'aria-labelledby'\n | 'aria-describedby'\n | 'aria-invalid'\n | 'aria-required'\n > & {\n items?: readonly (SelectItem | SelectItemGroup)[];\n };\n\n/**\n * A `Select` needs an accessible name, so one of the three routes to one is required.\n *\n * - `role=\"combobox\"` is not a name-from-content role: neither the selected item's label nor the\n * `placeholder` names the trigger.\n * - `id` counts only when a `<Label htmlFor>` points at it — the type cannot check that pair.\n * - Passing more than one is allowed; `aria-label` wins over a `<Label htmlFor>`.\n */\nexport type SelectProps = BaseProps &\n (\n | Required<Pick<BaseProps, 'aria-label'>>\n | Required<Pick<BaseProps, 'aria-labelledby'>>\n | Required<Pick<BaseProps, 'id'>>\n );\n\n/**\n * Single selection from a short enumerated list. Built on Radix Select.\n *\n * **When to use:** picking one value from ~10 or fewer options where search adds no value (status,\n * region, role). Pass a flat `items` array or grouped arrays with optional labels for headings.\n * **When NOT to use:** for longer lists with search use `Combobox`; for multi-select use `MultiCombobox`.\n * **Composition:** wrap in `FormGroup` for label + help text, or use `useAppForm` + `field.SelectField`\n * for forms with validation. Use the compound parts (`Select.Root`, `Select.Trigger`, `Select.Content`,\n * `Select.Item`) for custom item layouts; the top-level `Select` covers the common cases.\n */\nexport const Select = ({\n // root\n value,\n defaultValue,\n onValueChange,\n disabled,\n name,\n required,\n open,\n defaultOpen,\n onOpenChange,\n dir,\n autoComplete,\n form,\n // trigger\n variant,\n state,\n sizing,\n placeholder,\n className,\n onBlur,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n // items\n items = [],\n // `id` / `aria-label` / `aria-labelledby` stay grouped: the trigger requires one of them, and\n // destructuring them apart would hand it three independently optional props instead.\n ...accessibleName\n}: SelectProps) => {\n const groupKeyId = useId();\n\n const renderItem = (item: SelectItem) => (\n <SelectItemComponent\n key={item.value}\n value={item.value}\n icon={item.icon}\n hint={item.hint}\n disabled={item.disabled}\n >\n {item.label}\n </SelectItemComponent>\n );\n\n return (\n <SelectRoot\n value={value}\n defaultValue={defaultValue}\n onValueChange={onValueChange}\n disabled={disabled}\n name={name}\n required={required}\n open={open}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n dir={dir}\n autoComplete={autoComplete}\n form={form}\n >\n <SelectTrigger\n {...accessibleName}\n variant={variant}\n state={state}\n sizing={sizing}\n placeholder={placeholder}\n className={className}\n onBlur={onBlur}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n aria-required={ariaRequired}\n />\n <SelectContent>\n {items.map((itemOrGroup, index) => {\n if (isGroup(itemOrGroup)) {\n return (\n <SelectGroup key={`${groupKeyId}-group-${index}`}>\n {itemOrGroup.label && <SelectLabel>{itemOrGroup.label}</SelectLabel>}\n {itemOrGroup.items.map(renderItem)}\n </SelectGroup>\n );\n }\n\n return renderItem(itemOrGroup);\n })}\n </SelectContent>\n </SelectRoot>\n );\n};\n\nSelect.Root = SelectRoot;\nSelect.Trigger = SelectTrigger;\nSelect.Content = SelectContent;\nSelect.Item = SelectItemComponent;\nSelect.Group = SelectGroup;\nSelect.Label = SelectLabel;\nSelect.Separator = SelectSeparator;\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { Tooltip, TooltipProvider } from "./utils-
|
|
2
|
+
import { Tooltip, TooltipProvider } from "./utils-DSvrhU8E.js";
|
|
3
3
|
import { mergeRefs } from "./internal/utils/mergeRefs.js";
|
|
4
4
|
import { ChevronDown, Search } from "./icons-Cek151jC.js";
|
|
5
5
|
import { DropdownMenu } from "./DropdownMenu-CASr-jgl.js";
|
|
@@ -7,7 +7,7 @@ import { ScrollArea } from "./internal/components/ScrollArea.js";
|
|
|
7
7
|
import { Separator } from "./internal/components/Separator.js";
|
|
8
8
|
import { HoverCard } from "./HoverCard-B9ZMJxjn.js";
|
|
9
9
|
import { Collapsible } from "./Collapsible-BQXWEOBC.js";
|
|
10
|
-
import { BrandLogo } from "./BrandLogo-
|
|
10
|
+
import { BrandLogo } from "./BrandLogo-CoKBk4MI.js";
|
|
11
11
|
import { useElement } from "./useElement-DkF6esWL.js";
|
|
12
12
|
import { useScrollbarPosition } from "./internal/hooks/useScrollbarPosition.js";
|
|
13
13
|
import { Root, Slot, Slottable } from "@radix-ui/react-slot";
|
|
@@ -15,27 +15,44 @@ import { createContext, use, useCallback, useEffect, useLayoutEffect, useMemo, u
|
|
|
15
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
16
|
//#region src/components/Sidebar/SidebarProvider/useTransitionPresence.ts
|
|
17
17
|
const FALLBACK_TIMEOUT_MS = 500;
|
|
18
|
+
/** Under reduced motion there is no `transitionend` to wait for, so the mount is not deferred. */
|
|
19
|
+
const prefersReducedMotion = () => typeof window !== "undefined" && (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false);
|
|
18
20
|
const reducer = (state, event) => {
|
|
19
21
|
switch (event) {
|
|
20
22
|
case "MOUNT": return "mounted";
|
|
21
|
-
case "
|
|
22
|
-
case "
|
|
23
|
+
case "ENTER": return state === "unmounted" ? "enterSuspended" : "mounted";
|
|
24
|
+
case "TRANSITION_OUT":
|
|
25
|
+
if (state === "enterSuspended") return "unmounted";
|
|
26
|
+
return state === "mounted" ? "unmountSuspended" : state;
|
|
27
|
+
case "TRANSITION_END":
|
|
28
|
+
if (state === "unmountSuspended") return "unmounted";
|
|
29
|
+
if (state === "enterSuspended") return "mounted";
|
|
30
|
+
return state;
|
|
23
31
|
default: return state;
|
|
24
32
|
}
|
|
25
33
|
};
|
|
26
|
-
const useTransitionPresence = ({ mounted, keepMounted = false }) => {
|
|
34
|
+
const useTransitionPresence = ({ mounted, keepMounted = false, mountAfterEnter = false }) => {
|
|
27
35
|
const [state, send] = useReducer(reducer, mounted ? "mounted" : "unmounted");
|
|
28
36
|
useLayoutEffect(() => {
|
|
29
37
|
if (keepMounted) return;
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
if (!mounted) {
|
|
39
|
+
send("TRANSITION_OUT");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
send(mountAfterEnter && !prefersReducedMotion() ? "ENTER" : "MOUNT");
|
|
43
|
+
}, [
|
|
44
|
+
mounted,
|
|
45
|
+
keepMounted,
|
|
46
|
+
mountAfterEnter
|
|
47
|
+
]);
|
|
32
48
|
useEffect(() => {
|
|
33
|
-
if (state !== "unmountSuspended") return;
|
|
49
|
+
if (state !== "unmountSuspended" && state !== "enterSuspended") return;
|
|
34
50
|
const id = setTimeout(() => send("TRANSITION_END"), FALLBACK_TIMEOUT_MS);
|
|
35
51
|
return () => clearTimeout(id);
|
|
36
52
|
}, [state]);
|
|
37
53
|
return useMemo(() => ({
|
|
38
|
-
isMounted: keepMounted || state
|
|
54
|
+
isMounted: keepMounted || state === "mounted" || state === "unmountSuspended",
|
|
55
|
+
/** Resolves whichever transition the subtree is waiting on. */
|
|
39
56
|
completeUnmount: () => send("TRANSITION_END")
|
|
40
57
|
}), [state, keepMounted]);
|
|
41
58
|
};
|
|
@@ -224,11 +241,14 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
|
|
|
224
241
|
});
|
|
225
242
|
const toggleLeftFill = useCallback(() => setFilledSide((prev) => prev === "left" ? null : "left"), []);
|
|
226
243
|
const toggleRightFill = useCallback(() => setFilledSide((prev) => prev === "right" ? null : "right"), []);
|
|
244
|
+
const setLeftFill = useCallback((fill) => setFilledSide((prev) => fill ? "left" : prev === "left" ? null : prev), []);
|
|
245
|
+
const setRightFill = useCallback((fill) => setFilledSide((prev) => fill ? "right" : prev === "right" ? null : prev), []);
|
|
227
246
|
const value = useMemo(() => ({
|
|
228
247
|
left: {
|
|
229
248
|
...leftState,
|
|
230
249
|
isFill: filledSide === "left",
|
|
231
250
|
toggleFill: toggleLeftFill,
|
|
251
|
+
setFill: setLeftFill,
|
|
232
252
|
widths: calcEffectiveWidths({
|
|
233
253
|
variant: leftVariant,
|
|
234
254
|
width: leftDragWidth ?? leftWidth,
|
|
@@ -248,6 +268,7 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
|
|
|
248
268
|
...rightState,
|
|
249
269
|
isFill: filledSide === "right",
|
|
250
270
|
toggleFill: toggleRightFill,
|
|
271
|
+
setFill: setRightFill,
|
|
251
272
|
widths: calcEffectiveWidths({
|
|
252
273
|
variant: rightVariant,
|
|
253
274
|
width: rightDragWidth ?? rightWidth,
|
|
@@ -267,6 +288,7 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
|
|
|
267
288
|
leftState,
|
|
268
289
|
filledSide,
|
|
269
290
|
toggleLeftFill,
|
|
291
|
+
setLeftFill,
|
|
270
292
|
leftVariant,
|
|
271
293
|
leftWidth,
|
|
272
294
|
leftDragWidth,
|
|
@@ -275,6 +297,7 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
|
|
|
275
297
|
isLeftDragging,
|
|
276
298
|
rightState,
|
|
277
299
|
toggleRightFill,
|
|
300
|
+
setRightFill,
|
|
278
301
|
rightVariant,
|
|
279
302
|
rightWidth,
|
|
280
303
|
rightDragWidth,
|
|
@@ -339,9 +362,9 @@ const SidebarGroupLabel = ({ ref, className, children, ...props }) => /* @__PURE
|
|
|
339
362
|
children: [/* @__PURE__ */ jsx(Separator, {
|
|
340
363
|
orientation: "horizontal",
|
|
341
364
|
size: "3/4",
|
|
342
|
-
className: cn("tw:opacity-0", "tw:group-data-[state=collapsed]/sidebar:opacity-100", "tw:absolute", "tw:w-full", "tw:left-0", "tw:top-1/2 tw:-translate-y-1/2", "tw:transition-opacity", "tw:duration-
|
|
365
|
+
className: cn("tw:opacity-0", "tw:group-data-[state=collapsed]/sidebar:opacity-100", "tw:absolute", "tw:w-full", "tw:left-0", "tw:top-1/2 tw:-translate-y-1/2", "tw:transition-opacity", "tw:duration-(--sidebar-motion-duration)", "tw:ease-(--sidebar-motion-easing)", "tw:motion-reduce:transition-none")
|
|
343
366
|
}), /* @__PURE__ */ jsx("span", {
|
|
344
|
-
className: cn("tw:flex", "tw:group-data-[state=collapsed]/sidebar:opacity-0", "tw:items-center", "tw:flex-1", "tw:text-muted-foreground", "tw:whitespace-nowrap", "tw:transition-opacity", "tw:duration-
|
|
367
|
+
className: cn("tw:flex", "tw:group-data-[state=collapsed]/sidebar:opacity-0", "tw:items-center", "tw:flex-1", "tw:text-muted-foreground", "tw:whitespace-nowrap", "tw:transition-opacity", "tw:duration-(--sidebar-motion-duration)", "tw:ease-(--sidebar-motion-easing)", "tw:motion-reduce:transition-none"),
|
|
345
368
|
children
|
|
346
369
|
})]
|
|
347
370
|
});
|
|
@@ -372,7 +395,7 @@ const SidebarHeader = ({ className, children, ...props }) => {
|
|
|
372
395
|
//#region src/components/Sidebar/SidebarMenu/SidebarMenu.tsx
|
|
373
396
|
const SidebarMenu = ({ className, ...props }) => /* @__PURE__ */ jsx("ul", {
|
|
374
397
|
"data-sidebar": "menu",
|
|
375
|
-
className: cn("tw:flex", "tw:w-full", "tw:min-w-0", "tw:flex-col", "tw:gap-1", "tw:transition-[margin,opacity]", "tw:duration-
|
|
398
|
+
className: cn("tw:flex", "tw:w-full", "tw:min-w-0", "tw:flex-col", "tw:gap-1", "tw:transition-[margin,opacity]", "tw:duration-(--sidebar-motion-duration)", "tw:ease-(--sidebar-motion-easing)", "tw:motion-reduce:transition-none", "tw:pl-0", className),
|
|
376
399
|
...props
|
|
377
400
|
});
|
|
378
401
|
//#endregion
|
|
@@ -474,7 +497,7 @@ const SidebarMenuCard = ({ children, className, icon, title, ...rest }) => {
|
|
|
474
497
|
...rest,
|
|
475
498
|
"data-slot": "sidebar-menu-card",
|
|
476
499
|
tabIndex: isExpanded ? -1 : 0,
|
|
477
|
-
className: cn("tw:group/sidebar-menu-card", "tw:peer/sidebar-menu-card", "tw:overflow-hidden", "tw:border", "tw:border-sidebar-border", "tw:rounded-2xl", "tw:grid", "tw:grid-rows-[1fr]", "tw:flex-1", "tw:p-4", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:p-2", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:border-transparent", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:grid-rows-[18px]", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:rounded-md", "tw:outline-hidden", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:hover:bg-sidebar-accent", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:focus-visible:ring-2", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:focus-visible:ring-sidebar-ring/50", "tw:transition-[padding,border]", "tw:duration-
|
|
500
|
+
className: cn("tw:group/sidebar-menu-card", "tw:peer/sidebar-menu-card", "tw:overflow-hidden", "tw:border", "tw:border-sidebar-border", "tw:rounded-2xl", "tw:grid", "tw:grid-rows-[1fr]", "tw:flex-1", "tw:p-4", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:p-2", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:border-transparent", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:grid-rows-[18px]", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:rounded-md", "tw:outline-hidden", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:hover:bg-sidebar-accent", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:focus-visible:ring-2", "tw:group-data-[fill=false]/sidebar:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:focus-visible:ring-sidebar-ring/50", "tw:transition-[padding,border]", "tw:duration-(--sidebar-motion-duration)", "tw:ease-(--sidebar-motion-easing)", "tw:motion-reduce:transition-none"),
|
|
478
501
|
children: /* @__PURE__ */ jsxs("div", {
|
|
479
502
|
className: "tw:flex tw:flex-col tw:gap-2",
|
|
480
503
|
children: [/* @__PURE__ */ jsxs(Title, { children: [/* @__PURE__ */ jsx(SidebarMenuIcon, {
|
|
@@ -505,7 +528,7 @@ const SidebarMenuBadge = ({ ref, className, ...props }) => {
|
|
|
505
528
|
ref,
|
|
506
529
|
"data-slot": "sidebar-menu-badge",
|
|
507
530
|
"data-sidebar": "menu-badge",
|
|
508
|
-
className: cn("tw:flex", "tw:items-center", "tw:justify-center", "tw:z-20", "tw:absolute", "tw:peer-[]/sidebar-menu-button:right-2", "tw:peer-[]/sidebar-menu-card:right-4", "tw:peer-[]/sidebar-menu-card:top-4", "tw:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:right-0", "tw:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:-top-1", "tw:text-xs", "tw:text-sidebar-primary-foreground", "tw:bg-sidebar-primary", "tw:px-1", "tw:min-w-5", "tw:h-5", "tw:rounded-full", "tw:pointer-events-none", "tw:font-medium", "tw:tabular-nums", "tw:select-none", "tw:transition-[top,right]", "tw:delay-50", "tw:ease-
|
|
531
|
+
className: cn("tw:flex", "tw:items-center", "tw:justify-center", "tw:z-20", "tw:absolute", "tw:peer-[]/sidebar-menu-button:right-2", "tw:peer-[]/sidebar-menu-card:right-4", "tw:peer-[]/sidebar-menu-card:top-4", "tw:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:right-0", "tw:group-data-[state=collapsed]/sidebar:group-data-[collapsible=icon]/sidebar:-top-1", "tw:text-xs", "tw:text-sidebar-primary-foreground", "tw:bg-sidebar-primary", "tw:px-1", "tw:min-w-5", "tw:h-5", "tw:rounded-full", "tw:pointer-events-none", "tw:font-medium", "tw:tabular-nums", "tw:select-none", "tw:transition-[top,right]", "tw:delay-50", "tw:duration-(--sidebar-motion-duration)", "tw:ease-(--sidebar-motion-easing)", "tw:motion-reduce:transition-none", className),
|
|
509
532
|
...props
|
|
510
533
|
});
|
|
511
534
|
};
|
|
@@ -715,12 +738,13 @@ const SidebarTrigger = ({ side = "left", onClick, hideWhenCollapsed = false, cla
|
|
|
715
738
|
};
|
|
716
739
|
//#endregion
|
|
717
740
|
//#region src/components/Sidebar/Sidebar.tsx
|
|
718
|
-
const Sidebar = ({ children, className, id, side = "left", style, container = false, keepMounted, resizable = false, ...rest }) => {
|
|
741
|
+
const Sidebar = ({ children, className, id, side = "left", style, container = false, keepMounted, mountAfterEnter, resizable = false, ...rest }) => {
|
|
719
742
|
const oppositeSide = side === "left" ? "right" : "left";
|
|
720
743
|
const { setSidebarElement, state, mode, isFill, widths, collapsible, variant, isDragging } = useSidebar(side);
|
|
721
744
|
const { isMounted, completeUnmount } = useTransitionPresence({
|
|
722
745
|
mounted: collapsible !== "off-canvas" || mode !== "collapsed",
|
|
723
|
-
keepMounted
|
|
746
|
+
keepMounted,
|
|
747
|
+
mountAfterEnter
|
|
724
748
|
});
|
|
725
749
|
const { widths: oppositeWidths } = useSidebar(oppositeSide);
|
|
726
750
|
const sidebarInstanceContextValue = useMemo(() => ({
|
|
@@ -757,14 +781,14 @@ const Sidebar = ({ children, className, id, side = "left", style, container = fa
|
|
|
757
781
|
"data-variant": variant,
|
|
758
782
|
"data-fill": isFill,
|
|
759
783
|
style: styles,
|
|
760
|
-
className: cn("tailwindcss-preflight", "tw:flex", "tw:relative", mode === "expand-on-hover" ? "tw:z-[51]" : "tw:z-50", { "tw:group/sidebar tw:peer/sidebar": !container }, "tw:[&>[data-slot=gap]]:w-(--sidebar-width-gap)", "tw:[&[data-side=right]>[data-slot=gap]]:rotate-180", "tw:[&>[data-slot=sidebar-wrapper]]:w-(--sidebar-width)", "tw:[&[data-side=left]>[data-slot=sidebar-wrapper]]:left-0", "tw:[&[data-side=right]>[data-slot=sidebar-wrapper]]:right-0", "tw:[&[data-state=collapsed][data-collapsible=off-canvas][data-side=left]>[data-slot=sidebar-wrapper]]:-translate-x-full", "tw:[&[data-state=collapsed][data-collapsible=off-canvas][data-side=right]>[data-slot=sidebar-wrapper]]:translate-x-full", "tw:[&[data-variant=sided-floating]>[data-slot=sidebar-wrapper]]:pt-(--sidebar-floating-padding)", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]]:pr-(--sidebar-floating-padding)", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]]:pl-(--sidebar-floating-padding)", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]]:p-(--sidebar-floating-padding)", "tw:[&[data-fill=true]>[data-slot=sidebar-wrapper]]:!w-[calc(100svw-var(--opposite-sidebar-width))]", "tw:[&[data-fill=true][data-variant=floating]>[data-slot=sidebar-wrapper]]:!p-(--sidebar-floating-padding)", "tw:[&[data-fill=true][data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:!rounded-tr-xl", "tw:[&[data-fill=true][data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:!rounded-tl-xl", "tw:[&[data-variant=inset][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-r", "tw:[&[data-variant=inset][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-l", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:shadow", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-xl", "tw:[&[data-variant=sided-floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:shadow", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-tr-xl", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-tl-xl", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-r", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-l", isDragging ? "tw:transition-none" : "tw:transition-[width,translate,transform] tw:duration-
|
|
784
|
+
className: cn("tailwindcss-preflight", "tw:flex", "tw:relative", mode === "expand-on-hover" ? "tw:z-[51]" : "tw:z-50", { "tw:group/sidebar tw:peer/sidebar": !container }, "tw:[&>[data-slot=gap]]:w-(--sidebar-width-gap)", "tw:[&[data-side=right]>[data-slot=gap]]:rotate-180", "tw:[&>[data-slot=sidebar-wrapper]]:w-(--sidebar-width)", "tw:[&[data-side=left]>[data-slot=sidebar-wrapper]]:left-0", "tw:[&[data-side=right]>[data-slot=sidebar-wrapper]]:right-0", "tw:[&[data-state=collapsed][data-collapsible=off-canvas][data-side=left]>[data-slot=sidebar-wrapper]]:-translate-x-full", "tw:[&[data-state=collapsed][data-collapsible=off-canvas][data-side=right]>[data-slot=sidebar-wrapper]]:translate-x-full", "tw:[&[data-variant=sided-floating]>[data-slot=sidebar-wrapper]]:pt-(--sidebar-floating-padding)", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]]:pr-(--sidebar-floating-padding)", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]]:pl-(--sidebar-floating-padding)", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]]:p-(--sidebar-floating-padding)", "tw:[&[data-fill=true]>[data-slot=sidebar-wrapper]]:!w-[calc(100svw-var(--opposite-sidebar-width))]", "tw:[&[data-fill=true][data-variant=floating]>[data-slot=sidebar-wrapper]]:!p-(--sidebar-floating-padding)", "tw:[&[data-fill=true][data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:!rounded-tr-xl", "tw:[&[data-fill=true][data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:!rounded-tl-xl", "tw:[&[data-variant=inset][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-r", "tw:[&[data-variant=inset][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-l", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:shadow", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-xl", "tw:[&[data-variant=sided-floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:shadow", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-tr-xl", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-tl-xl", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-r", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-l", isDragging ? "tw:transition-none" : "tw:transition-[width,translate,transform] tw:duration-(--sidebar-motion-duration) tw:ease-(--sidebar-motion-easing) tw:motion-reduce:transition-none"),
|
|
761
785
|
children: [/* @__PURE__ */ jsx("div", {
|
|
762
786
|
"data-slot": "gap",
|
|
763
|
-
className: cn("tw:bg-transparent", isDragging ? "" : "tw:transition-[width] tw:duration-
|
|
787
|
+
className: cn("tw:bg-transparent", isDragging ? "" : "tw:transition-[width] tw:duration-(--sidebar-motion-duration) tw:ease-(--sidebar-motion-easing) tw:motion-reduce:transition-none")
|
|
764
788
|
}), /* @__PURE__ */ jsxs("div", {
|
|
765
789
|
"data-slot": "sidebar-wrapper",
|
|
766
790
|
onTransitionEnd: handleTransitionEnd,
|
|
767
|
-
className: cn("tw:fixed", "tw:inset-y-0", "tw:border-border", isDragging ? "tw:transition-none" : "tw:transition-[width,translate,transform] tw:duration-
|
|
791
|
+
className: cn("tw:fixed", "tw:inset-y-0", "tw:border-border", isDragging ? "tw:transition-none" : "tw:transition-[width,translate,transform] tw:duration-(--sidebar-motion-duration) tw:ease-(--sidebar-motion-easing) tw:motion-reduce:transition-none", "tw:transform-gpu", className),
|
|
768
792
|
style,
|
|
769
793
|
children: [resizable && /* @__PURE__ */ jsx(SidebarResizeHandle, { side }), /* @__PURE__ */ jsx("div", {
|
|
770
794
|
"data-slot": "sidebar",
|
|
@@ -798,4 +822,4 @@ Sidebar.SubItem = SidebarMenuSubItem;
|
|
|
798
822
|
//#endregion
|
|
799
823
|
export { Sidebar, SidebarProvider, useOptionalSidebar, useSidebar };
|
|
800
824
|
|
|
801
|
-
//# sourceMappingURL=Sidebar-
|
|
825
|
+
//# sourceMappingURL=Sidebar-D3cY1kha.js.map
|