@sableui/react 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { AspectBox, AspectBoxProps, Bleed, BleedProps, Breakpoint, Center, Cente
9
9
  export { Icon, IconContextValue, IconProps, IconProvider, IconProviderProps, composeIconSets, useIconSet } from './icon/index.js';
10
10
  export { a as IconRenderProps, I as IconSet, b as IconVariant } from './registry-CyL28OzJ.js';
11
11
  import * as react from 'react';
12
- import { ReactNode, AnimationEvent, ComponentPropsWithoutRef, ElementType, ReactElement, Ref, ComponentPropsWithRef, MouseEvent, ComponentProps, AriaAttributes, FormEvent } from 'react';
12
+ import { ReactNode, AnimationEvent, ComponentPropsWithoutRef, ElementType, ReactElement, Ref, ComponentPropsWithRef, MouseEvent, ComponentProps, AriaAttributes, RefObject, FormEvent } from 'react';
13
13
  import { VariantProps } from 'class-variance-authority';
14
14
  import { useRender } from '@base-ui/react/use-render';
15
15
  import * as class_variance_authority_types from 'class-variance-authority/types';
@@ -6471,6 +6471,67 @@ declare namespace SideNavItem {
6471
6471
 
6472
6472
  declare const sideNavMeta: ComponentMeta;
6473
6473
 
6474
+ interface SectionRailSection {
6475
+ /** The section element's `id` — the rail links to `#id` and watches it. */
6476
+ id: string;
6477
+ /** The section's name: the tooltip, and the link's accessible name. */
6478
+ label: string;
6479
+ }
6480
+ interface SectionRailProps extends Omit<ComponentPropsWithRef<"nav">, "children"> {
6481
+ /** The sections, in document order. */
6482
+ sections: readonly SectionRailSection[];
6483
+ /**
6484
+ * The current section's id, when the parent decides it. Leave it unset and
6485
+ * the rail follows the scroll itself.
6486
+ */
6487
+ value?: string;
6488
+ /** Called with the new id when the reader scrolls into a section or picks one. */
6489
+ onValueChange?: (id: string) => void;
6490
+ /**
6491
+ * Where the reading line sits, as a fraction of the viewport from its top.
6492
+ * A section becomes current once its top crosses it.
6493
+ * @default 0.35
6494
+ */
6495
+ offset?: number;
6496
+ /** The element that scrolls, when it is not the window. */
6497
+ root?: RefObject<HTMLElement | null>;
6498
+ /**
6499
+ * Which edge of the page the rail sits on. The labels open toward the
6500
+ * content, on the other side.
6501
+ * @default "left"
6502
+ */
6503
+ side?: "left" | "right";
6504
+ /**
6505
+ * How much motion this component uses: `full` (default) inherits the app's
6506
+ * policy, `subtle` keeps feedback and drops the marker's glide, `off` stills
6507
+ * it. It can only turn motion down — it never overrides a reader's
6508
+ * reduce-motion setting.
6509
+ */
6510
+ motion?: MotionLevel;
6511
+ }
6512
+ /**
6513
+ * SectionRail — a slim vertical rail of dots, one per section of a long page,
6514
+ * that shows where the reader is and jumps to any section. A bar marks the
6515
+ * current section and glides to the next as the page scrolls; hovering or
6516
+ * focusing a dot names its section in a tooltip that travels with the pointer.
6517
+ *
6518
+ * <SectionRail
6519
+ * sections={[{ id: "overview", label: "Overview" }, { id: "process", label: "Process" }]}
6520
+ * className="fixed top-1/2 left-6 z-(--z-nav) -translate-y-1/2 max-lg:hidden"
6521
+ * />
6522
+ *
6523
+ * It renders in flow; place it with layout classes. Picking a dot scrolls to
6524
+ * the section with the page's own `scroll-behavior` (instantly under reduced
6525
+ * motion) and, at page level, puts its id in the URL without adding a history
6526
+ * entry. Give sections a `scroll-mt-*` when a sticky header would cover them.
6527
+ */
6528
+ declare function SectionRail({ sections, value, onValueChange, offset, root, side, motion, className, "aria-label": ariaLabel, ref, ...props }: SectionRailProps): react.JSX.Element;
6529
+ declare namespace SectionRail {
6530
+ var displayName: string;
6531
+ }
6532
+
6533
+ declare const sectionRailMeta: ComponentMeta;
6534
+
6474
6535
  /**
6475
6536
  * BottomNav — the mobile bottom tab bar. Fixed to the bottom edge, hidden at
6476
6537
  * `lg` (the desktop Sidebar takes over). Pads the home-indicator safe area and
@@ -9880,6 +9941,39 @@ interface SmoothWheelOptions {
9880
9941
  */
9881
9942
  declare function useSmoothWheel({ axis, mapVertical, smooth, }?: SmoothWheelOptions): (node: HTMLElement | null) => void;
9882
9943
 
9883
- declare const SABLE_UI_VERSION: "0.16.0";
9944
+ interface UseActiveSectionOptions {
9945
+ /**
9946
+ * Where the reading line sits, as a fraction of the viewport's height from
9947
+ * its top. A section becomes current once its top crosses the line, so the
9948
+ * one being read wins over the one merely peeking in at the bottom.
9949
+ * @default 0.35
9950
+ */
9951
+ offset?: number;
9952
+ /**
9953
+ * The element that scrolls, when it is not the window — a `Scroller`, an
9954
+ * inset `AppShell` main, a docs preview.
9955
+ */
9956
+ root?: RefObject<HTMLElement | null>;
9957
+ }
9958
+ /**
9959
+ * useActiveSection — which of these sections the reader is in. The scroll spy
9960
+ * behind `SectionRail`, exported for a contents list a consumer draws itself
9961
+ * (an "On this page" column, a chapter select).
9962
+ *
9963
+ * const active = useActiveSection(["intro", "usage", "api"])
9964
+ *
9965
+ * The current section is the last one, in the order given, whose top has
9966
+ * crossed the reading line (`offset`). Before any has, the first one is
9967
+ * current: the reader is at the start. Once the scroller reaches its end the
9968
+ * last section in view wins instead, because a short closing section can never
9969
+ * climb to the line and would otherwise never become current.
9970
+ *
9971
+ * Measures on scroll and resize, at most once a frame. Ids missing from the
9972
+ * document are skipped, so sections may mount late. Returns `null` only for an
9973
+ * empty list.
9974
+ */
9975
+ declare function useActiveSection(ids: readonly string[], { offset, root }?: UseActiveSectionOptions): string | null;
9976
+
9977
+ declare const SABLE_UI_VERSION: "0.17.0";
9884
9978
 
9885
- export { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, AppHeader, type AppHeaderProps, AppShell, type AppShellProps, AreaChart, type AreaChartProps, type ArtIntensity, type ArtTone, Attachment, type AttachmentProps, Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, type AvatarGroupCountProps, type AvatarGroupProps, AvatarImage, type AvatarProps, AvatarRoot, BADGE_APPEARANCES, BADGE_TONES, Badge, type BadgeAppearance, type BadgeProps, type BadgeTone, Banner, type BannerProps, BarChart, type BarChartProps, BottomNav, BottomNavItem, type BottomNavItemProps, BreadcrumbItem, type BreadcrumbItemProps, BreadcrumbLink, type BreadcrumbLinkProps, BreadcrumbPage, type BreadcrumbPageProps, BreadcrumbSeparator, type BreadcrumbSeparatorProps, Breadcrumbs, type BreadcrumbsProps, Browser, type BrowserProps, Bubble, type BubbleProps, BubbleReaction, BubbleReactionAdd, type BubbleReactionAddProps, type BubbleReactionProps, BubbleReactions, type BubbleReactionsProps, Burst, type BurstProps, Button, type ButtonBleed, ButtonGroup, type ButtonGroupProps, type ButtonProps, CHART_SERIES_COUNT, COMPONENT_GROUPS, COMPONENT_TAXONOMY, Calendar, type CalendarProps, Card, CardAction, CardContent, type CardContentProps, CardDescription, CardFooter, type CardFooterProps, CardHeader, CardList, type CardProps, CardTitle, type CardTitleProps, CaretMenu, CaretMenuItem, type CaretMenuItemProps, type CaretMenuProps, type CaretTrigger, type CaretTriggerField, type CaretTriggerMatch, Carousel, type CarouselProps, type CarouselSlidesToShow, type ChartCategories, type ChartCenterLabel, type ChartCurve, type ChartDatum, type ChartSeries, type ChartTone, type ChartTooltipIndicator, type ChartTooltipOptions, type ChartValueFormatter, ChatComposer, type ChatComposerProps, Checkbox, CheckboxCard, type CheckboxCardProps, type CheckboxCardTone, CheckboxGroup, type CheckboxGroupProps, Code, CodeBlock, type CodeBlockProps, CodeHighlightProvider, type CodeHighlighter, type CodeProps, Collapsible, CollapsibleIndicator, CollapsiblePanel, CollapsibleTrigger, ColorField, type ColorFieldProps, Combobox, ComboboxChips, ComboboxClear, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, type ComboboxItemGroup, ComboboxItemIndicator, ComboboxList, ComboboxPortal, type ComboboxProps, ComboboxValue, ComboboxVirtualList, type ComboboxVirtualListProps, type CommandFilter, type CommandItem, CommandMenu, CommandMenuGroup, type CommandMenuGroupProps, CommandMenuItem, type CommandMenuItemProps, CommandMenuPanel, type CommandMenuPanelProps, type CommandMenuProps, CommandMenuTrigger, type CommandMenuTriggerProps, type ComponentGroup, type ComponentGuidance, ComponentMeta, type ComponentRegister, ConfirmButton, type ConfirmButtonProps, type ConstraintFlag, ContextCard, ContextCardArrow, ContextCardContent, ContextCardPortal, ContextCardTrigger, ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuGroupLabel, ContextMenuItem, ContextMenuPortal, ContextMenuSeparator, ContextMenuTrigger, type CopySource, DEFAULT_REACTIONS, DataTable, type DataTableColumn, type DataTableProps, type DataTableRowKey, DatePicker, type DatePickerProps, DateTile, type DateTileProps, Density, DensityProvider, Density as DensityValue, DestructiveActionModal, type DestructiveActionModalProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, type DialogSize, DialogTitle, DialogTrigger, DisclosurePicker, DisclosurePickerEmpty, DisclosurePickerList, type DisclosurePickerListProps, DisclosurePickerOption, type DisclosurePickerOptionProps, DisclosurePickerPanel, type DisclosurePickerPanelProps, type DisclosurePickerProps, type DisclosurePickerSearch, DisclosurePickerTrigger, type DisclosurePickerTriggerProps, EmptyState, type EmptyStateProps, Entity, type EntityProps, Feedback, type FeedbackData, type FeedbackProps, type FeedbackRating, Field, type FieldProps, Fieldset, FieldsetContent, FieldsetDescription, FieldsetFooter, FieldsetLegend, type FieldsetVariant, FileDropzone, type FileDropzoneProps, type FileRejection, type FileRejectionCode, FontPicker, type FontPickerFont, type FontPickerOption, type FontPickerProps, Form, type FormProps, GlidingHighlight, type GlidingHighlightProps, GradientArt, type GradientArtProps, type Hsv, InlineStatus, type InlineStatusProps, type StatusTone as InlineTone, Input, InputGroup, type InputGroupProps, type InputProps$1 as InputProps, Kbd, KbdGroup, type KbdGroupProps, type KbdProps, Label, type LabelProps$2 as LabelProps, LikeButton, type LikeButtonProps, LineChart, type LineChartProps, Marker, type MarkerProps, Marquee, type MarqueeProps, MediaImage, type MediaImageProps, MediaTile, type MediaTileProps, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPortal, MenuRadioGroup, MenuRadioItem, MenuReactions, type MenuReactionsProps, MenuSeparator, MenuSubmenu, MenuSubmenuTrigger, MenuTrigger, Menubar, type MenubarProps, MenubarTrigger, type MenubarTriggerProps, Message, type MessageProps, MessageScroller, type MessageScrollerHandle, type MessageScrollerProps, Meter, MeterIndicator, MeterLabel, type MeterSize, type MeterTone, MeterTrack, MeterValue, MiddleTruncate, type MiddleTruncateProps, type MotionLevel, type MotionPolicy, MotionProvider, type MotionProviderProps, MotionScope, type MotionScopeProps, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, Note, type NoteAction, type NoteProps, NotificationBadge, type NotificationBadgeProps, NumberField, type NumberFieldProps, NumberTicker, type NumberTickerProps, type OrbMode, type OrbSize, OtpField, type OtpFieldProps, OverflowMenu, type OverflowMenuProps, PALETTE_COLORS, PALETTE_FAMILIES, PALETTE_SCALES, PALETTE_STEPS, PALETTE_TONES, PageHeader, type PageHeaderProps, PageLoader, type PageLoaderProps, Pagination, type PaginationProps, type PaletteColor, type PaletteFamily, type PaletteStep, Panel, PanelGroup, PanelResizer, type PanelResizerProps, PanelSection, type PanelWidthBounds, Phone, type PhoneProps, PieChart, type PieChartProps, Pill, type PillProps, Popover, PopoverArrow, PopoverClose, PopoverContent, PopoverDescription, PopoverPortal, PopoverTitle, PopoverTrigger, Presence, type PresenceProps, type Presentation, PresentationProvider, Progress, ProgressIndicator, ProgressLabel, type ProgressSize, ProgressTrack, ProgressValue, PropertyGroup, PropertyPair, PropertyRow, RadarChart, type RadarChartProps, RadialChart, type RadialChartProps, Radio, RadioCard, type RadioCardProps, type RadioCardTone, RadioGroup, type Reaction, ReactionPicker, type ReactionPickerProps, RelativeTime, type RelativeTimeProps, Reveal, type RevealProps, type Rgb, SABLE_UI_VERSION, SEGMENTED_BAR_TONES, STATUS_TONES, STATUS_TONE_ICON, type ScrollCommandOptions, Scroller, type ScrollerProps, ScrubField, type ScrubFieldProps, SearchInput, type SearchInputProps, SectionHeader, type SectionHeaderProps, SegmentedBar, type SegmentedBarProps, type SegmentedBarSegment, type SegmentedBarTone, Select, SelectContent, SelectGroup, SelectGroupLabel, SelectItem, SelectPortal, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps$2 as SeparatorProps, SettingsMenu, type SettingsMenuProps, SettingsRow, type SettingsRowProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetList, SheetPortal, type SheetProps, type SheetSnapPoint, SheetTitle, SheetTrigger, ShowMore, type ShowMoreProps, SideNav, type SideNavActiveVariant, SideNavGroup, type SideNavGroupProps, SideNavItem, type SideNavItemProps, type SideNavProps, type SideNavSize, Sidebar, SidebarBrand, type SidebarBrandProps, SidebarFooter, SidebarHeader, SidebarItem, type SidebarItemProps, SidebarNav, type SidebarProps, SimpleTooltip, Skeleton, SkipLink, Slider, SliderControl, SliderIndicator, SliderRoot, SliderThumb, SliderTrack, SliderValue, type SmoothWheelOptions, Sparkline, type SparklineProps, Spinner, type SpinnerProps, StatusBar, StatusBarGroup, StatusBarSeparator, StatusDot, type StatusDotProps, type StatusTone, type StepStatus, Stepper, StepperItem, type StepperItemProps, type StepperOrientation, type StepperProps, StreamingText, type StreamingTextProps, Switch, TOOL_CALL_STATUS_LABELS, TRANSPARENT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsPanel as TabsContent, TabsList, TabsPanel, TabsTrigger, TextReveal, type TextRevealProps, Textarea, type TextareaProps, ThemeId, ThemeManifest, ThemeMode$1 as ThemeManifestMode, type ThemeMode, ThemePreview, type ThemePreviewProps, ThemeSelector, type ThemeSelectorProps, ThemeSwitcher, type ThemeSwitcherProps, ThinkingOrb, type ThinkingOrbProps, ToastAction, type ToastApi, ToastClose, ToastContent, ToastDescription, type ToastManagerApi, type ToastOptions, type ToastPosition, ToastProvider, type ToastProviderProps, ToastRoot, ToastTitle, type ToastType, ToastViewport, Toggle, ToggleGroup, type ToggleGroupAppearance, Toggle as ToggleGroupItem, ToolCall, type ToolCallProps, type ToolCallStatus, Toolbar, ToolbarButton, type ToolbarButtonProps, ToolbarGroup, type ToolbarGroupProps, ToolbarInput, type ToolbarInputProps, ToolbarLink, type ToolbarLinkProps, type ToolbarProps, ToolbarSeparator, type ToolbarSeparatorProps, Tooltip, TooltipArrow, TooltipContent, TooltipGroup, type TooltipGroupProps, TooltipPortal, TooltipProvider, TooltipTrigger, Tree, TreeAddRow, TreeEmpty, TreeRow, TreeSection, type UseCaretTriggerOptions, type UseCaretTriggerResult, type UseCopyOptions, type UseCopyResult, type UseInViewOptions, type UseMatchHighlightOptions, type UsePanelWidthOptions, Video, type VideoProps, ViewTransitionName, type ViewTransitionNameProps, Workspace, WorkspaceBar, WorkspaceCanvas, accordionMeta, appHeaderMeta, appShellMeta, areaChartMeta, attachmentMeta, avatarGroupVariants, avatarMeta, avatarVariants, badgeMeta, badgeVariants, bannerMeta, bannerVariants, barChartMeta, bottomNavMeta, breadcrumbsMeta, browserMeta, bubbleMeta, buttonGroupMeta, buttonMeta, buttonVariants, calendarMeta, cardMeta, caretMenuMeta, carouselMeta, chartColor, toneColor as chartToneColor, chatComposerMeta, checkboxCardMeta, checkboxMeta, cn, codeBlockMeta, codeMeta, collapsibleMeta, colorFieldMeta, comboboxMeta, commandMenuMeta, componentGuidance, componentLabel, componentSlug, componentsInGroup, confirmButtonMeta, contextCardMeta, contextMenuMeta, dataTableMeta, datePickerMeta, dateTileMeta, destructiveActionModalMeta, dialogMeta, disclosurePickerMeta, emptyStateMeta, entityMeta, feedbackMeta, fieldsetMeta, fileDropzoneMeta, fileDropzoneVariants, fontPickerMeta, formMeta, formatFileSize, formatHex, glidingHighlightMeta, gradientArtMeta, hsvToRgb, hueColor, inlineStatusMeta, inputGroupMeta, inputMeta, isPaletteColor, isTransparent, kbdMeta, labelMeta, likeButtonMeta, lineChartMeta, markerMeta, marqueeMeta, mediaImageMeta, mediaTileMeta, menuMeta, menubarMeta, messageMeta, messageScrollerMeta, meterIndicatorVariants, meterMeta, meterTrackVariants, middleTruncateMeta, motionAttribute, navigationMenuMeta, noteMeta, noteVariants, notificationBadgeMeta, notificationCountVariants, notificationDotVariants, numberFieldMeta, numberTickerMeta, otpFieldMeta, overflowMenuMeta, pageHeaderMeta, pageLoaderMeta, paginationMeta, panelGroupMeta, panelSectionMeta, parseHex, phoneMeta, pieChartMeta, pillMeta, pillVariants, popoverMeta, progressMeta, progressTrackVariants, radarChartMeta, radialChartMeta, radioCardMeta, radioMeta, reactionPickerMeta, relativeTimeMeta, rgbToHsv, scrollerMeta, scrubFieldMeta, searchInputMeta, sectionHeaderMeta, segmentedBarMeta, segmentedBarSegmentVariants, segmentedBarVariants, selectMeta, separatorMeta, settingsMenuMeta, sheetMeta, sheetVariants, showMoreMeta, sideNavMeta, sidebarMeta, skeletonMeta, sliderMeta, sparklineMeta, spinnerMeta, startViewTransition, statusBarMeta, statusDotMeta, statusDotVariants, stepperConnectorVariants, stepperIndicatorVariants, stepperMeta, streamingTextMeta, supportsViewTransitions, switchMeta, tableMeta, tabsMeta, textareaMeta, themeSelectorMeta, themeSwitcherMeta, thinkingOrbMeta, toast, toastMeta, toggleMeta, toolCallMeta, toolbarGroupVariants, toolbarMeta, toolbarSeparatorVariants, toolbarVariants, tooltipMeta, treeIndent, treeMeta, useAnchoredDensity, useAutoSize, useCaretTrigger, useComboboxFilteredItems, useCommandMenuShortcut, useCopy, useDensity, useDisclosurePicker, useInView, useMatchHighlight, useMotion, useMotionLevel, usePanelWidth, usePresentation, useReducedMotion, useScrollActivity, useShake, useSidebar, useSmoothWheel, useToast, useToastManager, useTypeTier, videoMeta, workspaceMeta };
9979
+ export { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, AppHeader, type AppHeaderProps, AppShell, type AppShellProps, AreaChart, type AreaChartProps, type ArtIntensity, type ArtTone, Attachment, type AttachmentProps, Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, type AvatarGroupCountProps, type AvatarGroupProps, AvatarImage, type AvatarProps, AvatarRoot, BADGE_APPEARANCES, BADGE_TONES, Badge, type BadgeAppearance, type BadgeProps, type BadgeTone, Banner, type BannerProps, BarChart, type BarChartProps, BottomNav, BottomNavItem, type BottomNavItemProps, BreadcrumbItem, type BreadcrumbItemProps, BreadcrumbLink, type BreadcrumbLinkProps, BreadcrumbPage, type BreadcrumbPageProps, BreadcrumbSeparator, type BreadcrumbSeparatorProps, Breadcrumbs, type BreadcrumbsProps, Browser, type BrowserProps, Bubble, type BubbleProps, BubbleReaction, BubbleReactionAdd, type BubbleReactionAddProps, type BubbleReactionProps, BubbleReactions, type BubbleReactionsProps, Burst, type BurstProps, Button, type ButtonBleed, ButtonGroup, type ButtonGroupProps, type ButtonProps, CHART_SERIES_COUNT, COMPONENT_GROUPS, COMPONENT_TAXONOMY, Calendar, type CalendarProps, Card, CardAction, CardContent, type CardContentProps, CardDescription, CardFooter, type CardFooterProps, CardHeader, CardList, type CardProps, CardTitle, type CardTitleProps, CaretMenu, CaretMenuItem, type CaretMenuItemProps, type CaretMenuProps, type CaretTrigger, type CaretTriggerField, type CaretTriggerMatch, Carousel, type CarouselProps, type CarouselSlidesToShow, type ChartCategories, type ChartCenterLabel, type ChartCurve, type ChartDatum, type ChartSeries, type ChartTone, type ChartTooltipIndicator, type ChartTooltipOptions, type ChartValueFormatter, ChatComposer, type ChatComposerProps, Checkbox, CheckboxCard, type CheckboxCardProps, type CheckboxCardTone, CheckboxGroup, type CheckboxGroupProps, Code, CodeBlock, type CodeBlockProps, CodeHighlightProvider, type CodeHighlighter, type CodeProps, Collapsible, CollapsibleIndicator, CollapsiblePanel, CollapsibleTrigger, ColorField, type ColorFieldProps, Combobox, ComboboxChips, ComboboxClear, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, type ComboboxItemGroup, ComboboxItemIndicator, ComboboxList, ComboboxPortal, type ComboboxProps, ComboboxValue, ComboboxVirtualList, type ComboboxVirtualListProps, type CommandFilter, type CommandItem, CommandMenu, CommandMenuGroup, type CommandMenuGroupProps, CommandMenuItem, type CommandMenuItemProps, CommandMenuPanel, type CommandMenuPanelProps, type CommandMenuProps, CommandMenuTrigger, type CommandMenuTriggerProps, type ComponentGroup, type ComponentGuidance, ComponentMeta, type ComponentRegister, ConfirmButton, type ConfirmButtonProps, type ConstraintFlag, ContextCard, ContextCardArrow, ContextCardContent, ContextCardPortal, ContextCardTrigger, ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuGroupLabel, ContextMenuItem, ContextMenuPortal, ContextMenuSeparator, ContextMenuTrigger, type CopySource, DEFAULT_REACTIONS, DataTable, type DataTableColumn, type DataTableProps, type DataTableRowKey, DatePicker, type DatePickerProps, DateTile, type DateTileProps, Density, DensityProvider, Density as DensityValue, DestructiveActionModal, type DestructiveActionModalProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, type DialogSize, DialogTitle, DialogTrigger, DisclosurePicker, DisclosurePickerEmpty, DisclosurePickerList, type DisclosurePickerListProps, DisclosurePickerOption, type DisclosurePickerOptionProps, DisclosurePickerPanel, type DisclosurePickerPanelProps, type DisclosurePickerProps, type DisclosurePickerSearch, DisclosurePickerTrigger, type DisclosurePickerTriggerProps, EmptyState, type EmptyStateProps, Entity, type EntityProps, Feedback, type FeedbackData, type FeedbackProps, type FeedbackRating, Field, type FieldProps, Fieldset, FieldsetContent, FieldsetDescription, FieldsetFooter, FieldsetLegend, type FieldsetVariant, FileDropzone, type FileDropzoneProps, type FileRejection, type FileRejectionCode, FontPicker, type FontPickerFont, type FontPickerOption, type FontPickerProps, Form, type FormProps, GlidingHighlight, type GlidingHighlightProps, GradientArt, type GradientArtProps, type Hsv, InlineStatus, type InlineStatusProps, type StatusTone as InlineTone, Input, InputGroup, type InputGroupProps, type InputProps$1 as InputProps, Kbd, KbdGroup, type KbdGroupProps, type KbdProps, Label, type LabelProps$2 as LabelProps, LikeButton, type LikeButtonProps, LineChart, type LineChartProps, Marker, type MarkerProps, Marquee, type MarqueeProps, MediaImage, type MediaImageProps, MediaTile, type MediaTileProps, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPortal, MenuRadioGroup, MenuRadioItem, MenuReactions, type MenuReactionsProps, MenuSeparator, MenuSubmenu, MenuSubmenuTrigger, MenuTrigger, Menubar, type MenubarProps, MenubarTrigger, type MenubarTriggerProps, Message, type MessageProps, MessageScroller, type MessageScrollerHandle, type MessageScrollerProps, Meter, MeterIndicator, MeterLabel, type MeterSize, type MeterTone, MeterTrack, MeterValue, MiddleTruncate, type MiddleTruncateProps, type MotionLevel, type MotionPolicy, MotionProvider, type MotionProviderProps, MotionScope, type MotionScopeProps, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, Note, type NoteAction, type NoteProps, NotificationBadge, type NotificationBadgeProps, NumberField, type NumberFieldProps, NumberTicker, type NumberTickerProps, type OrbMode, type OrbSize, OtpField, type OtpFieldProps, OverflowMenu, type OverflowMenuProps, PALETTE_COLORS, PALETTE_FAMILIES, PALETTE_SCALES, PALETTE_STEPS, PALETTE_TONES, PageHeader, type PageHeaderProps, PageLoader, type PageLoaderProps, Pagination, type PaginationProps, type PaletteColor, type PaletteFamily, type PaletteStep, Panel, PanelGroup, PanelResizer, type PanelResizerProps, PanelSection, type PanelWidthBounds, Phone, type PhoneProps, PieChart, type PieChartProps, Pill, type PillProps, Popover, PopoverArrow, PopoverClose, PopoverContent, PopoverDescription, PopoverPortal, PopoverTitle, PopoverTrigger, Presence, type PresenceProps, type Presentation, PresentationProvider, Progress, ProgressIndicator, ProgressLabel, type ProgressSize, ProgressTrack, ProgressValue, PropertyGroup, PropertyPair, PropertyRow, RadarChart, type RadarChartProps, RadialChart, type RadialChartProps, Radio, RadioCard, type RadioCardProps, type RadioCardTone, RadioGroup, type Reaction, ReactionPicker, type ReactionPickerProps, RelativeTime, type RelativeTimeProps, Reveal, type RevealProps, type Rgb, SABLE_UI_VERSION, SEGMENTED_BAR_TONES, STATUS_TONES, STATUS_TONE_ICON, type ScrollCommandOptions, Scroller, type ScrollerProps, ScrubField, type ScrubFieldProps, SearchInput, type SearchInputProps, SectionHeader, type SectionHeaderProps, SectionRail, type SectionRailProps, type SectionRailSection, SegmentedBar, type SegmentedBarProps, type SegmentedBarSegment, type SegmentedBarTone, Select, SelectContent, SelectGroup, SelectGroupLabel, SelectItem, SelectPortal, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps$2 as SeparatorProps, SettingsMenu, type SettingsMenuProps, SettingsRow, type SettingsRowProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetList, SheetPortal, type SheetProps, type SheetSnapPoint, SheetTitle, SheetTrigger, ShowMore, type ShowMoreProps, SideNav, type SideNavActiveVariant, SideNavGroup, type SideNavGroupProps, SideNavItem, type SideNavItemProps, type SideNavProps, type SideNavSize, Sidebar, SidebarBrand, type SidebarBrandProps, SidebarFooter, SidebarHeader, SidebarItem, type SidebarItemProps, SidebarNav, type SidebarProps, SimpleTooltip, Skeleton, SkipLink, Slider, SliderControl, SliderIndicator, SliderRoot, SliderThumb, SliderTrack, SliderValue, type SmoothWheelOptions, Sparkline, type SparklineProps, Spinner, type SpinnerProps, StatusBar, StatusBarGroup, StatusBarSeparator, StatusDot, type StatusDotProps, type StatusTone, type StepStatus, Stepper, StepperItem, type StepperItemProps, type StepperOrientation, type StepperProps, StreamingText, type StreamingTextProps, Switch, TOOL_CALL_STATUS_LABELS, TRANSPARENT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsPanel as TabsContent, TabsList, TabsPanel, TabsTrigger, TextReveal, type TextRevealProps, Textarea, type TextareaProps, ThemeId, ThemeManifest, ThemeMode$1 as ThemeManifestMode, type ThemeMode, ThemePreview, type ThemePreviewProps, ThemeSelector, type ThemeSelectorProps, ThemeSwitcher, type ThemeSwitcherProps, ThinkingOrb, type ThinkingOrbProps, ToastAction, type ToastApi, ToastClose, ToastContent, ToastDescription, type ToastManagerApi, type ToastOptions, type ToastPosition, ToastProvider, type ToastProviderProps, ToastRoot, ToastTitle, type ToastType, ToastViewport, Toggle, ToggleGroup, type ToggleGroupAppearance, Toggle as ToggleGroupItem, ToolCall, type ToolCallProps, type ToolCallStatus, Toolbar, ToolbarButton, type ToolbarButtonProps, ToolbarGroup, type ToolbarGroupProps, ToolbarInput, type ToolbarInputProps, ToolbarLink, type ToolbarLinkProps, type ToolbarProps, ToolbarSeparator, type ToolbarSeparatorProps, Tooltip, TooltipArrow, TooltipContent, TooltipGroup, type TooltipGroupProps, TooltipPortal, TooltipProvider, TooltipTrigger, Tree, TreeAddRow, TreeEmpty, TreeRow, TreeSection, type UseActiveSectionOptions, type UseCaretTriggerOptions, type UseCaretTriggerResult, type UseCopyOptions, type UseCopyResult, type UseInViewOptions, type UseMatchHighlightOptions, type UsePanelWidthOptions, Video, type VideoProps, ViewTransitionName, type ViewTransitionNameProps, Workspace, WorkspaceBar, WorkspaceCanvas, accordionMeta, appHeaderMeta, appShellMeta, areaChartMeta, attachmentMeta, avatarGroupVariants, avatarMeta, avatarVariants, badgeMeta, badgeVariants, bannerMeta, bannerVariants, barChartMeta, bottomNavMeta, breadcrumbsMeta, browserMeta, bubbleMeta, buttonGroupMeta, buttonMeta, buttonVariants, calendarMeta, cardMeta, caretMenuMeta, carouselMeta, chartColor, toneColor as chartToneColor, chatComposerMeta, checkboxCardMeta, checkboxMeta, cn, codeBlockMeta, codeMeta, collapsibleMeta, colorFieldMeta, comboboxMeta, commandMenuMeta, componentGuidance, componentLabel, componentSlug, componentsInGroup, confirmButtonMeta, contextCardMeta, contextMenuMeta, dataTableMeta, datePickerMeta, dateTileMeta, destructiveActionModalMeta, dialogMeta, disclosurePickerMeta, emptyStateMeta, entityMeta, feedbackMeta, fieldsetMeta, fileDropzoneMeta, fileDropzoneVariants, fontPickerMeta, formMeta, formatFileSize, formatHex, glidingHighlightMeta, gradientArtMeta, hsvToRgb, hueColor, inlineStatusMeta, inputGroupMeta, inputMeta, isPaletteColor, isTransparent, kbdMeta, labelMeta, likeButtonMeta, lineChartMeta, markerMeta, marqueeMeta, mediaImageMeta, mediaTileMeta, menuMeta, menubarMeta, messageMeta, messageScrollerMeta, meterIndicatorVariants, meterMeta, meterTrackVariants, middleTruncateMeta, motionAttribute, navigationMenuMeta, noteMeta, noteVariants, notificationBadgeMeta, notificationCountVariants, notificationDotVariants, numberFieldMeta, numberTickerMeta, otpFieldMeta, overflowMenuMeta, pageHeaderMeta, pageLoaderMeta, paginationMeta, panelGroupMeta, panelSectionMeta, parseHex, phoneMeta, pieChartMeta, pillMeta, pillVariants, popoverMeta, progressMeta, progressTrackVariants, radarChartMeta, radialChartMeta, radioCardMeta, radioMeta, reactionPickerMeta, relativeTimeMeta, rgbToHsv, scrollerMeta, scrubFieldMeta, searchInputMeta, sectionHeaderMeta, sectionRailMeta, segmentedBarMeta, segmentedBarSegmentVariants, segmentedBarVariants, selectMeta, separatorMeta, settingsMenuMeta, sheetMeta, sheetVariants, showMoreMeta, sideNavMeta, sidebarMeta, skeletonMeta, sliderMeta, sparklineMeta, spinnerMeta, startViewTransition, statusBarMeta, statusDotMeta, statusDotVariants, stepperConnectorVariants, stepperIndicatorVariants, stepperMeta, streamingTextMeta, supportsViewTransitions, switchMeta, tableMeta, tabsMeta, textareaMeta, themeSelectorMeta, themeSwitcherMeta, thinkingOrbMeta, toast, toastMeta, toggleMeta, toolCallMeta, toolbarGroupVariants, toolbarMeta, toolbarSeparatorVariants, toolbarVariants, tooltipMeta, treeIndent, treeMeta, useActiveSection, useAnchoredDensity, useAutoSize, useCaretTrigger, useComboboxFilteredItems, useCommandMenuShortcut, useCopy, useDensity, useDisclosurePicker, useInView, useMatchHighlight, useMotion, useMotionLevel, usePanelWidth, usePresentation, useReducedMotion, useScrollActivity, useShake, useSidebar, useSmoothWheel, useToast, useToastManager, useTypeTier, videoMeta, workspaceMeta };
package/dist/index.js CHANGED
@@ -130,6 +130,7 @@ export * from "./components/color-field/index.js";
130
130
  export * from "./components/app-shell/index.js";
131
131
  export * from "./components/sidebar/index.js";
132
132
  export * from "./components/side-nav/index.js";
133
+ export * from "./components/section-rail/index.js";
133
134
  export * from "./components/bottom-nav/index.js";
134
135
  export * from "./components/app-header/index.js";
135
136
  export * from "./components/page-header/index.js";
@@ -176,12 +177,13 @@ import { useScrollActivity } from "./lib/use-scroll-activity.js";
176
177
  import { useMatchHighlight } from "./lib/use-match-highlight.js";
177
178
  import { useCopy } from "./lib/use-copy.js";
178
179
  import { useSmoothWheel } from "./lib/use-smooth-wheel.js";
180
+ import { useActiveSection } from "./lib/use-active-section.js";
179
181
  import {
180
182
  useCaretTrigger
181
183
  } from "./lib/use-caret-trigger.js";
182
184
  import { STATUS_TONES, STATUS_TONE_ICON } from "./lib/status-tone.js";
183
185
  import { PALETTE_COLORS, PALETTE_FAMILIES, PALETTE_SCALES, PALETTE_STEPS, PALETTE_TONES, isPaletteColor } from "./lib/palette.js";
184
- var SABLE_UI_VERSION = "0.16.0";
186
+ var SABLE_UI_VERSION = "0.17.0";
185
187
  export {
186
188
  APP_SHELL_TOKENS,
187
189
  ART_TOKENS,
@@ -234,6 +236,7 @@ export {
234
236
  themeIds,
235
237
  themeManifestById,
236
238
  themeManifests,
239
+ useActiveSection,
237
240
  useAnchoredDensity,
238
241
  useCaretTrigger,
239
242
  useCopy,
@@ -90,6 +90,7 @@ var COMPONENT_TAXONOMY = {
90
90
  BottomNav: ["Navigation", "page"],
91
91
  NavigationMenu: ["Navigation", "page"],
92
92
  Pagination: ["Navigation", "either"],
93
+ SectionRail: ["Navigation", "page"],
93
94
  ShowMore: ["Navigation", "page"],
94
95
  SideNav: ["Navigation", "page"],
95
96
  Sidebar: ["Navigation", "page"],
@@ -0,0 +1,59 @@
1
+ "use client";
2
+
3
+ // src/lib/use-active-section.ts
4
+ import { useEffect, useState } from "react";
5
+ var END_SLACK = 2;
6
+ function useActiveSection(ids, { offset = 0.35, root } = {}) {
7
+ const [active, setActive] = useState(ids[0] ?? null);
8
+ const key = ids.join("\n");
9
+ useEffect(() => {
10
+ const list = key ? key.split("\n") : [];
11
+ if (list.length === 0) {
12
+ setActive(null);
13
+ return;
14
+ }
15
+ const scroller = root?.current ?? null;
16
+ let frame = 0;
17
+ const measure = () => {
18
+ frame = 0;
19
+ const top = scroller ? scroller.getBoundingClientRect().top : 0;
20
+ const height = scroller ? scroller.clientHeight : window.innerHeight;
21
+ const line = top + height * offset;
22
+ const bottom = top + height;
23
+ const scrolled = scroller ? scroller.scrollTop : window.scrollY;
24
+ const range = scroller ? scroller.scrollHeight - scroller.clientHeight : document.documentElement.scrollHeight - window.innerHeight;
25
+ const atEnd = range > END_SLACK && scrolled >= range - END_SLACK;
26
+ let current = list[0];
27
+ for (const id of list) {
28
+ const section = document.getElementById(id);
29
+ if (!section) continue;
30
+ const sectionTop = section.getBoundingClientRect().top;
31
+ if (sectionTop <= line || atEnd && sectionTop < bottom) current = id;
32
+ }
33
+ setActive(current);
34
+ };
35
+ const schedule = () => {
36
+ if (!frame) frame = requestAnimationFrame(measure);
37
+ };
38
+ measure();
39
+ const target = scroller ?? window;
40
+ target.addEventListener("scroll", schedule, { passive: true });
41
+ window.addEventListener("resize", schedule);
42
+ const resize = new ResizeObserver(schedule);
43
+ resize.observe(scroller ?? document.documentElement);
44
+ for (const id of list) {
45
+ const section = document.getElementById(id);
46
+ if (section) resize.observe(section);
47
+ }
48
+ return () => {
49
+ cancelAnimationFrame(frame);
50
+ target.removeEventListener("scroll", schedule);
51
+ window.removeEventListener("resize", schedule);
52
+ resize.disconnect();
53
+ };
54
+ }, [key, offset, root]);
55
+ return active;
56
+ }
57
+ export {
58
+ useActiveSection
59
+ };
@@ -1,48 +1,45 @@
1
1
  # ApprovalBlock
2
2
 
3
- An agent asking permission for one tool call: the question, what will happen and what can't be undone, the call's details, an "allow for the rest of this chat" Checkbox, and Deny / Allow.
3
+ An agent asking permission for one tool call: the question, what is at stake, the call itself as a ToolCall with its exact input, and Deny / Always allow / Allow once.
4
4
 
5
- **Intent:** Reach for this in a chat or agent run when a tool call waits on the person — sending, paying, deleting, publishing. The call itself, before and after the decision, is a ToolCall with status="awaiting", then "complete" or "denied". A destructive action outside an agent is DestructiveActionModal.
5
+ **Intent:** Reach for this in a chat or agent run when a tool call waits on the person — running a command, sending, paying, deleting, publishing. It wraps the call's own ToolCall, which shows status="awaiting" until the person answers and then "complete" or "denied". A destructive action outside an agent is DestructiveActionModal.
6
6
 
7
7
  **Block:** AI & agents · card · designed for 18rem–28rem wide (fills its container up to the max)
8
8
 
9
9
  ## Notes
10
10
 
11
- - The title is the question in plain words ("Send the invoice to Ada?"), not the tool's name; the tool's name is one row of the details, for the person who wants to know exactly what runs.
12
- - The description says what can't be undone. That sentence is what the person is deciding on.
13
- - Deny comes first and Allow is the primary on the end, the same order as every Sable confirmation. Neither is focused on arrival: an approval that a stray Enter can grant is not an approval.
14
- - After a decision the buttons give way to one InlineStatus line saying what happened, so the thread keeps a record of the answer.
11
+ - The title is the question in plain words ("Run this command?"); the description says what is at stake. That sentence is what the person is deciding on.
12
+ - The call is shown as the agent made it — tool name and raw input, open on arrival — because the exact arguments are what a careful person checks. Do not paraphrase them into a form.
13
+ - Three answers, as agent products settle on: Deny on the start edge, then Always allow and Allow once, the primary on the end. Neither is focused on arrival: an approval that a stray Enter can grant is not an approval.
14
+ - After a decision the buttons give way to one InlineStatus line saying what happened, and the ToolCall shows the outcome, so the thread keeps a record of the answer.
15
15
 
16
16
  ## Accessibility
17
17
 
18
18
  - Focus moves to the outcome line when the buttons leave, instead of dropping to the page; the line is a role=status region, so the decision is announced.
19
- - The details are a dl, so each value is read with its label.
20
- - The remember Checkbox has its own Label, so the tool name inside it is part of its accessible name.
19
+ - The ToolCall announces its own status change, and its input is a labelled code view.
21
20
 
22
21
  ## Source
23
22
 
24
23
  ```tsx
25
- import { useState, useEffect, useRef, useId } from "react"
26
- import { Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, cn, Code, InlineStatus, Label } from "@sableui/react"
24
+ import { useState, useEffect, useRef } from "react"
25
+ import { Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, cn, InlineStatus, ToolCall } from "@sableui/react"
27
26
 
28
27
  const request = {
29
- tool: "send_email",
30
- title: "Send the invoice to Ada?",
31
- description: "The agent wants to email invoice INV-1042. An email can't be unsent.",
32
- details: [
33
- { label: "To", value: "ada@example.com" },
34
- { label: "Subject", value: "INV-1042 for October" },
35
- { label: "Attached", value: "INV-1042.pdf" },
36
- ],
37
- allowed: "Allowed. Sending the email.",
38
- denied: "Denied. The agent won't send it.",
28
+ title: "Run this command?",
29
+ description: "The agent wants to migrate the production database in acme/api. It changes live data.",
30
+ tool: "run_command",
31
+ action: "Run a command",
32
+ // A command reads as the command; a structured call would pass its arguments object.
33
+ input: "pnpm db:migrate --env production",
34
+ allowed: "Allowed. Running the migration.",
35
+ denied: "Denied. The agent won't run it.",
39
36
  }
40
37
 
41
38
  export interface ApprovalBlockProps {
42
39
  className?: string
43
40
  /** false drops the card's surface and border — for a chat column that already frames it. */
44
41
  framed?: boolean
45
- /** The person allowed the call. `remember` is the "for the rest of this chat" choice. */
42
+ /** The person allowed the call. `remember` is true for "Always allow". */
46
43
  onApprove?: (options: { remember: boolean }) => void
47
44
  /** The person declined the call. */
48
45
  onDeny?: () => void
@@ -50,8 +47,6 @@ export interface ApprovalBlockProps {
50
47
 
51
48
  export function ApprovalBlock({ className, framed = true, onApprove, onDeny }: ApprovalBlockProps) {
52
49
  const [decision, setDecision] = useState<"allowed" | "denied" | null>(null)
53
- const [remember, setRemember] = useState(false)
54
- const id = useId()
55
50
  const outcome = useRef<HTMLDivElement>(null)
56
51
  // The buttons leave with the decision, so focus moves to the line that
57
52
  // replaces them instead of falling back to the top of the page.
@@ -59,37 +54,30 @@ export function ApprovalBlock({ className, framed = true, onApprove, onDeny }: A
59
54
  if (decision) outcome.current?.focus()
60
55
  }, [decision])
61
56
 
57
+ const approve = (remember: boolean) => {
58
+ setDecision("allowed")
59
+ onApprove?.({ remember })
60
+ }
61
+
62
62
  return (
63
63
  <Card variant={framed ? "default" : "flat"} className={cn("w-full max-w-md", className)}>
64
64
  <CardHeader>
65
65
  <CardTitle>{request.title}</CardTitle>
66
66
  <CardDescription>{request.description}</CardDescription>
67
67
  </CardHeader>
68
- <CardContent className="flex flex-col gap-4">
69
- <dl className="grid grid-cols-[auto_minmax(0,1fr)] gap-x-4 gap-y-1.5 text-body-sm">
70
- {request.details.map((d) => (
71
- <div key={d.label} className="contents">
72
- <dt className="text-muted-foreground">{d.label}</dt>
73
- <dd className="truncate text-foreground">{d.value}</dd>
74
- </div>
75
- ))}
76
- <div className="contents">
77
- <dt className="text-muted-foreground">Tool</dt>
78
- <dd className="min-w-0">
79
- <Code>{request.tool}</Code>
80
- </dd>
81
- </div>
82
- </dl>
83
- {decision ? null : (
84
- <div className="flex items-center gap-2">
85
- <Checkbox id={`${id}-remember`} checked={remember} onCheckedChange={(v: boolean) => setRemember(v)} />
86
- <Label htmlFor={`${id}-remember`} className="text-body-sm">
87
- Allow <Code>{request.tool}</Code> for the rest of this chat
88
- </Label>
89
- </div>
90
- )}
68
+ <CardContent>
69
+ {/* The call itself, exactly as the agent made it. It answers with the
70
+ person: held, then done or denied. */}
71
+ <ToolCall
72
+ name={request.tool}
73
+ title={request.action}
74
+ status={decision === "allowed" ? "complete" : decision === "denied" ? "denied" : "awaiting"}
75
+ statusLabel={decision === "allowed" ? "Allowed" : undefined}
76
+ input={request.input}
77
+ defaultOpen
78
+ />
91
79
  </CardContent>
92
- <CardFooter actions className="justify-end">
80
+ <CardFooter actions>
93
81
  {decision ? (
94
82
  <InlineStatus
95
83
  ref={outcome}
@@ -103,7 +91,8 @@ export function ApprovalBlock({ className, framed = true, onApprove, onDeny }: A
103
91
  ) : (
104
92
  <>
105
93
  <Button
106
- variant="outline"
94
+ variant="ghost"
95
+ className="me-auto"
107
96
  onClick={() => {
108
97
  setDecision("denied")
109
98
  onDeny?.()
@@ -111,14 +100,10 @@ export function ApprovalBlock({ className, framed = true, onApprove, onDeny }: A
111
100
  >
112
101
  Deny
113
102
  </Button>
114
- <Button
115
- onClick={() => {
116
- setDecision("allowed")
117
- onApprove?.({ remember })
118
- }}
119
- >
120
- Allow
103
+ <Button variant="outline" onClick={() => approve(true)}>
104
+ Always allow
121
105
  </Button>
106
+ <Button onClick={() => approve(false)}>Allow once</Button>
122
107
  </>
123
108
  )}
124
109
  </CardFooter>
@@ -0,0 +1,101 @@
1
+ # SectionRail
2
+
3
+ **Status:** stable
4
+
5
+ A slim vertical rail of dots, one per section of a long page, that shows where the reader is and jumps to any section. The current section's bar glides as the page scrolls; a shared tooltip names each dot.
6
+
7
+ **Keywords:** section rail, scroll spy, scrollspy, dot navigation, page navigation, table of contents, on this page, chapter nav, scroll progress, case study nav
8
+
9
+ ## Usage
10
+
11
+ Use SectionRail beside a long, single-column read — a case study, an essay, a long landing page — so the reader can see which section they are in and jump to another without leaving the text. It follows the scroll by itself (useActiveSection); pass value when the parent already knows the current section.
12
+
13
+ ### Best practices
14
+
15
+ - Do: Give every section an id that matches its entry, and keep the list to the page's top-level sections — about ten at most, so the rail stays shorter than the viewport.
16
+ - Do: Place it with layout classes — usually `fixed top-1/2 left-6 z-(--z-nav) -translate-y-1/2` — and hide it below the width where it would overlap the text (`max-lg:hidden`). Offer the same links another way on narrow screens, such as a Collapsible list at the top of the page.
17
+ - Do: Pass `root` when the content scrolls inside an element (a Scroller, an inset AppShell main) rather than the window, and give sections `scroll-mt-*` when a sticky header would cover their tops after a jump.
18
+ - Do: Set `side="right"` when the rail sits on the right edge, so labels open toward the content.
19
+ - Don't: Use it for app navigation between pages; that is SideNav or Sidebar. A SectionRail only moves within one page. → use **SideNav**, **Sidebar**
20
+ - Don't: Use it to show the steps of a task or a flow; that is Stepper, which shows progress through steps rather than position in a read. → use **Stepper**
21
+ - Don't: Use it for a handful of switchable views in one place; that is Tabs. → use **Tabs**
22
+
23
+ ### Anatomy
24
+
25
+ | Part | Required | Description |
26
+ | --- | --- | --- |
27
+ | Rail | yes | The `<nav>` landmark: a rounded muted track holding one link per section. |
28
+ | Dot | yes | A link to `#id`, drawn as a small dot that grows under the pointer or focus. |
29
+ | Marker | yes | One primary bar that sits on the current section's dot and glides to the next. |
30
+ | Label | yes | A shared tooltip that names the hovered or focused dot and travels between dots. |
31
+
32
+ ## Props
33
+
34
+ | Name | Type | Default | Description |
35
+ | --- | --- | --- | --- |
36
+ | sections | readonly { id: string; label: string }[] | — | The sections, in document order. `id` is the section element's id (the link goes to `#id`); `label` is the tooltip and the link's accessible name. |
37
+ | value | string | — | The current section's id, when the parent decides it. Leave it unset and the rail follows the scroll itself. |
38
+ | onValueChange | (id: string) => void | — | Called with the new id when the reader scrolls into a section or picks one. |
39
+ | offset | number | 0.35 | Where the reading line sits, as a fraction of the viewport from its top. A section becomes current once its top crosses it. |
40
+ | root | RefObject<HTMLElement \| null> | — | The element that scrolls, when it is not the window. |
41
+ | side | "left" \| "right" | "left" | Which edge of the page the rail sits on. The labels open on the other side, toward the content. |
42
+ | motion | "full" \| "subtle" \| "off" | "full" | How much motion this component uses: `full` inherits the app's policy, `subtle` keeps feedback and drops the marker's glide, `off` stills it. It can only turn motion down — it never overrides a reader's reduce-motion setting. |
43
+ | aria-label | string | "Sections" | The nav landmark's name. Name it for the page ("Case study sections") when it has other navs. |
44
+
45
+ ## Tokens used
46
+
47
+ `muted`, `muted-foreground`, `foreground`, `primary`, `ring`, `popover`, `popover-foreground`, `border-floating`
48
+
49
+ ## Motion
50
+
51
+ - **arrival** · Root · _no motion_ — Page chrome arrives with the page; the marker lands on the current section with no transition, because a bar sliding in on load narrates a move nobody made.
52
+ - **response** · Dot · `motion-interactive` — The dot darkens and grows under the pointer or focus, and the label travels between dots as one tooltip (TooltipGroup) rather than closing and reopening at each.
53
+ - **transition** · Marker · `motion-glide` — One bar travels to the new section as the page scrolls, so the change reads as movement down the page. A picked section holds the bar until the reader scrolls by hand, so it goes straight there instead of stepping through every section in between, and stays on the pick even when the page ends before that section can reach the reading line. Expressive: `subtle` moves it at once.
54
+ - **activity** · Root · _no motion_ — Navigation chrome has no working state.
55
+
56
+ ## Accessibility
57
+
58
+ - Renders a <nav> landmark (default name "Sections") of real links to `#id`, so it works with no script, middle-click and copy-link.
59
+ - Each link is named by its section's label; the current one carries aria-current="location".
60
+ - Activating a link from the keyboard moves focus into the section, as following an anchor does, so the next Tab continues from there.
61
+ - The tooltip opens on focus as well as hover; the dots are 44×32 targets.
62
+ - Under reduced motion the jump is instant and the marker moves without travel.
63
+
64
+ ## Related
65
+
66
+ - Components: SideNav, Tooltip, Stepper, Tabs, GlidingHighlight
67
+
68
+ ## Examples
69
+
70
+ ### Fixed beside a long read
71
+
72
+ ```tsx
73
+ import { SectionRail } from "@sableui/react"
74
+
75
+ <SectionRail
76
+ aria-label="Case study sections"
77
+ sections={[
78
+ { id: "overview", label: "Overview" },
79
+ { id: "problem", label: "The problem" },
80
+ { id: "process", label: "Process" },
81
+ { id: "outcome", label: "Outcome" },
82
+ ]}
83
+ className="fixed top-1/2 left-6 z-(--z-nav) -translate-y-1/2 max-lg:hidden"
84
+ />
85
+ ```
86
+
87
+ ### On the right edge
88
+
89
+ ```tsx
90
+ import { SectionRail } from "@sableui/react"
91
+
92
+ <SectionRail
93
+ side="right"
94
+ sections={[
95
+ { id: "intro", label: "Introduction" },
96
+ { id: "usage", label: "Usage" },
97
+ { id: "api", label: "API" },
98
+ ]}
99
+ className="fixed top-1/2 right-6 z-(--z-nav) -translate-y-1/2 max-lg:hidden"
100
+ />
101
+ ```