@adea-ai/ui 0.114.0 → 0.115.1

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.
Files changed (66) hide show
  1. package/dist/components/composites/list-row/list-row-control.d.ts +6 -0
  2. package/dist/components/composites/list-row/list-row-control.d.ts.map +1 -1
  3. package/dist/components/composites/list-row/list-row-control.js +4 -0
  4. package/dist/components/composites/list-row/list-row-control.js.map +1 -1
  5. package/dist/components/composites/tree/index.d.ts +1 -1
  6. package/dist/components/composites/tree/index.d.ts.map +1 -1
  7. package/dist/components/composites/tree/index.js +2 -2
  8. package/dist/components/composites/tree/tree.d.ts +12 -0
  9. package/dist/components/composites/tree/tree.d.ts.map +1 -1
  10. package/dist/components/composites/tree/tree.js +27 -2
  11. package/dist/components/composites/tree/tree.js.map +1 -1
  12. package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts +7 -0
  13. package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts.map +1 -1
  14. package/dist/components/layout/contextual-sidebar/contextual-sidebar.js +25 -6
  15. package/dist/components/layout/contextual-sidebar/contextual-sidebar.js.map +1 -1
  16. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts +6 -0
  17. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts.map +1 -1
  18. package/dist/components/layout/sidebar-nav/sidebar-nav.js +5 -3
  19. package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
  20. package/dist/components/layout/top-bar/top-bar.d.ts.map +1 -1
  21. package/dist/components/layout/top-bar/top-bar.js +3 -3
  22. package/dist/components/layout/top-bar/top-bar.js.map +1 -1
  23. package/dist/components/ui/input/input-control.d.ts +7 -1
  24. package/dist/components/ui/input/input-control.d.ts.map +1 -1
  25. package/dist/components/ui/input/input-control.js +10 -2
  26. package/dist/components/ui/input/input-control.js.map +1 -1
  27. package/dist/components/ui/input/input.d.ts +5 -4
  28. package/dist/components/ui/input/input.d.ts.map +1 -1
  29. package/dist/components/ui/input/input.js.map +1 -1
  30. package/dist/components/ui/modal-dialog/modal-dialog.d.ts +2 -1
  31. package/dist/components/ui/modal-dialog/modal-dialog.d.ts.map +1 -1
  32. package/dist/components/ui/modal-dialog/modal-dialog.js +3 -0
  33. package/dist/components/ui/modal-dialog/modal-dialog.js.map +1 -1
  34. package/dist/components/ui/resizable/resizable.d.ts.map +1 -1
  35. package/dist/components/ui/resizable/resizable.js +1 -1
  36. package/dist/components/ui/resizable/resizable.js.map +1 -1
  37. package/dist/components/ui/status-chip/status-chip.d.ts +5 -3
  38. package/dist/components/ui/status-chip/status-chip.d.ts.map +1 -1
  39. package/dist/components/ui/status-chip/status-chip.js +5 -1
  40. package/dist/components/ui/status-chip/status-chip.js.map +1 -1
  41. package/dist/index.js +2 -2
  42. package/dist/r/src/components/composites/list-row/list-row-control.tsx +8 -0
  43. package/dist/r/src/components/composites/tree/index.ts +1 -1
  44. package/dist/r/src/components/composites/tree/tree.tsx +31 -1
  45. package/dist/r/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +23 -4
  46. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +25 -2
  47. package/dist/r/src/components/layout/top-bar/top-bar.tsx +14 -5
  48. package/dist/r/src/components/ui/input/input-control.tsx +14 -3
  49. package/dist/r/src/components/ui/input/input.tsx +5 -5
  50. package/dist/r/src/components/ui/modal-dialog/modal-dialog.tsx +3 -1
  51. package/dist/r/src/components/ui/resizable/resizable.tsx +4 -3
  52. package/dist/r/src/components/ui/status-chip/status-chip.tsx +13 -2
  53. package/dist/r/src/styles/base.css +7 -6
  54. package/package.json +1 -1
  55. package/src/components/composites/list-row/list-row-control.tsx +8 -0
  56. package/src/components/composites/tree/index.ts +1 -1
  57. package/src/components/composites/tree/tree.tsx +31 -1
  58. package/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +23 -4
  59. package/src/components/layout/sidebar-nav/sidebar-nav.tsx +25 -2
  60. package/src/components/layout/top-bar/top-bar.tsx +14 -5
  61. package/src/components/ui/input/input-control.tsx +14 -3
  62. package/src/components/ui/input/input.tsx +5 -5
  63. package/src/components/ui/modal-dialog/modal-dialog.tsx +3 -1
  64. package/src/components/ui/resizable/resizable.tsx +4 -3
  65. package/src/components/ui/status-chip/status-chip.tsx +13 -2
  66. package/src/styles/base.css +7 -6
@@ -1 +1 @@
1
- {"version":3,"file":"status-chip.js","names":["Show","splitProps","ComponentProps","JSX","cva","cn","Tooltip","TooltipContent","TooltipTrigger","statusDotVariants","variants","tone","neutral","success","warning","danger","info","unknown","defaultVariants","labelTone","Record","StatusTone","StatusChipProps","Omit","label","compact","detail","trailing","Element","StatusChip","props","local","rest","chip","_el$","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_$spread","_$mergeProps","class","_$insert","_$effect","_p$","_v$","_v$2","e","_$className","t","undefined","_$createComponent","when","fallback","children","as","StatusEntry","Readonly","id","name","StatusList","entries","_el$4","_tmpl$2","map","entry","_el$5","_tmpl$4","_el$7","_el$6","_tmpl$3","_$mergeProps","_$className","_$createComponent"],"sources":["../../../../src/components/ui/status-chip/status-chip.tsx"],"sourcesContent":["import { Show, splitProps, type ComponentProps, type JSX } from 'solid-js'\nimport { cva } from '#lib/variants'\nimport { cn } from '#lib/utils'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'\n\n/**\n * StatusChip.\n *\n * A state, said in one word, with the reason available on hover. It exists\n * because a status readout has three parts that are always the same three parts —\n * a tone, a label, and the detail that justifies the label — and rendering them\n * ad hoc produces the two failures this component is here to prevent: a colour\n * with no text (unreadable to anyone who cannot see it) and a bare word with no\n * explanation (\"Needs configuration\" — of what?).\n *\n * The tones are deliberately not a rainbow. Six cover what a status can actually\n * mean:\n *\n * - `neutral` — fine, and there is nothing to say about it.\n * - `success` — a check passed, a capability is ready, a job finished.\n * - `warning` — degraded, or needs a decision from the user.\n * - `danger` — blocked, failed, unrecoverable without intervention.\n * - `info` — in flight or scheduled; work is happening, nothing is wrong.\n * - `unknown` — the honest absence of information.\n *\n * `unknown` is not the same as `neutral`, and collapsing them is the mistake\n * worth avoiding: \"this is idle\" and \"we have not been told yet\" are different\n * facts, and a product that shows the second as the first is lying quietly. The\n * ring is hollow so it also reads as different in greyscale.\n *\n * The dot is `aria-hidden` and the label carries the meaning, so a tone is never\n * the only signal.\n */\nexport const statusDotVariants = cva('size-2 shrink-0 rounded-full', {\n variants: {\n tone: {\n neutral: 'bg-muted-foreground',\n success: 'bg-success',\n warning: 'bg-warning',\n danger: 'bg-destructive',\n info: 'bg-info',\n unknown: 'border border-muted-foreground bg-transparent',\n },\n },\n defaultVariants: { tone: 'neutral' },\n})\n\nconst labelTone: Record<StatusTone, string> = {\n neutral: 'text-foreground',\n success: 'text-foreground',\n warning: 'text-foreground',\n danger: 'text-foreground',\n info: 'text-foreground',\n unknown: 'text-muted-foreground',\n}\n\nexport type StatusTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'unknown'\n\nexport type StatusChipProps = Omit<ComponentProps<'span'>, 'children'> & {\n tone?: StatusTone\n label: string\n /** Visually hide the text while preserving it for assistive technology. */\n compact?: boolean\n /** Why the status is what it is. Shown in a tooltip; omit for a self-evident label. */\n detail?: string\n /** A trailing slot: a timestamp, a retry affordance, a count. */\n trailing?: JSX.Element\n}\n\nexport function StatusChip(props: StatusChipProps) {\n const [local, rest] = splitProps(props, [\n 'tone',\n 'label',\n 'compact',\n 'detail',\n 'trailing',\n 'class',\n ])\n\n const chip = (\n <span\n class={cn(\n 'inline-flex w-fit items-center gap-1.5 text-xs font-medium whitespace-nowrap',\n labelTone[local.tone ?? 'neutral'],\n local.class\n )}\n {...rest}\n >\n <span class={statusDotVariants({ tone: local.tone })} aria-hidden=\"true\" />\n <span class={cn(local.compact && 'sr-only')}>{local.label}</span>\n {local.trailing}\n </span>\n )\n\n return (\n <Show when={local.detail} fallback={chip}>\n {(detail) => (\n <Tooltip>\n <TooltipTrigger as=\"span\" class=\"inline-flex\">\n {chip}\n </TooltipTrigger>\n <TooltipContent data-slot=\"tooltip-content\">{detail()}</TooltipContent>\n </Tooltip>\n )}\n </Show>\n )\n}\n\nexport type StatusEntry = Readonly<{\n /** A stable key for the row. */\n id: string\n /** What is being reported — \"Configuration\", \"Runtime\", \"Sync\". */\n name: string\n tone: StatusTone\n label: string\n detail?: string\n}>\n\n/**\n * StatusList.\n *\n * The several-facts-about-one-thing shape: an agent with a configuration state, a\n * runtime state and an activity state; a service with a build, a deploy and a\n * health check. It is a definition list rather than a table because there is no\n * column to sort or compare — the rows are facets of a single subject, and a\n * screen reader should hear them as such.\n *\n * Fixed width on the name column is what makes a column of these scannable; the\n * rows line up without a table's semantics.\n */\nexport function StatusList(props: {\n entries: readonly StatusEntry[]\n class?: string\n /** Hide the name column and show only the chips — for a compact badge strip. */\n compact?: boolean\n}) {\n return (\n <dl class={cn('grid gap-2 text-sm', props.class)}>\n {props.entries.map((entry) => (\n <div class=\"flex items-baseline justify-between gap-4\">\n <Show when={!props.compact}>\n <dt class=\"text-muted-foreground\">{entry.name}</dt>\n </Show>\n <dd class={cn(!props.compact && 'shrink-0')}>\n <StatusChip tone={entry.tone} label={entry.label} detail={entry.detail} />\n </dd>\n </div>\n ))}\n </dl>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"status-chip.js","names":["Show","splitProps","ComponentProps","JSX","cva","cn","Tooltip","TooltipContent","TooltipTrigger","statusDotVariants","variants","tone","neutral","success","warning","danger","info","pending","unknown","defaultVariants","labelTone","Record","StatusTone","StatusChipProps","Omit","label","compact","detail","trailing","Element","StatusChip","props","local","rest","chip","_el$","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_$spread","_$mergeProps","class","_$insert","_$effect","_p$","_v$","_v$2","e","_$className","t","undefined","_$createComponent","when","fallback","children","as","StatusEntry","Readonly","id","name","StatusList","entries","_el$4","_tmpl$2","map","entry","_el$5","_tmpl$4","_el$7","_el$6","_tmpl$3","_$mergeProps","_$className","_$createComponent"],"sources":["../../../../src/components/ui/status-chip/status-chip.tsx"],"sourcesContent":["import { Show, splitProps, type ComponentProps, type JSX } from 'solid-js'\nimport { cva } from '#lib/variants'\nimport { cn } from '#lib/utils'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'\n\n/**\n * StatusChip.\n *\n * A state, said in one word, with the reason available on hover. It exists\n * because a status readout has three parts that are always the same three parts —\n * a tone, a label, and the detail that justifies the label — and rendering them\n * ad hoc produces the two failures this component is here to prevent: a colour\n * with no text (unreadable to anyone who cannot see it) and a bare word with no\n * explanation (\"Needs configuration\" — of what?).\n *\n * The tones are deliberately not a rainbow. Seven cover what a status can actually\n * mean:\n *\n * - `neutral` — fine, and there is nothing to say about it.\n * - `success` — a check passed, a capability is ready, a job finished.\n * - `warning` — degraded, or needs a decision from the user.\n * - `danger` — blocked, failed, unrecoverable without intervention.\n * - `info` — in flight or scheduled; work is happening, nothing is wrong.\n * - `pending` — running now with no result yet (a check, a build). The ring\n * turns, so it reads as live rather than as a settled state.\n * - `unknown` — the honest absence of information.\n *\n * `unknown` is not the same as `neutral`, and collapsing them is the mistake\n * worth avoiding: \"this is idle\" and \"we have not been told yet\" are different\n * facts, and a product that shows the second as the first is lying quietly. The\n * ring is hollow so it also reads as different in greyscale.\n *\n * The dot is `aria-hidden` and the label carries the meaning, so a tone is never\n * the only signal.\n */\nexport const statusDotVariants = cva('size-2 shrink-0 rounded-full', {\n variants: {\n tone: {\n neutral: 'bg-muted-foreground',\n success: 'bg-success',\n warning: 'bg-warning',\n danger: 'bg-destructive',\n info: 'bg-info',\n pending: 'border-2 border-info border-r-transparent motion-safe:animate-spin',\n unknown: 'border border-muted-foreground bg-transparent',\n },\n },\n defaultVariants: { tone: 'neutral' },\n})\n\nconst labelTone: Record<StatusTone, string> = {\n neutral: 'text-foreground',\n success: 'text-foreground',\n warning: 'text-foreground',\n danger: 'text-foreground',\n info: 'text-foreground',\n pending: 'text-foreground',\n unknown: 'text-muted-foreground',\n}\n\nexport type StatusTone =\n | 'neutral'\n | 'success'\n | 'warning'\n | 'danger'\n | 'info'\n | 'pending'\n | 'unknown'\n\nexport type StatusChipProps = Omit<ComponentProps<'span'>, 'children'> & {\n tone?: StatusTone\n label: string\n /** Visually hide the text while preserving it for assistive technology. */\n compact?: boolean\n /** Why the status is what it is. Shown in a tooltip; omit for a self-evident label. */\n detail?: string\n /** A trailing slot: a timestamp, a retry affordance, a count. */\n trailing?: JSX.Element\n}\n\nexport function StatusChip(props: StatusChipProps) {\n const [local, rest] = splitProps(props, [\n 'tone',\n 'label',\n 'compact',\n 'detail',\n 'trailing',\n 'class',\n ])\n\n const chip = (\n <span\n class={cn(\n 'inline-flex w-fit items-center gap-1.5 text-xs font-medium whitespace-nowrap',\n labelTone[local.tone ?? 'neutral'],\n local.class\n )}\n {...rest}\n >\n <span class={statusDotVariants({ tone: local.tone })} aria-hidden=\"true\" />\n <span class={cn(local.compact && 'sr-only')}>{local.label}</span>\n {local.trailing}\n </span>\n )\n\n return (\n <Show when={local.detail} fallback={chip}>\n {(detail) => (\n <Tooltip>\n <TooltipTrigger as=\"span\" class=\"inline-flex\">\n {chip}\n </TooltipTrigger>\n <TooltipContent data-slot=\"tooltip-content\">{detail()}</TooltipContent>\n </Tooltip>\n )}\n </Show>\n )\n}\n\nexport type StatusEntry = Readonly<{\n /** A stable key for the row. */\n id: string\n /** What is being reported — \"Configuration\", \"Runtime\", \"Sync\". */\n name: string\n tone: StatusTone\n label: string\n detail?: string\n}>\n\n/**\n * StatusList.\n *\n * The several-facts-about-one-thing shape: an agent with a configuration state, a\n * runtime state and an activity state; a service with a build, a deploy and a\n * health check. It is a definition list rather than a table because there is no\n * column to sort or compare — the rows are facets of a single subject, and a\n * screen reader should hear them as such.\n *\n * Fixed width on the name column is what makes a column of these scannable; the\n * rows line up without a table's semantics.\n */\nexport function StatusList(props: {\n entries: readonly StatusEntry[]\n class?: string\n /** Hide the name column and show only the chips — for a compact badge strip. */\n compact?: boolean\n}) {\n return (\n <dl class={cn('grid gap-2 text-sm', props.class)}>\n {props.entries.map((entry) => (\n <div class=\"flex items-baseline justify-between gap-4\">\n <Show when={!props.compact}>\n <dt class=\"text-muted-foreground\">{entry.name}</dt>\n </Show>\n <dd class={cn(!props.compact && 'shrink-0')}>\n <StatusChip tone={entry.tone} label={entry.label} detail={entry.detail} />\n </dd>\n </div>\n ))}\n </dl>\n )\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -115,7 +115,7 @@ import { CatalogBrowser } from "./components/composites/catalog-browser/catalog-
115
115
  import { CatalogDetail, CatalogDetailSection } from "./components/composites/catalog-browser/catalog-detail.js";
116
116
  import { ListRowControl } from "./components/composites/list-row/list-row-control.js";
117
117
  import { ListGroup, ListRow } from "./components/composites/list-row/list-row.js";
118
- import { Tree, TreeRow } from "./components/composites/tree/tree.js";
118
+ import { Tree, TreeRow, TreeRowActions } from "./components/composites/tree/tree.js";
119
119
  import { SettingsField, SettingsPage, SettingsRow, SettingsSection } from "./components/composites/settings/settings.js";
120
120
  import { SettingsNavigation } from "./components/composites/settings/settings-navigation.js";
121
121
  import { SettingsLayout } from "./components/composites/settings/settings-layout.js";
@@ -130,4 +130,4 @@ import { AboutDialog } from "./components/composites/about-dialog/about-dialog.j
130
130
  import { HelpCenter } from "./components/composites/help-center/help-center.js";
131
131
  import { WorkspaceMark } from "./components/composites/workspace-mark/workspace-mark.js";
132
132
  import { writeClipboardText } from "./lib/clipboard.js";
133
- export { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, AboutDialog, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AccountMenu, ActionButton, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnnotationSurface, AppShell, AppShellBody, AppShellContent, AppShellMain, AppearanceEditor, AppearanceEditorActions, AppearanceFontSettingsGroup, AppearancePanel, AppearancePopover, AspectRatio, AttachmentCard, Avatar, AvatarFallback, AvatarImage, Badge, Board, BoardCardBody, BoardCardTitle, BoardCardTrigger, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator, BusySendButton, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CalendarSurface, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CatalogBrowser, CatalogDetail, CatalogDetailSection, ChatComposer, Checkbox, CheckboxDescription, CheckboxLabel, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxClear, ComboboxContent, ComboboxControl, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposerAttachmentButton, ComposerHint, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ContextualSidebar, ConversationAvatar, ConversationSurface, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, DatePicker, DetailPanel, DetailPanelBody, DetailPanelField, DetailPanelHeader, DetailPanelSection, Dialog, DialogClose, DialogCloseButton, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffBlock, DiffSummary, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, EntityIcon, FLOATING_PREVIEW_CORNER_RADIUS, FLOATING_PREVIEW_EDGE_GAP, Field, FieldDescription, FieldError, FieldGroup, FieldInput, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTextArea, FloatingPreview, FormField, Heading, HelpCenter, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputControl, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOtp, InputOtpCaret, Item, ItemDescription, ItemEmpty, ItemGroup, ItemGroupEntry, ItemTitle, Kbd, KbdChord, KbdGroup, Label, ListGroup, ListRow, ListRowControl, MAX_LAYOUT_DEPTH, MAX_LAYOUT_LEAVES, MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MessageBody, MessageComposer, MessageDayDivider, MessageGroup, MessageRow, ModalDialog, Motion, NO_FLOATING_PREVIEW_OBSTACLES, NO_PREVIEW_MINI_PLAYER_OBSTACLES, NativeSelect, NavigationMenu, NavigationMenuContent, NavigationMenuGroup, NavigationMenuGroupLabel, NavigationMenuItem, NavigationMenuMenu, NavigationMenuSeparator, NavigationMenuTrigger, NavigationMenuViewport, NumberField, OrbitItem, OrbitLayout, PASTE_THRESHOLD_CHARS, PASTE_THRESHOLD_LINES, PASTE_TOKEN_REGEX, PREVIEW_MINI_PLAYER_CORNER_RADIUS, PREVIEW_MINI_PLAYER_EDGE_GAP, Page, PageHeader, PageHeaderActions, PageHeaderContent, PageHeaderDescription, PageHeaderTitle, PageSection, Pagination, PaginationEllipsis, PaginationItem, PaginationNext, PaginationPrevious, PalettePreview, Panel, PanelActions, PanelBody, PanelCard, PanelDescription, PanelFooter, PanelHeader, PanelPlaceholder, PanelTitle, PanelToolbar, PixelResizeHandle, Popover, PopoverAnchor, PopoverCloseButton, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Presence, Progress, PropertyList, PropertyRow, PropertyTerm, PropertyValue, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, SceneControls, ScrollArea, SecretInputGroup, Select, SelectChevronsUpDown, SelectContent, SelectItem, SelectLabel, SelectSection, SelectTrigger, SelectValue, Separator, SettingsField, SettingsLayout, SettingsNavigation, SettingsPage, SettingsRow, SettingsSection, Sheet, SheetBody, SheetCloseButton, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SideRail, SideRailButton, SideRailContent, SideRailFooter, SideRailHeader, SideRailItem, SideRailSection, SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavResizeHandle, SidebarNavRow, SidebarNavSection, SidebarNavTitle, Skeleton, SkipLink, Slider, Spinner, SplitLayout, Stat, StatGroup, StatusBar, StatusBarItem, StatusBarSpacer, StatusChip, StatusList, Switch, SwitchDescription, SwitchLabel, TALL_CODE_BLOCK_PX, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableNumericCell, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, TextLink, Textarea, ThemeMiniature, ThemeMiniatureSplit, ThemeModeToggle, ThemePicker, ThemePreview, ThemeProvider, ThemeSwatch, ThemeToggle, ThreadPanel, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopBar, TopBarBreadcrumb, TopBarPill, TopBarSearch, TopBarSection, TopBarTitle, TranscriptComposition, Tree, TreeRow, UpdateChannelControl, UpdateDialog, ValueCombobox, VirtualWindow, WorkspaceMark, accentPresets, alertVariants, allTokens, appearancePreviewThemes, applyAppearanceFontSettings, badgeVariants, boardCardTitleVariants, builtinThemes, buttonVariants, clampFloatingPreviewPosition, clampPreviewMiniPlayerPosition, closePane, cn, colorTokens, computeLayoutFrames, contrastRatio, controlInteractive, controlSize, controlSizeIcon, controlSizes, countLeaves, countLines, createAppMenuItems, createLayoutState, cva, defaultDarkThemeId, defaultLightThemeId, defaultThemeSelection, densityTokens, designTokens, diffLineVariants, diffStats, diffTargetPath, elevationTokens, entityIconVariants, expandAll, findTokenRanges, focusPane, fontOptions, fontSettingsBootstrapScript, formatBytes, formatReleaseDate, formatToken, headingElement, headingVariants, initialsFrom, inlineScriptLiteral, isPasteBlock, isThemeAccentId, itemVariants, kbdChordKeys, kbdGroupVariants, kbdVariants, keyedRows, layoutDepth, listLeaves, monogram, motionTokens, movePane, neighborLeaf, nextSeq, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize, normalizeLayout, parseDiff, plainTextFromMarkdown, pruneBlocks, radiusTokens, recollapsePastes, remapCarriedBlocks, resizeFloatingPreview, resizePreviewMiniPlayer, resizeSplit, resolveAccentPreset, resolveFloatingPreviewFrame, resolvePreviewMiniPlayerFrame, resolvedDensity, sheetVariants, shouldCollapse, sidebarNavItemClass, sidebarNavItemStateClass, splitPane, splitPaneBalanced, statusDotVariants, stripTrailingBlankLines, surfaceInteractive, swapPanes, textElement, textVariants, textareaVariants, themeAccentsFor, themeById, themeCssVariables, themeFamilies, themeRecordById, themeRecords, themeScript, themesForAppearance, toast, toaster, toggleVariants, tokenRangeAt, transcriptDisclosureKey, typographyTokens, undoClosePane, undocumentedTokenAliases, useSideRail, useTheme, validateTheme, validateThemeRegistry, withAccent, writeClipboardText, zIndexTokens };
133
+ export { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, AboutDialog, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AccountMenu, ActionButton, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnnotationSurface, AppShell, AppShellBody, AppShellContent, AppShellMain, AppearanceEditor, AppearanceEditorActions, AppearanceFontSettingsGroup, AppearancePanel, AppearancePopover, AspectRatio, AttachmentCard, Avatar, AvatarFallback, AvatarImage, Badge, Board, BoardCardBody, BoardCardTitle, BoardCardTrigger, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator, BusySendButton, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CalendarSurface, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CatalogBrowser, CatalogDetail, CatalogDetailSection, ChatComposer, Checkbox, CheckboxDescription, CheckboxLabel, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxClear, ComboboxContent, ComboboxControl, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposerAttachmentButton, ComposerHint, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ContextualSidebar, ConversationAvatar, ConversationSurface, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, DatePicker, DetailPanel, DetailPanelBody, DetailPanelField, DetailPanelHeader, DetailPanelSection, Dialog, DialogClose, DialogCloseButton, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffBlock, DiffSummary, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, EntityIcon, FLOATING_PREVIEW_CORNER_RADIUS, FLOATING_PREVIEW_EDGE_GAP, Field, FieldDescription, FieldError, FieldGroup, FieldInput, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTextArea, FloatingPreview, FormField, Heading, HelpCenter, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputControl, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOtp, InputOtpCaret, Item, ItemDescription, ItemEmpty, ItemGroup, ItemGroupEntry, ItemTitle, Kbd, KbdChord, KbdGroup, Label, ListGroup, ListRow, ListRowControl, MAX_LAYOUT_DEPTH, MAX_LAYOUT_LEAVES, MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MessageBody, MessageComposer, MessageDayDivider, MessageGroup, MessageRow, ModalDialog, Motion, NO_FLOATING_PREVIEW_OBSTACLES, NO_PREVIEW_MINI_PLAYER_OBSTACLES, NativeSelect, NavigationMenu, NavigationMenuContent, NavigationMenuGroup, NavigationMenuGroupLabel, NavigationMenuItem, NavigationMenuMenu, NavigationMenuSeparator, NavigationMenuTrigger, NavigationMenuViewport, NumberField, OrbitItem, OrbitLayout, PASTE_THRESHOLD_CHARS, PASTE_THRESHOLD_LINES, PASTE_TOKEN_REGEX, PREVIEW_MINI_PLAYER_CORNER_RADIUS, PREVIEW_MINI_PLAYER_EDGE_GAP, Page, PageHeader, PageHeaderActions, PageHeaderContent, PageHeaderDescription, PageHeaderTitle, PageSection, Pagination, PaginationEllipsis, PaginationItem, PaginationNext, PaginationPrevious, PalettePreview, Panel, PanelActions, PanelBody, PanelCard, PanelDescription, PanelFooter, PanelHeader, PanelPlaceholder, PanelTitle, PanelToolbar, PixelResizeHandle, Popover, PopoverAnchor, PopoverCloseButton, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Presence, Progress, PropertyList, PropertyRow, PropertyTerm, PropertyValue, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, SceneControls, ScrollArea, SecretInputGroup, Select, SelectChevronsUpDown, SelectContent, SelectItem, SelectLabel, SelectSection, SelectTrigger, SelectValue, Separator, SettingsField, SettingsLayout, SettingsNavigation, SettingsPage, SettingsRow, SettingsSection, Sheet, SheetBody, SheetCloseButton, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SideRail, SideRailButton, SideRailContent, SideRailFooter, SideRailHeader, SideRailItem, SideRailSection, SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavResizeHandle, SidebarNavRow, SidebarNavSection, SidebarNavTitle, Skeleton, SkipLink, Slider, Spinner, SplitLayout, Stat, StatGroup, StatusBar, StatusBarItem, StatusBarSpacer, StatusChip, StatusList, Switch, SwitchDescription, SwitchLabel, TALL_CODE_BLOCK_PX, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableNumericCell, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, TextLink, Textarea, ThemeMiniature, ThemeMiniatureSplit, ThemeModeToggle, ThemePicker, ThemePreview, ThemeProvider, ThemeSwatch, ThemeToggle, ThreadPanel, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopBar, TopBarBreadcrumb, TopBarPill, TopBarSearch, TopBarSection, TopBarTitle, TranscriptComposition, Tree, TreeRow, TreeRowActions, UpdateChannelControl, UpdateDialog, ValueCombobox, VirtualWindow, WorkspaceMark, accentPresets, alertVariants, allTokens, appearancePreviewThemes, applyAppearanceFontSettings, badgeVariants, boardCardTitleVariants, builtinThemes, buttonVariants, clampFloatingPreviewPosition, clampPreviewMiniPlayerPosition, closePane, cn, colorTokens, computeLayoutFrames, contrastRatio, controlInteractive, controlSize, controlSizeIcon, controlSizes, countLeaves, countLines, createAppMenuItems, createLayoutState, cva, defaultDarkThemeId, defaultLightThemeId, defaultThemeSelection, densityTokens, designTokens, diffLineVariants, diffStats, diffTargetPath, elevationTokens, entityIconVariants, expandAll, findTokenRanges, focusPane, fontOptions, fontSettingsBootstrapScript, formatBytes, formatReleaseDate, formatToken, headingElement, headingVariants, initialsFrom, inlineScriptLiteral, isPasteBlock, isThemeAccentId, itemVariants, kbdChordKeys, kbdGroupVariants, kbdVariants, keyedRows, layoutDepth, listLeaves, monogram, motionTokens, movePane, neighborLeaf, nextSeq, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize, normalizeLayout, parseDiff, plainTextFromMarkdown, pruneBlocks, radiusTokens, recollapsePastes, remapCarriedBlocks, resizeFloatingPreview, resizePreviewMiniPlayer, resizeSplit, resolveAccentPreset, resolveFloatingPreviewFrame, resolvePreviewMiniPlayerFrame, resolvedDensity, sheetVariants, shouldCollapse, sidebarNavItemClass, sidebarNavItemStateClass, splitPane, splitPaneBalanced, statusDotVariants, stripTrailingBlankLines, surfaceInteractive, swapPanes, textElement, textVariants, textareaVariants, themeAccentsFor, themeById, themeCssVariables, themeFamilies, themeRecordById, themeRecords, themeScript, themesForAppearance, toast, toaster, toggleVariants, tokenRangeAt, transcriptDisclosureKey, typographyTokens, undoClosePane, undocumentedTokenAliases, useSideRail, useTheme, validateTheme, validateThemeRegistry, withAccent, writeClipboardText, zIndexTokens };
@@ -18,6 +18,12 @@ export type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicP
18
18
  trailing?: JSX.Element
19
19
  /** A second line that wraps and grows the row to fit its content. */
20
20
  description?: string
21
+ /**
22
+ * Whether a described row may drop its trailing slot onto its own line when
23
+ * the row gets narrow (the default). Pass `false` for a short, truncating
24
+ * label whose single action must stay beside it.
25
+ */
26
+ stackTrailing?: boolean
21
27
  /** Native button type; defaults to `button` for button rows. */
22
28
  type?: ComponentProps<'button'>['type']
23
29
  }
@@ -37,6 +43,7 @@ export function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowC
37
43
  'leading',
38
44
  'trailing',
39
45
  'description',
46
+ 'stackTrailing',
40
47
  'type',
41
48
  'tabIndex',
42
49
  'children',
@@ -52,6 +59,7 @@ export function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowC
52
59
  aria-current={local.selected ? 'true' : undefined}
53
60
  data-selected={local.selected ? '' : undefined}
54
61
  data-description={local.description ? '' : undefined}
62
+ data-stack-trailing={local.stackTrailing === false ? 'never' : undefined}
55
63
  class={cn(
56
64
  'group/row list-row-description flex min-w-0 items-center gap-2.5 rounded-md px-2 text-sm',
57
65
  'transition-colors ease-out outline-none',
@@ -1,3 +1,3 @@
1
1
  /** Keyboard-accessible tree rows with virtualization-aware focus handoff. */
2
- export { Tree, TreeRow, type TreeProps, type TreeRowProps } from './tree'
2
+ export { Tree, TreeRow, TreeRowActions, type TreeProps, type TreeRowProps } from './tree'
3
3
  export type { TreeItemDescriptor } from './tree-navigation'
@@ -238,7 +238,12 @@ export function Tree(props: TreeProps) {
238
238
  role="tree"
239
239
  aria-multiselectable={local.selectionMode === 'multiple' ? 'true' : undefined}
240
240
  data-slot="tree"
241
- class={cn('flex min-w-0 flex-col', local.class)}
241
+ class={cn(
242
+ /* A virtualized host remounts rows as it scrolls; scroll anchoring
243
+ would latch onto the focused row and fight the scrollbar. */
244
+ 'flex min-w-0 flex-col [overflow-anchor:none]',
245
+ local.class
246
+ )}
242
247
  onKeyDown={handleKeyDown}
243
248
  >
244
249
  {local.children}
@@ -382,6 +387,31 @@ export function TreeRow(props: TreeRowProps) {
382
387
  )
383
388
  }
384
389
 
390
+ /**
391
+ * TreeRowActions.
392
+ *
393
+ * Row-level commands (rename, copy, delete) that stay out of the way until the
394
+ * row is hovered or holds focus, so a long tree reads as names rather than a
395
+ * wall of buttons. Put it in `TreeRow`'s `trailing` slot beside any status that
396
+ * must stay visible. `pinned` keeps the actions shown, e.g. while a destructive
397
+ * action waits for its confirming second press.
398
+ */
399
+ export function TreeRowActions(props: ComponentProps<'span'> & { pinned?: boolean }) {
400
+ const [local, rest] = splitProps(props, ['class', 'pinned'])
401
+ return (
402
+ <span
403
+ data-slot="tree-row-actions"
404
+ data-pinned={local.pinned ? '' : undefined}
405
+ class={cn(
406
+ 'flex shrink-0 items-center gap-1 opacity-0 transition-opacity ease-out',
407
+ 'group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 data-pinned:opacity-100',
408
+ local.class
409
+ )}
410
+ {...rest}
411
+ />
412
+ )
413
+ }
414
+
385
415
  function isActionTarget(target: EventTarget | null, currentTarget: HTMLElement): boolean {
386
416
  if (!(target instanceof Element) || target === currentTarget) return false
387
417
  return Boolean(
@@ -27,6 +27,13 @@ export type ContextualSidebarProps = {
27
27
  label: string
28
28
  /** Visible navigation title and mobile dialog title. */
29
29
  title: string
30
+ /**
31
+ * Where the title row shows. `always` (default) draws it on desktop and in
32
+ * the mobile sheet; `mobile` keeps the desktop title for assistive
33
+ * technology only and drops the desktop row, for hosts whose top bar
34
+ * already names the context. A `header` slot keeps the row visible.
35
+ */
36
+ titleVisibility?: 'always' | 'mobile'
30
37
  /** Host-controlled expanded state for the desktop panel and mobile dialog. */
31
38
  open: boolean
32
39
  onOpenChange(open: boolean): void
@@ -157,6 +164,9 @@ export function ContextualSidebar(props: ContextualSidebarProps) {
157
164
  >
158
165
  <Show when={!mobile && props.open}>
159
166
  <PixelResizeHandle
167
+ // The ruler spans the sidebar as a pointer-events-none overlay; lift
168
+ // it above the neighbouring pane so the edge stays grabbable.
169
+ class="z-(--z-docked)"
160
170
  side="left"
161
171
  value={props.width}
162
172
  minimum={props.minimum}
@@ -169,10 +179,19 @@ export function ContextualSidebar(props: ContextualSidebarProps) {
169
179
  />
170
180
  </Show>
171
181
  <Show when={!mobile || mobileMount()?.connected}>
172
- <SidebarNavHeader class={cn(mobile && 'pe-12', props.headerClass)}>
173
- <SidebarNavTitle as={props.headingAs ?? 'h2'}>{props.title}</SidebarNavTitle>
174
- {props.header?.(context)}
175
- </SidebarNavHeader>
182
+ <Show
183
+ when={mobile || props.titleVisibility !== 'mobile' || props.header}
184
+ fallback={
185
+ <SidebarNavTitle as={props.headingAs ?? 'h2'} class="sr-only">
186
+ {props.title}
187
+ </SidebarNavTitle>
188
+ }
189
+ >
190
+ <SidebarNavHeader class={cn(mobile && 'pe-12', props.headerClass)}>
191
+ <SidebarNavTitle as={props.headingAs ?? 'h2'}>{props.title}</SidebarNavTitle>
192
+ {props.header?.(context)}
193
+ </SidebarNavHeader>
194
+ </Show>
176
195
  <SidebarNavContent class={props.contentClass}>{props.content(context)}</SidebarNavContent>
177
196
  {props.footer ? (
178
197
  <SidebarNavFooter class={props.footerClass}>{props.footer(context)}</SidebarNavFooter>
@@ -88,7 +88,12 @@ export function SidebarNavContent(props: ComponentProps<'div'>) {
88
88
  return (
89
89
  <div
90
90
  data-slot="sidebar-nav-content"
91
- class={cn('flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2', local.class)}
91
+ class={cn(
92
+ /* A stable gutter keeps rows from shifting sideways when the list
93
+ grows past the fold and the scrollbar appears. */
94
+ 'flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2 [scrollbar-gutter:stable]',
95
+ local.class
96
+ )}
92
97
  {...rest}
93
98
  />
94
99
  )
@@ -140,6 +145,12 @@ export type SidebarNavSectionProps = ComponentProps<'div'> & {
140
145
  count?: number
141
146
  /** A control at the trailing edge of the heading row. */
142
147
  action?: JSX.Element
148
+ /**
149
+ * When the trailing action shows. `hover` (default) reveals it on hover or
150
+ * focus; `always` keeps it visible, for a section whose primary action is
151
+ * creating its first item.
152
+ */
153
+ actionVisibility?: 'hover' | 'always'
143
154
  /** Semantic heading element for a host's section hierarchy. */
144
155
  headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
145
156
  }
@@ -156,6 +167,7 @@ export function SidebarNavSection(props: SidebarNavSectionProps) {
156
167
  'triggerProps',
157
168
  'count',
158
169
  'action',
170
+ 'actionVisibility',
159
171
  'headingAs',
160
172
  'children',
161
173
  ])
@@ -229,6 +241,11 @@ export function SidebarNavSection(props: SidebarNavSectionProps) {
229
241
  }}
230
242
  class={cn(
231
243
  'flex min-w-0 flex-1 items-center gap-1.5 rounded-sm text-2xs font-medium tracking-wide uppercase outline-none transition-colors ease-out hover:text-sidebar-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle [@media(any-pointer:coarse)]:min-h-11',
244
+ /* WCAG 2.5.8: the row's vertical padding sits on the header, so
245
+ the bare label would be a ~16px target. Stretch the button
246
+ across that padding; the row's height does not change. A
247
+ coarse pointer already gets min-h-11 on an unpadded row. */
248
+ '-my-1.5 py-1.5 [@media(any-pointer:coarse)]:my-0 [@media(any-pointer:coarse)]:py-0',
232
249
  local.active ? 'text-foreground' : 'text-sidebar-muted-foreground'
233
250
  )}
234
251
  >
@@ -237,7 +254,13 @@ export function SidebarNavSection(props: SidebarNavSectionProps) {
237
254
  </Show>
238
255
  </Polymorphic>
239
256
  <Show when={local.action}>
240
- <span class="shrink-0 opacity-0 transition-opacity ease-out group-hover/section-header:opacity-100 focus-within:opacity-100 [@media(any-pointer:coarse)]:opacity-100">
257
+ <span
258
+ data-slot="sidebar-nav-section-action"
259
+ class={cn('shrink-0', {
260
+ 'opacity-0 transition-opacity ease-out group-hover/section-header:opacity-100 focus-within:opacity-100 [@media(any-pointer:coarse)]:opacity-100':
261
+ local.actionVisibility !== 'always',
262
+ })}
263
+ >
241
264
  {local.action}
242
265
  </span>
243
266
  </Show>
@@ -42,11 +42,15 @@ export function TopBar(props: TopBarProps) {
42
42
  <header
43
43
  data-slot="top-bar"
44
44
  class={cn(
45
- 'h-topbar relative z-(--z-sticky) grid shrink-0 grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3 border-b border-border bg-card text-card-foreground px-3 md:grid-cols-[minmax(0,1fr)_clamp(240px,22vw,480px)_minmax(0,1fr)]',
45
+ 'h-topbar relative z-(--z-sticky) grid shrink-0 grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3 border-b border-border bg-card text-card-foreground md:grid-cols-[minmax(0,1fr)_clamp(240px,22vw,480px)_minmax(0,1fr)]',
46
46
  local.glass && 'glass-panel',
47
47
  local.draggable && 'window-drag',
48
- local.macosInset && 'window-inset-macos',
49
- local.windowsInset && 'window-inset-windows',
48
+ /* Each edge gets exactly one inline-padding utility. A window inset
49
+ and px-3 would share a layer and tie-break by build order, and a
50
+ build that put px-3 last hid the leading controls under the
51
+ traffic lights. */
52
+ local.macosInset ? 'window-inset-macos' : 'ps-3',
53
+ local.windowsInset ? 'window-inset-windows' : 'pe-3',
50
54
  local.class
51
55
  )}
52
56
  {...rest}
@@ -99,7 +103,9 @@ export function TopBarTitle(
99
103
  <div
100
104
  data-slot="top-bar-title"
101
105
  class={cn(
102
- 'truncate text-sm font-medium',
106
+ /* The title slot sits in the drag region; a link, button or field
107
+ placed in it (a breadcrumb, a view's search) must stay pressable. */
108
+ 'truncate text-sm font-medium [&_:is(a,button,input)]:window-no-drag',
103
109
  local.align === 'center' && 'text-center',
104
110
  local.class
105
111
  )}
@@ -114,7 +120,10 @@ export function TopBarBreadcrumb(props: ComponentProps<'div'>) {
114
120
  return (
115
121
  <div
116
122
  data-slot="top-bar-breadcrumb"
117
- class={cn('flex min-w-0 items-center gap-1.5 text-sm', local.class)}
123
+ class={cn(
124
+ 'flex min-w-0 items-center gap-1.5 text-sm [&_:is(a,button,input)]:window-no-drag',
125
+ local.class
126
+ )}
118
127
  {...rest}
119
128
  />
120
129
  )
@@ -9,17 +9,28 @@ import { cn } from '../../../lib/utils'
9
9
  * when a consumer needs only the control; `Input` adds native datalist
10
10
  * suggestions for forms that need them.
11
11
  */
12
- export type InputControlProps = ComponentProps<'input'>
12
+ export type InputControlProps = Omit<ComponentProps<'input'>, 'size'> & {
13
+ /**
14
+ * The control rung, matching `SelectTrigger`: `sm` for a dense toolbar or
15
+ * pane filter beside `icon-sm` actions, `md` (the default) everywhere else.
16
+ */
17
+ size?: 'sm' | 'md' | 'lg'
18
+ }
13
19
 
14
20
  export function InputControl(props: InputControlProps) {
15
- const [local, rest] = splitProps(props, ['class', 'type'])
21
+ const [local, rest] = splitProps(props, ['class', 'type', 'size'])
16
22
 
17
23
  return (
18
24
  <input
19
25
  data-slot="input"
20
26
  type={local.type ?? 'text'}
21
27
  class={cn(
22
- 'h-control-md w-full min-w-0 rounded-md border border-input bg-transparent px-control-md py-1 text-sm',
28
+ 'w-full min-w-0 rounded-md border border-input bg-transparent py-1',
29
+ {
30
+ 'h-control-sm px-control-sm text-xs': local.size === 'sm',
31
+ 'h-control-md px-control-md text-sm': local.size === 'md' || local.size === undefined,
32
+ 'h-control-lg px-control-lg text-sm': local.size === 'lg',
33
+ },
23
34
  'transition-[color,box-shadow,border-color] ease-out outline-none',
24
35
  'placeholder:text-muted-foreground',
25
36
  'selection:bg-primary selection:text-primary-foreground',
@@ -1,7 +1,6 @@
1
- import type { ComponentProps } from 'solid-js'
2
1
  import { createUniqueId, For, Show, splitProps } from 'solid-js'
3
2
  import { useFormFieldControl } from '../../../lib/form-field'
4
- import { InputControl } from './input-control'
3
+ import { InputControl, type InputControlProps } from './input-control'
5
4
 
6
5
  /**
7
6
  * Input.
@@ -12,10 +11,11 @@ import { InputControl } from './input-control'
12
11
  * them separate is what lets an input sit inside a custom control without
13
12
  * inheriting a form's ARIA graph.
14
13
  *
15
- * Height comes from `h-control-md`; an input cannot be given a new height
16
- * without a new token, which is what keeps it aligned with Button and Select.
14
+ * Height comes from the control tokens (`size`, `md` by default); an input
15
+ * cannot be given a height off that ladder, which is what keeps it aligned
16
+ * with Button and Select.
17
17
  */
18
- export type InputProps = ComponentProps<'input'> & {
18
+ export type InputProps = InputControlProps & {
19
19
  /** Native text suggestions; custom values remain valid and submit unchanged. */
20
20
  suggestions?: readonly string[]
21
21
  }
@@ -42,7 +42,8 @@ import {
42
42
  *
43
43
  * Use `Dialog` directly when you need its composition; use this when you want a
44
44
  * dialog that is correct by default. `size="settings"` supplies a wide, bounded
45
- * shell for a shared settings layout; ordinary dialogs keep their compact default.
45
+ * shell for a shared settings layout, titled by a banded header like a sheet's;
46
+ * ordinary dialogs keep their compact default.
46
47
  */
47
48
  export type ModalDialogProps = Omit<
48
49
  ComponentProps<typeof DialogContent>,
@@ -154,6 +155,7 @@ export function ModalDialog(props: ModalDialogProps) {
154
155
  onCloseAutoFocus={focusRestoration.onCloseAutoFocus}
155
156
  >
156
157
  <DialogHeader
158
+ band={local.size === 'settings'}
157
159
  class={
158
160
  local.size === 'settings'
159
161
  ? 'shrink-0 gap-1 border-b border-border px-5 pt-4 pb-3 pe-14'
@@ -94,12 +94,13 @@ export function ResizableHandle(props: ResizableHandleProps) {
94
94
  class={cn(
95
95
  'group/resize bg-border relative flex w-px shrink-0 items-center justify-center',
96
96
  /* Widen the hit target without moving the visual line: the divider is
97
- a hairline, but a hairline is far too small to grab. */
98
- 'after:absolute after:inset-y-0 after:-inset-x-1 after:w-3',
97
+ a hairline, but a hairline is far too small to grab. 24px on the
98
+ drag axis meets WCAG 2.5.8's minimum target. */
99
+ 'after:absolute after:inset-y-0 after:-inset-x-3 after:w-6',
99
100
  'transition-colors ease-out hover:bg-primary',
100
101
  'focus-visible:bg-primary focus-visible:outline-none',
101
102
  'data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full',
102
- 'data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full',
103
+ 'data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-3 data-[orientation=vertical]:after:h-6 data-[orientation=vertical]:after:w-full',
103
104
  local.class
104
105
  )}
105
106
  {...rest}
@@ -13,7 +13,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'
13
13
  * with no text (unreadable to anyone who cannot see it) and a bare word with no
14
14
  * explanation ("Needs configuration" — of what?).
15
15
  *
16
- * The tones are deliberately not a rainbow. Six cover what a status can actually
16
+ * The tones are deliberately not a rainbow. Seven cover what a status can actually
17
17
  * mean:
18
18
  *
19
19
  * - `neutral` — fine, and there is nothing to say about it.
@@ -21,6 +21,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'
21
21
  * - `warning` — degraded, or needs a decision from the user.
22
22
  * - `danger` — blocked, failed, unrecoverable without intervention.
23
23
  * - `info` — in flight or scheduled; work is happening, nothing is wrong.
24
+ * - `pending` — running now with no result yet (a check, a build). The ring
25
+ * turns, so it reads as live rather than as a settled state.
24
26
  * - `unknown` — the honest absence of information.
25
27
  *
26
28
  * `unknown` is not the same as `neutral`, and collapsing them is the mistake
@@ -39,6 +41,7 @@ export const statusDotVariants = cva('size-2 shrink-0 rounded-full', {
39
41
  warning: 'bg-warning',
40
42
  danger: 'bg-destructive',
41
43
  info: 'bg-info',
44
+ pending: 'border-2 border-info border-r-transparent motion-safe:animate-spin',
42
45
  unknown: 'border border-muted-foreground bg-transparent',
43
46
  },
44
47
  },
@@ -51,10 +54,18 @@ const labelTone: Record<StatusTone, string> = {
51
54
  warning: 'text-foreground',
52
55
  danger: 'text-foreground',
53
56
  info: 'text-foreground',
57
+ pending: 'text-foreground',
54
58
  unknown: 'text-muted-foreground',
55
59
  }
56
60
 
57
- export type StatusTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'unknown'
61
+ export type StatusTone =
62
+ | 'neutral'
63
+ | 'success'
64
+ | 'warning'
65
+ | 'danger'
66
+ | 'info'
67
+ | 'pending'
68
+ | 'unknown'
58
69
 
59
70
  export type StatusChipProps = Omit<ComponentProps<'span'>, 'children'> & {
60
71
  tone?: StatusTone
@@ -96,7 +96,8 @@
96
96
  }
97
97
 
98
98
  /* Emitted only when ListRowControl is used. A described row changes its own
99
- height and stacks trailing actions when its available width gets tight. */
99
+ height and stacks trailing actions when its available width gets tight,
100
+ unless the row opts out with `stackTrailing={false}`. */
100
101
  @utility list-row-description {
101
102
  &[data-description] {
102
103
  align-items: flex-start;
@@ -111,23 +112,23 @@
111
112
  }
112
113
 
113
114
  @container list-row (width < 28rem) {
114
- &[data-description] [data-slot='list-row-content'] {
115
+ &[data-description]:not([data-stack-trailing='never']) [data-slot='list-row-content'] {
115
116
  align-items: stretch;
116
117
  flex-direction: column;
117
118
  }
118
119
 
119
- &[data-description] [data-slot='list-row-label'],
120
- &[data-description] [data-slot='list-row-trailing'] {
120
+ &[data-description]:not([data-stack-trailing='never']) [data-slot='list-row-label'],
121
+ &[data-description]:not([data-stack-trailing='never']) [data-slot='list-row-trailing'] {
121
122
  flex: none;
122
123
  width: 100%;
123
124
  }
124
125
 
125
- &[data-description] [data-slot='list-row-trailing'] {
126
+ &[data-description]:not([data-stack-trailing='never']) [data-slot='list-row-trailing'] {
126
127
  flex-wrap: wrap;
127
128
  justify-content: flex-end;
128
129
  }
129
130
 
130
- &[data-description] [data-slot='list-row-trailing'] button {
131
+ &[data-description]:not([data-stack-trailing='never']) [data-slot='list-row-trailing'] button {
131
132
  max-width: 100%;
132
133
  white-space: normal;
133
134
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.114.0",
3
+ "version": "0.115.1",
4
4
  "description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
5
5
  "keywords": [
6
6
  "adea",
@@ -18,6 +18,12 @@ export type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicP
18
18
  trailing?: JSX.Element
19
19
  /** A second line that wraps and grows the row to fit its content. */
20
20
  description?: string
21
+ /**
22
+ * Whether a described row may drop its trailing slot onto its own line when
23
+ * the row gets narrow (the default). Pass `false` for a short, truncating
24
+ * label whose single action must stay beside it.
25
+ */
26
+ stackTrailing?: boolean
21
27
  /** Native button type; defaults to `button` for button rows. */
22
28
  type?: ComponentProps<'button'>['type']
23
29
  }
@@ -37,6 +43,7 @@ export function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowC
37
43
  'leading',
38
44
  'trailing',
39
45
  'description',
46
+ 'stackTrailing',
40
47
  'type',
41
48
  'tabIndex',
42
49
  'children',
@@ -52,6 +59,7 @@ export function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowC
52
59
  aria-current={local.selected ? 'true' : undefined}
53
60
  data-selected={local.selected ? '' : undefined}
54
61
  data-description={local.description ? '' : undefined}
62
+ data-stack-trailing={local.stackTrailing === false ? 'never' : undefined}
55
63
  class={cn(
56
64
  'group/row list-row-description flex min-w-0 items-center gap-2.5 rounded-md px-2 text-sm',
57
65
  'transition-colors ease-out outline-none',
@@ -1,3 +1,3 @@
1
1
  /** Keyboard-accessible tree rows with virtualization-aware focus handoff. */
2
- export { Tree, TreeRow, type TreeProps, type TreeRowProps } from './tree'
2
+ export { Tree, TreeRow, TreeRowActions, type TreeProps, type TreeRowProps } from './tree'
3
3
  export type { TreeItemDescriptor } from './tree-navigation'
@@ -238,7 +238,12 @@ export function Tree(props: TreeProps) {
238
238
  role="tree"
239
239
  aria-multiselectable={local.selectionMode === 'multiple' ? 'true' : undefined}
240
240
  data-slot="tree"
241
- class={cn('flex min-w-0 flex-col', local.class)}
241
+ class={cn(
242
+ /* A virtualized host remounts rows as it scrolls; scroll anchoring
243
+ would latch onto the focused row and fight the scrollbar. */
244
+ 'flex min-w-0 flex-col [overflow-anchor:none]',
245
+ local.class
246
+ )}
242
247
  onKeyDown={handleKeyDown}
243
248
  >
244
249
  {local.children}
@@ -382,6 +387,31 @@ export function TreeRow(props: TreeRowProps) {
382
387
  )
383
388
  }
384
389
 
390
+ /**
391
+ * TreeRowActions.
392
+ *
393
+ * Row-level commands (rename, copy, delete) that stay out of the way until the
394
+ * row is hovered or holds focus, so a long tree reads as names rather than a
395
+ * wall of buttons. Put it in `TreeRow`'s `trailing` slot beside any status that
396
+ * must stay visible. `pinned` keeps the actions shown, e.g. while a destructive
397
+ * action waits for its confirming second press.
398
+ */
399
+ export function TreeRowActions(props: ComponentProps<'span'> & { pinned?: boolean }) {
400
+ const [local, rest] = splitProps(props, ['class', 'pinned'])
401
+ return (
402
+ <span
403
+ data-slot="tree-row-actions"
404
+ data-pinned={local.pinned ? '' : undefined}
405
+ class={cn(
406
+ 'flex shrink-0 items-center gap-1 opacity-0 transition-opacity ease-out',
407
+ 'group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 data-pinned:opacity-100',
408
+ local.class
409
+ )}
410
+ {...rest}
411
+ />
412
+ )
413
+ }
414
+
385
415
  function isActionTarget(target: EventTarget | null, currentTarget: HTMLElement): boolean {
386
416
  if (!(target instanceof Element) || target === currentTarget) return false
387
417
  return Boolean(