@cueplusplus/ui 0.7.0 → 0.9.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +272 -0
  2. package/README.md +49 -0
  3. package/dist/chat/message-list.js +2 -1
  4. package/dist/configurator/_export.d.ts +1 -1
  5. package/dist/configurator/_export.js +53 -13
  6. package/dist/configurator/_overrides.d.ts +25 -6
  7. package/dist/configurator/_overrides.js +30 -17
  8. package/dist/configurator/configurator.js +8 -3
  9. package/dist/configurator/panel-sections.js +43 -13
  10. package/dist/elements/command-palette.js +1 -1
  11. package/dist/elements/flow-graph.js +2 -2
  12. package/dist/elements/markdown.js +1 -1
  13. package/dist/elements/surfaces.js +4 -3
  14. package/dist/index.d.ts +5 -2
  15. package/dist/index.js +2 -1
  16. package/dist/instruments/_ledger-disclosure.js +103 -0
  17. package/dist/instruments/_ledger.d.ts +21 -0
  18. package/dist/instruments/_ledger.js +5 -0
  19. package/dist/instruments/ledger.d.ts +112 -13
  20. package/dist/instruments/ledger.js +128 -38
  21. package/dist/midi/piano-keyboard.js +5 -1
  22. package/dist/primitives/chip.d.ts +1 -1
  23. package/dist/styles.css +23 -1
  24. package/dist/system/density.d.ts +17 -8
  25. package/dist/system/density.js +39 -16
  26. package/dist/system/index.d.ts +5 -2
  27. package/dist/system/index.js +2 -1
  28. package/dist/system/overrides.d.ts +43 -0
  29. package/dist/system/overrides.js +238 -0
  30. package/dist/system/portal.d.ts +4 -2
  31. package/dist/system/portal.js +34 -3
  32. package/dist/system/prepaint.d.ts +58 -7
  33. package/dist/system/prepaint.js +72 -20
  34. package/dist/system/theme-provider.d.ts +133 -8
  35. package/dist/system/theme-provider.js +203 -72
  36. package/dist/system/theme-registry.d.ts +53 -0
  37. package/dist/system/theme-registry.js +66 -0
  38. package/dist/system/use-density.d.ts +13 -5
  39. package/dist/system/use-density.js +142 -13
  40. package/dist/system/use-theme.d.ts +5 -3
  41. package/dist/system/use-theme.js +5 -3
  42. package/dist/system/vocabulary.d.ts +15 -0
  43. package/dist/system/vocabulary.js +111 -0
  44. package/dist/theming/contrast.d.ts +2 -122
  45. package/dist/theming/contrast.js +2 -194
  46. package/dist/theming/create-theme.d.ts +37 -11
  47. package/dist/theming/create-theme.js +54 -17
  48. package/dist/theming/index.d.ts +3 -4
  49. package/dist/theming/index.js +3 -4
  50. package/dist/theming/serialize.d.ts +24 -11
  51. package/dist/theming/serialize.js +16 -18
  52. package/manifest/components/colors-section.json +2 -3
  53. package/manifest/components/cue-portal-frame.json +1 -1
  54. package/manifest/components/data-tree.json +1 -0
  55. package/manifest/components/density.json +1 -1
  56. package/manifest/components/export-dialog.json +0 -3
  57. package/manifest/components/ledger.json +82 -7
  58. package/manifest/components/preset-section.json +2 -3
  59. package/manifest/components/shape-section.json +2 -3
  60. package/manifest/components/theme-configurator.json +0 -3
  61. package/manifest/components/theme-provider.json +24 -9
  62. package/manifest/components/token-editor.json +0 -3
  63. package/manifest/manifest.json +148 -27
  64. package/manifest/tokens.json +121 -11
  65. package/package.json +15 -6
  66. package/dist/theming/_presets.d.ts +0 -11
  67. package/dist/theming/_presets.js +0 -678
@@ -1,22 +1,20 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { Input } from "../forms/input.js";
4
- import { DENSITY_LEVELS } from "../system/density.js";
4
+ import { useDensities, useThemes } from "../system/theme-registry.js";
5
5
  import { SectionHeader } from "../chrome/section-header.js";
6
6
  import { SegmentedControl } from "../chrome/segmented-control.js";
7
7
  import { Field, FieldLabel } from "../forms/field.js";
8
8
  import { Slider } from "../forms/slider.js";
9
9
  import { Kbd } from "../primitives/kbd.js";
10
10
  import { useTheme } from "../system/use-theme.js";
11
- import { THEME_PRESETS } from "../theming/_presets.js";
12
11
  import { tokenProperty } from "../theming/serialize.js";
13
12
  import { COLOR_TOKENS, FONT_TOKENS, isSafeCssValue } from "./_overrides.js";
14
13
  import { TokenEditor } from "./token-editor.js";
15
14
  import * as React from "react";
16
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
+ import { resolve } from "@cueplusplus/theme-base";
17
17
  //#region src/configurator/panel-sections.tsx
18
- /** The presets, in menu order, with the palette each one is announced by. */
19
- const PRESETS = Object.keys(THEME_PRESETS);
20
18
  /** The five colours a preset is recognisable from, in reading order. */
21
19
  const SWATCH_TOKENS = [
22
20
  "bg",
@@ -44,13 +42,25 @@ const MODE_ITEMS = [
44
42
  * and `Ultra-large` alone are 25 characters — so the segmented control wears
45
43
  * the garment sizes and the value it sets is still the ladder's own name.
46
44
  */
47
- const DENSITY_LABELS = {
45
+ const BASE_DENSITY_LABELS = {
48
46
  "ultra-compact": "XS",
49
47
  "compact": "S",
50
48
  "normal": "M",
51
49
  "large": "L",
52
50
  "ultra-large": "XL"
53
51
  };
52
+ /**
53
+ * What a rung is called in the panel.
54
+ *
55
+ * A lookup rather than a table, because the ladder is open now: a theme may add
56
+ * a rung, and this package has no garment size to give it. Its own name is the
57
+ * only label that is certainly true — longer than a letter, and honest about
58
+ * being the theme's rather than the ladder's. The base five keep their sizes,
59
+ * so nothing a user has learned moves.
60
+ */
61
+ function densityLabel(rung) {
62
+ return BASE_DENSITY_LABELS[rung] ?? rung;
63
+ }
54
64
  /** Bounds of the text-scale knob, from spec §6's `fontScale`. */
55
65
  const FONT_SCALE = {
56
66
  min: .8,
@@ -77,7 +87,16 @@ const FONT_LABELS = {
77
87
  };
78
88
  /** Base UI hands a range slider an array; every slider here has one thumb. */
79
89
  const single = (value) => Array.isArray(value) ? value[0] ?? 0 : value;
80
- /** A number knob wired to one token, live on drag and persisted on release. */
90
+ /**
91
+ * A number knob wired to one token, live on drag and persisted on release.
92
+ *
93
+ * The three it is used for are `--cue-radius-scale` and `--cue-density`, both
94
+ * crossed with the density ladder when they are written, and `--cue-font-scale`,
95
+ * which the provider publishes inline. Naming them here is not decoration: the
96
+ * package manifest's token list is scraped for literal `--cue-*` spellings, and
97
+ * a token whose only spelling in this file is the bare `token="radius-scale"`
98
+ * prop is a token the docs page for this section does not list.
99
+ */
81
100
  function ScaleSlider({ label, token, edits, bounds }) {
82
101
  const value = Number(edits.value(token));
83
102
  return /* @__PURE__ */ jsx(Slider, {
@@ -147,16 +166,27 @@ function TextTokenField({ label, token, edits, placeholder }) {
147
166
  */
148
167
  function PresetSection({ edits, zoom, className }) {
149
168
  const { theme, density, mode, resolvedMode, setTheme, setDensity, setMode } = useTheme();
169
+ const themes = useThemes();
170
+ const densities = useDensities();
150
171
  return /* @__PURE__ */ jsxs(SectionHeader, {
151
172
  label: "Preset",
152
173
  collapsible: true,
153
174
  className,
154
175
  children: [
155
- /* @__PURE__ */ jsx("div", {
176
+ themes.length === 0 ? /* @__PURE__ */ jsxs("p", {
177
+ className: "text-fg-muted text-ui",
178
+ children: [
179
+ "No themes registered — pass ",
180
+ /* @__PURE__ */ jsx("code", { children: "themes" }),
181
+ " to ",
182
+ /* @__PURE__ */ jsx("code", { children: "ThemeProvider" }),
183
+ "."
184
+ ]
185
+ }) : /* @__PURE__ */ jsx("div", {
156
186
  className: "grid grid-cols-2 gap-(--cue-space-2)",
157
- children: PRESETS.map((name) => {
158
- const preset = THEME_PRESETS[name];
159
- const palette = (resolvedMode === "light" ? preset.light : preset.dark) ?? preset.dark;
187
+ children: themes.map((manifest) => {
188
+ const name = manifest.name;
189
+ const palette = resolve(manifest, { mode: resolvedMode }).colors;
160
190
  const active = name === theme;
161
191
  return /* @__PURE__ */ jsxs("button", {
162
192
  type: "button",
@@ -197,9 +227,9 @@ function PresetSection({ edits, zoom, className }) {
197
227
  itemClassName: "flex-1",
198
228
  value: density,
199
229
  onValueChange: (next) => setDensity(next),
200
- items: DENSITY_LEVELS.map((level) => ({
201
- value: level,
202
- label: DENSITY_LABELS[level]
230
+ items: densities.map((rung) => ({
231
+ value: rung.name,
232
+ label: densityLabel(rung.name)
203
233
  }))
204
234
  }),
205
235
  /* @__PURE__ */ jsx(ScaleSlider, {
@@ -32,7 +32,7 @@ function ElementsCommandPalette({ commands, query, activeId, onQueryChange, onAc
32
32
  if (next) onActiveChange?.(next.id);
33
33
  };
34
34
  useEffect(() => {
35
- document.getElementById(optionId(activeId))?.scrollIntoView({ block: "nearest" });
35
+ document.getElementById(`${listId}-${activeId}`)?.scrollIntoView({ block: "nearest" });
36
36
  }, [activeId, listId]);
37
37
  const onKeyDown = (event) => {
38
38
  if (event.nativeEvent.isComposing) return;
@@ -47,7 +47,7 @@ function FlowGraph({ nodes, edges, visibleCount, className, ...props }) {
47
47
  const from = nodes.find((node) => node.id === edge.from);
48
48
  const to = nodes.find((node) => node.id === edge.to);
49
49
  if (!from || !to) return null;
50
- shownIds.has(edge.from) && shownIds.has(edge.to);
50
+ const live = shownIds.has(edge.from) && shownIds.has(edge.to);
51
51
  const a = center(from);
52
52
  const b = center(to);
53
53
  const midX = (a.x + b.x) / 2;
@@ -55,7 +55,7 @@ function FlowGraph({ nodes, edges, visibleCount, className, ...props }) {
55
55
  d: `M ${a.x + NODE_W / 2} ${a.y} C ${midX} ${a.y}, ${midX} ${b.y}, ${b.x - NODE_W / 2} ${b.y}`,
56
56
  fill: "none",
57
57
  strokeWidth: "1.5",
58
- className: cn("transition-opacity duration-500 motion-reduce:transition-none", "stroke-fg-subtle")
58
+ className: cn("transition-opacity duration-500 motion-reduce:transition-none", "stroke-fg-subtle", live ? "opacity-100" : "opacity-30")
59
59
  }, `${edge.from}-${edge.to}`);
60
60
  })
61
61
  }), shown.map((node) => /* @__PURE__ */ jsx("div", {
@@ -130,7 +130,7 @@ function safeUrl(value) {
130
130
  const FENCE = /^ {0,3}(`{3,}|~{3,})/;
131
131
  /** Whether a character can sit next to a delimiter run without closing a word. */
132
132
  function isBoundary(char) {
133
- return char === "" || /[\s!-\/:-@[-`{-~]/.test(char);
133
+ return char === "" || /[\s!-/:-@[-`{-~]/.test(char);
134
134
  }
135
135
  /**
136
136
  * Where the last block of `source` begins: after the final blank line that is
@@ -80,10 +80,11 @@ function ShimmerLabel({ active = true, className, ...props }) {
80
80
  * announced nor copied into a selection.
81
81
  */
82
82
  function SwapLabel({ active, children, className }) {
83
- const layers = [useRef(null), useRef(null)];
83
+ const restingRef = useRef(null);
84
+ const activeRef = useRef(null);
84
85
  const [width, setWidth] = useState(null);
85
86
  useLayoutEffect(() => {
86
- const target = layers[active]?.current;
87
+ const target = (active === 0 ? restingRef : activeRef).current;
87
88
  if (!target) return void 0;
88
89
  const measure = () => setWidth(Math.ceil(target.getBoundingClientRect().width));
89
90
  measure();
@@ -96,7 +97,7 @@ function SwapLabel({ active, children, className }) {
96
97
  style: width === null ? void 0 : { width },
97
98
  className: cn("grid overflow-x-clip transition-[width] duration-300 ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none", className),
98
99
  children: children.map((layer, index) => /* @__PURE__ */ jsx("span", {
99
- ref: layers[index],
100
+ ref: index === 0 ? restingRef : activeRef,
100
101
  "aria-hidden": active !== index,
101
102
  className: cn(labelSwap, active === index ? labelSwapIn : labelSwapOut),
102
103
  children: layer
package/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@ import { Tree, TreeProps, TreeVisibility, TreeVisibilityToggle, TreeVisibilityTo
33
33
  import { Toolbar, ToolbarButtonProps, ToolbarGroupProps, ToolbarRootProps, ToolbarSeparatorProps } from "./chrome/toolbar.js";
34
34
  import "./chrome/index.js";
35
35
  import { ControlVariantProps, FormControlSize, bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants } from "./forms/_chassis.js";
36
+ import { TokenOverrides } from "./system/overrides.js";
36
37
  import { FontFamilies, ResolvedMode, ThemeContextValue, ThemeProvider, ThemeProviderProps } from "./system/theme-provider.js";
37
38
  import { Autocomplete, AutocompleteProps } from "./forms/autocomplete.js";
38
39
  import { ButtonGroup, ButtonGroupOrientation, ButtonGroupProps } from "./forms/button-group.js";
@@ -122,7 +123,9 @@ import "./primitives/index.js";
122
123
  import { Density, DensityProps } from "./system/density.js";
123
124
  import { CuePortalFrame, CuePortalFrameProps, useCuePortalProps } from "./system/portal.js";
124
125
  import { DEFAULT_STORAGE_KEY, PersistedPreferences, PrepaintDefaults, PrepaintOptions, prepaintScript } from "./system/prepaint.js";
126
+ import { ThemeRegistry } from "./system/vocabulary.js";
127
+ import { useDensities, useFonts, useThemes } from "./system/theme-registry.js";
125
128
  import { ControlSize, useControlHeight, useDensity } from "./system/use-density.js";
126
129
  import { useTheme } from "./system/use-theme.js";
127
- import { DensityLevel, FontName, Mode, ThemeName } from "./system/index.js";
128
- export { AGENT_COLOR_PROPERTY, AGENT_HUES, AGENT_ROOT_COLOR, Accordion, type AccordionHeaderProps, type AccordionItemProps, type AccordionPanelProps, type AccordionRootProps, type AccordionTriggerProps, type AgentColorOptions, AgentPile, type AgentPileEntry, type AgentPileProps, type AgentPileSize, AlertDialog, type AlertDialogActionProps, type AlertDialogCancelProps, type AlertDialogContentProps, type AlertDialogDescriptionProps, type AlertDialogFooterProps, type AlertDialogRootProps, type AlertDialogTitleProps, type AlertDialogTriggerProps, AppBar, type AppBarActionsProps, type AppBarBrandProps, type AppBarLinkProps, type AppBarNavProps, type AppBarRegister, type AppBarRootProps, type AppBarSeparatorProps, AppShell, type AppShellAsideProps, type AppShellBarProps, type AppShellBodyProps, type AppShellContentProps, type AppShellNavTriggerProps, type AppShellRootProps, type AppShellScrollerProps, type AppShellSidebarProps, AppWindowFrame, type AppWindowFrameProps, type AskAnswer, AskBox, type AskBoxProps, type AskDanger, type AskKind, type AskOption, AudienceIcon, Autocomplete, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize, type BarOverflow, type BrandAssetProps, type BrandSize, type BrandTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, ButtonGroup, type ButtonGroupOrientation, type ButtonGroupProps, type ButtonProps, Card, type CardContentProps, type CardDescriptionProps, type CardFooterProps, type CardHeaderProps, type CardRootProps, type CardTitleProps, CatalogueIcon, ChannelBetaIcon, ChannelReleasedIcon, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Chip, type ChipProps, CliToolIcon, Collapsible, type CollapsiblePanelProps, type CollapsibleRootProps, type CollapsibleTriggerProps, Combobox, type ComboboxOption, type ComboboxProps, CommandPalette, type CommandPaletteItem, type CommandPaletteProps, Composer, type ComposerProps, type ComposerSubmitKey, Container, type ContainerProps, type ContainerWidth, ContextMenu, type ContextMenuContentProps, type ContextMenuRootProps, type ContextMenuTriggerProps, type ControlSize, type ControlVariantProps, CopyButton, type CopyButtonProps, CueLogotype, type CueLogotypeProps, CueMark, type CueMarkProps, CuePortalFrame, type CuePortalFrameProps, DEFAULT_STORAGE_KEY, DataRow, type DataRowDisclosure, type DataRowRootProps, type DataRowSlotProps, DataTree, type DataTreeItem, type DataTreeProps, type DataTreeRowState, DelegationCard, type DelegationCardProps, type DelegationDirection, type DelegationStatus, Density, type DensityLevel, type DensityProps, DescriptionList, type DescriptionListDetailProps, type DescriptionListLayout, type DescriptionListRootProps, type DescriptionListTermProps, Dialog, type DialogCloseProps, type DialogContentProps, type DialogDescriptionProps, type DialogFooterProps, type DialogRootProps, type DialogTitleProps, type DialogTriggerProps, Disclosure, type DisclosureProps, Drawer, type DrawerCloseProps, type DrawerContentProps, type DrawerDescriptionProps, type DrawerFooterProps, type DrawerRootProps, type DrawerSwipeDirection, type DrawerTitleProps, type DrawerTriggerProps, DropdownMenu, type DropdownMenuCheckboxItemProps, type DropdownMenuContentProps, type DropdownMenuGroupProps, type DropdownMenuItemProps, type DropdownMenuLabelProps, type DropdownMenuRootProps, type DropdownMenuSeparatorProps, type DropdownMenuTriggerProps, EmptyState, type EmptyStateProps, EnvVarInput, type EnvVarInputProps, Eyebrow, type EyebrowProps, Field, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, type FieldIssue, FieldLabel, type FieldLabelProps, type FieldProps, type FilePartition, type FilePartitionOptions, type FileRejectReason, type FileRejection, FileUpload, type FileUploadProps, FolderIcon, type FontFamilies, type FontName, Footer, type FooterProps, type FormControlSize, Grid, type GridColumns, type GridProps, GroupBar, type GroupBarItem, type GroupBarProps, type GroupBarTone, HoverCard, type HoverCardContentProps, type HoverCardRootProps, type HoverCardTriggerProps, IconButton, type IconButtonProps, InfoTip, type InfoTipProps, Input, InputGroup, type InputGroupProps, type InputProps, Item, type ItemProps, Kbd, type KbdProps, Ledger, type LedgerEmptyProps, type LedgerGroupProps, type LedgerRootProps, type LedgerTierProps, Link, type LinkProps, McpServerIcon, Menubar, type MenubarContentProps, type MenubarMenuProps, type MenubarRootProps, type MenubarTriggerProps, Message, MessageList, type MessageListProps, type MessageProps, type MessageRole, Meter, type MeterProps, type MeterProvenance, type MeterTone, type Mode, MultiSelect, type MultiSelectProps, NavigationMenu, type NavigationMenuContentProps, type NavigationMenuItemProps, type NavigationMenuLinkProps, type NavigationMenuListProps, type NavigationMenuRootProps, type NavigationMenuTriggerProps, type NavigationMenuViewportProps, NumberField, type NumberFieldProps, OTPField, type OTPFieldProps, OVERLAY_SIDE_OFFSET, PageShell, type PageShellProps, type PageWidth, Pagination, type PaginationEntry, type PaginationProps, Panel, PanelHeader, type PanelHeaderProps, type PanelProps, PasswordInput, type PasswordInputProps, type PersistedPreferences, Plussie, type PlussieExpression, type PlussieProps, Popover, type PopoverCloseProps, type PopoverContentProps, type PopoverDescriptionProps, type PopoverRootProps, type PopoverTitleProps, type PopoverTriggerProps, type PrepaintDefaults, type PrepaintOptions, Progress, type ProgressProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Rating, type RatingProps, type RatingSize, type ResolvedMode, Row, type RowProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, type ScrollEdges, ScrollableTabsList, type ScrollableTabsListProps, ScrubInput, type ScrubInputProps, SeamCell, type SeamCellProps, SeamGrid, type SeamGridProps, type SeamGround, SeamList, type SeamListProps, SearchInput, type SearchInputProps, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlItem, type SegmentedControlProps, type SegmentedControlSize, Select, type SelectOption, type SelectProps, Separator, type SeparatorProps, Sheet, type SheetCloseProps, type SheetContentProps, type SheetDescriptionProps, type SheetFooterProps, type SheetRootProps, type SheetTitleProps, type SheetTriggerProps, Sidebar, type SidebarItemProps, type SidebarRailProps, type SidebarRootProps, type SidebarSectionProps, Skeleton, type SkeletonProps, SkillIcon, Slider, type SliderProps, type SpaceStep, Sparkline, type SparklineProps, Spinner, type SpinnerProps, Stack, type StackAlign, StackIcon, type StackJustify, type StackProps, StacksMatrixIcon, Stat, type StatProps, type StatTone, StatusBar, type StatusBarGroupProps, type StatusBarItemProps, type StatusBarProminence, type StatusBarProps, type StatusBarTone, StatusDot, type StatusDotProps, type StatusTone, Stepper, type StepperProps, type StepperState, type StepperStep, Switch, type SwitchProps, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Table, type TableCaptionProps, type TableCellProps, type TableGroupRowProps, type TableHeadProps, type TableRootProps, type TableRowProps, TableScrollRegion, type TableScrollRegionProps, type TableSectionProps, Tabs, type TabsListProps, type TabsPanelProps, type TabsRootProps, type TabsTabProps, TagsInput, type TagsInputProps, TerminalFrame, type TerminalFrameLine, type TerminalFrameProps, type TerminalLine, type TerminalLineTone, type TerminalScript, type TerminalStep, Textarea, type TextareaProps, type ThemeContextValue, type ThemeName, ThemeProvider, type ThemeProviderProps, Timeline, type TimelineContentProps, type TimelineItemProps, type TimelineMarkerProps, type TimelineRootProps, TitleBar, type TitleBarProps, Toast, type ToastManager, type ToastOptions, type ToastProviderProps, type ToastTone, type ToastViewportProps, Toggle, ToggleGroup, type ToggleGroupProps, type ToggleProps, Toolbar, type ToolbarButtonProps, type ToolbarGroupProps, type ToolbarRootProps, type ToolbarSeparatorProps, Tooltip, type TooltipContentProps, type TooltipProviderProps, type TooltipRootProps, type TooltipTriggerProps, Tree, type TreeGuide, type TreeItem, type TreeProps, type TreeRow, type TreeVisibility, TreeVisibilityToggle, type TreeVisibilityToggleProps, TwoStepButton, type TwoStepButtonProps, type TwoStepTone, type UploadFile, type UploadStatus, UsageChart, type UsageChartPoint, type UsageChartProps, type UsageChartTone, activateRowFromClick, activateRowFromKeyDown, agentColor, agentColorStyle, bareControlClasses, buttonVariants, chipVariants, computeScrollEdges, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, edgeFadeMask, envReference, flattenTree, itemVariants, linkVariants, menuItemClasses, menuLabelClasses, menuPopupClasses, menuSeparatorClasses, overlayDescriptionClasses, overlayFooterClasses, overlayModalTransitionClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses, overlayTextClasses, overlayTitleClasses, paginationRange, parseEnvReference, partitionFiles, prepaintScript, rowVariants, scrimClasses, useControlHeight, useCuePortalProps, useDensity, useSidebar, useTheme, useToast };
130
+ import { DensityEntry, DensityLevel, FontEntry, FontName, Mode, ThemeManifest, ThemeName } from "./system/index.js";
131
+ export { AGENT_COLOR_PROPERTY, AGENT_HUES, AGENT_ROOT_COLOR, Accordion, type AccordionHeaderProps, type AccordionItemProps, type AccordionPanelProps, type AccordionRootProps, type AccordionTriggerProps, type AgentColorOptions, AgentPile, type AgentPileEntry, type AgentPileProps, type AgentPileSize, AlertDialog, type AlertDialogActionProps, type AlertDialogCancelProps, type AlertDialogContentProps, type AlertDialogDescriptionProps, type AlertDialogFooterProps, type AlertDialogRootProps, type AlertDialogTitleProps, type AlertDialogTriggerProps, AppBar, type AppBarActionsProps, type AppBarBrandProps, type AppBarLinkProps, type AppBarNavProps, type AppBarRegister, type AppBarRootProps, type AppBarSeparatorProps, AppShell, type AppShellAsideProps, type AppShellBarProps, type AppShellBodyProps, type AppShellContentProps, type AppShellNavTriggerProps, type AppShellRootProps, type AppShellScrollerProps, type AppShellSidebarProps, AppWindowFrame, type AppWindowFrameProps, type AskAnswer, AskBox, type AskBoxProps, type AskDanger, type AskKind, type AskOption, AudienceIcon, Autocomplete, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize, type BarOverflow, type BrandAssetProps, type BrandSize, type BrandTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, ButtonGroup, type ButtonGroupOrientation, type ButtonGroupProps, type ButtonProps, Card, type CardContentProps, type CardDescriptionProps, type CardFooterProps, type CardHeaderProps, type CardRootProps, type CardTitleProps, CatalogueIcon, ChannelBetaIcon, ChannelReleasedIcon, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Chip, type ChipProps, CliToolIcon, Collapsible, type CollapsiblePanelProps, type CollapsibleRootProps, type CollapsibleTriggerProps, Combobox, type ComboboxOption, type ComboboxProps, CommandPalette, type CommandPaletteItem, type CommandPaletteProps, Composer, type ComposerProps, type ComposerSubmitKey, Container, type ContainerProps, type ContainerWidth, ContextMenu, type ContextMenuContentProps, type ContextMenuRootProps, type ContextMenuTriggerProps, type ControlSize, type ControlVariantProps, CopyButton, type CopyButtonProps, CueLogotype, type CueLogotypeProps, CueMark, type CueMarkProps, CuePortalFrame, type CuePortalFrameProps, DEFAULT_STORAGE_KEY, DataRow, type DataRowDisclosure, type DataRowRootProps, type DataRowSlotProps, DataTree, type DataTreeItem, type DataTreeProps, type DataTreeRowState, DelegationCard, type DelegationCardProps, type DelegationDirection, type DelegationStatus, Density, type DensityEntry, type DensityLevel, type DensityProps, DescriptionList, type DescriptionListDetailProps, type DescriptionListLayout, type DescriptionListRootProps, type DescriptionListTermProps, Dialog, type DialogCloseProps, type DialogContentProps, type DialogDescriptionProps, type DialogFooterProps, type DialogRootProps, type DialogTitleProps, type DialogTriggerProps, Disclosure, type DisclosureProps, Drawer, type DrawerCloseProps, type DrawerContentProps, type DrawerDescriptionProps, type DrawerFooterProps, type DrawerRootProps, type DrawerSwipeDirection, type DrawerTitleProps, type DrawerTriggerProps, DropdownMenu, type DropdownMenuCheckboxItemProps, type DropdownMenuContentProps, type DropdownMenuGroupProps, type DropdownMenuItemProps, type DropdownMenuLabelProps, type DropdownMenuRootProps, type DropdownMenuSeparatorProps, type DropdownMenuTriggerProps, EmptyState, type EmptyStateProps, EnvVarInput, type EnvVarInputProps, Eyebrow, type EyebrowProps, Field, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, type FieldIssue, FieldLabel, type FieldLabelProps, type FieldProps, type FilePartition, type FilePartitionOptions, type FileRejectReason, type FileRejection, FileUpload, type FileUploadProps, FolderIcon, type FontEntry, type FontFamilies, type FontName, Footer, type FooterProps, type FormControlSize, Grid, type GridColumns, type GridProps, GroupBar, type GroupBarItem, type GroupBarProps, type GroupBarTone, HoverCard, type HoverCardContentProps, type HoverCardRootProps, type HoverCardTriggerProps, IconButton, type IconButtonProps, InfoTip, type InfoTipProps, Input, InputGroup, type InputGroupProps, type InputProps, Item, type ItemProps, Kbd, type KbdProps, Ledger, type LedgerEmptyProps, type LedgerGroupProps, type LedgerRootProps, type LedgerTierProps, Link, type LinkProps, McpServerIcon, Menubar, type MenubarContentProps, type MenubarMenuProps, type MenubarRootProps, type MenubarTriggerProps, Message, MessageList, type MessageListProps, type MessageProps, type MessageRole, Meter, type MeterProps, type MeterProvenance, type MeterTone, type Mode, MultiSelect, type MultiSelectProps, NavigationMenu, type NavigationMenuContentProps, type NavigationMenuItemProps, type NavigationMenuLinkProps, type NavigationMenuListProps, type NavigationMenuRootProps, type NavigationMenuTriggerProps, type NavigationMenuViewportProps, NumberField, type NumberFieldProps, OTPField, type OTPFieldProps, OVERLAY_SIDE_OFFSET, PageShell, type PageShellProps, type PageWidth, Pagination, type PaginationEntry, type PaginationProps, Panel, PanelHeader, type PanelHeaderProps, type PanelProps, PasswordInput, type PasswordInputProps, type PersistedPreferences, Plussie, type PlussieExpression, type PlussieProps, Popover, type PopoverCloseProps, type PopoverContentProps, type PopoverDescriptionProps, type PopoverRootProps, type PopoverTitleProps, type PopoverTriggerProps, type PrepaintDefaults, type PrepaintOptions, Progress, type ProgressProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Rating, type RatingProps, type RatingSize, type ResolvedMode, Row, type RowProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, type ScrollEdges, ScrollableTabsList, type ScrollableTabsListProps, ScrubInput, type ScrubInputProps, SeamCell, type SeamCellProps, SeamGrid, type SeamGridProps, type SeamGround, SeamList, type SeamListProps, SearchInput, type SearchInputProps, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlItem, type SegmentedControlProps, type SegmentedControlSize, Select, type SelectOption, type SelectProps, Separator, type SeparatorProps, Sheet, type SheetCloseProps, type SheetContentProps, type SheetDescriptionProps, type SheetFooterProps, type SheetRootProps, type SheetTitleProps, type SheetTriggerProps, Sidebar, type SidebarItemProps, type SidebarRailProps, type SidebarRootProps, type SidebarSectionProps, Skeleton, type SkeletonProps, SkillIcon, Slider, type SliderProps, type SpaceStep, Sparkline, type SparklineProps, Spinner, type SpinnerProps, Stack, type StackAlign, StackIcon, type StackJustify, type StackProps, StacksMatrixIcon, Stat, type StatProps, type StatTone, StatusBar, type StatusBarGroupProps, type StatusBarItemProps, type StatusBarProminence, type StatusBarProps, type StatusBarTone, StatusDot, type StatusDotProps, type StatusTone, Stepper, type StepperProps, type StepperState, type StepperStep, Switch, type SwitchProps, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Table, type TableCaptionProps, type TableCellProps, type TableGroupRowProps, type TableHeadProps, type TableRootProps, type TableRowProps, TableScrollRegion, type TableScrollRegionProps, type TableSectionProps, Tabs, type TabsListProps, type TabsPanelProps, type TabsRootProps, type TabsTabProps, TagsInput, type TagsInputProps, TerminalFrame, type TerminalFrameLine, type TerminalFrameProps, type TerminalLine, type TerminalLineTone, type TerminalScript, type TerminalStep, Textarea, type TextareaProps, type ThemeContextValue, type ThemeManifest, type ThemeName, ThemeProvider, type ThemeProviderProps, type ThemeRegistry, Timeline, type TimelineContentProps, type TimelineItemProps, type TimelineMarkerProps, type TimelineRootProps, TitleBar, type TitleBarProps, Toast, type ToastManager, type ToastOptions, type ToastProviderProps, type ToastTone, type ToastViewportProps, Toggle, ToggleGroup, type ToggleGroupProps, type ToggleProps, type TokenOverrides, Toolbar, type ToolbarButtonProps, type ToolbarGroupProps, type ToolbarRootProps, type ToolbarSeparatorProps, Tooltip, type TooltipContentProps, type TooltipProviderProps, type TooltipRootProps, type TooltipTriggerProps, Tree, type TreeGuide, type TreeItem, type TreeProps, type TreeRow, type TreeVisibility, TreeVisibilityToggle, type TreeVisibilityToggleProps, TwoStepButton, type TwoStepButtonProps, type TwoStepTone, type UploadFile, type UploadStatus, UsageChart, type UsageChartPoint, type UsageChartProps, type UsageChartTone, activateRowFromClick, activateRowFromKeyDown, agentColor, agentColorStyle, bareControlClasses, buttonVariants, chipVariants, computeScrollEdges, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, edgeFadeMask, envReference, flattenTree, itemVariants, linkVariants, menuItemClasses, menuLabelClasses, menuPopupClasses, menuSeparatorClasses, overlayDescriptionClasses, overlayFooterClasses, overlayModalTransitionClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses, overlayTextClasses, overlayTitleClasses, paginationRange, parseEnvReference, partitionFiles, prepaintScript, rowVariants, scrimClasses, useControlHeight, useCuePortalProps, useDensities, useDensity, useFonts, useSidebar, useTheme, useThemes, useToast };
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ import { AppBar } from "./chrome/app-bar.js";
25
25
  import { Sidebar, useSidebar } from "./layout/sidebar.js";
26
26
  import { Density } from "./system/density.js";
27
27
  import { DEFAULT_STORAGE_KEY, prepaintScript } from "./system/prepaint.js";
28
+ import { useDensities, useFonts, useThemes } from "./system/theme-registry.js";
28
29
  import { ThemeProvider } from "./system/theme-provider.js";
29
30
  import { CuePortalFrame, useCuePortalProps } from "./system/portal.js";
30
31
  import { OVERLAY_SIDE_OFFSET, menuItemClasses, menuLabelClasses, menuPopupClasses, menuSeparatorClasses, overlayDescriptionClasses, overlayFooterClasses, overlayModalTransitionClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses, overlayTextClasses, overlayTitleClasses, scrimClasses } from "./overlays/_surface.js";
@@ -112,4 +113,4 @@ import { Kbd } from "./primitives/kbd.js";
112
113
  import { Skeleton } from "./primitives/skeleton.js";
113
114
  import { useControlHeight, useDensity } from "./system/use-density.js";
114
115
  import { useTheme } from "./system/use-theme.js";
115
- export { AGENT_COLOR_PROPERTY, AGENT_HUES, AGENT_ROOT_COLOR, Accordion, AgentPile, AlertDialog, AppBar, AppShell, AppWindowFrame, AskBox, AudienceIcon, Autocomplete, Avatar, AvatarGroup, Breadcrumb, Button, ButtonGroup, Card, CatalogueIcon, ChannelBetaIcon, ChannelReleasedIcon, Checkbox, CheckboxGroup, Chip, CliToolIcon, Collapsible, Combobox, CommandPalette, Composer, Container, ContextMenu, CopyButton, CueLogotype, CueMark, CuePortalFrame, DEFAULT_STORAGE_KEY, DataRow, DataTree, DelegationCard, Density, DescriptionList, Dialog, Disclosure, Drawer, DropdownMenu, EmptyState, EnvVarInput, Eyebrow, Field, FieldDescription, FieldError, FieldLabel, FileUpload, FolderIcon, Footer, Grid, GroupBar, HoverCard, IconButton, InfoTip, Input, InputGroup, Item, Kbd, Ledger, Link, McpServerIcon, Menubar, Message, MessageList, Meter, MultiSelect, NavigationMenu, NumberField, OTPField, OVERLAY_SIDE_OFFSET, PageShell, Pagination, Panel, PanelHeader, PasswordInput, Plussie, Popover, Progress, Radio, RadioGroup, Rating, Row, ScrollArea, ScrollableTabsList, ScrubInput, SeamCell, SeamGrid, SeamList, SearchInput, SectionHeader, SegmentedControl, Select, Separator, Sheet, Sidebar, Skeleton, SkillIcon, Slider, Sparkline, Spinner, Stack, StackIcon, StacksMatrixIcon, Stat, StatusBar, StatusDot, Stepper, Switch, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Table, TableScrollRegion, Tabs, TagsInput, TerminalFrame, Textarea, ThemeProvider, Timeline, TitleBar, Toast, Toggle, ToggleGroup, Toolbar, Tooltip, Tree, TreeVisibilityToggle, TwoStepButton, UsageChart, activateRowFromClick, activateRowFromKeyDown, agentColor, agentColorStyle, bareControlClasses, buttonVariants, chipVariants, computeScrollEdges, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, edgeFadeMask, envReference, flattenTree, itemVariants, linkVariants, menuItemClasses, menuLabelClasses, menuPopupClasses, menuSeparatorClasses, overlayDescriptionClasses, overlayFooterClasses, overlayModalTransitionClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses, overlayTextClasses, overlayTitleClasses, paginationRange, parseEnvReference, partitionFiles, prepaintScript, rowVariants, scrimClasses, useControlHeight, useCuePortalProps, useDensity, useSidebar, useTheme, useToast };
116
+ export { AGENT_COLOR_PROPERTY, AGENT_HUES, AGENT_ROOT_COLOR, Accordion, AgentPile, AlertDialog, AppBar, AppShell, AppWindowFrame, AskBox, AudienceIcon, Autocomplete, Avatar, AvatarGroup, Breadcrumb, Button, ButtonGroup, Card, CatalogueIcon, ChannelBetaIcon, ChannelReleasedIcon, Checkbox, CheckboxGroup, Chip, CliToolIcon, Collapsible, Combobox, CommandPalette, Composer, Container, ContextMenu, CopyButton, CueLogotype, CueMark, CuePortalFrame, DEFAULT_STORAGE_KEY, DataRow, DataTree, DelegationCard, Density, DescriptionList, Dialog, Disclosure, Drawer, DropdownMenu, EmptyState, EnvVarInput, Eyebrow, Field, FieldDescription, FieldError, FieldLabel, FileUpload, FolderIcon, Footer, Grid, GroupBar, HoverCard, IconButton, InfoTip, Input, InputGroup, Item, Kbd, Ledger, Link, McpServerIcon, Menubar, Message, MessageList, Meter, MultiSelect, NavigationMenu, NumberField, OTPField, OVERLAY_SIDE_OFFSET, PageShell, Pagination, Panel, PanelHeader, PasswordInput, Plussie, Popover, Progress, Radio, RadioGroup, Rating, Row, ScrollArea, ScrollableTabsList, ScrubInput, SeamCell, SeamGrid, SeamList, SearchInput, SectionHeader, SegmentedControl, Select, Separator, Sheet, Sidebar, Skeleton, SkillIcon, Slider, Sparkline, Spinner, Stack, StackIcon, StacksMatrixIcon, Stat, StatusBar, StatusDot, Stepper, Switch, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Table, TableScrollRegion, Tabs, TagsInput, TerminalFrame, Textarea, ThemeProvider, Timeline, TitleBar, Toast, Toggle, ToggleGroup, Toolbar, Tooltip, Tree, TreeVisibilityToggle, TwoStepButton, UsageChart, activateRowFromClick, activateRowFromKeyDown, agentColor, agentColorStyle, bareControlClasses, buttonVariants, chipVariants, computeScrollEdges, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, edgeFadeMask, envReference, flattenTree, itemVariants, linkVariants, menuItemClasses, menuLabelClasses, menuPopupClasses, menuSeparatorClasses, overlayDescriptionClasses, overlayFooterClasses, overlayModalTransitionClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses, overlayTextClasses, overlayTitleClasses, paginationRange, parseEnvReference, partitionFiles, prepaintScript, rowVariants, scrimClasses, useControlHeight, useCuePortalProps, useDensities, useDensity, useFonts, useSidebar, useTheme, useThemes, useToast };
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { ChevronRightGlyph } from "../chrome/_glyphs.js";
4
+ import { headingTag } from "./_ledger.js";
5
+ import * as React from "react";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/instruments/_ledger-disclosure.tsx
8
+ /**
9
+ * A heading that folds the rows beneath it: the accordion pattern, once, for
10
+ * both of the ledger's headings.
11
+ *
12
+ * ## Why the button is inside the heading rather than instead of it
13
+ *
14
+ * This is the disclosure shape the APG calls an accordion, and the one
15
+ * `Table.GroupRow`'s own note already points at — *"a real
16
+ * `<button aria-expanded aria-controls>` inside this cell, never the row
17
+ * itself"*. The heading element survives, so the page's `h2`/`h3` outline is
18
+ * unchanged whether a tier folds or not, and a screen-reader user who navigates
19
+ * a two-hundred-row ledger by heading — which is what the outline is *for* —
20
+ * finds the same places in the same order either way. Making the heading the
21
+ * button, or replacing it with one, would trade that outline for a control, and
22
+ * the outline is the more valuable of the two.
23
+ *
24
+ * The glyph is `aria-hidden`, so the button's accessible name is the heading's
25
+ * own words. A reader hears "Ours, 13, collapsed button", not "button".
26
+ *
27
+ * ## Why the folded rows are hidden rather than unmounted
28
+ *
29
+ * A folded run of rows stays mounted inside a panel that carries `hidden`. The
30
+ * obvious alternative — dropping the children while the run is shut, so that
31
+ * folding something away costs nothing to have folded — is wrong here, and the
32
+ * reason is that **the rows are not always inert**. A `Ledger.Group` inside a
33
+ * tier is itself a disclosure holding its own uncontrolled state: unmount it
34
+ * and that state goes with it, so a reader who folds three groups, folds the
35
+ * tier over them and opens it again finds all three sprung back open. A control
36
+ * that says nothing about touching them had quietly undone their work. React
37
+ * state below a fold is the caller's too, and this component is not entitled to
38
+ * throw it away.
39
+ *
40
+ * Nothing is given up in exchange. A `hidden` subtree is out of the
41
+ * accessibility tree exactly as an absent one is — no heading in it reaches the
42
+ * outline, no row in it answers `getByRole`, and a screen reader walks past all
43
+ * of it — so the two forms are indistinguishable to the reader this component
44
+ * is built for. What differs is only that the caller's state survives.
45
+ *
46
+ * The panel element itself would have to stay in any case: `aria-controls` must
47
+ * name an element that exists, and pointed at a node that leaves with its
48
+ * contents it becomes a dangling reference and an `aria-valid-attr-value`
49
+ * failure — the very trap `DataRowDisclosure.controls` documents.
50
+ *
51
+ * ## Why the folded panel wears no classes at all
52
+ *
53
+ * `hidden` is a UA rule, `[hidden] { display: none }`, and **any author
54
+ * `display` beats it**: a panel that keeps `flex` while it is `hidden` is a
55
+ * panel that is not hidden. Rather than fight that with a `display` utility
56
+ * whose win depends on Tailwind's emission order, the folded panel is given no
57
+ * class list at all, and the layout classes come back when it opens.
58
+ *
59
+ * Keeping the rows mounted is what makes this load-bearing rather than tidy.
60
+ * When the panel was emptied on folding there was nothing inside to leak; now
61
+ * the panel's own `display: none` is the only thing standing between a folded
62
+ * run of rows and a visible one. It is enough — a `display: none` element
63
+ * generates no boxes for any of its descendants, whatever `display` each of
64
+ * them asks for — but it has to actually apply, and jsdom cannot see whether it
65
+ * does, which is why `tests/browser/data-surfaces.spec.ts` reads the computed
66
+ * `display` on both real engines.
67
+ */
68
+ function LedgerDisclosure({ headingLevel, headingSlot, headingClassName, toggleSlot, toggleClassName, panelSlot, panelClassName, label, expanded: expandedProp, defaultExpanded = true, onExpandedChange, children }) {
69
+ const [selfExpanded, setSelfExpanded] = React.useState(defaultExpanded);
70
+ const expanded = expandedProp ?? selfExpanded;
71
+ const panelId = React.useId();
72
+ const Heading = headingTag(headingLevel);
73
+ const toggle = () => {
74
+ const next = !expanded;
75
+ if (expandedProp === void 0) setSelfExpanded(next);
76
+ onExpandedChange?.(next);
77
+ };
78
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Heading, {
79
+ "data-slot": headingSlot,
80
+ className: headingClassName,
81
+ children: /* @__PURE__ */ jsxs("button", {
82
+ type: "button",
83
+ "data-slot": toggleSlot,
84
+ "aria-expanded": expanded,
85
+ "aria-controls": panelId,
86
+ onClick: toggle,
87
+ className: toggleClassName,
88
+ children: [/* @__PURE__ */ jsx(ChevronRightGlyph, {
89
+ "aria-hidden": "true",
90
+ "data-slot": `${toggleSlot}-glyph`,
91
+ className: cn("size-icon-sm shrink-0 self-center transition-transform duration-150 motion-reduce:transition-none", expanded ? "rotate-90" : null)
92
+ }), label]
93
+ })
94
+ }), /* @__PURE__ */ jsx("div", {
95
+ id: panelId,
96
+ "data-slot": panelSlot,
97
+ hidden: !expanded,
98
+ className: expanded ? panelClassName : void 0,
99
+ children
100
+ })] });
101
+ }
102
+ //#endregion
103
+ export { LedgerDisclosure };
@@ -0,0 +1,21 @@
1
+ //#region src/instruments/_ledger.d.ts
2
+ /**
3
+ * The outline half of the ledger, in a module carrying no runtime directive.
4
+ *
5
+ * `ledger.tsx` renders on the server and has to keep doing so — a document of
6
+ * two hundred rows that ships its own JavaScript in order to be *read* is
7
+ * exactly what the static form exists to avoid — while the disclosure in
8
+ * `_ledger-disclosure.tsx` holds React state and is therefore `"use client"`.
9
+ *
10
+ * A server module may **render** a client one, but it may not **call into** it:
11
+ * every value imported from a `"use client"` file is a client reference, and
12
+ * invoking one during a server render throws rather than returning a tag name.
13
+ * So the two symbols both halves need — what a heading level is, and which
14
+ * element it names — live here, in a plain module either graph can compile,
15
+ * instead of being copied into both and drifting the day one of them learns
16
+ * about `h5`.
17
+ */
18
+ /** The heading elements a tier or a group may be given. */
19
+ type LedgerHeadingLevel = 2 | 3 | 4;
20
+ //#endregion
21
+ export { LedgerHeadingLevel };
@@ -0,0 +1,5 @@
1
+ //#region src/instruments/_ledger.ts
2
+ /** `headingLevel` as a tag name, so the outline is real elements, not roles. */
3
+ const headingTag = (level) => level === 2 ? "h2" : level === 3 ? "h3" : "h4";
4
+ //#endregion
5
+ export { headingTag };
@@ -1,7 +1,6 @@
1
+ import { LedgerHeadingLevel } from "./_ledger.js";
1
2
  import * as React from "react";
2
3
  //#region src/instruments/ledger.d.ts
3
- /** The heading elements a tier or a group may be given. */
4
- type LedgerHeadingLevel = 2 | 3 | 4;
5
4
  interface LedgerRootProps extends React.ComponentPropsWithoutRef<"div"> {
6
5
  /**
7
6
  * Make the ledger a size container, so a caller's `@container` rules shed
@@ -40,6 +39,48 @@ interface LedgerTierProps extends React.ComponentPropsWithoutRef<"section"> {
40
39
  headingLevel?: LedgerHeadingLevel;
41
40
  /** A qualifier printed after the name — a date, a source, a state. */
42
41
  note?: React.ReactNode;
42
+ /**
43
+ * Put a disclosure in the tier's heading that folds its rows away. Defaults
44
+ * to `false`, and a tier with no `heading` has nothing to fold from, so it
45
+ * ignores this and renders as it always has.
46
+ *
47
+ * **This is the accordion pattern, not the tree pattern.** What folds is the
48
+ * heading — a *place* — and the `<h2>` stays exactly where it was with a real
49
+ * `<button aria-expanded aria-controls>` inside it. The rows below are hidden
50
+ * while it is shut, which takes them out of the accessibility tree and out of
51
+ * the layout but keeps whatever state they hold. If what you are folding is a
52
+ * *row*, and the thing under it is that row's children rather than that
53
+ * place's contents, you want `DataTree` and its `treeitem` semantics instead.
54
+ */
55
+ collapsible?: boolean;
56
+ /**
57
+ * Whether the tier is open, when the caller owns the state.
58
+ *
59
+ * **Persistence is the caller's.** Which places a reader has folded is a fact
60
+ * about the reader, not about the list, and it belongs wherever that consumer
61
+ * keeps the rest of them — `localStorage`, a URL, a profile. This library
62
+ * stores nothing. Pass this with {@link LedgerTierProps.onExpandedChange};
63
+ * omit both and the tier keeps its own state from
64
+ * {@link LedgerTierProps.defaultExpanded}. Ignored unless `collapsible`.
65
+ */
66
+ expanded?: boolean;
67
+ /**
68
+ * Whether an uncontrolled tier starts open. Defaults to `true`.
69
+ *
70
+ * Open, because a ledger whose content is folded away on first paint has
71
+ * hidden the thing the reader came for; the reader folds what they are done
72
+ * with. Ignored unless `collapsible`, and ignored entirely once
73
+ * {@link LedgerTierProps.expanded} is passed.
74
+ */
75
+ defaultExpanded?: boolean;
76
+ /**
77
+ * Called with the tier's next state each time the reader presses the
78
+ * disclosure — `true` when it is being opened, `false` when it is being shut.
79
+ *
80
+ * Fires in both the controlled and the uncontrolled form, so a consumer can
81
+ * record what was folded without also having to own the state.
82
+ */
83
+ onExpandedChange?: (expanded: boolean) => void;
43
84
  }
44
85
  interface LedgerGroupProps extends React.ComponentPropsWithoutRef<"div"> {
45
86
  /**
@@ -64,24 +105,70 @@ interface LedgerGroupProps extends React.ComponentPropsWithoutRef<"div"> {
64
105
  * rather than measuring at runtime.
65
106
  */
66
107
  sticky?: boolean;
108
+ /**
109
+ * Put a disclosure in the group's slug that folds its rows away. Defaults to
110
+ * `false`, and an unlabelled group has no slug to fold from, so it ignores
111
+ * this. The same accordion pattern the tier takes — see
112
+ * {@link LedgerTierProps.collapsible} for why it is not the tree pattern.
113
+ */
114
+ collapsible?: boolean;
115
+ /**
116
+ * Whether the group is open, when the caller owns the state. Persistence is
117
+ * the caller's; see {@link LedgerTierProps.expanded}.
118
+ */
119
+ expanded?: boolean;
120
+ /** Whether an uncontrolled group starts open. Defaults to `true`. */
121
+ defaultExpanded?: boolean;
122
+ /** Called with the group's next state each time the reader presses the slug. */
123
+ onExpandedChange?: (expanded: boolean) => void;
67
124
  }
68
125
  interface LedgerEmptyProps extends React.ComponentPropsWithoutRef<"p"> {}
69
126
  /**
70
127
  * A grouped run of dense rows under sticky headings: the ledger idiom.
71
128
  *
72
- * The flattest of the three surfaces this package ships over one row model, and
73
- * the one that does the least: headings, slugs, rows. **Nothing here collapses.**
74
- * A ledger with a disclosure on it would be a tree with worse semantics, so the
75
- * component emits no `aria-expanded` anywhere, and a test holds it to that —
76
- * collapse belongs to `DataTree`, and grouping-with-columns belongs to a
77
- * grouped `Table`.
129
+ * The flattest of the three surfaces this package ships over one row model:
130
+ * headings, slugs, rows. What it owns above all is the document outline. Tiers
131
+ * and groups are real `<h2>` / `<h3>` elements at caller-chosen levels, because
132
+ * in a list of two hundred rows the heading list *is* how a screen-reader user
133
+ * navigates.
134
+ *
135
+ * ## Folding: the accordion pattern, opt-in, and why it lives here
78
136
  *
79
- * What it does own is the document outline. Tiers and groups are real `<h2>` /
80
- * `<h3>` elements at caller-chosen levels, because in a list of two hundred
81
- * rows the heading list *is* how a screen-reader user navigates.
137
+ * This component used to refuse disclosure outright, on the grounds that *a
138
+ * ledger which folds is a tree with worse semantics*. That ruling was right
139
+ * about rows and wrong about places, and the distinction is the whole of
140
+ * {@link LedgerTierProps.collapsible}:
82
141
  *
83
- * Static markup — no `"use client"`. The rows inside it may be anything;
84
- * `DataRow` is the intended tenant.
142
+ * - **`DataTree` folds a row.** Its `role="treeitem"` rows carry their own
143
+ * `aria-expanded`, its chevron is `role="presentation"` because in tree
144
+ * semantics the row owns its expansion, and a tier and a subgroup drawn
145
+ * through it stop being places and become rows. A consumer who measured this
146
+ * exact shape through `DataTree` counted **zero** `h2`/`h3` elements and zero
147
+ * `button[aria-expanded]`, which is `DataTree` working correctly and still
148
+ * not being what a grouped document needs.
149
+ * - **`Ledger` folds a place.** A tier is already an `<h2>`, which is already
150
+ * the right element for it, so the disclosure goes *inside* the heading as a
151
+ * real `<button aria-expanded aria-controls>` — the accordion pattern, and
152
+ * the same one `Table.GroupRow`'s note has always pointed at for a table that
153
+ * genuinely needs to fold. The outline is untouched: the heading list of a
154
+ * folding ledger and a plain one are identical, which is what lets a page
155
+ * offer both idioms over one dataset without the outline moving under a
156
+ * reader who switches.
157
+ *
158
+ * So it is one component with two forms rather than a `DisclosureLedger` beside
159
+ * it: everything a folding ledger needs — the gutter track, the sticky offsets,
160
+ * the label recipe, the type contract — is this component, and a sibling would
161
+ * have been a copy of all of it wrapped around one `<button>`.
162
+ *
163
+ * Expansion is controllable and stores nothing. *Which* places a reader has
164
+ * folded is a fact about the reader; consumers keep that set themselves and
165
+ * pass it back in. A folded run of rows is hidden rather than unmounted, so a
166
+ * group that keeps its own fold inside a tier still keeps it after the tier has
167
+ * been shut and opened over it.
168
+ *
169
+ * Static markup — no `"use client"` — **until a heading is asked to fold**, at
170
+ * which point that heading and its rows become a small client island and the
171
+ * rest of the ledger keeps rendering on the server.
85
172
  *
86
173
  * @example
87
174
  * <Ledger.Root className="[--cue-data-row-cols:1fr_8rem_auto]">
@@ -94,6 +181,18 @@ interface LedgerEmptyProps extends React.ComponentPropsWithoutRef<"p"> {}
94
181
  * </Ledger.Group>
95
182
  * </Ledger.Tier>
96
183
  * </Ledger.Root>
184
+ *
185
+ * @example
186
+ * // Folded places are the reader's, so the reader's storage holds them.
187
+ * <Ledger.Tier
188
+ * heading="Ours"
189
+ * count={13}
190
+ * collapsible
191
+ * expanded={!folded.includes("ours")}
192
+ * onExpandedChange={(open) => remember("ours", open)}
193
+ * >
194
+ * <Ledger.Group label="released">…</Ledger.Group>
195
+ * </Ledger.Tier>
97
196
  */
98
197
  declare const Ledger: {
99
198
  Root: React.ForwardRefExoticComponent<LedgerRootProps & React.RefAttributes<HTMLDivElement>>;