@cloudgrid-io/ui 0.39.0 → 0.41.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 (119) hide show
  1. package/README.md +9 -5
  2. package/dist/badge/palette.d.ts +1 -1
  3. package/dist/badge/palette.d.ts.map +1 -1
  4. package/dist/badge/palette.js +2 -2
  5. package/dist/badge/palette.js.map +1 -1
  6. package/dist/blocks/action-link.d.ts +31 -0
  7. package/dist/blocks/action-link.d.ts.map +1 -0
  8. package/dist/blocks/action-link.js +40 -0
  9. package/dist/blocks/action-link.js.map +1 -0
  10. package/dist/blocks/activity-row.d.ts +42 -0
  11. package/dist/blocks/activity-row.d.ts.map +1 -0
  12. package/dist/blocks/activity-row.js +37 -0
  13. package/dist/blocks/activity-row.js.map +1 -0
  14. package/dist/blocks/add-tile.d.ts +31 -0
  15. package/dist/blocks/add-tile.d.ts.map +1 -0
  16. package/dist/blocks/add-tile.js +29 -0
  17. package/dist/blocks/add-tile.js.map +1 -0
  18. package/dist/blocks/avatar-stack.d.ts +40 -0
  19. package/dist/blocks/avatar-stack.d.ts.map +1 -0
  20. package/dist/blocks/avatar-stack.js +41 -0
  21. package/dist/blocks/avatar-stack.js.map +1 -0
  22. package/dist/blocks/avatar.d.ts +31 -5
  23. package/dist/blocks/avatar.d.ts.map +1 -1
  24. package/dist/blocks/avatar.js +57 -9
  25. package/dist/blocks/avatar.js.map +1 -1
  26. package/dist/blocks/copy-button.d.ts +59 -0
  27. package/dist/blocks/copy-button.d.ts.map +1 -0
  28. package/dist/blocks/copy-button.js +76 -0
  29. package/dist/blocks/copy-button.js.map +1 -0
  30. package/dist/blocks/dashed-banner.d.ts +36 -0
  31. package/dist/blocks/dashed-banner.d.ts.map +1 -0
  32. package/dist/blocks/dashed-banner.js +31 -0
  33. package/dist/blocks/dashed-banner.js.map +1 -0
  34. package/dist/blocks/dashed-line.d.ts +44 -0
  35. package/dist/blocks/dashed-line.d.ts.map +1 -0
  36. package/dist/blocks/dashed-line.js +46 -0
  37. package/dist/blocks/dashed-line.js.map +1 -0
  38. package/dist/blocks/empty-creations.d.ts +18 -1
  39. package/dist/blocks/empty-creations.d.ts.map +1 -1
  40. package/dist/blocks/empty-creations.js +25 -9
  41. package/dist/blocks/empty-creations.js.map +1 -1
  42. package/dist/blocks/entity-card.d.ts +37 -2
  43. package/dist/blocks/entity-card.d.ts.map +1 -1
  44. package/dist/blocks/entity-card.js +70 -7
  45. package/dist/blocks/entity-card.js.map +1 -1
  46. package/dist/blocks/filter-tabs.d.ts +45 -0
  47. package/dist/blocks/filter-tabs.d.ts.map +1 -0
  48. package/dist/blocks/filter-tabs.js +48 -0
  49. package/dist/blocks/filter-tabs.js.map +1 -0
  50. package/dist/blocks/header-menu.d.ts +54 -0
  51. package/dist/blocks/header-menu.d.ts.map +1 -0
  52. package/dist/blocks/header-menu.js +63 -0
  53. package/dist/blocks/header-menu.js.map +1 -0
  54. package/dist/blocks/header-pill.d.ts +41 -0
  55. package/dist/blocks/header-pill.d.ts.map +1 -0
  56. package/dist/blocks/header-pill.js +67 -0
  57. package/dist/blocks/header-pill.js.map +1 -0
  58. package/dist/blocks/icons.d.ts +47 -2
  59. package/dist/blocks/icons.d.ts.map +1 -1
  60. package/dist/blocks/icons.js +50 -2
  61. package/dist/blocks/icons.js.map +1 -1
  62. package/dist/blocks/menu-trigger.d.ts +35 -0
  63. package/dist/blocks/menu-trigger.d.ts.map +1 -0
  64. package/dist/blocks/menu-trigger.js +24 -0
  65. package/dist/blocks/menu-trigger.js.map +1 -0
  66. package/dist/blocks/meter.d.ts +9 -1
  67. package/dist/blocks/meter.d.ts.map +1 -1
  68. package/dist/blocks/meter.js +6 -2
  69. package/dist/blocks/meter.js.map +1 -1
  70. package/dist/blocks/phosphor-marks.d.ts +48 -2
  71. package/dist/blocks/phosphor-marks.d.ts.map +1 -1
  72. package/dist/blocks/phosphor-marks.js +72 -3
  73. package/dist/blocks/phosphor-marks.js.map +1 -1
  74. package/dist/blocks/plugged-dialog.d.ts +102 -0
  75. package/dist/blocks/plugged-dialog.d.ts.map +1 -0
  76. package/dist/blocks/plugged-dialog.js +93 -0
  77. package/dist/blocks/plugged-dialog.js.map +1 -0
  78. package/dist/blocks/ranked-list.d.ts +15 -1
  79. package/dist/blocks/ranked-list.d.ts.map +1 -1
  80. package/dist/blocks/ranked-list.js +18 -5
  81. package/dist/blocks/ranked-list.js.map +1 -1
  82. package/dist/blocks/scroll-rail.d.ts +15 -0
  83. package/dist/blocks/scroll-rail.d.ts.map +1 -0
  84. package/dist/blocks/scroll-rail.js +134 -0
  85. package/dist/blocks/scroll-rail.js.map +1 -0
  86. package/dist/blocks/section-heading.d.ts +21 -0
  87. package/dist/blocks/section-heading.d.ts.map +1 -0
  88. package/dist/blocks/section-heading.js +18 -0
  89. package/dist/blocks/section-heading.js.map +1 -0
  90. package/dist/blocks/side-nav.d.ts +12 -2
  91. package/dist/blocks/side-nav.d.ts.map +1 -1
  92. package/dist/blocks/side-nav.js +49 -15
  93. package/dist/blocks/side-nav.js.map +1 -1
  94. package/dist/blocks/stat-tile.d.ts +21 -1
  95. package/dist/blocks/stat-tile.d.ts.map +1 -1
  96. package/dist/blocks/stat-tile.js +11 -6
  97. package/dist/blocks/stat-tile.js.map +1 -1
  98. package/dist/console.css +55 -19
  99. package/dist/index.d.ts +14 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +14 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/theme.css +36 -0
  104. package/dist/tokens/base.json +55 -5
  105. package/dist/tokens.css +46 -12
  106. package/dist/tokens.json +8 -3
  107. package/dist/ui/button.d.ts +2 -2
  108. package/dist/ui/button.d.ts.map +1 -1
  109. package/dist/ui/button.js +26 -0
  110. package/dist/ui/button.js.map +1 -1
  111. package/dist/ui/dialog.d.ts +6 -0
  112. package/dist/ui/dialog.d.ts.map +1 -1
  113. package/dist/ui/dialog.js +7 -1
  114. package/dist/ui/dialog.js.map +1 -1
  115. package/dist/ui/drawer.d.ts +7 -5
  116. package/dist/ui/drawer.d.ts.map +1 -1
  117. package/dist/ui/drawer.js +7 -5
  118. package/dist/ui/drawer.js.map +1 -1
  119. package/package.json +1 -1
@@ -0,0 +1,134 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/cloudgrid-cn.js";
5
+ import { RailNextIcon, RailPreviousIcon } from "./icons.js";
6
+ /**
7
+ * A horizontal row that scrolls: Home's My Creations and On the Grid rails
8
+ * (#382, spec §4.4 and §4.8, Figma scroll button `11355:10564`).
9
+ *
10
+ * ## What it draws
11
+ *
12
+ * Any nodes, one list item each, `gap` apart (default 20, the frames'), in a
13
+ * viewport that scrolls sideways and snaps each item's start edge. At either
14
+ * side that has more, a 64px fade into the rail's fade colour (the page colour
15
+ * by default, spec §8.6: the frames fade into pure white on a page-coloured
16
+ * page) and a 48px square button (white, radius 16, a 1px `--cg-tertiary-dark`
17
+ * line, a 20px arrow in the same teal), at the edge and vertically centred. At
18
+ * an end the button is disabled and invisible and its fade is gone, so a rail
19
+ * that fits draws neither.
20
+ *
21
+ * ## Measured, so the server draws no controls
22
+ *
23
+ * Which side has more is a measurement, and the server has no layout. The
24
+ * first paint shows the row alone; the browser measures on mount, on scroll and
25
+ * whenever the viewport or the list changes size (a `ResizeObserver`), so a
26
+ * window resized from overflowing to fitting drops its controls.
27
+ *
28
+ * ## A press
29
+ *
30
+ * Moves by the viewport's width less one fade, so the item that was half under
31
+ * the fade becomes the first one shown; the snap then settles it on its edge.
32
+ * Smooth, or instant under `prefers-reduced-motion: reduce`.
33
+ *
34
+ * ## Keyboard and touch
35
+ *
36
+ * The viewport is a named, focusable region, so the arrow keys scroll it even
37
+ * when the items hold nothing focusable; a focused card inside it is scrolled
38
+ * into view by the browser. A button that reaches its end hands focus to the
39
+ * other one, so pressing Enter through the row never drops focus to the page. On a coarse pointer the buttons are not drawn
40
+ * (`pointer-coarse:hidden`): the row scrolls under a finger, and the fades stay
41
+ * to say there is more.
42
+ *
43
+ * The line and the arrow are `--cg-tertiary-dark` (ui#381), the frames'
44
+ * Tertiary Dark.
45
+ */
46
+ /** The fade's width, and how much of the viewport a press does not travel. */
47
+ const FADE = 64;
48
+ /** How long a press counts for the focus hand-off: longer than a smooth scroll. */
49
+ const PRESS_WINDOW = 1000;
50
+ const useIsoLayoutEffect = typeof document === "undefined" ? React.useEffect : React.useLayoutEffect;
51
+ function ScrollRail({ children, label, gap = 20, previousLabel = "Scroll back", nextLabel = "Scroll forward", className, style, ...props }) {
52
+ const id = React.useId();
53
+ const viewport = React.useRef(null);
54
+ const list = React.useRef(null);
55
+ const startButton = React.useRef(null);
56
+ const endButton = React.useRef(null);
57
+ // Both "at the end" until measured: the server draws no controls.
58
+ const [edges, setEdges] = React.useState({ start: true, end: true });
59
+ const measure = React.useCallback(() => {
60
+ const el = viewport.current;
61
+ if (!el)
62
+ return;
63
+ const start = el.scrollLeft <= 1;
64
+ const end = el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;
65
+ setEdges((prev) => (prev.start === start && prev.end === end ? prev : { start, end }));
66
+ }, []);
67
+ useIsoLayoutEffect(() => {
68
+ const el = viewport.current;
69
+ if (!el)
70
+ return;
71
+ measure();
72
+ el.addEventListener("scroll", measure, { passive: true });
73
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
74
+ observer?.observe(el);
75
+ if (list.current)
76
+ observer?.observe(list.current);
77
+ return () => {
78
+ el.removeEventListener("scroll", measure);
79
+ observer?.disconnect();
80
+ };
81
+ }, [measure]);
82
+ // A button disables itself at its end, and a disabled button loses focus to
83
+ // the page. When that happens to the focused one, hand focus to the other
84
+ // button, or to the region when the row fits, so a keyboard reader stays here.
85
+ //
86
+ // The browser has already moved focus to the body by the time this runs, so
87
+ // what is tracked is the button last pressed while it held focus. A press
88
+ // only counts for the scroll it starts: it is forgotten after PRESS_WINDOW,
89
+ // so reaching the end later by wheel or trackpad never pulls focus in.
90
+ const pressed = React.useRef(null);
91
+ const pressedTimer = React.useRef(undefined);
92
+ React.useEffect(() => () => clearTimeout(pressedTimer.current), []);
93
+ React.useEffect(() => {
94
+ const side = pressed.current;
95
+ if (!side || !edges[side])
96
+ return;
97
+ pressed.current = null;
98
+ const active = document.activeElement;
99
+ const own = side === "start" ? startButton.current : endButton.current;
100
+ if (active !== own && active !== document.body && active !== null)
101
+ return;
102
+ const other = side === "start" ? (edges.end ? null : endButton.current) : edges.start ? null : startButton.current;
103
+ (other ?? viewport.current)?.focus();
104
+ }, [edges]);
105
+ const scroll = (direction) => {
106
+ const el = viewport.current;
107
+ if (!el)
108
+ return;
109
+ const reduce = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
110
+ el.scrollBy({ left: direction * Math.max(el.clientWidth - FADE, el.clientWidth / 2), behavior: reduce ? "auto" : "smooth" });
111
+ };
112
+ const items = React.Children.toArray(children);
113
+ const sideButton = (side) => {
114
+ const atEnd = side === "start" ? edges.start : edges.end;
115
+ const Icon = side === "start" ? RailPreviousIcon : RailNextIcon;
116
+ return (_jsx("button", { ref: side === "start" ? startButton : endButton, type: "button", "data-slot": "scroll-rail-button", "data-side": side, "aria-label": side === "start" ? previousLabel : nextLabel, "aria-controls": id, disabled: atEnd, onClick: (event) => {
117
+ pressed.current = event.currentTarget === document.activeElement ? side : null;
118
+ clearTimeout(pressedTimer.current);
119
+ pressedTimer.current = setTimeout(() => {
120
+ pressed.current = null;
121
+ }, PRESS_WINDOW);
122
+ scroll(side === "start" ? -1 : 1);
123
+ }, className: cn("absolute top-1/2 z-10 inline-flex size-12 -translate-y-1/2 items-center justify-center rounded-xl border border-(--cg-tertiary-dark) bg-card text-(--cg-tertiary-dark) outline-none", "hover:[background-image:linear-gradient(var(--cg-hover),var(--cg-hover))] focus-visible:ring-3 focus-visible:ring-ring", "pointer-coarse:hidden", side === "start" ? "left-0" : "right-0", atEnd && "invisible"), children: _jsx(Icon, { className: "size-5" }) }));
124
+ };
125
+ const sideFade = (side) => {
126
+ const atEnd = side === "start" ? edges.start : edges.end;
127
+ return (_jsx("span", { "data-slot": "scroll-rail-fade", "data-side": side, "aria-hidden": "true", className: cn("pointer-events-none absolute inset-y-0 z-[1] w-16 from-(--scroll-rail-fade) to-transparent", side === "start" ? "left-0 bg-linear-to-r" : "right-0 bg-linear-to-l", atEnd && "hidden") }));
128
+ };
129
+ return (_jsxs("div", { "data-slot": "scroll-rail", className: cn("relative min-w-0", className), style: { "--scroll-rail-fade": "var(--cg-surface-page)", ...style }, ...props, children: [_jsx("div", { ref: viewport, id: id, role: "region", "aria-label": label,
130
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- a scroll region must be reachable by keyboard even when its items hold nothing focusable (WCAG 2.1.1; axe's scrollable-region-focusable)
131
+ tabIndex: 0, "data-slot": "scroll-rail-viewport", className: "snap-x snap-mandatory overflow-x-auto overscroll-x-contain outline-none [scrollbar-width:none] focus-visible:ring-3 focus-visible:ring-ring [&::-webkit-scrollbar]:hidden", children: _jsx("ul", { ref: list, "data-slot": "scroll-rail-list", className: "m-0 flex w-max list-none p-0", style: { gap }, children: items.map((child, i) => (_jsx("li", { "data-slot": "scroll-rail-item", className: "shrink-0 snap-start", children: child }, React.isValidElement(child) && child.key != null ? child.key : i))) }) }), sideFade("start"), sideFade("end"), sideButton("start"), sideButton("end")] }));
132
+ }
133
+ export { ScrollRail };
134
+ //# sourceMappingURL=scroll-rail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-rail.js","sourceRoot":"","sources":["../../src/blocks/scroll-rail.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ /**
3
+ * A section's heading row on the 2026 Home (#382, spec §4.4, §4.6 to §4.8).
4
+ *
5
+ * The title at the frames' H4 (`text-heading-lg`, 22 / 1.2, Medium) in Ink, not
6
+ * the `#000000` two of the frames paint (spec §8.3). `inline` sits 24 to its
7
+ * right: My Creations' filter tabs. `action` sits at the far end: On the Grid's
8
+ * "Explore All". The heading level is the caller's, because the page decides
9
+ * the outline.
10
+ */
11
+ declare function SectionHeading({ title, level, inline, action, className, ...props }: Omit<React.ComponentProps<"div">, "title" | "children"> & {
12
+ title: React.ReactNode;
13
+ /** The heading element. Default 2. */
14
+ level?: 2 | 3 | 4;
15
+ /** 24px after the title: the filter tabs. */
16
+ inline?: React.ReactNode;
17
+ /** At the far end: "Explore All". */
18
+ action?: React.ReactNode;
19
+ }): React.JSX.Element;
20
+ export { SectionHeading };
21
+ //# sourceMappingURL=section-heading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-heading.d.ts","sourceRoot":"","sources":["../../src/blocks/section-heading.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B;;;;;;;;GAQG;AACH,iBAAS,cAAc,CAAC,EACtB,KAAK,EACL,KAAS,EACT,MAAM,EACN,MAAM,EACN,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IAC3D,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,sCAAsC;IACtC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACjB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,qCAAqC;IACrC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB,qBA0BA;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../lib/cloudgrid-cn.js";
4
+ /**
5
+ * A section's heading row on the 2026 Home (#382, spec §4.4, §4.6 to §4.8).
6
+ *
7
+ * The title at the frames' H4 (`text-heading-lg`, 22 / 1.2, Medium) in Ink, not
8
+ * the `#000000` two of the frames paint (spec §8.3). `inline` sits 24 to its
9
+ * right: My Creations' filter tabs. `action` sits at the far end: On the Grid's
10
+ * "Explore All". The heading level is the caller's, because the page decides
11
+ * the outline.
12
+ */
13
+ function SectionHeading({ title, level = 2, inline, action, className, ...props }) {
14
+ const Heading = `h${level}`;
15
+ return (_jsxs("div", { "data-slot": "section-heading", className: cn("flex min-w-0 items-center justify-between gap-6 text-ink", className), ...props, children: [_jsxs("div", { "data-slot": "section-heading-start", className: "flex min-w-0 items-center gap-6", children: [_jsx(Heading, { "data-slot": "section-heading-title", className: "m-0 shrink-0 text-heading-lg font-medium text-ink", children: title }), inline ? (_jsx("div", { "data-slot": "section-heading-inline", className: "min-w-0", children: inline })) : null] }), action ? (_jsx("div", { "data-slot": "section-heading-action", className: "shrink-0", children: action })) : null] }));
16
+ }
17
+ export { SectionHeading };
18
+ //# sourceMappingURL=section-heading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-heading.js","sourceRoot":"","sources":["../../src/blocks/section-heading.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;GAQG;AACH,SAAS,cAAc,CAAC,EACtB,KAAK,EACL,KAAK,GAAG,CAAC,EACT,MAAM,EACN,MAAM,EACN,SAAS,EACT,GAAG,KAAK,EAST;IACC,MAAM,OAAO,GAAG,IAAI,KAAK,EAAwB,CAAA;IAEjD,OAAO,CACL,4BACY,iBAAiB,EAC3B,SAAS,EAAE,EAAE,CAAC,0DAA0D,EAAE,SAAS,CAAC,KAChF,KAAK,aAET,4BAAe,uBAAuB,EAAC,SAAS,EAAC,iCAAiC,aAChF,KAAC,OAAO,iBAAW,uBAAuB,EAAC,SAAS,EAAC,mDAAmD,YACrG,KAAK,GACE,EACT,MAAM,CAAC,CAAC,CAAC,CACR,2BAAe,wBAAwB,EAAC,SAAS,EAAC,SAAS,YACxD,MAAM,GACH,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,EACL,MAAM,CAAC,CAAC,CAAC,CACR,2BAAe,wBAAwB,EAAC,SAAS,EAAC,UAAU,YACzD,MAAM,GACH,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAA;AACH,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -30,10 +30,20 @@ declare function SideNavGroup({ label, icon, collapsible, open, defaultOpen, onO
30
30
  onOpenChange?: (open: boolean) => void;
31
31
  children?: React.ReactNode;
32
32
  }): React.JSX.Element;
33
- declare function SideNavItem({ label, icon, count, active, render, className, onKeyDown, ...props }: Omit<useRender.ComponentProps<"button">, "children"> & {
33
+ declare function SideNavItem({ label, icon, activeIcon, count, active, render, className, onKeyDown, ...props }: Omit<useRender.ComponentProps<"button">, "children"> & {
34
34
  label: React.ReactNode;
35
- /** 14 to 16px. The row's label is what gets announced, so the glyph carries no name. */
35
+ /**
36
+ * The row's glyph, drawn at 20px. The label is what gets announced, so the
37
+ * glyph carries no name.
38
+ */
36
39
  icon?: React.ReactNode;
40
+ /**
41
+ * The same glyph, filled, for when this row is the page you are on (#377).
42
+ * Pass the pair once, `icon={<PeopleIcon />} activeIcon={<PeopleFilledIcon />}`,
43
+ * and the row draws the right one for its state. Without it the row draws
44
+ * `icon` in both states.
45
+ */
46
+ activeIcon?: React.ReactNode;
37
47
  /**
38
48
  * The trailing pill. The frame's Feedback row wears a `0`.
39
49
  *
@@ -1 +1 @@
1
- {"version":3,"file":"side-nav.d.ts","sourceRoot":"","sources":["../../src/blocks/side-nav.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AA0GrD,iBAAS,OAAO,CAAC,EACf,KAAK,EACL,OAAO,EACP,SAAS,EACT,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG;IAC5C;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,qBAsCA;AAED,iBAAS,YAAY,CAAC,EACpB,KAAK,EACL,IAAI,EACJ,WAAW,EACX,IAAI,EACJ,WAAmB,EACnB,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,GAAG;IACzD,6DAA6D;IAC7D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;OAGG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,qBAgGA;AAED,iBAAS,WAAW,CAAC,EACnB,KAAK,EACL,IAAI,EACJ,KAAK,EACL,MAAM,EACN,MAAM,EACN,SAAS,EACT,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG;IACxD,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,wFAAwF;IACxF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,0EAmEA;AAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"side-nav.d.ts","sourceRoot":"","sources":["../../src/blocks/side-nav.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AA2IrD,iBAAS,OAAO,CAAC,EACf,KAAK,EACL,OAAO,EACP,SAAS,EACT,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG;IAC5C;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,qBAsCA;AAED,iBAAS,YAAY,CAAC,EACpB,KAAK,EACL,IAAI,EACJ,WAAW,EACX,IAAI,EACJ,WAAmB,EACnB,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,GAAG;IACzD,6DAA6D;IAC7D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;OAGG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,qBAkGA;AAED,iBAAS,WAAW,CAAC,EACnB,KAAK,EACL,IAAI,EACJ,UAAU,EACV,KAAK,EACL,MAAM,EACN,MAAM,EACN,SAAS,EACT,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG;IACxD,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,0EA4EA;AAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,CAAA"}
@@ -56,18 +56,28 @@ import { cn } from "../lib/cloudgrid-cn.js";
56
56
  *
57
57
  * ## The active row does not flip, and that is the decision
58
58
  *
59
- * The frame's active row is a pale lavender chip carrying purple text:
60
- * `--cg-primary-tint` under `--cg-primary`. Both are declared at `:root` only,
61
- * so the row paints the same two values on the page, on the purple panel and on
62
- * ink — and that is the point rather than an oversight.
59
+ * The active row is a pale lavender chip, `--cg-primary-tint`, with the glyph
60
+ * FILLED in `--cg-primary` and the label in ink (#377, the 2026 Admin menu,
61
+ * Figma 7414:5979; before that the label was purple too). The tint is primary
62
+ * at 10% over white to within one unit per channel, so the opaque token is the
63
+ * frame's ground. The tint, the purple and the label's ink
64
+ * (`--cg-neutral-900`, read from the ramp, NOT `text-ink`) are all declared at
65
+ * `:root` only, so the row paints the same three values on the page, on the
66
+ * purple panel and on ink — and that is the point rather than an oversight.
63
67
  *
64
68
  * It is the kind badge's rule (#196) applied to a row: the chip brings its own
65
- * ground, so it does not need the surface's answer for one. The pair measures
66
- * 5.02:1, which clears AA for its 15px label everywhere, and the chip measures
69
+ * ground, so it does not need the surface's answer for one. The ink label
70
+ * measures 13.69:1 on it and the purple glyph 5.02:1, and the chip measures
67
71
  * 1.16:1 against the white card, 5.02:1 against the panel and 13.68:1 on ink.
68
72
  * `packages/ui/test/contrast-guardrail.test.mjs` holds every one of those
69
73
  * numbers, and says why the chip's own floor is not 3:1.
70
74
  *
75
+ * The state is said three ways: the chip, the glyph's SHAPE (filled, when the
76
+ * caller hands `activeIcon`), and `aria-current`. An inactive row's glyph is
77
+ * N3 (`--cg-slate-500`, the `steel` utility) on the light page; N3 is a :root
78
+ * ramp value that measures 1.71:1 on the panel, so on the panel and on ink the
79
+ * glyph takes that surface's own `--cg-text-muted` instead.
80
+ *
71
81
  * The alternative was a surface-scoped `--cg-primary-tint`, and it fails on the
72
82
  * panel for a measured reason the token file already records: a white wash over
73
83
  * the brand purple gives white text 4.31:1, under the floor, and white is the
@@ -87,6 +97,24 @@ import { cn } from "../lib/cloudgrid-cn.js";
87
97
  * the obvious reach and it is lavender at `:root` only, so a hovered row on the
88
98
  * purple panel would have been white text on near-white.
89
99
  */
100
+ /**
101
+ * A row's box, and a collapsible group's header, which sits in the column and
102
+ * looks like one. Figma 7414:5979 (#377): 12 vertical and 20 horizontal, a 12px
103
+ * gap, radius 12, Manrope Medium 15; with the 20px glyph that makes a 44px row.
104
+ *
105
+ * The frame's `leading-none` stays on the row, but the LABEL span sets a 20px
106
+ * line box (`leading-5`). It is `truncate`, which is `overflow: hidden`, and a
107
+ * 15px box clips Manrope's descenders: the g in Billing, the y in Activity
108
+ * (measured scrollHeight 18 against clientHeight 15 on #380). The Figma text
109
+ * node does not clip, so its `leading-none` does not carry over to the label.
110
+ */
111
+ const ROW = cn("flex w-full items-center gap-3 rounded-md px-5 py-3 text-left font-ui text-body-sm leading-none font-medium no-underline", "transition-colors focus-visible:ring-3 focus-visible:ring-ring focus-visible:outline-none");
112
+ /**
113
+ * The 20px glyph box. It sizes the caller's svg as well as itself, so a mark
114
+ * passed with a `size-4` of its own (the Console's, today) still draws at the
115
+ * frame's 20px rather than sitting small inside a 20px box.
116
+ */
117
+ const GLYPH = "flex size-5 shrink-0 items-center justify-center [&>svg]:size-5";
90
118
  /** Rows and group headers, in the order the column draws them. */
91
119
  const ROW_SELECTOR = '[data-slot="side-nav-item"],[data-slot="side-nav-group-header"]';
92
120
  /**
@@ -123,7 +151,7 @@ function SideNav({ label, context, className, children, onKeyDown, ...props }) {
123
151
  // text-ink because text does not flip by inheritance: without it every
124
152
  // row inside a panel would inherit the page's dark ink and stay dark on
125
153
  // purple.
126
- className: cn("flex w-full flex-col gap-6 text-ink", className), ...props, children: [context ? (_jsx("div", { "data-slot": "side-nav-context", className: "px-3 text-caption text-faint", children: context })) : null, children] }));
154
+ className: cn("flex w-full flex-col gap-6 text-ink", className), ...props, children: [context ? (_jsx("div", { "data-slot": "side-nav-context", className: "px-5 text-caption text-faint", children: context })) : null, children] }));
127
155
  }
128
156
  function SideNavGroup({ label, icon, collapsible, open, defaultOpen = false, onOpenChange, className, children, ...props }) {
129
157
  const panelId = React.useId();
@@ -157,9 +185,9 @@ function SideNavGroup({ label, icon, collapsible, open, defaultOpen = false, onO
157
185
  // step is one edit in eyebrow.tsx. Caps and the caption size are this
158
186
  // frame's treatment of it, which is what `className` is for — see the
159
187
  // eyebrow's own note on not being uppercase by default.
160
- _jsx(Eyebrow, { className: "px-3 text-caption uppercase", children: label })) : null, rows] }));
188
+ _jsx(Eyebrow, { className: "px-5 text-caption uppercase", children: label })) : null, rows] }));
161
189
  }
162
- return (_jsxs("div", { "data-slot": "side-nav-group", "data-collapsible": "", "data-open": isOpen ? "" : undefined, className: cn("flex flex-col gap-0.5", className), ...props, children: [_jsxs("button", { type: "button", "data-slot": "side-nav-group-header", "aria-expanded": isOpen, "aria-controls": panelId, onClick: toggle, className: cn("flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-body-sm text-body", "transition-colors hover:bg-(--cg-hover) hover:text-ink", "focus-visible:ring-3 focus-visible:ring-ring focus-visible:outline-none"), children: [icon ? (_jsx("span", { "data-slot": "side-nav-icon", className: "flex size-4 shrink-0 items-center justify-center", children: icon })) : null, _jsx("span", { className: "min-w-0 flex-1 truncate", children: label }), _jsx(ChevronDownIcon
190
+ return (_jsxs("div", { "data-slot": "side-nav-group", "data-collapsible": "", "data-open": isOpen ? "" : undefined, className: cn("flex flex-col gap-0.5", className), ...props, children: [_jsxs("button", { type: "button", "data-slot": "side-nav-group-header", "aria-expanded": isOpen, "aria-controls": panelId, onClick: toggle, className: cn(ROW, "text-ink hover:bg-(--cg-hover)"), children: [icon ? (_jsx("span", { "data-slot": "side-nav-icon", className: cn(GLYPH, "text-steel in-data-[cg-surface=panel]:text-faint in-data-[cg-surface=ink]:text-faint"), children: icon })) : null, _jsx("span", { className: "min-w-0 flex-1 truncate leading-5", children: label }), _jsx(ChevronDownIcon
163
191
  // The caret is the only thing in this block that moves. It rotates
164
192
  // rather than swapping to a second glyph, so the direction it points
165
193
  // is continuous with the panel opening under it.
@@ -169,7 +197,7 @@ function SideNavGroup({ label, icon, collapsible, open, defaultOpen = false, onO
169
197
  // is continuous with the panel opening under it.
170
198
  className: cn("size-4 shrink-0 transition-transform duration-[var(--cg-duration)] ease-out", isOpen ? "rotate-0" : "-rotate-90") })] }), _jsx("div", { id: panelId, hidden: !isOpen, className: isOpen ? "pl-3" : undefined, children: rows })] }));
171
199
  }
172
- function SideNavItem({ label, icon, count, active, render, className, onKeyDown, ...props }) {
200
+ function SideNavItem({ label, icon, activeIcon, count, active, render, className, onKeyDown, ...props }) {
173
201
  function handleKeyDown(event) {
174
202
  onKeyDown?.(event);
175
203
  if (event.defaultPrevented)
@@ -184,6 +212,7 @@ function SideNavItem({ label, icon, count, active, render, className, onKeyDown,
184
212
  event.preventDefault();
185
213
  el.click();
186
214
  }
215
+ const glyph = active && activeIcon ? activeIcon : icon;
187
216
  return useRender({
188
217
  render,
189
218
  defaultTagName: "button",
@@ -197,16 +226,21 @@ function SideNavItem({ label, icon, count, active, render, className, onKeyDown,
197
226
  // and `render={<Link />}` is the common case.
198
227
  ...(render ? {} : { type: "button" }),
199
228
  onKeyDown: handleKeyDown,
200
- className: cn("flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-body-sm no-underline", "transition-colors focus-visible:ring-3 focus-visible:ring-ring focus-visible:outline-none", active
229
+ className: cn(ROW, active
201
230
  ? // The self-contained chip. See the module note for the numbers and
202
- // for why it is the same two values on all three surfaces.
203
- "bg-brand-tint font-medium text-brand"
204
- : "text-body hover:bg-(--cg-hover) hover:text-ink", className),
231
+ // for why it is the same two values on all three surfaces. The
232
+ // label is the :root ink, not `text-ink`, which flips to white
233
+ // inside a panel while the chip under it does not.
234
+ "bg-brand-tint text-(--cg-neutral-900)"
235
+ : "text-ink hover:bg-(--cg-hover)", className),
205
236
  // The row's content is composed from the three slots rather than taken as
206
237
  // `children`, which is why `children` is omitted from the props type: a
207
238
  // caller who could pass both would have two ways to fill one row and no
208
239
  // rule about which wins.
209
- children: (_jsxs(_Fragment, { children: [icon ? (_jsx("span", { "data-slot": "side-nav-icon", className: "flex size-4 shrink-0 items-center justify-center", children: icon })) : null, _jsx("span", { className: "min-w-0 flex-1 truncate", children: label }), count === undefined ? null : (_jsx("span", { "data-slot": "side-nav-count",
240
+ children: (_jsxs(_Fragment, { children: [glyph ? (_jsx("span", { "data-slot": "side-nav-icon", className: cn(GLYPH, active
241
+ ? "text-brand"
242
+ : // N3, and the surface's own muted text where N3 vanishes.
243
+ "text-steel in-data-[cg-surface=panel]:text-faint in-data-[cg-surface=ink]:text-faint"), children: glyph })) : null, _jsx("span", { className: "min-w-0 flex-1 truncate leading-5", children: label }), count === undefined ? null : (_jsx("span", { "data-slot": "side-nav-count",
210
244
  // The wash again, for the reason the hover uses it: a pale grey
211
245
  // pill named `bg-raised` is neutral-50 at :root only, so it would
212
246
  // be a near-white pill on the purple panel.
@@ -1 +1 @@
1
- {"version":3,"file":"side-nav.js","sourceRoot":"","sources":["../../src/blocks/side-nav.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"side-nav.js","sourceRoot":"","sources":["../../src/blocks/side-nav.tsx"],"names":[],"mappings":"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"}
@@ -88,7 +88,25 @@ export type StatHintTone = "neutral" | "positive";
88
88
  type StatTileIcon = React.ComponentType<{
89
89
  className?: string;
90
90
  }>;
91
- declare function StatTile({ label, value, hint, hintTone, pending, icon: Icon, valueFirst, example, className, ...props }: Omit<React.ComponentProps<"div">, "ref" | "children"> & {
91
+ /**
92
+ * ## `tone`, the Home tile (#382, spec §4.2, Figma 4964:4905)
93
+ *
94
+ * The App page's KPI tile puts a purple mark on a violet square. The 2026 Home
95
+ * draws the same arrangement in neutrals: a slate glyph on a page-coloured
96
+ * square, the number in Manrope Medium 24 (not the display face), the card
97
+ * rounded at 12 rather than 16, and 16 by 24 of padding with the hairline drawn
98
+ * inside it, so the tile is the frame's 79 tall.
99
+ *
100
+ * `brand` is the default and is the 0.39 tile exactly. `tone` only changes a
101
+ * tile that has an `icon`: without one there is no square to retone.
102
+ *
103
+ * The label stays on `--cg-text-muted-strong`, not the frame's slate-500:
104
+ * #828C98 is 3.41:1 on white, and a label is content (#232). So the neutral tile
105
+ * does not take the brand tile's ink label either; it reads muted, as drawn,
106
+ * at the rung that clears AA.
107
+ */
108
+ export type StatTileTone = "brand" | "neutral";
109
+ declare function StatTile({ label, value, hint, hintTone, pending, icon: Icon, valueFirst, example, tone, className, ...props }: Omit<React.ComponentProps<"div">, "ref" | "children"> & {
92
110
  /** Names the metric. Small and muted, above the value. */
93
111
  label: React.ReactNode;
94
112
  /** The measurement. Ignored when `pending`. */
@@ -104,6 +122,8 @@ declare function StatTile({ label, value, hint, hintTone, pending, icon: Icon, v
104
122
  valueFirst?: boolean;
105
123
  /** The values are illustrative: set them muted. Pair with a ComingSoonTag on the card. */
106
124
  example?: boolean;
125
+ /** The icon square's palette: the App page's brand violet, or Home's neutrals. */
126
+ tone?: StatTileTone;
107
127
  }): React.JSX.Element;
108
128
  declare function StatTileRow({ className, children, ...props }: Omit<React.ComponentProps<"div">, "ref">): React.JSX.Element;
109
129
  export { StatTile, StatTileRow };
@@ -1 +1 @@
1
- {"version":3,"file":"stat-tile.d.ts","sourceRoot":"","sources":["../../src/blocks/stat-tile.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,iGAAiG;AACjG,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,CAAA;AAWjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,KAAK,YAAY,GAAG,KAAK,CAAC,aAAa,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAE/D,iBAAS,QAAQ,CAAC,EAChB,KAAK,EACL,KAAK,EACL,IAAI,EACJ,QAAoB,EACpB,OAAO,EACP,IAAI,EAAE,IAAI,EACV,UAAU,EACV,OAAO,EACP,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,GAAG;IACzD,0DAA0D;IAC1D,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,qEAAqE;IACrE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kFAAkF;IAClF,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,qBAsFA;AAsBD,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,qBAiB1C;AAcD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"stat-tile.d.ts","sourceRoot":"","sources":["../../src/blocks/stat-tile.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,iGAAiG;AACjG,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,CAAA;AAWjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,KAAK,YAAY,GAAG,KAAK,CAAC,aAAa,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAE/D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,CAAA;AAE9C,iBAAS,QAAQ,CAAC,EAChB,KAAK,EACL,KAAK,EACL,IAAI,EACJ,QAAoB,EACpB,OAAO,EACP,IAAI,EAAE,IAAI,EACV,UAAU,EACV,OAAO,EACP,IAAc,EACd,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,GAAG;IACzD,0DAA0D;IAC1D,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,qEAAqE;IACrE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kFAAkF;IAClF,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kFAAkF;IAClF,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB,qBA+FA;AAsBD,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,qBAiB1C;AAcD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAA"}
@@ -9,21 +9,24 @@ const HINT_TONE = {
9
9
  neutral: "text-faint-strong",
10
10
  positive: "text-online-strong",
11
11
  };
12
- function StatTile({ label, value, hint, hintTone = "neutral", pending, icon: Icon, valueFirst, example, className, ...props }) {
12
+ function StatTile({ label, value, hint, hintTone = "neutral", pending, icon: Icon, valueFirst, example, tone = "brand", className, ...props }) {
13
13
  const muted = example && !pending;
14
14
  const kpi = Icon !== undefined;
15
+ const neutral = kpi && tone === "neutral";
15
16
  const order = kpi || valueFirst ? "value-first" : undefined;
16
17
  const labelNode = (_jsx("span", { "data-slot": "stat-tile-label", className: "text-caption text-faint-strong", children: label }));
17
18
  const valueNode = (_jsx("span", { "data-slot": "stat-tile-value", "data-pending": pending ? "" : undefined, className: cn(
18
19
  // The KPI tile's value is the 24px title rung, whose own leading is
19
20
  // tight; spelled as a separate string rather than an override, so no
20
21
  // merge has to decide between two leadings.
21
- kpi
22
- ? "font-display text-title-24 font-medium tabular-nums"
23
- : "font-display text-display-sm leading-display font-medium tabular-nums", pending && "text-faint", muted && "text-faint-strong"), children: pending ? "Coming soon" : value }));
22
+ neutral
23
+ ? "font-ui text-title-24 leading-none font-medium tabular-nums"
24
+ : kpi
25
+ ? "font-display text-title-24 font-medium tabular-nums"
26
+ : "font-display text-display-sm leading-display font-medium tabular-nums", pending && "text-faint", muted && "text-faint-strong"), children: pending ? "Coming soon" : value }));
24
27
  const hintNode = hint ? (_jsx("span", { "data-slot": "stat-tile-hint", "data-tone": hintTone, className: cn("text-caption", HINT_TONE[hintTone]), children: hint })) : null;
25
28
  const lines = order ? (_jsxs(_Fragment, { children: [valueNode, labelNode, hintNode] })) : (_jsxs(_Fragment, { children: [labelNode, valueNode, hintNode] }));
26
- return (_jsx("div", { "data-slot": "stat-tile", "data-pending": pending ? "" : undefined, "data-example": muted ? "" : undefined, "data-order": order, "data-icon": kpi ? "" : undefined,
29
+ return (_jsx("div", { "data-slot": "stat-tile", "data-pending": pending ? "" : undefined, "data-example": muted ? "" : undefined, "data-order": order, "data-icon": kpi ? "" : undefined, "data-tone": neutral ? "neutral" : undefined,
27
30
  // text-ink on the root, because text does not flip by inheritance
28
31
  // (rule 3): without it a tile inside a panel inherits the page's dark ink
29
32
  // and its value stays dark on purple.
@@ -33,7 +36,9 @@ function StatTile({ label, value, hint, hintTone = "neutral", pending, icon: Ico
33
36
  // In the KPI tile the label captions a value that leads: ink, as drawn.
34
37
  // Set from the root so the label keeps its one class string (#232's
35
38
  // guardrail pins it).
36
- kpi && !muted && "**:data-[slot=stat-tile-label]:text-ink", className), ...props, children: kpi ? (_jsxs(_Fragment, { children: [_jsx("span", { "data-slot": "stat-tile-icon", "aria-hidden": "true", className: "flex size-10 shrink-0 items-center justify-center rounded-xl bg-brand-100 text-brand", children: _jsx(Icon, { className: "size-6" }) }), _jsx("div", { className: "flex min-w-0 flex-col gap-1", children: lines })] })) : (lines) }));
39
+ kpi && !neutral && !muted && "**:data-[slot=stat-tile-label]:text-ink",
40
+ // Home's tile: radius 12, and 16 by 24 less the hairline it draws inside.
41
+ neutral && "rounded-md px-[23px] py-[15px]", className), ...props, children: kpi ? (_jsxs(_Fragment, { children: [_jsx("span", { "data-slot": "stat-tile-icon", "aria-hidden": "true", className: cn("flex size-10 shrink-0 items-center justify-center", neutral ? "rounded-md bg-page text-steel" : "rounded-xl bg-brand-100 text-brand"), children: _jsx(Icon, { className: "size-6" }) }), _jsx("div", { className: "flex min-w-0 flex-col gap-1", children: lines })] })) : (lines) }));
37
42
  }
38
43
  /**
39
44
  * A row of tiles: two, three or four, side by side, stacking as the column
@@ -1 +1 @@
1
- {"version":3,"file":"stat-tile.js","sourceRoot":"","sources":["../../src/blocks/stat-tile.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stat-tile.js","sourceRoot":"","sources":["../../src/blocks/stat-tile.tsx"],"names":[],"mappings":"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"}
package/dist/console.css CHANGED
@@ -1,28 +1,69 @@
1
1
  /*
2
2
  A PRODUCT PRESET, not a theme and not a second brand.
3
3
 
4
- The Console's type is the UI face, Manrope, for body and for display. This
5
- file states that in the library, so the Console does not carry a font stack of
6
- its own. ui#250, 2026-09-20.
4
+ The Console's body type is the UI face, Manrope; its headlines are the
5
+ display face, Tanker. This file states that in the library, so the Console
6
+ does not carry a font stack of its own. ui#250, 2026-09-20; revised by ui#371,
7
+ 2026-11-01.
7
8
 
8
- Two declarations, and deliberately nothing else: no colour, no spacing, no
9
+ One declaration, and deliberately nothing else: no colour, no spacing, no
9
10
  size, no component. A preset that grew a second concern would become a theme,
10
11
  and this package has one brand.
11
12
 
13
+ THE SOURCE. The CloudGrid 2026 Figma (file 5ouhISIL0mwYGHurvCGoEO), its text
14
+ variables as read on 2026-11-01:
15
+
16
+ Body Manrope Regular 15 / 1.46
17
+ Body Bold Manrope SemiBold 15 / 1.46
18
+ Small Manrope Regular 13 / 1.46
19
+ H4 Manrope Medium 22 / 1.2
20
+ fontHeadline Tanker (the Profile name; the Plugged popup's
21
+ headline, node 11324:93350, 46 / 1.2)
22
+
12
23
  WHY IT EXISTS. #243 moved --cg-font-body to Space Grotesk and --cg-font-display
13
24
  to Tanker, measured against the six canonical marketing frames, and that is
14
- correct for the marketing site. The Console deleted its own @theme font
15
- forwards (console#652) and inherits every family from here, so installing
16
- 0.28.0 changed every face in it at once. The marketing default is untouched by
17
- this file; the Console imports it and gets back exactly the two values both
18
- tokens held before ef8dc00.
25
+ correct for the marketing site. The Console inherits every family from here
26
+ (its own @theme font forwards were deleted in console#652), so without this
27
+ file every Console paragraph renders in Space Grotesk. The marketing default
28
+ in tokens.css is untouched by this file.
29
+
30
+ WHAT CHANGED IN #371, AND WHY. #250 re-declared BOTH faces as Manrope. Its
31
+ reason for the display half was StatTile: Tanker is an all-caps face, so a
32
+ value such as `15s` or `Coming soon` rendered as `15S` or `COMING SOON`. The
33
+ 2026 Figma settles the display role the other way: its `fontHeadline` is
34
+ Tanker, in the Console as on the site. So this preset no longer touches
35
+ --cg-font-display, and headlines stay Tanker. The StatTile case is now the
36
+ caller's choice of role, not the preset's: a stat value that must read as
37
+ typed uses the body or UI face (`text-stat`, Manrope Medium 32), not the
38
+ display face. Repointing the display role to fix one component would have
39
+ taken every Console headline off the design with it.
40
+
41
+ THE FIVE ROLES, as tokens. A Console page picks a role, not a size. Every
42
+ role below already has a token and a utility; nothing new was added for them.
43
+
44
+ Body text-body-sm --cg-body-sm 15, --cg-body-line 1.46,
45
+ on the body face (this file: Manrope)
46
+ Body Bold text-body-sm font-bold the same, at --cg-weight-bold 600
47
+ Small text-caption --cg-caption 13, --cg-body-line 1.46
48
+ H4 text-heading-lg --cg-heading-lg 22, --cg-heading-line
49
+ font-medium 1.2, at --cg-weight-medium 500, on the
50
+ body face
51
+ Headline font-display the display face, Tanker. The face is
52
+ the role; the size is the page's
53
+ (the title-* and display-* rungs).
54
+ 46 has no rung of its own today.
55
+
56
+ THE TANKER FILE. tokens.css names Tanker in the display stack, but this
57
+ package does not ship the font (ITF Free Font Licence, see fonts.css). A
58
+ consumer that has not declared its own @font-face for Tanker falls through to
59
+ the Manrope stack behind it. The Console declares Tanker itself.
19
60
 
20
61
  WHY var(--cg-font-ui) RATHER THAN THE STACK. --cg-font-ui is already the
21
62
  Manrope stack, and its docblock in tokens.css records that its value is
22
63
  --cg-font-body's previous value byte for byte. Aliasing keeps one copy of the
23
64
  fallback chain in the package. A consumer that spelled the stack out instead
24
- went stale the moment the library's fallbacks moved — cloudgrid-landing PR
25
- #132 did exactly that with the display stack — and a copy one repo further
65
+ went stale the moment the library's fallbacks moved (cloudgrid-landing PR
66
+ #132 did exactly that with the display stack), and a copy one repo further
26
67
  away goes stale the same way.
27
68
 
28
69
  IMPORT ORDER. After tokens.css, which is what it re-declares. Where it sits
@@ -50,18 +91,13 @@
50
91
  Three selectors is a cheaper price than that failure, and
51
92
  test/console-preset.test.mjs pins it.
52
93
 
53
- WHO IMPORTS IT. The Console first. Any product whose type is the UI face
54
- rather than the display face imports the same file; nothing here is named for
55
- the Console except this sentence.
56
-
57
- SIDE EFFECT WORTH KNOWING. StatTile values read as typed again. Tanker is an
58
- all-caps face, so `15s` and `Coming soon` rendered as `15S` and `COMING SOON`
59
- under the marketing display token. No component changed to fix that.
94
+ WHO IMPORTS IT. The Console first. Any product whose body type is the UI face
95
+ imports the same file; nothing here is named for the Console except this
96
+ sentence.
60
97
  */
61
98
 
62
99
  :root,
63
100
  [data-cg-surface='panel'],
64
101
  [data-cg-surface='ink'] {
65
102
  --cg-font-body: var(--cg-font-ui);
66
- --cg-font-display: var(--cg-font-ui);
67
103
  }