@cueplusplus/ui 0.1.0 → 0.3.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 (246) hide show
  1. package/CHANGELOG.md +705 -0
  2. package/dist/brand/_chassis.d.ts +54 -0
  3. package/dist/brand/_chassis.js +81 -0
  4. package/dist/brand/_geometry.js +41 -0
  5. package/dist/brand/cue-logotype.d.ts +29 -0
  6. package/dist/brand/cue-logotype.js +60 -0
  7. package/dist/brand/cue-mark.d.ts +30 -0
  8. package/dist/brand/cue-mark.js +61 -0
  9. package/dist/brand/index.d.ts +5 -0
  10. package/dist/brand/plussie.d.ts +67 -0
  11. package/dist/brand/plussie.js +125 -0
  12. package/dist/chat/agent-pile.js +1 -1
  13. package/dist/chat/ask-box.js +2 -2
  14. package/dist/chat/delegation-card.js +1 -1
  15. package/dist/chat/message.js +2 -2
  16. package/dist/chrome/_edge-scroller.d.ts +45 -0
  17. package/dist/chrome/_edge-scroller.js +149 -0
  18. package/dist/chrome/_glyphs.js +19 -1
  19. package/dist/chrome/_tabs-scroll.d.ts +13 -8
  20. package/dist/chrome/_tabs-scroll.js +13 -8
  21. package/dist/chrome/app-bar.d.ts +103 -0
  22. package/dist/chrome/app-bar.js +175 -0
  23. package/dist/chrome/app-shell.d.ts +125 -0
  24. package/dist/chrome/app-shell.js +167 -0
  25. package/dist/chrome/footer.d.ts +75 -0
  26. package/dist/chrome/footer.js +68 -0
  27. package/dist/chrome/index.d.ts +5 -1
  28. package/dist/chrome/index.js +4 -1
  29. package/dist/chrome/navigation-menu.js +1 -1
  30. package/dist/chrome/page-shell.d.ts +1 -1
  31. package/dist/chrome/page-shell.js +15 -5
  32. package/dist/chrome/segmented-control.d.ts +19 -0
  33. package/dist/chrome/segmented-control.js +40 -21
  34. package/dist/chrome/tabs.js +21 -65
  35. package/dist/chrome/toolbar.d.ts +22 -0
  36. package/dist/chrome/toolbar.js +26 -5
  37. package/dist/configurator/_overrides.js +22 -8
  38. package/dist/configurator/configurator.js +1 -1
  39. package/dist/configurator/panel-sections.js +10 -4
  40. package/dist/dmx/channel-matrix.js +1 -1
  41. package/dist/forms/otp-field.js +1 -1
  42. package/dist/index.d.ts +18 -9
  43. package/dist/index.js +16 -10
  44. package/dist/instruments/data-table.js +1 -1
  45. package/dist/instruments/index.d.ts +2 -2
  46. package/dist/instruments/index.js +2 -2
  47. package/dist/instruments/table.d.ts +14 -1
  48. package/dist/instruments/table.js +20 -1
  49. package/dist/layout/carousel.js +1 -1
  50. package/dist/layout/container.d.ts +1 -1
  51. package/dist/layout/container.js +6 -3
  52. package/dist/layout/index.d.ts +3 -3
  53. package/dist/layout/index.js +3 -3
  54. package/dist/layout/pagination.js +1 -1
  55. package/dist/layout/sidebar.d.ts +23 -3
  56. package/dist/layout/sidebar.js +18 -7
  57. package/dist/midi/spectrum-visualizer.js +1 -1
  58. package/dist/midi/timeline-ruler.js +1 -1
  59. package/dist/overlays/command-palette.js +1 -1
  60. package/dist/overlays/dialog.js +1 -1
  61. package/dist/overlays/dropdown-menu.js +2 -2
  62. package/dist/overlays/hover-card.js +1 -1
  63. package/dist/overlays/index.js +1 -1
  64. package/dist/overlays/popover.js +1 -1
  65. package/dist/overlays/sheet.js +1 -1
  66. package/dist/overlays/toast.js +1 -1
  67. package/dist/primitives/chip.d.ts +1 -1
  68. package/dist/primitives/index.d.ts +1 -1
  69. package/dist/primitives/index.js +1 -1
  70. package/dist/primitives/status-dot.d.ts +7 -0
  71. package/dist/primitives/status-dot.js +8 -1
  72. package/dist/styles.css +58 -2
  73. package/dist/system/density.d.ts +4 -1
  74. package/dist/system/density.js +12 -4
  75. package/dist/system/index.d.ts +4 -4
  76. package/dist/system/portal.d.ts +5 -5
  77. package/dist/system/portal.js +30 -11
  78. package/dist/system/prepaint.d.ts +34 -9
  79. package/dist/system/prepaint.js +48 -25
  80. package/dist/system/theme-provider.d.ts +48 -11
  81. package/dist/system/theme-provider.js +109 -35
  82. package/dist/system/use-density.d.ts +3 -3
  83. package/dist/system/use-density.js +16 -6
  84. package/dist/system/use-theme.d.ts +4 -2
  85. package/dist/system/use-theme.js +4 -2
  86. package/dist/theming/_presets.js +133 -5
  87. package/dist/theming/create-theme.d.ts +2 -2
  88. package/dist/theming/create-theme.js +37 -19
  89. package/dist/theming/serialize.d.ts +1 -1
  90. package/dist/theming/serialize.js +25 -1
  91. package/manifest/components/accordion.json +154 -0
  92. package/manifest/components/agent-pile.json +116 -0
  93. package/manifest/components/alert-dialog.json +190 -0
  94. package/manifest/components/app-bar.json +244 -0
  95. package/manifest/components/app-shell.json +291 -0
  96. package/manifest/components/app-window-frame.json +102 -0
  97. package/manifest/components/ask-box.json +209 -0
  98. package/manifest/components/autocomplete.json +197 -0
  99. package/manifest/components/avatar-group.json +72 -0
  100. package/manifest/components/avatar.json +95 -0
  101. package/manifest/components/breadcrumb.json +74 -0
  102. package/manifest/components/button-group.json +74 -0
  103. package/manifest/components/button.json +125 -0
  104. package/manifest/components/calendar.json +65 -0
  105. package/manifest/components/card.json +140 -0
  106. package/manifest/components/carousel.json +200 -0
  107. package/manifest/components/channel-matrix.json +173 -0
  108. package/manifest/components/chart-container.json +111 -0
  109. package/manifest/components/chart-ramp.json +72 -0
  110. package/manifest/components/chart-swatch.json +65 -0
  111. package/manifest/components/chart-tooltip-content.json +114 -0
  112. package/manifest/components/checkbox-group.json +68 -0
  113. package/manifest/components/checkbox.json +93 -0
  114. package/manifest/components/chip.json +132 -0
  115. package/manifest/components/collapsible.json +120 -0
  116. package/manifest/components/color-area.json +59 -0
  117. package/manifest/components/color-field.json +79 -0
  118. package/manifest/components/color-picker.json +175 -0
  119. package/manifest/components/color-slider.json +75 -0
  120. package/manifest/components/color-swatch.json +68 -0
  121. package/manifest/components/colors-section.json +66 -0
  122. package/manifest/components/combobox.json +198 -0
  123. package/manifest/components/command-palette.json +177 -0
  124. package/manifest/components/composer.json +176 -0
  125. package/manifest/components/container.json +60 -0
  126. package/manifest/components/context-menu.json +121 -0
  127. package/manifest/components/copy-button.json +93 -0
  128. package/manifest/components/cue-logotype.json +96 -0
  129. package/manifest/components/cue-mark.json +97 -0
  130. package/manifest/components/cue-portal-frame.json +55 -0
  131. package/manifest/components/data-table-pagination.json +83 -0
  132. package/manifest/components/data-table-toolbar.json +104 -0
  133. package/manifest/components/date-field.json +80 -0
  134. package/manifest/components/date-picker.json +191 -0
  135. package/manifest/components/date-range-picker.json +191 -0
  136. package/manifest/components/delegation-card.json +144 -0
  137. package/manifest/components/density.json +58 -0
  138. package/manifest/components/description-list.json +84 -0
  139. package/manifest/components/dialog.json +198 -0
  140. package/manifest/components/disclosure.json +109 -0
  141. package/manifest/components/dmx-bar.json +94 -0
  142. package/manifest/components/dmx-strip.json +101 -0
  143. package/manifest/components/drawer.json +179 -0
  144. package/manifest/components/dropdown-menu.json +229 -0
  145. package/manifest/components/empty-state.json +90 -0
  146. package/manifest/components/env-var-input.json +150 -0
  147. package/manifest/components/export-dialog.json +84 -0
  148. package/manifest/components/eyebrow.json +56 -0
  149. package/manifest/components/field-description.json +63 -0
  150. package/manifest/components/field-error.json +77 -0
  151. package/manifest/components/field-label.json +63 -0
  152. package/manifest/components/field.json +79 -0
  153. package/manifest/components/file-upload.json +159 -0
  154. package/manifest/components/flow-background.json +50 -0
  155. package/manifest/components/flow-controls.json +50 -0
  156. package/manifest/components/footer.json +112 -0
  157. package/manifest/components/grid.json +81 -0
  158. package/manifest/components/group-bar.json +102 -0
  159. package/manifest/components/hover-card.json +151 -0
  160. package/manifest/components/icon-button.json +88 -0
  161. package/manifest/components/info-tip.json +98 -0
  162. package/manifest/components/input-group.json +91 -0
  163. package/manifest/components/input.json +89 -0
  164. package/manifest/components/item.json +129 -0
  165. package/manifest/components/kbd.json +52 -0
  166. package/manifest/components/link.json +81 -0
  167. package/manifest/components/log-viewer.json +139 -0
  168. package/manifest/components/menubar.json +157 -0
  169. package/manifest/components/message-list.json +100 -0
  170. package/manifest/components/message.json +116 -0
  171. package/manifest/components/meter.json +114 -0
  172. package/manifest/components/multi-select.json +190 -0
  173. package/manifest/components/musical-time-input.json +113 -0
  174. package/manifest/components/navigation-menu.json +226 -0
  175. package/manifest/components/node-card.json +109 -0
  176. package/manifest/components/node-handle.json +69 -0
  177. package/manifest/components/number-field.json +107 -0
  178. package/manifest/components/otp-field.json +128 -0
  179. package/manifest/components/page-shell.json +96 -0
  180. package/manifest/components/pagination.json +92 -0
  181. package/manifest/components/panel-header.json +77 -0
  182. package/manifest/components/panel.json +71 -0
  183. package/manifest/components/password-input.json +119 -0
  184. package/manifest/components/piano-keyboard.json +120 -0
  185. package/manifest/components/plussie.json +111 -0
  186. package/manifest/components/popover.json +193 -0
  187. package/manifest/components/preset-section.json +73 -0
  188. package/manifest/components/progress.json +95 -0
  189. package/manifest/components/radio-group.json +73 -0
  190. package/manifest/components/radio.json +80 -0
  191. package/manifest/components/rating.json +141 -0
  192. package/manifest/components/resizable.json +88 -0
  193. package/manifest/components/row.json +109 -0
  194. package/manifest/components/scroll-area.json +91 -0
  195. package/manifest/components/scrollable-tabs-list.json +83 -0
  196. package/manifest/components/scrub-input.json +200 -0
  197. package/manifest/components/seam-cell.json +75 -0
  198. package/manifest/components/seam-grid.json +75 -0
  199. package/manifest/components/seam-list.json +56 -0
  200. package/manifest/components/search-input.json +134 -0
  201. package/manifest/components/section-header.json +112 -0
  202. package/manifest/components/segmented-control.json +138 -0
  203. package/manifest/components/select.json +194 -0
  204. package/manifest/components/separator.json +53 -0
  205. package/manifest/components/shape-section.json +66 -0
  206. package/manifest/components/sheet.json +186 -0
  207. package/manifest/components/sidebar.json +198 -0
  208. package/manifest/components/signal-edge.json +56 -0
  209. package/manifest/components/skeleton.json +46 -0
  210. package/manifest/components/slider.json +89 -0
  211. package/manifest/components/sparkline.json +76 -0
  212. package/manifest/components/spectrum-visualizer.json +115 -0
  213. package/manifest/components/spinner.json +61 -0
  214. package/manifest/components/stack.json +96 -0
  215. package/manifest/components/stat.json +87 -0
  216. package/manifest/components/status-bar.json +58 -0
  217. package/manifest/components/status-dot.json +78 -0
  218. package/manifest/components/stepper.json +89 -0
  219. package/manifest/components/switch.json +87 -0
  220. package/manifest/components/table-scroll-region.json +69 -0
  221. package/manifest/components/table.json +155 -0
  222. package/manifest/components/tabs.json +145 -0
  223. package/manifest/components/tags-input.json +190 -0
  224. package/manifest/components/terminal-frame.json +119 -0
  225. package/manifest/components/textarea.json +76 -0
  226. package/manifest/components/theme-configurator.json +124 -0
  227. package/manifest/components/theme-provider.json +134 -0
  228. package/manifest/components/threshold-rail.json +160 -0
  229. package/manifest/components/time-field.json +80 -0
  230. package/manifest/components/timeline-ruler.json +139 -0
  231. package/manifest/components/timeline.json +115 -0
  232. package/manifest/components/title-bar.json +82 -0
  233. package/manifest/components/toast.json +130 -0
  234. package/manifest/components/toggle-group.json +106 -0
  235. package/manifest/components/toggle.json +109 -0
  236. package/manifest/components/token-editor.json +90 -0
  237. package/manifest/components/toolbar.json +163 -0
  238. package/manifest/components/tooltip.json +164 -0
  239. package/manifest/components/tree-visibility-toggle.json +84 -0
  240. package/manifest/components/tree.json +140 -0
  241. package/manifest/components/two-step-button.json +113 -0
  242. package/manifest/components/universe-grid.json +127 -0
  243. package/manifest/components/usage-chart.json +124 -0
  244. package/manifest/manifest.json +2142 -0
  245. package/manifest/tokens.json +138 -0
  246. package/package.json +13 -5
@@ -7,7 +7,27 @@ interface SidebarContextValue {
7
7
  }
8
8
  /** Read the collapse state of the nearest {@link SidebarRoot}. */
9
9
  declare function useSidebar(): SidebarContextValue;
10
+ /**
11
+ * Which landmark a navigation column announces as.
12
+ *
13
+ * `"navigation"` renders `<nav>`, `"complementary"` renders `<aside>`. Two
14
+ * values rather than a free `role`, because those are the only two a column of
15
+ * destinations can honestly be — and naming the landmark keeps the element and
16
+ * the role from ever disagreeing.
17
+ */
18
+ type SidebarLandmark = "navigation" | "complementary";
10
19
  interface SidebarRootProps extends React.ComponentPropsWithoutRef<"aside"> {
20
+ /**
21
+ * Which landmark the column is. Defaults to `"navigation"`, rendering
22
+ * `<nav>`; `"complementary"` renders `<aside>` instead.
23
+ *
24
+ * A column of `Sidebar.Item`s is a list of destinations, one of which carries
25
+ * `aria-current="page"` — that is primary navigation, and announcing it as
26
+ * complementary tells a screen-reader user the site's main map is an aside.
27
+ * `"complementary"` is there for the column that genuinely is one: a filter
28
+ * rail, an inspector, a related-links strip.
29
+ */
30
+ landmark?: SidebarLandmark;
11
31
  /** Collapsed state when controlled. Pass with `onCollapsedChange`. */
12
32
  collapsed?: boolean;
13
33
  /** Initial collapsed state when uncontrolled. Defaults to `false`. */
@@ -46,8 +66,8 @@ interface SidebarRailProps extends Omit<React.ComponentPropsWithoutRef<"button">
46
66
  expandLabel?: string;
47
67
  }
48
68
  /**
49
- * The console's navigation column: sections of items, and a rail that collapses
50
- * the whole thing to icons.
69
+ * The console's navigation column: sections of items, a scroller of its own,
70
+ * and a rail that collapses the whole thing to icons.
51
71
  *
52
72
  * @example
53
73
  * <Sidebar.Root defaultCollapsed aria-label="Main">
@@ -64,4 +84,4 @@ declare const Sidebar: {
64
84
  Rail: React.ForwardRefExoticComponent<SidebarRailProps & React.RefAttributes<HTMLButtonElement>>;
65
85
  };
66
86
  //#endregion
67
- export { Sidebar, SidebarItemProps, SidebarRailProps, SidebarRootProps, SidebarSectionProps, useSidebar };
87
+ export { Sidebar, SidebarItemProps, SidebarLandmark, SidebarRailProps, SidebarRootProps, SidebarSectionProps, useSidebar };
@@ -19,9 +19,14 @@ const SidebarContext = React.createContext({
19
19
  function useSidebar() {
20
20
  return React.useContext(SidebarContext);
21
21
  }
22
+ /** The element each landmark is spelled with. */
23
+ const LANDMARK_ELEMENTS = {
24
+ navigation: "nav",
25
+ complementary: "aside"
26
+ };
22
27
  /**
23
- * The console's navigation column: sections of items, and a rail that collapses
24
- * the whole thing to icons.
28
+ * The console's navigation column: sections of items, a scroller of its own,
29
+ * and a rail that collapses the whole thing to icons.
25
30
  *
26
31
  * @example
27
32
  * <Sidebar.Root defaultCollapsed aria-label="Main">
@@ -32,7 +37,8 @@ function useSidebar() {
32
37
  * </Sidebar.Root>
33
38
  */
34
39
  const Sidebar = {
35
- Root: React.forwardRef(function SidebarRoot({ className, collapsed: collapsedProp, defaultCollapsed = false, onCollapsedChange, width = "14rem", collapsedWidth = "3rem", style, ...elementProps }, ref) {
40
+ Root: React.forwardRef(function SidebarRoot({ className, landmark = "navigation", collapsed: collapsedProp, defaultCollapsed = false, onCollapsedChange, width = "14rem", collapsedWidth = "3rem", style, children, ...elementProps }, ref) {
41
+ const Element = LANDMARK_ELEMENTS[landmark];
36
42
  const [uncontrolled, setUncontrolled] = React.useState(defaultCollapsed);
37
43
  const collapsed = collapsedProp ?? uncontrolled;
38
44
  const toggle = React.useCallback(() => {
@@ -50,16 +56,21 @@ const Sidebar = {
50
56
  }), [collapsed, toggle]);
51
57
  return /* @__PURE__ */ jsx(SidebarContext.Provider, {
52
58
  value: context,
53
- children: /* @__PURE__ */ jsx("aside", {
59
+ children: /* @__PURE__ */ jsx(Element, {
54
60
  ref,
55
61
  "data-slot": "sidebar",
56
62
  "data-collapsed": collapsed ? "" : void 0,
57
- className: cn("group/sidebar relative flex h-full shrink-0 flex-col gap-(--cue-space-4) border-r border-border bg-surface-1 py-(--cue-space-4) transition-[width] duration-150 ease-out motion-reduce:transition-none", className),
63
+ className: cn("group/sidebar relative flex h-full min-h-0 shrink-0 flex-col border-r border-border bg-surface-1 transition-[width] duration-150 ease-out motion-reduce:transition-none", className),
58
64
  style: {
59
65
  width: collapsed ? collapsedWidth : width,
60
66
  ...style
61
67
  },
62
- ...elementProps
68
+ ...elementProps,
69
+ children: /* @__PURE__ */ jsx("div", {
70
+ "data-slot": "sidebar-scroller",
71
+ className: "flex min-h-0 flex-1 flex-col gap-(--cue-space-4) overflow-y-auto py-(--cue-space-4)",
72
+ children
73
+ })
63
74
  })
64
75
  });
65
76
  }),
@@ -88,7 +99,7 @@ const Sidebar = {
88
99
  "data-slot": "sidebar-item",
89
100
  "data-active": active ? "" : void 0,
90
101
  "aria-current": active ? "page" : void 0,
91
- className: cn("flex h-control-md w-full cursor-pointer items-center gap-(--cue-space-3) rounded-(--radius-control) border-0 bg-transparent px-(--cue-space-3) text-left font-mono text-(length:--cue-text-ui) text-fg-muted no-underline transition-colors duration-150 outline-none select-none hover:bg-surface-2 hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-accent data-[active]:bg-accent-soft data-[active]:text-accent disabled:pointer-events-none disabled:opacity-40", className),
102
+ className: cn("relative flex h-control-md w-full cursor-pointer items-center gap-(--cue-space-3) rounded-(--radius-control) border-0 bg-transparent px-(--cue-space-3) text-left font-mono text-(length:--cue-text-ui) text-fg-muted no-underline transition-colors duration-150 outline-none select-none hover:bg-surface-2 hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-accent data-[active]:bg-accent-soft data-[active]:text-accent disabled:pointer-events-none disabled:opacity-40", className),
92
103
  children: /* @__PURE__ */ jsxs(Fragment, { children: [
93
104
  Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
94
105
  "aria-hidden": "true",
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { useIsomorphicLayoutEffect } from "../system/use-isomorphic-layout-effect.js";
4
- import { toRem } from "../instruments/_rem.js";
5
4
  import { useComposedRefs } from "../lib/compose.js";
5
+ import { toRem } from "../instruments/_rem.js";
6
6
  import { resolveToken } from "../charts/_token.js";
7
7
  import { RAMPS } from "../charts/ramps.js";
8
8
  import * as React from "react";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { toRem } from "../instruments/_rem.js";
4
3
  import { useComposedRefs } from "../lib/compose.js";
4
+ import { toRem } from "../instruments/_rem.js";
5
5
  import { DEFAULT_TIME_SIGNATURE, barBeats, beatsToMusical, formatMusicalTime } from "./_time.js";
6
6
  import { rulerTicks } from "./_ruler.js";
7
7
  import * as React from "react";
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { SearchGlyph } from "./_glyphs.js";
3
4
  import { useCuePortalProps } from "../system/portal.js";
4
5
  import { overlayModalTransitionClasses, overlaySurfaceClasses, scrimClasses } from "./_surface.js";
5
6
  import { useDebouncedValue } from "./_debounce.js";
6
- import { SearchGlyph } from "./_glyphs.js";
7
7
  import * as React from "react";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Combobox } from "@base-ui/react/combobox";
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { cva } from "../lib/cva.js";
4
+ import { CrossGlyph } from "./_glyphs.js";
4
5
  import { useCuePortalProps } from "../system/portal.js";
5
6
  import { overlayDescriptionClasses, overlayFooterClasses, overlayModalTransitionClasses, overlaySurfaceClasses, overlayTitleClasses, scrimClasses } from "./_surface.js";
6
7
  import { IconButton } from "../primitives/icon-button.js";
7
- import { CrossGlyph } from "./_glyphs.js";
8
8
  import * as React from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import { Dialog } from "@base-ui/react/dialog";
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { useComposedRefs } from "../lib/compose.js";
4
+ import { TickGlyph } from "./_glyphs.js";
3
5
  import { useCuePortalProps } from "../system/portal.js";
4
6
  import { menuItemClasses, menuLabelClasses, menuPopupClasses, menuSeparatorClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses } from "./_surface.js";
5
- import { TickGlyph } from "./_glyphs.js";
6
- import { useComposedRefs } from "../lib/compose.js";
7
7
  import { useCloseOnWheel } from "./_wheel.js";
8
8
  import * as React from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { useComposedRefs } from "../lib/compose.js";
3
4
  import { useCuePortalProps } from "../system/portal.js";
4
5
  import { overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses } from "./_surface.js";
5
- import { useComposedRefs } from "../lib/compose.js";
6
6
  import { useCloseOnWheel } from "./_wheel.js";
7
7
  import * as React from "react";
8
8
  import { jsx } from "react/jsx-runtime";
@@ -1,10 +1,10 @@
1
1
  import { OVERLAY_SIDE_OFFSET, menuItemClasses, menuLabelClasses, menuPopupClasses, menuSeparatorClasses, overlayDescriptionClasses, overlayFooterClasses, overlayModalTransitionClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses, overlayTextClasses, overlayTitleClasses, scrimClasses } from "./_surface.js";
2
+ import { Drawer } from "./drawer.js";
2
3
  import { AlertDialog } from "./alert-dialog.js";
3
4
  import { CommandPalette } from "./command-palette.js";
4
5
  import { DropdownMenu } from "./dropdown-menu.js";
5
6
  import { ContextMenu } from "./context-menu.js";
6
7
  import { Dialog } from "./dialog.js";
7
- import { Drawer } from "./drawer.js";
8
8
  import { HoverCard } from "./hover-card.js";
9
9
  import { Tooltip } from "./tooltip.js";
10
10
  import { InfoTip } from "./info-tip.js";
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { useComposedRefs } from "../lib/compose.js";
3
4
  import { useCuePortalProps } from "../system/portal.js";
4
5
  import { overlayDescriptionClasses, overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses, overlayTitleClasses } from "./_surface.js";
5
- import { useComposedRefs } from "../lib/compose.js";
6
6
  import { useCloseOnWheel } from "./_wheel.js";
7
7
  import * as React from "react";
8
8
  import { jsx } from "react/jsx-runtime";
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { cva } from "../lib/cva.js";
4
+ import { CrossGlyph } from "./_glyphs.js";
4
5
  import { useCuePortalProps } from "../system/portal.js";
5
6
  import { overlayDescriptionClasses, overlayFooterClasses, overlaySurfaceClasses, overlayTitleClasses, scrimClasses } from "./_surface.js";
6
7
  import { IconButton } from "../primitives/icon-button.js";
7
- import { CrossGlyph } from "./_glyphs.js";
8
8
  import * as React from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import { Dialog } from "@base-ui/react/dialog";
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { CrossGlyph } from "./_glyphs.js";
3
4
  import { useCuePortalProps } from "../system/portal.js";
4
5
  import { overlaySurfaceClasses } from "./_surface.js";
5
- import { CrossGlyph } from "./_glyphs.js";
6
6
  import * as React from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Toast } from "@base-ui/react/toast";
@@ -15,7 +15,7 @@ import * as React from "react";
15
15
  * <span className={chipVariants({ tone: "danger", variant: "outline" })}>fault</span>
16
16
  */
17
17
  declare const chipVariants: (props?: ({
18
- tone?: "danger" | "info" | "warn" | "accent" | "ok" | "busy" | "neutral" | null | undefined;
18
+ tone?: "info" | "warn" | "danger" | "accent" | "ok" | "busy" | "neutral" | null | undefined;
19
19
  variant?: "outline" | "tinted" | null | undefined;
20
20
  interactive?: boolean | null | undefined;
21
21
  } & ClassProp) | undefined) => string;
@@ -1,10 +1,10 @@
1
+ import { Separator, SeparatorProps } from "./separator.js";
1
2
  import { Button, ButtonProps, buttonVariants } from "./button.js";
2
3
  import { StatusDot, StatusDotProps, StatusTone } from "./status-dot.js";
3
4
  import { Avatar, AvatarGroup, AvatarGroupProps, AvatarProps, AvatarSize } from "./avatar.js";
4
5
  import { Chip, ChipProps, chipVariants } from "./chip.js";
5
6
  import { IconButton, IconButtonProps } from "./icon-button.js";
6
7
  import { Kbd, KbdProps } from "./kbd.js";
7
- import { Separator, SeparatorProps } from "./separator.js";
8
8
  import { Skeleton, SkeletonProps } from "./skeleton.js";
9
9
  import { Spinner, SpinnerProps } from "./spinner.js";
10
10
  export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize, Button, type ButtonProps, Chip, type ChipProps, IconButton, type IconButtonProps, Kbd, type KbdProps, Separator, type SeparatorProps, Skeleton, type SkeletonProps, Spinner, type SpinnerProps, StatusDot, type StatusDotProps, type StatusTone, buttonVariants, chipVariants };
@@ -1,10 +1,10 @@
1
1
  import { Button, buttonVariants } from "./button.js";
2
2
  import { Chip, chipVariants } from "./chip.js";
3
3
  import { Spinner } from "./spinner.js";
4
+ import { Separator } from "./separator.js";
4
5
  import { IconButton } from "./icon-button.js";
5
6
  import { StatusDot } from "./status-dot.js";
6
7
  import { Avatar, AvatarGroup } from "./avatar.js";
7
8
  import { Kbd } from "./kbd.js";
8
- import { Separator } from "./separator.js";
9
9
  import { Skeleton } from "./skeleton.js";
10
10
  export { Avatar, AvatarGroup, Button, Chip, IconButton, Kbd, Separator, Skeleton, Spinner, StatusDot, buttonVariants, chipVariants };
@@ -32,6 +32,13 @@ interface StatusDotProps extends Omit<React.ComponentPropsWithoutRef<"span">, "c
32
32
  * component always emits an `sr-only` label inside a `role="status"` wrapper,
33
33
  * so the state is announced as well as shown (WCAG 1.4.1).
34
34
  *
35
+ * The wrapper is `relative` for that label's sake and no other reason.
36
+ * `.sr-only` is `position: absolute`; without a positioned ancestor its
37
+ * containing block is the initial one, so its scrollable overflow lands on
38
+ * `<html>` rather than on whatever scroller it is nested in. One dot is
39
+ * harmless and a table of two thousand rows is a document several thousand
40
+ * pixels taller than anything visible on it.
41
+ *
35
42
  * Static markup — no `"use client"`.
36
43
  *
37
44
  * @example
@@ -20,6 +20,13 @@ const toRem = (px) => `${px / 16}rem`;
20
20
  * component always emits an `sr-only` label inside a `role="status"` wrapper,
21
21
  * so the state is announced as well as shown (WCAG 1.4.1).
22
22
  *
23
+ * The wrapper is `relative` for that label's sake and no other reason.
24
+ * `.sr-only` is `position: absolute`; without a positioned ancestor its
25
+ * containing block is the initial one, so its scrollable overflow lands on
26
+ * `<html>` rather than on whatever scroller it is nested in. One dot is
27
+ * harmless and a table of two thousand rows is a document several thousand
28
+ * pixels taller than anything visible on it.
29
+ *
23
30
  * Static markup — no `"use client"`.
24
31
  *
25
32
  * @example
@@ -31,7 +38,7 @@ const StatusDot = React.forwardRef(function StatusDot({ className, tone, pulse =
31
38
  return /* @__PURE__ */ jsxs("span", {
32
39
  ref,
33
40
  role: "status",
34
- className: cn("inline-flex shrink-0 items-center justify-center", className),
41
+ className: cn("relative inline-flex shrink-0 items-center justify-center", className),
35
42
  ...elementProps,
36
43
  children: [/* @__PURE__ */ jsx("span", {
37
44
  "aria-hidden": "true",
package/dist/styles.css CHANGED
@@ -14,6 +14,62 @@
14
14
 
15
15
  @source "./";
16
16
 
17
- @custom-variant density-ultra (&:where([data-density="ultra-compact"], [data-density="ultra-compact"] *));
17
+ /* One variant per rung of the density ladder, each named after the rung it
18
+ * matches — so `density-large:` means the level a consumer writes as
19
+ * `density="large"`, and cannot drift from it.
20
+ *
21
+ * `density-ultra:` is gone with the five-rung rename of 2026-08-19: with an
22
+ * `ultra-large` rung in the ladder, "ultra" no longer names one level. Its
23
+ * replacement is `density-ultra-compact:`. `density-large:` survives the rename
24
+ * as a name and changes meaning with it — it matched the ladder's top rung
25
+ * before, and the ladder now has two rungs above that one. */
26
+ @custom-variant density-ultra-compact (&:where([data-density="ultra-compact"], [data-density="ultra-compact"] *));
27
+ @custom-variant density-compact (&:where([data-density="compact"], [data-density="compact"] *));
28
+ @custom-variant density-normal (&:where([data-density="normal"], [data-density="normal"] *));
18
29
  @custom-variant density-large (&:where([data-density="large"], [data-density="large"] *));
19
- @custom-variant mode-light (&:where([data-mode="light"], [data-mode="light"] *));
30
+ @custom-variant density-ultra-large (&:where([data-density="ultra-large"], [data-density="ultra-large"] *));
31
+ @custom-variant mode-light {
32
+ &:where([data-mode="light"], [data-mode="light"] *) {
33
+ @slot;
34
+ }
35
+
36
+ @media (prefers-color-scheme: light) {
37
+ &:where([data-mode="system"], [data-mode="system"] *) {
38
+ @slot;
39
+ }
40
+ }
41
+ }
42
+
43
+ /* The one keyframe this library's core needs, and the reason it cannot be a
44
+ * utility: `<Plussie idle />` blinks, and Tailwind has no `animate-*` for a
45
+ * two-frame squash about an SVG group's own centre.
46
+ *
47
+ * Same shape as the pulse in `flow.css`: a bespoke class, the keyframes beside
48
+ * it, and a `prefers-reduced-motion` block that switches it off. `fill-box`
49
+ * puts the transform origin at the eye's own centre rather than the SVG's
50
+ * corner, which is what makes the eye shut across its middle instead of sliding
51
+ * up. The class does nothing unless the prop asks for it — every other Plussie
52
+ * on the page is still. */
53
+ @keyframes cue-plussie-blink {
54
+ 0%,
55
+ 93%,
56
+ 100% {
57
+ transform: scaleY(1);
58
+ }
59
+ 95.5%,
60
+ 96.5% {
61
+ transform: scaleY(0.05);
62
+ }
63
+ }
64
+
65
+ .cue-plussie-idle {
66
+ transform-box: fill-box;
67
+ transform-origin: center;
68
+ animation: cue-plussie-blink 5.2s ease-in-out infinite;
69
+ }
70
+
71
+ @media (prefers-reduced-motion: reduce) {
72
+ .cue-plussie-idle {
73
+ animation: none;
74
+ }
75
+ }
@@ -2,7 +2,10 @@ import * as React from "react";
2
2
  import { Density } from "@cueplusplus/tokens";
3
3
  //#region src/system/density.d.ts
4
4
  interface DensityProps {
5
- /** Level to apply to this subtree: `ultra-compact`, `normal` or `large`. */
5
+ /**
6
+ * Level to apply to this subtree: `ultra-compact`, `compact`, `normal`,
7
+ * `large` or `ultra-large`.
8
+ */
6
9
  density: Density;
7
10
  /** Subtree that should render at `density`. */
8
11
  children: React.ReactNode;
@@ -2,13 +2,21 @@
2
2
  import * as React from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/system/density.tsx
5
- /** Density level every unstamped subtree falls back to. */
6
- const DEFAULT_DENSITY = "normal";
7
- /** The three levels, as a runtime array for validating persisted input. */
5
+ /**
6
+ * Density level every unstamped subtree falls back to.
7
+ *
8
+ * `compact`, which is the second rung and not the middle one. This is console
9
+ * software: the ladder is symmetric about `normal` for the sake of its names,
10
+ * but the level a screen gets when nobody chose is the dense one.
11
+ */
12
+ const DEFAULT_DENSITY = "compact";
13
+ /** The five levels, as a runtime array for validating persisted input. */
8
14
  const DENSITY_LEVELS = [
9
15
  "ultra-compact",
16
+ "compact",
10
17
  "normal",
11
- "large"
18
+ "large",
19
+ "ultra-large"
12
20
  ];
13
21
  /**
14
22
  * Nearest ambient density. `null` means "nothing has stamped a level yet", which
@@ -1,8 +1,8 @@
1
- import { ResolvedMode, ThemeContextValue, ThemeProvider, ThemeProviderProps } from "./theme-provider.js";
1
+ import { FontFamilies, ResolvedMode, ThemeContextValue, ThemeProvider, ThemeProviderProps } from "./theme-provider.js";
2
2
  import { Density, DensityProps } from "./density.js";
3
3
  import { CuePortalFrame, CuePortalFrameProps, useCuePortalProps } from "./portal.js";
4
- import { DEFAULT_STORAGE_KEY, PersistedPreferences, prepaintScript } from "./prepaint.js";
4
+ import { DEFAULT_STORAGE_KEY, PersistedPreferences, PrepaintDefaults, PrepaintOptions, prepaintScript } from "./prepaint.js";
5
5
  import { ControlSize, useControlHeight, useDensity } from "./use-density.js";
6
6
  import { useTheme } from "./use-theme.js";
7
- import { Density as DensityLevel, Mode, ThemeName } from "@cueplusplus/tokens";
8
- export { type ControlSize, CuePortalFrame, type CuePortalFrameProps, DEFAULT_STORAGE_KEY, Density, type DensityLevel, type DensityProps, type Mode, type PersistedPreferences, type ResolvedMode, type ThemeContextValue, type ThemeName, ThemeProvider, type ThemeProviderProps, prepaintScript, useControlHeight, useCuePortalProps, useDensity, useTheme };
7
+ import { Density as DensityLevel, FontName, Mode, ThemeName } from "@cueplusplus/tokens";
8
+ export { type ControlSize, CuePortalFrame, type CuePortalFrameProps, DEFAULT_STORAGE_KEY, Density, type DensityLevel, type DensityProps, type FontFamilies, type FontName, type Mode, type PersistedPreferences, type PrepaintDefaults, type PrepaintOptions, type ResolvedMode, type ThemeContextValue, type ThemeName, ThemeProvider, type ThemeProviderProps, prepaintScript, useControlHeight, useCuePortalProps, useDensity, useTheme };
@@ -2,11 +2,11 @@ import * as React from "react";
2
2
  //#region src/system/portal.d.ts
3
3
  /**
4
4
  * Props to spread onto a Base UI `Portal` part so the portal root inherits the
5
- * caller's theme, density and mode.
5
+ * caller's theme, density, font pairing and mode.
6
6
  *
7
7
  * Returns a `container` element appended to `document.body` and stamped with
8
- * `data-theme` / `data-density` / `data-mode` (plus `--cue-font-scale`) copied
9
- * from the nearest provider and density island. The container is
8
+ * `data-theme` / `data-density` / `data-font` / `data-mode` (plus
9
+ * `--cue-font-scale`) copied from the nearest provider and density island. The container is
10
10
  * `display: contents`, so it changes no layout and creates no containing block —
11
11
  * fixed-position overlay content behaves exactly as if it were a direct child of
12
12
  * `<body>`.
@@ -38,8 +38,8 @@ interface CuePortalFrameProps {
38
38
  * chosen (a third-party overlay, or content already portaled by something else).
39
39
  *
40
40
  * Wraps `children` in a `display: contents` element carrying the same
41
- * `data-theme` / `data-density` / `data-mode` triple and `--cue-font-scale` as
42
- * {@link useCuePortalProps}. Prefer the hook — a stamped container costs one
41
+ * `data-theme` / `data-density` / `data-font` / `data-mode` stamp and
42
+ * `--cue-font-scale` as {@link useCuePortalProps}. Prefer the hook — a stamped container costs one
43
43
  * element per overlay instead of one per render tree — and reach for this only
44
44
  * when the container prop is not available.
45
45
  *
@@ -1,14 +1,17 @@
1
1
  "use client";
2
2
  import { useIsomorphicLayoutEffect } from "./use-isomorphic-layout-effect.js";
3
3
  import { DensityContext } from "./density.js";
4
- import { FontScaleContext, ThemeContext } from "./theme-provider.js";
4
+ import { FontFamiliesContext, FontScaleContext, ThemeContext } from "./theme-provider.js";
5
5
  import * as React from "react";
6
6
  import { jsx } from "react/jsx-runtime";
7
+ import { DEFAULT_FONT } from "@cueplusplus/tokens";
7
8
  //#region src/system/portal.tsx
8
9
  const DEFAULT_THEME = "cue";
9
- const DEFAULT_RESOLVED_MODE = "dark";
10
+ const DEFAULT_MODE = "dark";
10
11
  /** Custom property the density text ladder multiplies by; see `FontScaleContext`. */
11
12
  const FONT_SCALE_PROPERTY = "--cue-font-scale";
13
+ const FONT_SANS_PROPERTY = "--cue-font-sans";
14
+ const FONT_MONO_PROPERTY = "--cue-font-mono";
12
15
  /**
13
16
  * Read the stamp from React context — never from the DOM. A portal is mounted
14
17
  * outside its owner's DOM subtree, so `getComputedStyle`-style discovery would
@@ -21,20 +24,23 @@ function usePortalStamp() {
21
24
  const theme = React.useContext(ThemeContext);
22
25
  const island = React.useContext(DensityContext);
23
26
  const fontScale = React.useContext(FontScaleContext);
27
+ const fontFamilies = React.useContext(FontFamiliesContext);
24
28
  return {
25
29
  theme: theme?.theme ?? DEFAULT_THEME,
26
- density: island ?? theme?.density ?? "normal",
27
- mode: theme?.resolvedMode ?? DEFAULT_RESOLVED_MODE,
28
- fontScale
30
+ density: island ?? theme?.density ?? "compact",
31
+ mode: theme?.mode ?? DEFAULT_MODE,
32
+ font: theme?.font ?? DEFAULT_FONT,
33
+ fontScale,
34
+ fontFamilies
29
35
  };
30
36
  }
31
37
  /**
32
38
  * Props to spread onto a Base UI `Portal` part so the portal root inherits the
33
- * caller's theme, density and mode.
39
+ * caller's theme, density, font pairing and mode.
34
40
  *
35
41
  * Returns a `container` element appended to `document.body` and stamped with
36
- * `data-theme` / `data-density` / `data-mode` (plus `--cue-font-scale`) copied
37
- * from the nearest provider and density island. The container is
42
+ * `data-theme` / `data-density` / `data-font` / `data-mode` (plus
43
+ * `--cue-font-scale`) copied from the nearest provider and density island. The container is
38
44
  * `display: contents`, so it changes no layout and creates no containing block —
39
45
  * fixed-position overlay content behaves exactly as if it were a direct child of
40
46
  * `<body>`.
@@ -75,8 +81,11 @@ function useCuePortalProps() {
75
81
  container,
76
82
  stamp.theme,
77
83
  stamp.density,
84
+ stamp.font,
78
85
  stamp.mode,
79
- stamp.fontScale
86
+ stamp.fontScale,
87
+ stamp.fontFamilies?.sans,
88
+ stamp.fontFamilies?.mono
80
89
  ]);
81
90
  return React.useMemo(() => container === null ? {} : { container }, [container]);
82
91
  }
@@ -84,17 +93,24 @@ function useCuePortalProps() {
84
93
  function applyStamp(element, stamp) {
85
94
  element.setAttribute("data-theme", stamp.theme);
86
95
  element.setAttribute("data-density", stamp.density);
96
+ element.setAttribute("data-font", stamp.font);
87
97
  element.setAttribute("data-mode", stamp.mode);
88
98
  if (stamp.fontScale === null) element.style.removeProperty(FONT_SCALE_PROPERTY);
89
99
  else element.style.setProperty(FONT_SCALE_PROPERTY, String(stamp.fontScale));
100
+ setOptionalProperty(element, FONT_SANS_PROPERTY, stamp.fontFamilies?.sans);
101
+ setOptionalProperty(element, FONT_MONO_PROPERTY, stamp.fontFamilies?.mono);
102
+ }
103
+ function setOptionalProperty(element, property, value) {
104
+ if (value === void 0) element.style.removeProperty(property);
105
+ else element.style.setProperty(property, value);
90
106
  }
91
107
  /**
92
108
  * Inline version of the portal contract, for portals whose container cannot be
93
109
  * chosen (a third-party overlay, or content already portaled by something else).
94
110
  *
95
111
  * Wraps `children` in a `display: contents` element carrying the same
96
- * `data-theme` / `data-density` / `data-mode` triple and `--cue-font-scale` as
97
- * {@link useCuePortalProps}. Prefer the hook — a stamped container costs one
112
+ * `data-theme` / `data-density` / `data-font` / `data-mode` stamp and
113
+ * `--cue-font-scale` as {@link useCuePortalProps}. Prefer the hook — a stamped container costs one
98
114
  * element per overlay instead of one per render tree — and reach for this only
99
115
  * when the container prop is not available.
100
116
  *
@@ -106,12 +122,15 @@ function CuePortalFrame({ children, className, style }) {
106
122
  const frameStyle = {
107
123
  display: "contents",
108
124
  ...stamp.fontScale === null ? null : { [FONT_SCALE_PROPERTY]: stamp.fontScale },
125
+ ...stamp.fontFamilies?.sans === void 0 ? null : { [FONT_SANS_PROPERTY]: stamp.fontFamilies.sans },
126
+ ...stamp.fontFamilies?.mono === void 0 ? null : { [FONT_MONO_PROPERTY]: stamp.fontFamilies.mono },
109
127
  ...style
110
128
  };
111
129
  return /* @__PURE__ */ jsx("div", {
112
130
  "data-cue-portal": "",
113
131
  "data-theme": stamp.theme,
114
132
  "data-density": stamp.density,
133
+ "data-font": stamp.font,
115
134
  "data-mode": stamp.mode,
116
135
  className,
117
136
  style: frameStyle,
@@ -1,4 +1,4 @@
1
- import { ThemeName } from "@cueplusplus/tokens";
1
+ import { Density, FontName, Mode, ThemeName } from "@cueplusplus/tokens";
2
2
  //#region src/system/prepaint.d.ts
3
3
  /** localStorage key the ThemeProvider and the pre-paint script share by default. */
4
4
  declare const DEFAULT_STORAGE_KEY = "cue-ui";
@@ -10,17 +10,36 @@ interface PersistedPreferences {
10
10
  density?: string;
11
11
  /** Last mode the user picked, including the literal `"system"`. */
12
12
  mode?: string;
13
+ /** Last font pairing the user picked. */
14
+ font?: string;
15
+ }
16
+ /** Complete server-authoritative fallback stamped when storage is absent or ignored. */
17
+ interface PrepaintDefaults {
18
+ theme: ThemeName;
19
+ density: Density;
20
+ mode: Mode;
21
+ /** Initial document-wide font pairing. Defaults to the token package's system pairing. */
22
+ font?: FontName;
23
+ }
24
+ /** Options form for apps whose server projection, not localStorage, owns first paint. */
25
+ interface PrepaintOptions {
26
+ /** localStorage key shared with ThemeProvider. */
27
+ storageKey?: string;
28
+ /** Complete validated fallback triple. */
29
+ defaults: PrepaintDefaults;
30
+ /** Whether valid stored axes may override `defaults`. Defaults to `true`. */
31
+ readStoredPreferences?: boolean;
13
32
  }
14
33
  /**
15
34
  * Build the blocking inline script that stamps `data-theme`, `data-density`,
16
- * `data-mode` and `color-scheme` on `<html>` from localStorage before the first
17
- * paint.
35
+ * `data-font`, `data-mode` and `color-scheme` on `<html>` from localStorage
36
+ * before the first paint.
18
37
  *
19
38
  * Render it as `<script dangerouslySetInnerHTML={{ __html: prepaintScript() }} />`
20
39
  * in `<head>`, above everything else. The output never contains `</script>` and
21
40
  * never throws: private-mode localStorage failures degrade to the dark-first
22
- * defaults (`cue` / `normal` / `dark`), which are also what bare `:root` in
23
- * `@cueplusplus/tokens/theme.css` already paints.
41
+ * defaults (`cue` / `compact` / `system` / `dark`), which are also what bare
42
+ * `:root` in `@cueplusplus/tokens/theme.css` already paints.
24
43
  *
25
44
  * @param storageKey - localStorage key to read. Must match the `storageKey`
26
45
  * passed to `<ThemeProvider>`. Defaults to {@link DEFAULT_STORAGE_KEY}.
@@ -28,11 +47,17 @@ interface PersistedPreferences {
28
47
  * Must match the `theme` passed to `<ThemeProvider>`, or the first paint
29
48
  * dresses `<html>` in one preset while the app renders in another. Defaults to
30
49
  * `"cue"`.
50
+ * @param defaultDensity - Density level to stamp for a visitor with nothing
51
+ * persisted yet. Same rule as `defaultTheme`: it must match the `density`
52
+ * passed to `<ThemeProvider>` or the first frame is drawn at one rung and
53
+ * every frame after it at another. Defaults to `"compact"`, the library's own
54
+ * fallback, which is what an app that passes no `density` renders at.
31
55
  * @returns One line of JavaScript, safe to inline verbatim.
32
56
  * @example
33
- * // An app whose provider is <ThemeProvider theme="terminal">:
34
- * prepaintScript(DEFAULT_STORAGE_KEY, "terminal");
57
+ * // An app whose provider is <ThemeProvider theme="terminal" density="normal">:
58
+ * prepaintScript(DEFAULT_STORAGE_KEY, "terminal", "normal");
35
59
  */
36
- declare function prepaintScript(storageKey?: string, defaultTheme?: ThemeName): string;
60
+ declare function prepaintScript(storageKey?: string, defaultTheme?: ThemeName, defaultDensity?: Density, defaultFont?: FontName): string;
61
+ declare function prepaintScript(options: PrepaintOptions): string;
37
62
  //#endregion
38
- export { DEFAULT_STORAGE_KEY, PersistedPreferences, prepaintScript };
63
+ export { DEFAULT_STORAGE_KEY, PersistedPreferences, PrepaintDefaults, PrepaintOptions, prepaintScript };