@cloudgrid-io/ui 0.27.1 → 0.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocks/icons.d.ts +1 -1
- package/dist/blocks/icons.d.ts.map +1 -1
- package/dist/blocks/icons.js +13 -1
- package/dist/blocks/icons.js.map +1 -1
- package/dist/blocks/side-nav.d.ts +49 -0
- package/dist/blocks/side-nav.d.ts.map +1 -0
- package/dist/blocks/side-nav.js +217 -0
- package/dist/blocks/side-nav.js.map +1 -0
- package/dist/blocks/stat-tile.d.ts +69 -0
- package/dist/blocks/stat-tile.d.ts.map +1 -0
- package/dist/blocks/stat-tile.js +54 -0
- package/dist/blocks/stat-tile.js.map +1 -0
- package/dist/blocks/tool-setup.d.ts +105 -4
- package/dist/blocks/tool-setup.d.ts.map +1 -1
- package/dist/blocks/tool-setup.js +238 -13
- package/dist/blocks/tool-setup.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/ui/popover.d.ts +83 -0
- package/dist/ui/popover.d.ts.map +1 -0
- package/dist/ui/popover.js +102 -0
- package/dist/ui/popover.js.map +1 -0
- package/dist/ui/radio-group.d.ts +21 -0
- package/dist/ui/radio-group.d.ts.map +1 -0
- package/dist/ui/radio-group.js +101 -0
- package/dist/ui/radio-group.js.map +1 -0
- package/package.json +1 -1
package/dist/blocks/icons.d.ts
CHANGED
|
@@ -338,7 +338,7 @@ export { SparkleMark as AiIcon, DatabaseMark as DatabaseIcon, HardDriveMark as S
|
|
|
338
338
|
/** The rest: glyphs an onboarding question or a sign-in method reaches for. */
|
|
339
339
|
export { UserMark as PersonIcon, EnvelopeMark as EmailIcon, MagnifyingGlassMark as SearchIcon, MegaphoneSimpleMark as AdIcon, StackMark as LayersIcon, ChartPieSliceMark as DashboardIcon, } from "./phosphor-marks.js";
|
|
340
340
|
/** Navigation: the shell's own furniture — a rail, a tab bar, a top bar. */
|
|
341
|
-
export { HouseSimpleMark as HomeIcon, PulseMark as ActivityIcon, CompassMark as DiscoverIcon, ArrowsLeftRightMark as SwitchGridIcon, GridFourMark as SpaceIcon, ListMark as MenuIcon, SidebarSimpleMark as SidebarToggleIcon, BellMark as NotificationsIcon, SignOutMark as SignOutIcon, CaretLeftMark as BackIcon, ArrowRightMark as ForwardIcon, } from "./phosphor-marks.js";
|
|
341
|
+
export { HouseSimpleMark as HomeIcon, PulseMark as ActivityIcon, CompassMark as DiscoverIcon, ArrowsLeftRightMark as SwitchGridIcon, GridFourMark as SpaceIcon, ListMark as MenuIcon, SidebarSimpleMark as SidebarToggleIcon, BellMark as NotificationsIcon, SignOutMark as SignOutIcon, CaretLeftMark as BackIcon, ArrowRightMark as ForwardIcon, GridFourMark as OverviewIcon, } from "./phosphor-marks.js";
|
|
342
342
|
/** Actions a row, a card kebab or a detail header offers. */
|
|
343
343
|
export { PencilSimpleMark as EditIcon, TrashMark as DeleteIcon, PushPinMark as PinIcon, ArrowsClockwiseMark as RefreshIcon, DownloadSimpleMark as DownloadIcon, FileTextMark as DocumentIcon, ArrowUpMark as SortAscendingIcon, ArrowDownMark as SortDescendingIcon, } from "./phosphor-marks.js";
|
|
344
344
|
/** Access, and the people it is about. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/blocks/icons.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyUG;AAEH,OAAO,EACL,QAAQ,IAAI,aAAa,EACzB,qBAAqB,IAAI,mBAAmB,EAC5C,UAAU,IAAI,WAAW,EACzB,gBAAgB,IAAI,YAAY,EAChC,eAAe,IAAI,mBAAmB,EACtC,WAAW,IAAI,YAAY,EAC3B,OAAO,IAAI,SAAS,EACpB,cAAc,IAAI,YAAY,EAC9B,WAAW,IAAI,QAAQ,EACvB,qBAAqB,IAAI,eAAe,GACzC,MAAM,8BAA8B,CAAA;AAErC,wEAAwE;AACxE,OAAO,EACL,aAAa,IAAI,eAAe,EAChC,WAAW,IAAI,aAAa,EAC5B,cAAc,IAAI,gBAAgB,EAClC,aAAa,IAAI,eAAe,EAChC,SAAS,IAAI,SAAS,EACtB,aAAa,IAAI,aAAa,EAC9B,KAAK,IAAI,SAAS,EAClB,QAAQ,IAAI,QAAQ,EACpB,SAAS,IAAI,SAAS,EACtB,QAAQ,IAAI,QAAQ,EACpB,aAAa,IAAI,aAAa,GAC/B,MAAM,8BAA8B,CAAA;AAErC,mDAAmD;AACnD,OAAO,EACL,eAAe,IAAI,WAAW,EAC9B,QAAQ,IAAI,QAAQ,EACpB,WAAW,IAAI,WAAW,EAC1B,kBAAkB,IAAI,SAAS,EAC/B,eAAe,IAAI,WAAW,EAC9B,eAAe,IAAI,YAAY,EAC/B,WAAW,IAAI,eAAe,GAC/B,MAAM,8BAA8B,CAAA;AAErC,qDAAqD;AACrD,OAAO,EACL,WAAW,IAAI,MAAM,EACrB,YAAY,IAAI,YAAY,EAC5B,aAAa,IAAI,WAAW,EAC5B,SAAS,IAAI,UAAU,EACvB,SAAS,IAAI,OAAO,EACpB,OAAO,IAAI,UAAU,EACrB,SAAS,IAAI,YAAY,EACzB,SAAS,IAAI,UAAU,EACvB,aAAa,IAAI,QAAQ,EACzB,QAAQ,IAAI,QAAQ,GACrB,MAAM,8BAA8B,CAAA;AAErC,+EAA+E;AAC/E,OAAO,EACL,QAAQ,IAAI,UAAU,EACtB,YAAY,IAAI,SAAS,EACzB,mBAAmB,IAAI,UAAU,EACjC,mBAAmB,IAAI,MAAM,EAC7B,SAAS,IAAI,UAAU,EACvB,iBAAiB,IAAI,aAAa,GACnC,MAAM,8BAA8B,CAAA;AAErC,4EAA4E;AAC5E,OAAO,EACL,eAAe,IAAI,QAAQ,EAC3B,SAAS,IAAI,YAAY,EACzB,WAAW,IAAI,YAAY,EAC3B,mBAAmB,IAAI,cAAc,EACrC,YAAY,IAAI,SAAS,EACzB,QAAQ,IAAI,QAAQ,EACpB,iBAAiB,IAAI,iBAAiB,EACtC,QAAQ,IAAI,iBAAiB,EAC7B,WAAW,IAAI,WAAW,EAC1B,aAAa,IAAI,QAAQ,EACzB,cAAc,IAAI,WAAW,
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/blocks/icons.tsx"],"names":[],"mappings":"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"}
|
package/dist/blocks/icons.js
CHANGED
|
@@ -338,7 +338,19 @@ export { SparkleMark as AiIcon, DatabaseMark as DatabaseIcon, HardDriveMark as S
|
|
|
338
338
|
/** The rest: glyphs an onboarding question or a sign-in method reaches for. */
|
|
339
339
|
export { UserMark as PersonIcon, EnvelopeMark as EmailIcon, MagnifyingGlassMark as SearchIcon, MegaphoneSimpleMark as AdIcon, StackMark as LayersIcon, ChartPieSliceMark as DashboardIcon, } from "./phosphor-marks.js";
|
|
340
340
|
/** Navigation: the shell's own furniture — a rail, a tab bar, a top bar. */
|
|
341
|
-
export { HouseSimpleMark as HomeIcon, PulseMark as ActivityIcon, CompassMark as DiscoverIcon, ArrowsLeftRightMark as SwitchGridIcon, GridFourMark as SpaceIcon, ListMark as MenuIcon, SidebarSimpleMark as SidebarToggleIcon, BellMark as NotificationsIcon, SignOutMark as SignOutIcon, CaretLeftMark as BackIcon, ArrowRightMark as ForwardIcon,
|
|
341
|
+
export { HouseSimpleMark as HomeIcon, PulseMark as ActivityIcon, CompassMark as DiscoverIcon, ArrowsLeftRightMark as SwitchGridIcon, GridFourMark as SpaceIcon, ListMark as MenuIcon, SidebarSimpleMark as SidebarToggleIcon, BellMark as NotificationsIcon, SignOutMark as SignOutIcon, CaretLeftMark as BackIcon, ArrowRightMark as ForwardIcon,
|
|
342
|
+
// The same glyph as `SpaceIcon`, under a second role name, and deliberately
|
|
343
|
+
// not a rename of it (#225). `grid-four` is what the app page's sidebar draws
|
|
344
|
+
// on its Overview row, and `SpaceIcon` is the name a GRID wears in the
|
|
345
|
+
// console's own shell — one is a destination inside a thing, the other is the
|
|
346
|
+
// thing. Writing `SpaceIcon` on an app's Overview row would teach a reader of
|
|
347
|
+
// the call site that the two are the same idea.
|
|
348
|
+
//
|
|
349
|
+
// The `SaveIcon` / `PinIcon` precedent (#200), applied: a duplicate costs a
|
|
350
|
+
// paragraph, and deleting a name is the one move that breaks every consumer
|
|
351
|
+
// at once. Both are pinned in icon-surface.test.mjs so the paragraph cannot
|
|
352
|
+
// quietly stop being true.
|
|
353
|
+
GridFourMark as OverviewIcon, } from "./phosphor-marks.js";
|
|
342
354
|
/** Actions a row, a card kebab or a detail header offers. */
|
|
343
355
|
export { PencilSimpleMark as EditIcon, TrashMark as DeleteIcon, PushPinMark as PinIcon, ArrowsClockwiseMark as RefreshIcon, DownloadSimpleMark as DownloadIcon, FileTextMark as DocumentIcon, ArrowUpMark as SortAscendingIcon, ArrowDownMark as SortDescendingIcon, } from "./phosphor-marks.js";
|
|
344
356
|
/** Access, and the people it is about. */
|
package/dist/blocks/icons.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.js","sourceRoot":"","sources":["../../src/blocks/icons.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyUG;AAEH,OAAO,EACL,QAAQ,IAAI,aAAa,EACzB,qBAAqB,IAAI,mBAAmB,EAC5C,UAAU,IAAI,WAAW,EACzB,gBAAgB,IAAI,YAAY,EAChC,eAAe,IAAI,mBAAmB,EACtC,WAAW,IAAI,YAAY,EAC3B,OAAO,IAAI,SAAS,EACpB,cAAc,IAAI,YAAY,EAC9B,WAAW,IAAI,QAAQ,EACvB,qBAAqB,IAAI,eAAe,GACzC,MAAM,8BAA8B,CAAA;AAErC,wEAAwE;AACxE,OAAO,EACL,aAAa,IAAI,eAAe,EAChC,WAAW,IAAI,aAAa,EAC5B,cAAc,IAAI,gBAAgB,EAClC,aAAa,IAAI,eAAe,EAChC,SAAS,IAAI,SAAS,EACtB,aAAa,IAAI,aAAa,EAC9B,KAAK,IAAI,SAAS,EAClB,QAAQ,IAAI,QAAQ,EACpB,SAAS,IAAI,SAAS,EACtB,QAAQ,IAAI,QAAQ,EACpB,aAAa,IAAI,aAAa,GAC/B,MAAM,8BAA8B,CAAA;AAErC,mDAAmD;AACnD,OAAO,EACL,eAAe,IAAI,WAAW,EAC9B,QAAQ,IAAI,QAAQ,EACpB,WAAW,IAAI,WAAW,EAC1B,kBAAkB,IAAI,SAAS,EAC/B,eAAe,IAAI,WAAW,EAC9B,eAAe,IAAI,YAAY,EAC/B,WAAW,IAAI,eAAe,GAC/B,MAAM,8BAA8B,CAAA;AAErC,qDAAqD;AACrD,OAAO,EACL,WAAW,IAAI,MAAM,EACrB,YAAY,IAAI,YAAY,EAC5B,aAAa,IAAI,WAAW,EAC5B,SAAS,IAAI,UAAU,EACvB,SAAS,IAAI,OAAO,EACpB,OAAO,IAAI,UAAU,EACrB,SAAS,IAAI,YAAY,EACzB,SAAS,IAAI,UAAU,EACvB,aAAa,IAAI,QAAQ,EACzB,QAAQ,IAAI,QAAQ,GACrB,MAAM,8BAA8B,CAAA;AAErC,+EAA+E;AAC/E,OAAO,EACL,QAAQ,IAAI,UAAU,EACtB,YAAY,IAAI,SAAS,EACzB,mBAAmB,IAAI,UAAU,EACjC,mBAAmB,IAAI,MAAM,EAC7B,SAAS,IAAI,UAAU,EACvB,iBAAiB,IAAI,aAAa,GACnC,MAAM,8BAA8B,CAAA;AAErC,4EAA4E;AAC5E,OAAO,EACL,eAAe,IAAI,QAAQ,EAC3B,SAAS,IAAI,YAAY,EACzB,WAAW,IAAI,YAAY,EAC3B,mBAAmB,IAAI,cAAc,EACrC,YAAY,IAAI,SAAS,EACzB,QAAQ,IAAI,QAAQ,EACpB,iBAAiB,IAAI,iBAAiB,EACtC,QAAQ,IAAI,iBAAiB,EAC7B,WAAW,IAAI,WAAW,EAC1B,aAAa,IAAI,QAAQ,EACzB,cAAc,IAAI,WAAW,
|
|
1
|
+
{"version":3,"file":"icons.js","sourceRoot":"","sources":["../../src/blocks/icons.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
declare function SideNav({ label, context, className, children, onKeyDown, ...props }: Omit<React.ComponentProps<"nav">, "ref"> & {
|
|
4
|
+
/**
|
|
5
|
+
* Names the landmark. Required, not optional: a page with two `<nav>`s and no
|
|
6
|
+
* names gives a screen-reader user two identical "navigation" entries and no
|
|
7
|
+
* way to tell the app's sidebar from the site's header.
|
|
8
|
+
*/
|
|
9
|
+
label: string;
|
|
10
|
+
/**
|
|
11
|
+
* The line above the groups. The frame's is "Atomic Labs / chimp-me", and the
|
|
12
|
+
* separator is in there because the caller composes it — this block does not
|
|
13
|
+
* know that a grid contains an app.
|
|
14
|
+
*/
|
|
15
|
+
context?: React.ReactNode;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
declare function SideNavGroup({ label, icon, collapsible, open, defaultOpen, onOpenChange, className, children, ...props }: Omit<React.ComponentProps<"div">, "ref" | "children"> & {
|
|
18
|
+
/** APP, MANAGE, or the header's words when `collapsible`. */
|
|
19
|
+
label?: React.ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* The header's leading glyph, for a collapsible group. A plain group is
|
|
22
|
+
* labelled by an eyebrow and has no glyph, which is what the frames draw.
|
|
23
|
+
*/
|
|
24
|
+
icon?: React.ReactNode;
|
|
25
|
+
collapsible?: boolean;
|
|
26
|
+
/** Controlled. Pass `onOpenChange` with it. */
|
|
27
|
+
open?: boolean;
|
|
28
|
+
/** Uncontrolled starting state. Ignored when `open` is passed. */
|
|
29
|
+
defaultOpen?: boolean;
|
|
30
|
+
onOpenChange?: (open: boolean) => void;
|
|
31
|
+
children?: React.ReactNode;
|
|
32
|
+
}): React.JSX.Element;
|
|
33
|
+
declare function SideNavItem({ label, icon, count, active, render, className, onKeyDown, ...props }: Omit<useRender.ComponentProps<"button">, "children"> & {
|
|
34
|
+
label: React.ReactNode;
|
|
35
|
+
/** 14 to 16px. The row's label is what gets announced, so the glyph carries no name. */
|
|
36
|
+
icon?: React.ReactNode;
|
|
37
|
+
/**
|
|
38
|
+
* The trailing pill. The frame's Feedback row wears a `0`.
|
|
39
|
+
*
|
|
40
|
+
* It renders as text inside the row, so the accessible name becomes
|
|
41
|
+
* "Feedback 0" — the same two pieces of information a sighted reader gets. A
|
|
42
|
+
* caller who needs "Feedback, 0 unread" passes that as `label` and leaves
|
|
43
|
+
* this alone, because only the caller knows what is being counted.
|
|
44
|
+
*/
|
|
45
|
+
count?: number;
|
|
46
|
+
active?: boolean;
|
|
47
|
+
}): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
|
48
|
+
export { SideNav, SideNavGroup, SideNavItem };
|
|
49
|
+
//# sourceMappingURL=side-nav.d.ts.map
|
|
@@ -0,0 +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,qBAqCA;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;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,0EAmEA;AAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { ChevronDownIcon } from "./icons.js";
|
|
6
|
+
import { Eyebrow } from "./eyebrow.js";
|
|
7
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
8
|
+
/**
|
|
9
|
+
* The vertical navigation that stands inside a page box: a context line, a set
|
|
10
|
+
* of labelled groups, and a column of rows one of which is the page you are on.
|
|
11
|
+
*
|
|
12
|
+
* Read from the Console's redesigned app page (ui#225, Figma 8010:385,
|
|
13
|
+
* 8316:2158, 8306:2294). Three roles see three different columns of the same
|
|
14
|
+
* nav — an owner sees APP with `Build & run` collapsed, a grid admin sees it
|
|
15
|
+
* expanded with seven children, a viewer sees APP alone — so the shape that
|
|
16
|
+
* ships is one nav whose groups and rows are handed in, not three sidebars.
|
|
17
|
+
*
|
|
18
|
+
* ## It draws and it behaves. It does not know where anything is
|
|
19
|
+
*
|
|
20
|
+
* The line #117 drew for the entity card, and the reason `render` below exists.
|
|
21
|
+
* This block builds no `href`, matches no route and gates no role. The consumer
|
|
22
|
+
* decides which rows a reader may see, which one is `active`, and what element
|
|
23
|
+
* a row actually is. Anything else would put the Console's URL helpers and its
|
|
24
|
+
* role model inside the design system, where neither can be right for long.
|
|
25
|
+
*
|
|
26
|
+
* ## Three parts, and what each is for
|
|
27
|
+
*
|
|
28
|
+
* `SideNav` the `<nav>` landmark, the context slot, and the keyboard.
|
|
29
|
+
* `SideNavGroup` an eyebrow-labelled run of rows (APP, MANAGE), or a
|
|
30
|
+
* collapsible one with a header of its own (Build & run).
|
|
31
|
+
* `SideNavItem` one row: a glyph, a label, an optional count, and whether
|
|
32
|
+
* it is the page you are on.
|
|
33
|
+
*
|
|
34
|
+
* ## The keyboard
|
|
35
|
+
*
|
|
36
|
+
* Every row is a real tab stop, so Tab walks the column in DOM order. Arrow
|
|
37
|
+
* keys are laid over that rather than replacing it: ArrowDown and ArrowUp move
|
|
38
|
+
* focus between rows and wrap at the ends, which is what a reader who has
|
|
39
|
+
* landed in a 15-row column expects and what Tab alone makes tedious.
|
|
40
|
+
*
|
|
41
|
+
* This is deliberately NOT a roving-tabindex tablist. A tablist owns one tab
|
|
42
|
+
* stop because its tabs are one control; these rows are links to separate
|
|
43
|
+
* pages, and making fourteen of them unreachable by Tab to satisfy a pattern
|
|
44
|
+
* they are not an instance of is a worse nav, not a more correct one.
|
|
45
|
+
*
|
|
46
|
+
* A collapsible group's header is in the same ring as the rows. It sits in the
|
|
47
|
+
* column and looks like a row, so an arrow key that skipped it would strand the
|
|
48
|
+
* one control that reveals six more.
|
|
49
|
+
*
|
|
50
|
+
* Space is handled explicitly, and only where the browser does not. A `<button>`
|
|
51
|
+
* activates on both Enter and Space already; an `<a href>` activates on Enter
|
|
52
|
+
* and SCROLLS THE PAGE on Space. Since a row is normally an anchor — that is
|
|
53
|
+
* what `render={<Link />}` makes it — the nav synthesises the click for Space
|
|
54
|
+
* on anything that is not a button. Doing it unconditionally would fire a
|
|
55
|
+
* button's activation twice, once here and once natively.
|
|
56
|
+
*
|
|
57
|
+
* ## The active row does not flip, and that is the decision
|
|
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.
|
|
63
|
+
*
|
|
64
|
+
* 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
|
|
67
|
+
* 1.16:1 against the white card, 5.02:1 against the panel and 13.68:1 on ink.
|
|
68
|
+
* `packages/ui/test/contrast-guardrail.test.mjs` holds every one of those
|
|
69
|
+
* numbers, and says why the chip's own floor is not 3:1.
|
|
70
|
+
*
|
|
71
|
+
* The alternative was a surface-scoped `--cg-primary-tint`, and it fails on the
|
|
72
|
+
* panel for a measured reason the token file already records: a white wash over
|
|
73
|
+
* the brand purple gives white text 4.31:1, under the floor, and white is the
|
|
74
|
+
* lightest colour there is. AA on a tinted row over that ground needs the FILL
|
|
75
|
+
* to move, which is a brand decision and not this block's.
|
|
76
|
+
*
|
|
77
|
+
* Everything else in the nav does flip: the rows' text, the hover wash, the
|
|
78
|
+
* hairline, the count pill. The root sets `text-ink` because text does not flip
|
|
79
|
+
* by inheritance (rule 3).
|
|
80
|
+
*
|
|
81
|
+
* ## No hover ground you can name
|
|
82
|
+
*
|
|
83
|
+
* The rows hover on `var(--cg-hover)` directly. It is the one token that means
|
|
84
|
+
* "a wash over whatever this sits on" and it is declared in all three scopes;
|
|
85
|
+
* `theme.css` gives it no utility on purpose, because `bg-hover` sits one
|
|
86
|
+
* character from Tailwind's own `hover:` variant. `bg-subtle` would have been
|
|
87
|
+
* the obvious reach and it is lavender at `:root` only, so a hovered row on the
|
|
88
|
+
* purple panel would have been white text on near-white.
|
|
89
|
+
*/
|
|
90
|
+
/** Rows and group headers, in the order the column draws them. */
|
|
91
|
+
const ROW_SELECTOR = '[data-slot="side-nav-item"],[data-slot="side-nav-group-header"]';
|
|
92
|
+
/**
|
|
93
|
+
* The rows a key press can actually reach.
|
|
94
|
+
*
|
|
95
|
+
* Filtered on `getClientRects()` rather than on the DOM, because a closed
|
|
96
|
+
* group's rows stay MOUNTED (see `SideNavGroup`) and a ring that counted them
|
|
97
|
+
* would move focus onto a `display: none` element, which silently drops it to
|
|
98
|
+
* the body.
|
|
99
|
+
*/
|
|
100
|
+
function reachableRows(root) {
|
|
101
|
+
return Array.from(root.querySelectorAll(ROW_SELECTOR)).filter((el) => el.getClientRects().length > 0 && !el.hasAttribute("disabled"));
|
|
102
|
+
}
|
|
103
|
+
function SideNav({ label, context, className, children, onKeyDown, ...props }) {
|
|
104
|
+
function handleKeyDown(event) {
|
|
105
|
+
onKeyDown?.(event);
|
|
106
|
+
if (event.defaultPrevented)
|
|
107
|
+
return;
|
|
108
|
+
const step = event.key === "ArrowDown" ? 1 : event.key === "ArrowUp" ? -1 : 0;
|
|
109
|
+
if (step === 0)
|
|
110
|
+
return;
|
|
111
|
+
const rows = reachableRows(event.currentTarget);
|
|
112
|
+
const from = rows.indexOf(document.activeElement);
|
|
113
|
+
// Not -1 only when focus is already on a row. A key press while focus sits
|
|
114
|
+
// in the context line should scroll the page, as it would anywhere else.
|
|
115
|
+
if (from === -1 || rows.length === 0)
|
|
116
|
+
return;
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
rows[(from + step + rows.length) % rows.length]?.focus();
|
|
119
|
+
}
|
|
120
|
+
return (_jsxs("nav", { "data-slot": "side-nav", "aria-label": label, onKeyDown: handleKeyDown,
|
|
121
|
+
// text-ink because text does not flip by inheritance: without it every
|
|
122
|
+
// row inside a panel would inherit the page's dark ink and stay dark on
|
|
123
|
+
// purple.
|
|
124
|
+
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] }));
|
|
125
|
+
}
|
|
126
|
+
function SideNavGroup({ label, icon, collapsible, open, defaultOpen = false, onOpenChange, className, children, ...props }) {
|
|
127
|
+
const panelId = React.useId();
|
|
128
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultOpen);
|
|
129
|
+
const isControlled = open !== undefined;
|
|
130
|
+
const isOpen = isControlled ? open : uncontrolled;
|
|
131
|
+
function toggle() {
|
|
132
|
+
const next = !isOpen;
|
|
133
|
+
if (!isControlled)
|
|
134
|
+
setUncontrolled(next);
|
|
135
|
+
onOpenChange?.(next);
|
|
136
|
+
}
|
|
137
|
+
const rows = (_jsx("div", { className:
|
|
138
|
+
// The display utility is applied ONLY when open, and that is not a
|
|
139
|
+
// shortcut. The UA's `[hidden] { display: none }` is an author-beatable
|
|
140
|
+
// rule, so a `flex` class on the same element wins it and the panel
|
|
141
|
+
// stays visible while announcing itself collapsed.
|
|
142
|
+
//
|
|
143
|
+
// Tailwind v4's preflight covers for that with
|
|
144
|
+
// `[hidden]:where(:not([hidden='until-found'])) { display: none
|
|
145
|
+
// !important }`, which is why the trap does not bite in this repo's own
|
|
146
|
+
// gallery. It bites in a consumer that takes the theme without the
|
|
147
|
+
// preflight — the Astro surface this registry serves, and anyone who
|
|
148
|
+
// disables it — so the fix belongs in the component rather than in a
|
|
149
|
+
// stylesheet the component does not ship. Same argument as `Eyebrow`'s
|
|
150
|
+
// `m-0`.
|
|
151
|
+
isOpen ? "flex flex-col gap-0.5" : undefined, children: children }));
|
|
152
|
+
if (!collapsible) {
|
|
153
|
+
return (_jsxs("div", { "data-slot": "side-nav-group", className: cn("flex flex-col gap-1", className), ...props, children: [label ? (
|
|
154
|
+
// The library's eyebrow rather than its recipe, so retuning the label
|
|
155
|
+
// step is one edit in eyebrow.tsx. Caps and the caption size are this
|
|
156
|
+
// frame's treatment of it, which is what `className` is for — see the
|
|
157
|
+
// eyebrow's own note on not being uppercase by default.
|
|
158
|
+
_jsx(Eyebrow, { className: "px-3 text-caption uppercase", children: label })) : null, rows] }));
|
|
159
|
+
}
|
|
160
|
+
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
|
|
161
|
+
// The caret is the only thing in this block that moves. It rotates
|
|
162
|
+
// rather than swapping to a second glyph, so the direction it points
|
|
163
|
+
// is continuous with the panel opening under it.
|
|
164
|
+
, {
|
|
165
|
+
// The caret is the only thing in this block that moves. It rotates
|
|
166
|
+
// rather than swapping to a second glyph, so the direction it points
|
|
167
|
+
// is continuous with the panel opening under it.
|
|
168
|
+
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 })] }));
|
|
169
|
+
}
|
|
170
|
+
function SideNavItem({ label, icon, count, active, render, className, onKeyDown, ...props }) {
|
|
171
|
+
function handleKeyDown(event) {
|
|
172
|
+
onKeyDown?.(event);
|
|
173
|
+
if (event.defaultPrevented)
|
|
174
|
+
return;
|
|
175
|
+
// See the module note: Space on an anchor scrolls. Synthesised only for the
|
|
176
|
+
// elements the browser does not already activate, or a button fires twice.
|
|
177
|
+
if (event.key !== " ")
|
|
178
|
+
return;
|
|
179
|
+
const el = event.currentTarget;
|
|
180
|
+
if (el.tagName === "BUTTON")
|
|
181
|
+
return;
|
|
182
|
+
event.preventDefault();
|
|
183
|
+
el.click();
|
|
184
|
+
}
|
|
185
|
+
return useRender({
|
|
186
|
+
render,
|
|
187
|
+
defaultTagName: "button",
|
|
188
|
+
props: {
|
|
189
|
+
"data-slot": "side-nav-item",
|
|
190
|
+
"data-active": active ? "" : undefined,
|
|
191
|
+
// aria-current is what says "this is the page you are on". The tint says
|
|
192
|
+
// it to a reader who can see it, and colour is never the only channel.
|
|
193
|
+
"aria-current": active ? "page" : undefined,
|
|
194
|
+
// Only when this really is a <button>. `type` on an anchor is invalid,
|
|
195
|
+
// and `render={<Link />}` is the common case.
|
|
196
|
+
...(render ? {} : { type: "button" }),
|
|
197
|
+
onKeyDown: handleKeyDown,
|
|
198
|
+
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
|
|
199
|
+
? // The self-contained chip. See the module note for the numbers and
|
|
200
|
+
// for why it is the same two values on all three surfaces.
|
|
201
|
+
"bg-brand-tint font-medium text-brand"
|
|
202
|
+
: "text-body hover:bg-(--cg-hover) hover:text-ink", className),
|
|
203
|
+
// The row's content is composed from the three slots rather than taken as
|
|
204
|
+
// `children`, which is why `children` is omitted from the props type: a
|
|
205
|
+
// caller who could pass both would have two ways to fill one row and no
|
|
206
|
+
// rule about which wins.
|
|
207
|
+
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",
|
|
208
|
+
// The wash again, for the reason the hover uses it: a pale grey
|
|
209
|
+
// pill named `bg-raised` is neutral-50 at :root only, so it would
|
|
210
|
+
// be a near-white pill on the purple panel.
|
|
211
|
+
className: "shrink-0 rounded-pill bg-(--cg-hover) px-2 text-caption text-body", children: count }))] })),
|
|
212
|
+
...props,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
export { SideNav, SideNavGroup, SideNavItem };
|
|
217
|
+
//# sourceMappingURL=side-nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"side-nav.js","sourceRoot":"","sources":["../../src/blocks/side-nav.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* One metric, in a bordered card: a small label, a large value, one line of
|
|
4
|
+
* sub-label under it.
|
|
5
|
+
*
|
|
6
|
+
* Every number on the Console's redesigned app page is this tile (ui#227, Figma
|
|
7
|
+
* 8010:385 and 8036:780) — Views, Time on view, AI tokens, Requests,
|
|
8
|
+
* Deployments, App type — laid out in rows of three or four. The Console
|
|
9
|
+
* hand-rolls the arrangement in `EntityAnalyticsBoard` today and Home keeps a
|
|
10
|
+
* second copy, which is two places for one tile and the reason this exists.
|
|
11
|
+
*
|
|
12
|
+
* ## `value` is a node, and that is load-bearing
|
|
13
|
+
*
|
|
14
|
+
* Six of the eight tiles in the Insights frame carry a number, and the other
|
|
15
|
+
* two carry "Static" and "11 plugs · 0 errors". A tile that took a `number`
|
|
16
|
+
* would have forced the Console to keep its own component for the two that are
|
|
17
|
+
* words, which is the duplication this block is replacing.
|
|
18
|
+
*
|
|
19
|
+
* ## `pending`, so a tile never invents a number
|
|
20
|
+
*
|
|
21
|
+
* The frame's "Time per request" tile reads "Coming soon" in the value's own
|
|
22
|
+
* position, muted, with the hint still saying "Latency". That is the whole
|
|
23
|
+
* state: the metric is real, the reporting is not built, and the tile says so
|
|
24
|
+
* rather than showing a zero that a reader would take for a measurement. The
|
|
25
|
+
* words are this block's rather than the caller's on purpose — one spelling,
|
|
26
|
+
* everywhere it is true.
|
|
27
|
+
*
|
|
28
|
+
* ## The hint's two tones
|
|
29
|
+
*
|
|
30
|
+
* `neutral` is the reporting period ("Last 30 days", "Median", "All time"), and
|
|
31
|
+
* it is the common case. `positive` is the one the frames do not draw and the
|
|
32
|
+
* issue asks for: "+50 this week", growth said in the state palette's own
|
|
33
|
+
* green.
|
|
34
|
+
*
|
|
35
|
+
* It resolves `--cg-online-strong` rather than `--cg-online`. The tone is tuned
|
|
36
|
+
* for a dot and its own note says so — "3.40:1 on white, never body text on
|
|
37
|
+
* white" — while `-strong` is the rung the system added for a status as WORDS
|
|
38
|
+
* and it holds 4.5:1. Inside the panel and ink scopes `-strong` resolves to the
|
|
39
|
+
* surface's own primary text, which is the token file's recorded decision, not
|
|
40
|
+
* a fallback invented here: there is no green on the purple panel that clears
|
|
41
|
+
* AA at any value. So a positive hint on a dark surface reads as the surface's
|
|
42
|
+
* brightest text beside a muted neutral one, which is still a difference a
|
|
43
|
+
* reader can see.
|
|
44
|
+
*
|
|
45
|
+
* No new colour was added for it, per ui#227.
|
|
46
|
+
*
|
|
47
|
+
* ## Type
|
|
48
|
+
*
|
|
49
|
+
* The value takes the display rung and the display face, and deliberately not
|
|
50
|
+
* `PageHeading`'s uppercase and display tracking: those are tuned for a lockup
|
|
51
|
+
* of words. `tabular-nums` because a column of tiles whose digits are
|
|
52
|
+
* proportional jitters when one of them ticks over.
|
|
53
|
+
*/
|
|
54
|
+
/** The hint's tone. `positive` is growth; there is no negative, because the frames draw none. */
|
|
55
|
+
export type StatHintTone = "neutral" | "positive";
|
|
56
|
+
declare function StatTile({ label, value, hint, hintTone, pending, className, ...props }: Omit<React.ComponentProps<"div">, "ref" | "children"> & {
|
|
57
|
+
/** Names the metric. Small and muted, above the value. */
|
|
58
|
+
label: React.ReactNode;
|
|
59
|
+
/** The measurement. Ignored when `pending`. */
|
|
60
|
+
value?: React.ReactNode;
|
|
61
|
+
/** One line under the value: the reporting period, or what moved. */
|
|
62
|
+
hint?: React.ReactNode;
|
|
63
|
+
hintTone?: StatHintTone;
|
|
64
|
+
/** The metric is real and the number is not available yet. */
|
|
65
|
+
pending?: boolean;
|
|
66
|
+
}): React.JSX.Element;
|
|
67
|
+
declare function StatTileRow({ className, children, ...props }: Omit<React.ComponentProps<"div">, "ref">): React.JSX.Element;
|
|
68
|
+
export { StatTile, StatTileRow };
|
|
69
|
+
//# sourceMappingURL=stat-tile.d.ts.map
|
|
@@ -0,0 +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;AAOjD,iBAAS,QAAQ,CAAC,EAChB,KAAK,EACL,KAAK,EACL,IAAI,EACJ,QAAoB,EACpB,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;CAClB,qBAkCA;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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
const HINT_TONE = {
|
|
5
|
+
neutral: "text-faint",
|
|
6
|
+
positive: "text-online-strong",
|
|
7
|
+
};
|
|
8
|
+
function StatTile({ label, value, hint, hintTone = "neutral", pending, className, ...props }) {
|
|
9
|
+
return (_jsxs("div", { "data-slot": "stat-tile", "data-pending": pending ? "" : undefined,
|
|
10
|
+
// text-ink on the root, because text does not flip by inheritance
|
|
11
|
+
// (rule 3): without it a tile inside a panel inherits the page's dark ink
|
|
12
|
+
// and its value stays dark on purple.
|
|
13
|
+
className: cn("flex min-w-0 flex-col gap-1 rounded-xl border border-hairline bg-card p-4 text-ink", className), ...props, children: [_jsx("span", { "data-slot": "stat-tile-label", className: "text-caption text-faint", children: label }), _jsx("span", { "data-slot": "stat-tile-value", "data-pending": pending ? "" : undefined, className: cn("font-display text-display-sm leading-display font-medium tabular-nums", pending && "text-faint"), children: pending ? "Coming soon" : value }), hint ? (_jsx("span", { "data-slot": "stat-tile-hint", "data-tone": hintTone, className: cn("text-caption", HINT_TONE[hintTone]), children: hint })) : null] }));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A row of tiles: two, three or four, side by side, stacking as the column
|
|
17
|
+
* narrows.
|
|
18
|
+
*
|
|
19
|
+
* The frames draw three on Overview and four on Insights, so the count is the
|
|
20
|
+
* caller's and the breakpoints are derived from it rather than passed. Four
|
|
21
|
+
* across at phone width would be four columns of two characters each.
|
|
22
|
+
*
|
|
23
|
+
* The class strings are a lookup rather than a template, and that is not
|
|
24
|
+
* stylistic: Tailwind emits only the utilities it finds by scanning source, so
|
|
25
|
+
* a built `lg:grid-cols-${n}` compiles to a class that exists in the markup and
|
|
26
|
+
* in no stylesheet. Nothing errors; the row simply never becomes a grid.
|
|
27
|
+
*/
|
|
28
|
+
const ROW_COLUMNS = {
|
|
29
|
+
1: "grid-cols-1",
|
|
30
|
+
2: "grid-cols-1 sm:grid-cols-2",
|
|
31
|
+
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
32
|
+
4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4",
|
|
33
|
+
};
|
|
34
|
+
function StatTileRow({ className, children, ...props }) {
|
|
35
|
+
// Counted rather than taken as a prop, so a tile added to a row cannot leave
|
|
36
|
+
// the layout describing the row it used to be. Anything over four falls to
|
|
37
|
+
// the four-column ramp: it wraps, which is a legible answer, and the issue's
|
|
38
|
+
// range is two to four.
|
|
39
|
+
const count = Math.min(4, Math.max(1, countTiles(children)));
|
|
40
|
+
return (_jsx("div", { "data-slot": "stat-tile-row", "data-tiles": count, className: cn("grid gap-4", ROW_COLUMNS[count], className), ...props, children: children }));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* How many tiles a caller actually handed over.
|
|
44
|
+
*
|
|
45
|
+
* `React.Children.count` counts a mapped array as one child, and a row built
|
|
46
|
+
* from data — which is how a consumer will build it — is exactly that shape. So
|
|
47
|
+
* this flattens first, and drops the nulls a `cond && <StatTile />` leaves
|
|
48
|
+
* behind, since a conditional tile that is absent must not hold a column open.
|
|
49
|
+
*/
|
|
50
|
+
function countTiles(children) {
|
|
51
|
+
return React.Children.toArray(children).length;
|
|
52
|
+
}
|
|
53
|
+
export { StatTile, StatTileRow };
|
|
54
|
+
//# sourceMappingURL=stat-tile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stat-tile.js","sourceRoot":"","sources":["../../src/blocks/stat-tile.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AA0DvC,MAAM,SAAS,GAAiC;IAC9C,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,oBAAoB;CAC/B,CAAA;AAED,SAAS,QAAQ,CAAC,EAChB,KAAK,EACL,KAAK,EACL,IAAI,EACJ,QAAQ,GAAG,SAAS,EACpB,OAAO,EACP,SAAS,EACT,GAAG,KAAK,EAWT;IACC,OAAO,CACL,4BACY,WAAW,kBACP,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;QACtC,kEAAkE;QAClE,0EAA0E;QAC1E,sCAAsC;QACtC,SAAS,EAAE,EAAE,CACX,oFAAoF,EACpF,SAAS,CACV,KACG,KAAK,aAET,4BAAgB,iBAAiB,EAAC,SAAS,EAAC,yBAAyB,YAClE,KAAK,GACD,EACP,4BACY,iBAAiB,kBACb,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EACtC,SAAS,EAAE,EAAE,CACX,uEAAuE,EACvE,OAAO,IAAI,YAAY,CACxB,YAEA,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,GAC3B,EACN,IAAI,CAAC,CAAC,CAAC,CACN,4BAAgB,gBAAgB,eAAY,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,cAAc,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,YACrG,IAAI,GACA,CACR,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,GAA2B;IAC1C,CAAC,EAAE,aAAa;IAChB,CAAC,EAAE,4BAA4B;IAC/B,CAAC,EAAE,2CAA2C;IAC9C,CAAC,EAAE,2CAA2C;CAC/C,CAAA;AAED,SAAS,WAAW,CAAC,EACnB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACiC;IACzC,6EAA6E;IAC7E,2EAA2E;IAC3E,6EAA6E;IAC7E,wBAAwB;IACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAE5D,OAAO,CACL,2BACY,eAAe,gBACb,KAAK,EACjB,SAAS,EAAE,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,KACtD,KAAK,YAER,QAAQ,GACL,CACP,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,UAAU,CAAC,QAAyB;IAC3C,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAA;AAChD,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -44,7 +44,64 @@ import { PageHeading } from "./page-heading.js";
|
|
|
44
44
|
* that an answer had been given when the user was reading. Tabs say "same
|
|
45
45
|
* screen, different content", which is what this is.
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* An install METHOD: MCP, CLI, Skills. Optional, and everything about the method
|
|
49
|
+
* axis is keyed on whether any are passed.
|
|
50
|
+
*
|
|
51
|
+
* A tool supports a method when it has steps for it. Nothing declares support
|
|
52
|
+
* separately, because two places to say the same thing is one place to get it
|
|
53
|
+
* wrong: the CLI tab drops ChatGPT because ChatGPT has no CLI steps, not because
|
|
54
|
+
* a flag says so.
|
|
55
|
+
*/
|
|
56
|
+
export interface ToolSetupMethod {
|
|
57
|
+
value: string;
|
|
58
|
+
label: string;
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A heading for a run of tools in the strip. Coding agents, chat apps.
|
|
63
|
+
*
|
|
64
|
+
* A group whose tools are all filtered out by the current method disappears,
|
|
65
|
+
* along with the divider that would have sat beside it. That is the same rule
|
|
66
|
+
* `HubIndex` encodes for its own groups, and for the same reason: a group may
|
|
67
|
+
* legitimately name nothing right now.
|
|
68
|
+
*/
|
|
69
|
+
export interface ToolSetupGroup {
|
|
70
|
+
value: string;
|
|
71
|
+
label: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* One step of a pane.
|
|
75
|
+
*
|
|
76
|
+
* `label` is an alternative marker ("Easiest", "Or") rather than a sequence
|
|
77
|
+
* position. A pane whose first step carries one is a set of CHOICES and renders
|
|
78
|
+
* as columns; a pane without is a SEQUENCE and renders as a numbered `StepList`,
|
|
79
|
+
* whose `<ol>` does the numbering for a screen reader.
|
|
80
|
+
*
|
|
81
|
+
* `body` is a node, not a string. Body copy carries emphasis, and a text grammar
|
|
82
|
+
* in the design system is a second content system arriving through the side
|
|
83
|
+
* door. The caller renders its own Markdown, or HTML, or nothing, and hands over
|
|
84
|
+
* what it wants painted. Same line #117, #121 and #126 drew.
|
|
85
|
+
*/
|
|
86
|
+
export interface ToolSetupStep {
|
|
87
|
+
/** "Easiest", "Or". Present on the first step makes the pane a set of choices. */
|
|
88
|
+
label?: string;
|
|
89
|
+
title: string;
|
|
90
|
+
body?: React.ReactNode;
|
|
91
|
+
/** A multi line prompt to hand an agent. */
|
|
92
|
+
prompt?: string;
|
|
93
|
+
/** A single command to run. */
|
|
94
|
+
code?: string;
|
|
95
|
+
link?: {
|
|
96
|
+
label: string;
|
|
97
|
+
href: string;
|
|
98
|
+
/** The caller's glyph. The library does not pick it, per HubIndex and #47. */
|
|
99
|
+
icon?: React.ReactNode;
|
|
100
|
+
/** Draw it as the primary action rather than a secondary one. */
|
|
101
|
+
primary?: boolean;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
interface ToolSetupToolBase {
|
|
48
105
|
/** What `onValueChange` reports. Stable, and never shown. */
|
|
49
106
|
value: string;
|
|
50
107
|
/** The words on the tab. Two short words wrap; they are not truncated. */
|
|
@@ -55,8 +112,14 @@ export interface ToolSetupTool {
|
|
|
55
112
|
* boilerplate at the exact moment the user needs to know where the text goes.
|
|
56
113
|
*/
|
|
57
114
|
instruction?: string;
|
|
58
|
-
/**
|
|
59
|
-
|
|
115
|
+
/** Which `ToolSetupGroup` this sits under. Ignored when no groups are passed. */
|
|
116
|
+
group?: string;
|
|
117
|
+
/**
|
|
118
|
+
* The vendor mark, supplied by the caller. A node rather than a name: which
|
|
119
|
+
* marks exist is content, and the trademark question in #47 is not this
|
|
120
|
+
* component's to answer.
|
|
121
|
+
*/
|
|
122
|
+
mark?: React.ReactNode;
|
|
60
123
|
/** Shown beside the instruction. For a tool with a manual path as well. */
|
|
61
124
|
alternative?: {
|
|
62
125
|
label: string;
|
|
@@ -64,8 +127,38 @@ export interface ToolSetupTool {
|
|
|
64
127
|
};
|
|
65
128
|
disabled?: boolean;
|
|
66
129
|
}
|
|
67
|
-
|
|
130
|
+
/**
|
|
131
|
+
* A tool has to have something to show, and the type says so.
|
|
132
|
+
*
|
|
133
|
+
* Making `prompt` merely optional was wrong: it took the guarantee away from
|
|
134
|
+
* every existing caller, so a typo in `prompt` stopped being a compile error and
|
|
135
|
+
* became a tab with an empty bordered panel under it. The union keeps the old
|
|
136
|
+
* contract for callers that pass no steps and adds the new one, without a
|
|
137
|
+
* runtime check standing in for a type.
|
|
138
|
+
*
|
|
139
|
+
* `prompt` stays readable on the union because both arms declare it, so the
|
|
140
|
+
* panel can fall back to it without narrowing.
|
|
141
|
+
*
|
|
142
|
+
* `steps` is keyed by method value. Passing it is what puts a tool on the method
|
|
143
|
+
* axis; a tool with no entry for the selected method is filtered out of the
|
|
144
|
+
* strip, which is also why a `prompt` only tool never appears in method mode.
|
|
145
|
+
*/
|
|
146
|
+
export type ToolSetupTool = ToolSetupToolBase & ({
|
|
147
|
+
prompt: string;
|
|
148
|
+
steps?: Record<string, ToolSetupStep[]>;
|
|
149
|
+
} | {
|
|
150
|
+
prompt?: string;
|
|
151
|
+
steps: Record<string, ToolSetupStep[]>;
|
|
152
|
+
});
|
|
153
|
+
declare function ToolSetup({ tools, methods, groups, method, defaultMethod, onMethodChange, value, defaultValue, onValueChange, title, sub, eyebrow, level, headingSize, continueLabel, emptyLabel, onContinue, canContinue, footer, className, ...props }: Omit<React.ComponentProps<"section">, "ref" | "title" | "defaultValue" | "onChange"> & {
|
|
68
154
|
tools: ToolSetupTool[];
|
|
155
|
+
/** Pass these and the method strip appears above the tool strip. */
|
|
156
|
+
methods?: ToolSetupMethod[];
|
|
157
|
+
/** Pass these and the tool strip is grouped, with empty groups dropped. */
|
|
158
|
+
groups?: ToolSetupGroup[];
|
|
159
|
+
method?: string;
|
|
160
|
+
defaultMethod?: string;
|
|
161
|
+
onMethodChange?: (method: string) => void;
|
|
69
162
|
value?: string;
|
|
70
163
|
defaultValue?: string;
|
|
71
164
|
onValueChange?: (value: string) => void;
|
|
@@ -89,6 +182,14 @@ declare function ToolSetup({ tools, value, defaultValue, onValueChange, title, s
|
|
|
89
182
|
* declarative opt-out works from both.
|
|
90
183
|
*/
|
|
91
184
|
continueLabel?: string | null;
|
|
185
|
+
/**
|
|
186
|
+
* Shown when the selected method leaves no tools to pick from. A default
|
|
187
|
+
* rather than a required prop, on the same reasoning as `continueLabel`: the
|
|
188
|
+
* state is reachable by passing a method nothing supports, and a heading over
|
|
189
|
+
* blank space is the "reads as broken" outcome the note on `first` exists to
|
|
190
|
+
* prevent.
|
|
191
|
+
*/
|
|
192
|
+
emptyLabel?: string;
|
|
92
193
|
onContinue?: () => void;
|
|
93
194
|
/**
|
|
94
195
|
* Defaults to `true`, unlike `OnboardingQuestion`'s. Nothing here is an answer
|