@nadicodeai/ui 12.1.163 → 12.1.165

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.
@@ -31,15 +31,21 @@ import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
31
31
  * “Enter and Space toggle. Don’t bind any other key globally; arrow keys move focus inside the panel content.” (https://vercel.com/geist/collapse)
32
32
  * “Render the panel content in the DOM when closed (with `hidden` or visibility) so search and find-in-page still hit it; lazy-render only for expensive content.” (https://vercel.com/geist/collapse)
33
33
  * Ours: a closed panel stays in the page, hidden until found, so find-in-page opens it; pass
34
- * `hiddenUntilFound={false}` on a heavy panel to mount it only when open. Headings keep the page's
35
- * outline.
34
+ * `hiddenUntilFound={false}` on a heavy panel to mount it only when open. A trigger's heading is
35
+ * an h3, and `level` sets the one that keeps the page's outline.
36
36
  */
37
37
  declare function Accordion({ className, size, ...props }: AccordionPrimitive.Root.Props & {
38
38
  size?: "default" | "small";
39
39
  }): React.JSX.Element;
40
40
  declare function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props): React.JSX.Element;
41
- declare function AccordionTrigger({ className, children, ...props }: Omit<AccordionPrimitive.Trigger.Props, "children"> & {
41
+ declare const HEADINGS: {
42
+ 2: React.JSX.Element;
43
+ 3: React.JSX.Element;
44
+ 4: React.JSX.Element;
45
+ };
46
+ declare function AccordionTrigger({ className, children, level, ...props }: Omit<AccordionPrimitive.Trigger.Props, "children"> & {
42
47
  children: React.ReactNode;
48
+ level?: keyof typeof HEADINGS;
43
49
  }): React.JSX.Element;
44
50
  declare function AccordionContent({ className, children, hiddenUntilFound, ...props }: AccordionPrimitive.Panel.Props): React.JSX.Element;
45
51
  export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../src/components/accordion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAK3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,iBAAS,SAAS,CAAC,EACjB,SAAS,EACT,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,GAAG;IAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CAAE,qBAShE;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,qBAQ5E;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAmBpF;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,gBAAuB,EACvB,GAAG,KAAK,EACT,EAAE,kBAAkB,CAAC,KAAK,CAAC,KAAK,qBAkBhC;AAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../src/components/accordion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAK3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,iBAAS,SAAS,CAAC,EACjB,SAAS,EACT,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,GAAG;IAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CAAE,qBAShE;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,qBAQ5E;AAED,QAAA,MAAM,QAAQ;;;;CAAsC,CAAC;AAErD,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,KAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG;IACtD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,OAAO,QAAQ,CAAC;CAC/B,qBAmBA;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,gBAAuB,EACvB,GAAG,KAAK,EACT,EAAE,kBAAkB,CAAC,KAAK,CAAC,KAAK,qBAkBhC;AAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
@@ -33,8 +33,8 @@ import { cn } from "../lib/utils.js";
33
33
  * “Enter and Space toggle. Don’t bind any other key globally; arrow keys move focus inside the panel content.” (https://vercel.com/geist/collapse)
34
34
  * “Render the panel content in the DOM when closed (with `hidden` or visibility) so search and find-in-page still hit it; lazy-render only for expensive content.” (https://vercel.com/geist/collapse)
35
35
  * Ours: a closed panel stays in the page, hidden until found, so find-in-page opens it; pass
36
- * `hiddenUntilFound={false}` on a heavy panel to mount it only when open. Headings keep the page's
37
- * outline.
36
+ * `hiddenUntilFound={false}` on a heavy panel to mount it only when open. A trigger's heading is
37
+ * an h3, and `level` sets the one that keeps the page's outline.
38
38
  */
39
39
  function Accordion({ className, size = "default", ...props }) {
40
40
  return (_jsx(AccordionPrimitive.Root, { "data-slot": "accordion", "data-size": size, className: cn("group/accordion flex w-full flex-col border-t", className), ...props }));
@@ -42,8 +42,9 @@ function Accordion({ className, size = "default", ...props }) {
42
42
  function AccordionItem({ className, ...props }) {
43
43
  return (_jsx(AccordionPrimitive.Item, { "data-slot": "accordion-item", className: cn("border-b", className), ...props }));
44
44
  }
45
- function AccordionTrigger({ className, children, ...props }) {
46
- return (_jsx(AccordionPrimitive.Header, { className: "flex", children: _jsxs(AccordionPrimitive.Trigger, { "data-slot": "accordion-trigger", className: cn("nc-transition-paint group/accordion-trigger flex min-h-touch-target flex-1 items-center justify-between gap-4 rounded-sm py-6.5 text-left text-heading-md aria-disabled:pointer-events-none aria-disabled:opacity-50 group-data-[size=small]/accordion:py-3 group-data-[size=small]/accordion:text-body-md group-data-[size=small]/accordion:font-medium [@media(hover:hover)_and_(pointer:fine)]:min-h-0", className), ...props, children: [children, _jsx(ChevronRightIcon, { "data-slot": "accordion-trigger-icon", className: "nc-transition-transform pointer-events-none size-4 shrink-0 group-aria-expanded/accordion-trigger:rotate-90" })] }) }));
45
+ const HEADINGS = { 2: _jsx("h2", {}), 3: _jsx("h3", {}), 4: _jsx("h4", {}) };
46
+ function AccordionTrigger({ className, children, level = 3, ...props }) {
47
+ return (_jsx(AccordionPrimitive.Header, { className: "flex", render: HEADINGS[level], children: _jsxs(AccordionPrimitive.Trigger, { "data-slot": "accordion-trigger", className: cn("nc-transition-paint group/accordion-trigger flex min-h-touch-target flex-1 items-center justify-between gap-4 rounded-sm py-6.5 text-left text-heading-md aria-disabled:pointer-events-none aria-disabled:opacity-50 group-data-[size=small]/accordion:py-3 group-data-[size=small]/accordion:text-body-md group-data-[size=small]/accordion:font-medium [@media(hover:hover)_and_(pointer:fine)]:min-h-0", className), ...props, children: [children, _jsx(ChevronRightIcon, { "data-slot": "accordion-trigger-icon", className: "nc-transition-transform pointer-events-none size-4 shrink-0 group-aria-expanded/accordion-trigger:rotate-90" })] }) }));
47
48
  }
48
49
  function AccordionContent({ className, children, hiddenUntilFound = true, ...props }) {
49
50
  return (_jsx(AccordionPrimitive.Panel, { "data-slot": "accordion-content", className: "h-(--accordion-panel-height) overflow-hidden text-body-md transition-[height] duration-[var(--nc-duration-open)] ease-[var(--nc-ease-out-strong)] data-ending-style:h-0 data-starting-style:h-0 motion-reduce:transition-none", hiddenUntilFound: hiddenUntilFound, ...props, children: _jsx("div", { className: cn("pb-4 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4", className), children: children }) }));
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  /**
3
3
  * Alveare's entry scene, the hive, which Alveare's desktop and Alveare Server
4
4
  * both stand their entry screens on (apps/alveare/docs/design-doctrine.md,
5
- * "Screens"): the app's picture on black, Alveare's logo at the upper left,
5
+ * "Screens"): the app's picture on black, the app's mark at the upper left,
6
6
  * six Agent orbs on the corners of a hexagon around the words, and the work
7
7
  * flowing between them and the people in the picture as particles in the
8
8
  * sending orb's colour. The orbs are artwork, so they take ambient motion and
@@ -43,7 +43,7 @@ export type HiveSceneProps = Omit<React.ComponentProps<"div">, "children"> & {
43
43
  mode: HiveSceneMode;
44
44
  /** How the words stand: `panel` for a screen of cards read from the leading edge. */
45
45
  column?: HiveSceneColumn;
46
- /** Alveare's logo, its app icon without the construction guides, and its name. */
46
+ /** The app's mark, its icon's ribbon alone without the tile, and the app's name. */
47
47
  logo: {
48
48
  src: string;
49
49
  label: string;
@@ -65,7 +65,7 @@ export type HiveSceneProps = Omit<React.ComponentProps<"div">, "children"> & {
65
65
  children?: React.ReactNode;
66
66
  };
67
67
  /**
68
- * Alveare's entry scene: its picture, its logo and six Agent orbs around the words.
68
+ * Alveare's entry scene: its picture, its mark and six Agent orbs around the words.
69
69
  *
70
70
  * @family Other
71
71
  * @when Alveare's entry screens, on its desktop and on Alveare Server: joining, loading, a failure.
@@ -1 +1 @@
1
- {"version":3,"file":"hive-scene.d.ts","sourceRoot":"","sources":["../../src/components/hive-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,6DAA6D;AAC7D,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IAC3E,IAAI,EAAE,aAAa,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,kFAAkF;IAClF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,KAAK,QAAQ,CAAC;IAClD,iEAAiE;IACjE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AA4LF;;;;;;;;;;;;;;GAcG;AACH,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAkB,EAClB,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,qBA4QhB;AAED,2DAA2D;AAC3D,iBAAS,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,qBAM9E;AAED,iEAAiE;AACjE,iBAAS,QAAQ,CAAC,EAChB,QAAQ,EACR,EAAE,EACF,IAAa,GACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACzB,qBAMA;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"hive-scene.d.ts","sourceRoot":"","sources":["../../src/components/hive-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,6DAA6D;AAC7D,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IAC3E,IAAI,EAAE,aAAa,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,oFAAoF;IACpF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,KAAK,QAAQ,CAAC;IAClD,iEAAiE;IACjE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AA4LF;;;;;;;;;;;;;;GAcG;AACH,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAkB,EAClB,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,qBA4QhB;AAED,2DAA2D;AAC3D,iBAAS,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,qBAM9E;AAED,iEAAiE;AACjE,iBAAS,QAAQ,CAAC,EAChB,QAAQ,EACR,EAAE,EACF,IAAa,GACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACzB,qBAMA;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC"}
@@ -159,7 +159,7 @@ function pick(items) {
159
159
  return items[Math.floor(Math.random() * items.length)];
160
160
  }
161
161
  /**
162
- * Alveare's entry scene: its picture, its logo and six Agent orbs around the words.
162
+ * Alveare's entry scene: its picture, its mark and six Agent orbs around the words.
163
163
  *
164
164
  * @family Other
165
165
  * @when Alveare's entry screens, on its desktop and on Alveare Server: joining, loading, a failure.
@@ -52,10 +52,10 @@ export type ObjectPageProps = {
52
52
  *
53
53
  * @family Compositions
54
54
  * @when One thing a person opened from a list and now reads or acts on: a customer, a partner, an Installation, a Library entry.
55
- * @instead "Use Context Card to reveal entity metadata on hover or focus: a user, a deployment, a project, an API key." (https://vercel.com/geist/context-card) Ours: that hover is a `HoverCard`, never this page. A list of records is a CollectionPage; a page of settings only is a SettingsPage, whose cards are SettingsSections; an Agent opens on its AgentProfileCard, the documented exception. A card of values a person saves is a setting card, never this one.
56
- * @behaviour "For a static key/value metadata block on a detail page, use `Description`." (https://vercel.com/geist/entity) "The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`." (https://vercel.com/geist/entity) "Lead the left column with a scannable identifier: an `Avatar` or icon, a Title Case label, then sentence-case secondary metadata (`Member since Mar 14, 2026`)." (https://vercel.com/geist/entity) "Don’t put interactive controls in the title slot. Buttons, menus, and links belong in the content (`<dd>`) or in the parent layout, not the label (`<dt>`)." (https://vercel.com/geist/description) Ours: as Vercel's deployment page (Deployment Details, then its steps), the object card is the first card of the page: a header bar with the name at the start and the object's commands at the end (a secondary, then the primary as the filled button, then the three dots, in `PageActions`' order, on the name's row while the name keeps 128 px, as on a phone, and under it otherwise; the primary is the one thing the object waits on its viewer for, such as approving a company that waits for approval, beside its alternative as the secondary, and an object with nothing waiting has none), for a company, the compact mark at 64 stands beside the name and optional line in the header, followed by full-width facts with four columns from `lg` and two below; other object kinds keep their mark and line beside their facts in the existing preview treatment (at least one fact is required: an object is never shown without what it is), each a muted label over its value in body text, then an optional footer with a hint at the start and one link at the end. Optional `entries` follow in a card of their own 12 px under it: rows that open one by one, each with its chevron first (it turns down when open), its title, and its summary at the trailing edge, as Vercel's Build Logs and Deployment Checks rows; an entry marked `defaultOpen` opens with the page, for a link that names it. The footer takes a link only, so no Save or other command of the object fits in it; the object's changes live in its sections, each a setting card with its own footer. The sections follow, 24 apart, each drawing its own states. The card is neutral; colour belongs to the company's compact identity, a semantic fact value, or an entry's status summary, with no coloured card ground.
55
+ * @instead "Use Context Card to reveal entity metadata on hover or focus: a user, a deployment, a project, an API key." (https://vercel.com/geist/context-card) Ours: that hover is a `HoverCard`, never this page. A list of records is a CollectionPage; a page of settings only is a SettingsPage, whose cards are SettingsSections; an Agent's Edit page in Nadia's window opens on its AgentProfileCard, the documented exception. A card of values a person saves is a setting card, never this one.
56
+ * @behaviour "For a static key/value metadata block on a detail page, use `Description`." (https://vercel.com/geist/entity) "The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`." (https://vercel.com/geist/entity) "Lead the left column with a scannable identifier: an `Avatar` or icon, a Title Case label, then sentence-case secondary metadata (`Member since Mar 14, 2026`)." (https://vercel.com/geist/entity) "Don’t put interactive controls in the title slot. Buttons, menus, and links belong in the content (`<dd>`) or in the parent layout, not the label (`<dt>`)." (https://vercel.com/geist/description) Ours: as Vercel's deployment page (Deployment Details, then its steps), the object card is the first card of the page: a header bar with the name at the start and the object's commands at the end (a secondary, then the primary as the filled button, then the three dots, in `PageActions`' order, on the name's row while the name keeps 128 px, as on a phone, and under it otherwise; the primary is the one thing the object waits on its viewer for, such as approving a company that waits for approval, beside its alternative as the secondary, and an object with nothing waiting has none), for a company, the compact mark at 64 stands beside the name and optional line in the header, followed by full-width facts in four columns once they have 36rem and two below; other object kinds keep their mark and line beside their facts in the existing preview treatment (at least one fact is required: an object is never shown without what it is), each a muted label over its value in body text, then an optional footer with a hint at the start and one link at the end. Optional `entries` follow in a card of their own 12 px under it: rows that open one by one, each with its chevron first (it turns down when open), its title, and its summary at the trailing edge, as Vercel's Build Logs and Deployment Checks rows; an entry marked `defaultOpen` opens with the page, for a link that names it. The footer takes a link only, so no Save or other command of the object fits in it; the object's changes live in its sections, each a setting card with its own footer. The sections follow, 24 apart, each drawing its own states. The card is neutral; colour belongs to the company's compact identity, a semantic fact value, or an entry's status summary, with no coloured card ground.
57
57
  * @words "Keep right-column buttons Verb + Noun (`Remove Member`, `Resend Invite`). Bare verbs like `Remove` or `Confirm` lose context once the row scrolls offscreen." (https://vercel.com/geist/entity) "Title slot is Title Case noun (`Last Deployed`, `Build Duration`); content is sentence case unless the value is a literal identifier, ID, or timestamp that should be preserved verbatim." (https://vercel.com/geist/description) Ours: sentence case throughout. The name as the object is called everywhere else; the line says what it is and whose ("Customer of Partner Alpha · since 3 August 2026"); a fact's label is a noun ("Plan"), its value the figure; an entry's title is a noun phrase; the hint is one sentence ("To update it, push to the main branch."); the link names where it goes ("Deployments"); the menu's trigger reads "More for {name}".
58
- * @access "Geist renders `<dl>`/`<dt>`/`<dd>` so screen readers announce each key/value pair as a definition." (https://vercel.com/geist/description) "Don’t wrap the component in extra paragraphs that break the list semantics." (https://vercel.com/geist/description) Ours: with `headingProps` the name is the page's h1; without them it is text, for a product whose chrome already titles the page. The mark is decorative beside the facts. Each entry is a button with `aria-expanded` that controls its panel.
58
+ * @access "Geist renders `<dl>`/`<dt>`/`<dd>` so screen readers announce each key/value pair as a definition." (https://vercel.com/geist/description) "Don’t wrap the component in extra paragraphs that break the list semantics." (https://vercel.com/geist/description) Ours: with `headingProps` the name is the page's h1; without them it is text, for a product whose chrome already titles the page. The mark is decorative beside the facts. Each entry is an h2 heading holding a button with `aria-expanded` that controls its panel.
59
59
  */
60
60
  export declare function ObjectPage({ mark, name, headingProps, description, facts, actions, entries, footer, children, }: ObjectPageProps): ReactElement;
61
61
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"object-page.d.ts","sourceRoot":"","sources":["../../src/components/object-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMrE,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,KAAK,gBAAgB,EAAqC,MAAM,gBAAgB,CAAC;AAE1F,KAAK,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAE1D,MAAM,MAAM,eAAe,GAAG;IAC5B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,EAAE,YAAY,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,kHAAkH;IAClH,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,IAAI,EAAE,cAAc,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,wFAAwF;IACxF,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,YAAY,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC;IACtD,qFAAqF;IACrF,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAC,cAAc,EAAE,GAAG,cAAc,EAAE,CAAC,CAAC;IACtD,8FAA8F;IAC9F,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC3C,2FAA2F;IAC3F,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC,4FAA4F;IAC5F,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,+HAA+H;IAC/H,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,QAAQ,GACT,EAAE,eAAe,GAAG,YAAY,CAqGhC"}
1
+ {"version":3,"file":"object-page.d.ts","sourceRoot":"","sources":["../../src/components/object-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMrE,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,KAAK,gBAAgB,EAAqC,MAAM,gBAAgB,CAAC;AAE1F,KAAK,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAE1D,MAAM,MAAM,eAAe,GAAG;IAC5B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,EAAE,YAAY,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,kHAAkH;IAClH,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,IAAI,EAAE,cAAc,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,wFAAwF;IACxF,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,YAAY,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC;IACtD,qFAAqF;IACrF,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAC,cAAc,EAAE,GAAG,cAAc,EAAE,CAAC,CAAC;IACtD,8FAA8F;IAC9F,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC3C,2FAA2F;IAC3F,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC,4FAA4F;IAC5F,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,+HAA+H;IAC/H,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,QAAQ,GACT,EAAE,eAAe,GAAG,YAAY,CAwGhC"}
@@ -11,15 +11,15 @@ import { PageActionsRow, PageCommandButton } from "./page-actions.js";
11
11
  *
12
12
  * @family Compositions
13
13
  * @when One thing a person opened from a list and now reads or acts on: a customer, a partner, an Installation, a Library entry.
14
- * @instead "Use Context Card to reveal entity metadata on hover or focus: a user, a deployment, a project, an API key." (https://vercel.com/geist/context-card) Ours: that hover is a `HoverCard`, never this page. A list of records is a CollectionPage; a page of settings only is a SettingsPage, whose cards are SettingsSections; an Agent opens on its AgentProfileCard, the documented exception. A card of values a person saves is a setting card, never this one.
15
- * @behaviour "For a static key/value metadata block on a detail page, use `Description`." (https://vercel.com/geist/entity) "The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`." (https://vercel.com/geist/entity) "Lead the left column with a scannable identifier: an `Avatar` or icon, a Title Case label, then sentence-case secondary metadata (`Member since Mar 14, 2026`)." (https://vercel.com/geist/entity) "Don’t put interactive controls in the title slot. Buttons, menus, and links belong in the content (`<dd>`) or in the parent layout, not the label (`<dt>`)." (https://vercel.com/geist/description) Ours: as Vercel's deployment page (Deployment Details, then its steps), the object card is the first card of the page: a header bar with the name at the start and the object's commands at the end (a secondary, then the primary as the filled button, then the three dots, in `PageActions`' order, on the name's row while the name keeps 128 px, as on a phone, and under it otherwise; the primary is the one thing the object waits on its viewer for, such as approving a company that waits for approval, beside its alternative as the secondary, and an object with nothing waiting has none), for a company, the compact mark at 64 stands beside the name and optional line in the header, followed by full-width facts with four columns from `lg` and two below; other object kinds keep their mark and line beside their facts in the existing preview treatment (at least one fact is required: an object is never shown without what it is), each a muted label over its value in body text, then an optional footer with a hint at the start and one link at the end. Optional `entries` follow in a card of their own 12 px under it: rows that open one by one, each with its chevron first (it turns down when open), its title, and its summary at the trailing edge, as Vercel's Build Logs and Deployment Checks rows; an entry marked `defaultOpen` opens with the page, for a link that names it. The footer takes a link only, so no Save or other command of the object fits in it; the object's changes live in its sections, each a setting card with its own footer. The sections follow, 24 apart, each drawing its own states. The card is neutral; colour belongs to the company's compact identity, a semantic fact value, or an entry's status summary, with no coloured card ground.
14
+ * @instead "Use Context Card to reveal entity metadata on hover or focus: a user, a deployment, a project, an API key." (https://vercel.com/geist/context-card) Ours: that hover is a `HoverCard`, never this page. A list of records is a CollectionPage; a page of settings only is a SettingsPage, whose cards are SettingsSections; an Agent's Edit page in Nadia's window opens on its AgentProfileCard, the documented exception. A card of values a person saves is a setting card, never this one.
15
+ * @behaviour "For a static key/value metadata block on a detail page, use `Description`." (https://vercel.com/geist/entity) "The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`." (https://vercel.com/geist/entity) "Lead the left column with a scannable identifier: an `Avatar` or icon, a Title Case label, then sentence-case secondary metadata (`Member since Mar 14, 2026`)." (https://vercel.com/geist/entity) "Don’t put interactive controls in the title slot. Buttons, menus, and links belong in the content (`<dd>`) or in the parent layout, not the label (`<dt>`)." (https://vercel.com/geist/description) Ours: as Vercel's deployment page (Deployment Details, then its steps), the object card is the first card of the page: a header bar with the name at the start and the object's commands at the end (a secondary, then the primary as the filled button, then the three dots, in `PageActions`' order, on the name's row while the name keeps 128 px, as on a phone, and under it otherwise; the primary is the one thing the object waits on its viewer for, such as approving a company that waits for approval, beside its alternative as the secondary, and an object with nothing waiting has none), for a company, the compact mark at 64 stands beside the name and optional line in the header, followed by full-width facts in four columns once they have 36rem and two below; other object kinds keep their mark and line beside their facts in the existing preview treatment (at least one fact is required: an object is never shown without what it is), each a muted label over its value in body text, then an optional footer with a hint at the start and one link at the end. Optional `entries` follow in a card of their own 12 px under it: rows that open one by one, each with its chevron first (it turns down when open), its title, and its summary at the trailing edge, as Vercel's Build Logs and Deployment Checks rows; an entry marked `defaultOpen` opens with the page, for a link that names it. The footer takes a link only, so no Save or other command of the object fits in it; the object's changes live in its sections, each a setting card with its own footer. The sections follow, 24 apart, each drawing its own states. The card is neutral; colour belongs to the company's compact identity, a semantic fact value, or an entry's status summary, with no coloured card ground.
16
16
  * @words "Keep right-column buttons Verb + Noun (`Remove Member`, `Resend Invite`). Bare verbs like `Remove` or `Confirm` lose context once the row scrolls offscreen." (https://vercel.com/geist/entity) "Title slot is Title Case noun (`Last Deployed`, `Build Duration`); content is sentence case unless the value is a literal identifier, ID, or timestamp that should be preserved verbatim." (https://vercel.com/geist/description) Ours: sentence case throughout. The name as the object is called everywhere else; the line says what it is and whose ("Customer of Partner Alpha · since 3 August 2026"); a fact's label is a noun ("Plan"), its value the figure; an entry's title is a noun phrase; the hint is one sentence ("To update it, push to the main branch."); the link names where it goes ("Deployments"); the menu's trigger reads "More for {name}".
17
- * @access "Geist renders `<dl>`/`<dt>`/`<dd>` so screen readers announce each key/value pair as a definition." (https://vercel.com/geist/description) "Don’t wrap the component in extra paragraphs that break the list semantics." (https://vercel.com/geist/description) Ours: with `headingProps` the name is the page's h1; without them it is text, for a product whose chrome already titles the page. The mark is decorative beside the facts. Each entry is a button with `aria-expanded` that controls its panel.
17
+ * @access "Geist renders `<dl>`/`<dt>`/`<dd>` so screen readers announce each key/value pair as a definition." (https://vercel.com/geist/description) "Don’t wrap the component in extra paragraphs that break the list semantics." (https://vercel.com/geist/description) Ours: with `headingProps` the name is the page's h1; without them it is text, for a product whose chrome already titles the page. The mark is decorative beside the facts. Each entry is an h2 heading holding a button with `aria-expanded` that controls its panel.
18
18
  */
19
19
  export function ObjectPage({ mark, name, headingProps, description, facts, actions, entries, footer, children, }) {
20
20
  const company = mark.kind === "company";
21
21
  const title = headingProps ? (_jsx("h1", { ...headingProps, className: cn("outline-none", headingProps.className), children: name })) : (name);
22
- return (_jsxs("div", { className: "grid min-w-0 gap-6", "data-slot": "object-page", children: [_jsxs("div", { className: "grid min-w-0 gap-3", children: [_jsxs(Card, { className: "min-w-0", render: _jsx("div", { "data-slot": "object-card" }), size: "sm", children: [_jsxs(CardHeader, { className: "flex flex-wrap items-center justify-between gap-x-4 gap-y-3 border-b", children: [company ? (_jsxs("div", { className: cn("flex min-w-0 flex-1 items-center gap-4", actions?.menu && !actions.secondary && !actions.primary ? "basis-0" : "basis-64"), children: [_jsx(IdentityMark, { ...mark, size: 64 }), _jsxs("div", { className: "grid min-w-0 gap-1", children: [_jsx(CardTitle, { className: "min-w-0 break-words group-data-[size=sm]/card:text-heading-sm", children: title }), description ? _jsx(CardDescription, { children: description }) : null] })] })) : (_jsx(CardTitle, { className: "min-w-0 flex-1 basis-32 break-words", children: title })), actions ? _jsx(PageActionsRow, { ...actions }) : null] }), _jsxs(CardContent, { className: cn("grid min-w-0 gap-x-6 gap-y-5", !company && "md:grid-cols-[minmax(0,18.75rem)_minmax(0,1fr)]"), children: [!company ? (_jsx("div", { className: "flex h-32 min-w-0 items-center md:h-auto md:aspect-[16/10] justify-center rounded-sm border border-border bg-muted", "data-slot": "object-page-tile", children: _jsx(IdentityMark, { ...mark, size: 64 }) })) : null, _jsxs("div", { className: "grid min-w-0 content-start gap-4", children: [!company && description ? (_jsx("div", { className: "min-w-0 text-body-sm text-muted-foreground", children: description })) : null, _jsx("dl", { className: "grid min-w-0 grid-cols-2 gap-x-6 gap-y-4 lg:grid-cols-4", "data-slot": "object-page-facts", children: facts.map((fact) => (_jsxs("div", { className: "grid min-w-0 content-start gap-1", children: [_jsx("dt", { className: "text-label-sm text-muted-foreground", children: fact.label }), _jsx("dd", { className: "min-w-0 text-body-sm break-words text-foreground", children: fact.value })] }, fact.label))) })] })] }), footer ? (_jsx(FooterStrip, { hint: footer.hint, hintSlot: "object-page-hint", children: _jsx(PageCommandButton, { command: footer.link, variant: "outline" }) })) : null] }), entries && entries.length > 0 ? (_jsx(Card, { className: "min-w-0 py-0", render: _jsx("div", { "data-slot": "object-page-entries" }), size: "sm", children: _jsx(Accordion, { className: "[&>:last-child]:border-b-0", defaultValue: entries
22
+ return (_jsxs("div", { className: "grid min-w-0 gap-6", "data-slot": "object-page", children: [_jsxs("div", { className: "grid min-w-0 gap-3", children: [_jsxs(Card, { className: "min-w-0", render: _jsx("div", { "data-slot": "object-card" }), size: "sm", children: [_jsxs(CardHeader, { className: "flex flex-wrap items-center justify-between gap-x-4 gap-y-3 border-b", children: [company ? (_jsxs("div", { className: cn("flex min-w-0 flex-1 items-center gap-4", actions?.menu && !actions.secondary && !actions.primary ? "basis-0" : "basis-64"), children: [_jsx(IdentityMark, { ...mark, size: 64 }), _jsxs("div", { className: "grid min-w-0 gap-1", children: [_jsx(CardTitle, { className: "min-w-0 break-words group-data-[size=sm]/card:text-heading-sm", children: title }), description ? _jsx(CardDescription, { children: description }) : null] })] })) : (_jsx(CardTitle, { className: "min-w-0 flex-1 basis-32 break-words", children: title })), actions ? _jsx(PageActionsRow, { ...actions }) : null] }), _jsxs(CardContent, { className: cn("grid min-w-0 gap-x-6 gap-y-5", !company && "md:grid-cols-[minmax(0,18.75rem)_minmax(0,1fr)]"), children: [!company ? (_jsx("div", { className: "flex h-32 min-w-0 items-center md:h-auto md:aspect-[16/10] justify-center rounded-sm border border-border bg-muted", "data-slot": "object-page-tile", children: _jsx(IdentityMark, { ...mark, size: 64 }) })) : null, _jsxs("div", { className: "@container/object-page-facts grid min-w-0 content-start gap-4", children: [!company && description ? (_jsx("div", { className: "min-w-0 text-body-sm text-muted-foreground", children: description })) : null, _jsx("dl", { className: "grid min-w-0 grid-cols-2 gap-x-6 gap-y-4 @xl/object-page-facts:grid-cols-4", "data-slot": "object-page-facts", children: facts.map((fact) => (_jsxs("div", { className: "grid min-w-0 content-start gap-1", children: [_jsx("dt", { className: "text-label-sm text-muted-foreground", children: fact.label }), _jsx("dd", { className: "min-w-0 text-body-sm break-words text-foreground", children: fact.value })] }, fact.label))) })] })] }), footer ? (_jsx(FooterStrip, { hint: footer.hint, hintSlot: "object-page-hint", children: _jsx(PageCommandButton, { command: footer.link, variant: "outline" }) })) : null] }), entries && entries.length > 0 ? (_jsx(Card, { className: "min-w-0 py-0", render: _jsx("div", { "data-slot": "object-page-entries" }), size: "sm", children: _jsx(Accordion, { className: "[&>:last-child]:border-b-0", defaultValue: entries
23
23
  .filter((entry) => entry.defaultOpen)
24
- .map((entry) => entry.title), multiple: true, size: "small", children: entries.map((entry) => (_jsxs(AccordionItem, { value: entry.title, children: [_jsxs(AccordionTrigger, { className: "justify-start gap-3 px-(--card-spacing) group-data-[size=small]/accordion:text-body-sm focus-visible:-outline-offset-2 [&>[data-slot=accordion-trigger-icon]]:order-first [&>[data-slot=accordion-trigger-icon]]:text-muted-foreground", children: [_jsx("span", { className: "min-w-0 flex-1", children: entry.title }), entry.summary] }), _jsx(AccordionContent, { className: "ps-[calc(var(--card-spacing)+1.75rem)] pe-(--card-spacing)", children: entry.children })] }, entry.title))) }) })) : null] }), children] }));
24
+ .map((entry) => entry.title), multiple: true, size: "small", children: entries.map((entry) => (_jsxs(AccordionItem, { value: entry.title, children: [_jsxs(AccordionTrigger, { className: "justify-start gap-3 px-(--card-spacing) group-data-[size=small]/accordion:text-body-sm focus-visible:-outline-offset-2 [&>[data-slot=accordion-trigger-icon]]:order-first [&>[data-slot=accordion-trigger-icon]]:text-muted-foreground", level: 2, children: [_jsx("span", { className: "min-w-0 flex-1", children: entry.title }), entry.summary] }), _jsx(AccordionContent, { className: "ps-[calc(var(--card-spacing)+1.75rem)] pe-(--card-spacing)", children: entry.children })] }, entry.title))) }) })) : null] }), children] }));
25
25
  }
@@ -20,6 +20,8 @@ type SettingsFactsBase = Omit<ComponentPropsWithoutRef<"section">, "children" |
20
20
  * lands when the editor closes and its trigger is gone from the page.
21
21
  */
22
22
  headingId: string;
23
+ /** The title's heading level: 2 under the page, 3 inside a heading of its own, such as an ObjectPage's row. */
24
+ headingLevel?: 2 | 3;
23
25
  title: string;
24
26
  };
25
27
  export type SettingsFactsSectionProps = SettingsFactsBase & ({
@@ -67,6 +69,6 @@ export type SettingsFactsSectionProps = SettingsFactsBase & ({
67
69
  * Ours: a `dl` of `dt` and `dd`, each value named by its label. The section is labelled by its heading, which also takes focus
68
70
  * when an editor closes. A dash carries screen-reader text.
69
71
  */
70
- export declare function SettingsFactsSection({ action, presentation, description, facts, footer, footerHint, missingValueLabel, headingId, title, surface, size, ...props }: SettingsFactsSectionProps): import("react").JSX.Element;
72
+ export declare function SettingsFactsSection({ action, presentation, description, facts, footer, footerHint, missingValueLabel, headingId, headingLevel, title, surface, size, ...props }: SettingsFactsSectionProps): import("react").JSX.Element;
71
73
  export {};
72
74
  //# sourceMappingURL=settings-facts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings-facts.d.ts","sourceRoot":"","sources":["../../src/components/settings-facts.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAC;AAM7E,OAAO,EACL,IAAI,EAMJ,KAAK,WAAW,EACjB,MAAM,QAAQ,CAAC;AAEhB,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,KAAK,iBAAiB,GAAG,IAAI,CAAC,wBAAwB,CAAC,SAAS,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IAC7F,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GACvD,CACI;IACE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,UAAU,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,wBAAwB,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;CACtD,GACD;IACE,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;CACd,CACJ,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,YAAqB,EACrB,WAAW,EACX,KAAK,EACL,MAAM,EACN,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,KAAK,EACL,OAAmB,EACnB,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,yBAAyB,+BAiE3B"}
1
+ {"version":3,"file":"settings-facts.d.ts","sourceRoot":"","sources":["../../src/components/settings-facts.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAC;AAM7E,OAAO,EACL,IAAI,EAMJ,KAAK,WAAW,EACjB,MAAM,QAAQ,CAAC;AAEhB,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,KAAK,iBAAiB,GAAG,IAAI,CAAC,wBAAwB,CAAC,SAAS,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IAC7F,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GACvD,CACI;IACE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,UAAU,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,wBAAwB,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;CACtD,GACD;IACE,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;CACd,CACJ,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,YAAqB,EACrB,WAAW,EACX,KAAK,EACL,MAAM,EACN,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,YAAgB,EAChB,KAAK,EACL,OAAmB,EACnB,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,yBAAyB,+BAkE3B"}
@@ -30,12 +30,13 @@ import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle,
30
30
  * Ours: a `dl` of `dt` and `dd`, each value named by its label. The section is labelled by its heading, which also takes focus
31
31
  * when an editor closes. A dash carries screen-reader text.
32
32
  */
33
- export function SettingsFactsSection({ action, presentation = "card", description, facts, footer, footerHint, missingValueLabel, headingId, title, surface = "resting", size = "default", ...props }) {
33
+ export function SettingsFactsSection({ action, presentation = "card", description, facts, footer, footerHint, missingValueLabel, headingId, headingLevel = 2, title, surface = "resting", size = "default", ...props }) {
34
34
  const termId = useId();
35
+ const Heading = headingLevel === 3 ? "h3" : "h2";
35
36
  if (presentation === "summary") {
36
- return (_jsxs("section", { ...props, "aria-labelledby": headingId, className: "grid min-w-0 gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { id: headingId, tabIndex: -1, className: "text-sm font-medium", children: title }), action] }), description ? _jsx("p", { className: "text-sm text-muted-foreground", children: description }) : null, _jsx("dl", { className: "flex flex-wrap items-start gap-x-6 gap-y-3", children: facts.map((fact, index) => (_jsxs("div", { className: "grid gap-1", children: [_jsx("dt", { className: "text-xs text-muted-foreground", id: `${termId}-${index}`, children: fact.label }), _jsx("dd", { "aria-labelledby": `${termId}-${index}`, className: "text-sm", children: fact.value ?? _jsx(TableValue, { missingLabel: missingValueLabel, value: null }) })] }, fact.label))) }), footer] }));
37
+ return (_jsxs("section", { ...props, "aria-labelledby": headingId, className: "grid min-w-0 gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx(Heading, { id: headingId, tabIndex: -1, className: "text-sm font-medium", children: title }), action] }), description ? _jsx("p", { className: "text-sm text-muted-foreground", children: description }) : null, _jsx("dl", { className: "flex flex-wrap items-start gap-x-6 gap-y-3", children: facts.map((fact, index) => (_jsxs("div", { className: "grid gap-1", children: [_jsx("dt", { className: "text-xs text-muted-foreground", id: `${termId}-${index}`, children: fact.label }), _jsx("dd", { "aria-labelledby": `${termId}-${index}`, className: "text-sm", children: fact.value ?? _jsx(TableValue, { missingLabel: missingValueLabel, value: null }) })] }, fact.label))) }), footer] }));
37
38
  }
38
- return (_jsxs(Card, { render: _jsx("section", {}), ...props, "aria-labelledby": headingId, surface: surface, size: size, className: "min-w-0", children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: _jsx("h2", { id: headingId, tabIndex: -1, children: title }) }), description ? _jsx(CardDescription, { children: description }) : null, action ? _jsx(CardAction, { children: action }) : null] }), _jsx(CardContent, { children: _jsx(ObjectFacts, { facts: facts.map((fact) => ({
39
+ return (_jsxs(Card, { render: _jsx("section", {}), ...props, "aria-labelledby": headingId, surface: surface, size: size, className: "min-w-0", children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: _jsx(Heading, { id: headingId, tabIndex: -1, children: title }) }), description ? _jsx(CardDescription, { children: description }) : null, action ? _jsx(CardAction, { children: action }) : null] }), _jsx(CardContent, { children: _jsx(ObjectFacts, { facts: facts.map((fact) => ({
39
40
  label: fact.label,
40
41
  block: fact.block,
41
42
  value: fact.value == null || fact.value === "" ? (_jsx(TableValue, { missingLabel: missingValueLabel, value: null })) : (fact.value),
@@ -20,9 +20,11 @@ type SettingsInfo = {
20
20
  type SettingsSectionBase = Omit<React.ComponentProps<"section">, "title" | "children"> & {
21
21
  /** One line saying what changing it does. It is the card's only help: no field carries its own. */
22
22
  description: string;
23
+ /** The title's heading level: 2 under the page, 3 inside a heading of its own, such as an ObjectPage's row. */
24
+ headingLevel?: 2 | 3;
23
25
  };
24
26
  type Titled = {
25
- /** The section's h2, on every card. */
27
+ /** The section's heading, on every card. */
26
28
  title: string;
27
29
  children?: React.ReactNode;
28
30
  };
@@ -83,9 +85,9 @@ export type SavingSettingsSectionProps = SettingsSectionBase & SavingSection;
83
85
  * @instead Read-only facts of an object are a SettingsFactsSection; a table or a list of records is a TableCard; Theme and Language live in the account menu; a record's edit in a list is a RowEditForm.
84
86
  * @behaviour "Groups related form controls inside a bordered card with optional footer actions." (https://vercel.com/geist/fieldset) Ours: one setting per card, a single SettingsField with the description its only help, unless the card's description covers several settings: then they are its SettingsRows, switches and selects together. A typed value (a name, a URL, a server, a port, a key) gets its own card. A semantic subgroup of related controls inside a field, such as radios or checkboxes, is a `FieldSet` with a `FieldLegend`. Several settings in one card are declared by SettingsRows, never by classes at the call site. "Use Toggle for a single boolean setting where ON takes effect immediately, like `Password Protection` or `Auto-Cancel Builds`." (https://vercel.com/geist/toggle) "Pair with a form footer only when the setting needs an explicit `Save` step." (https://vercel.com/geist/toggle) "Disable Toggle only when the action is impossible (missing plan, locked policy); pair with helper text or a `Tooltip` that names the resolver." (https://vercel.com/geist/toggle) Ours: a switch never applies on change; it is a row of the card, a draft until the footer's Save, as Vercel's settings cards are. A switch blocked from above is shown off and disabled, the footer saying why and never a tooltip. Required: the title and the description. The header's actions stand at the title's right; on a card narrower than 28 rem they keep the title's row and the description runs under both, as Vercel's cards read on a phone, and when the title's longest word would not fit beside them they move under the title, so they never cover it. The footer's left line (`footerHint`, `save.hint`) is optional and specific to the card, never a generic line repeated on every card: a limit, what a value is for, a plan it needs, a link; absent, it is nothing, and a card with neither a line nor a button has no footer. Ours: `save`: a typed value, one card with its own Save in the footer, always visible. The section owns the changed state: Save stays disabled until a field differs from what is saved and says `pendingLabel` while saving with Cancel beside it; a completed save calls `saved`, and the product raises one toast from its catalogue ("Completion toasts follow `{Noun} {past-participle}`: `Blob deleted`, `Domain added`, `Environment variable saved`. Never include `successfully`; the action name implies it." https://vercel.com/geist/toast), and Save returns to disabled, with no saved state in the footer. Ours: the section never raises a toast itself. A failed save keeps every value and shows under its field, or above the footer when no field owns it. `tone` marks a state with a command (a failed payment, a trial ending): a 1px border and a footer tinted in the hue with its line in it, the line saying the condition in words; title, line, fields and buttons stay neutral, an outline secondary then a default primary. A button takes the hue of its command, not of the card: `destructive` (red) for a permanent loss (Delete), `warning` (amber) for a disruptive command that can be undone (Pause, Archive). A delete card is `tone="error"` with the object's summary as its body; an archive card is neutral with a `warning` button in the footer. "Use a Note for inline contextual feedback next to the field, card, or section it describes: a region change warning above a region picker, a rate-limit notice next to a usage gauge." (https://vercel.com/geist/note) "One Note per concept." (https://vercel.com/geist/note) Ours: a message about the fields inside is a MessageNotice in the body, the card staying neutral. "Disabled checkboxes still need a Tooltip naming the reason; a greyed box with no explanation reads as a bug." (https://vercel.com/geist/checkbox) Ours: `lockedReason` (Geist's disabled wall) is the reason, written as the footer's line, not in a tooltip; it keeps the fields in view, inert with muted text, under a not-allowed cursor, the title and line unchanged; `unlock` is the way to get access, left out when nothing the person does unlocks it. A locked section has no `save` and no header `actions`.
85
87
  * @words "Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input) Ours: the description is that helper text for the whole card, and no field has its own. "Render an optional one-sentence description as a sibling under the label that explains ON only. Don’t describe OFF; it’s the negation." (https://vercel.com/geist/toggle) Ours: a header-switch card's description says what turning it on does. The title names the values ("Personal details"); the description says what changing them does, in one line; the footer line is a Learn more link, a limit ("Use 32 characters at most."), what stays unaffected, or what is blocked and why ("Ask an owner to change this."); Save and Saving come from the product's catalogue, and so does the toast a `saved` callback raises; a delete card's description opens "Permanently delete".
86
- * @access "Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`." (https://vercel.com/geist/toggle) Ours: the title is the section's h2 and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.
88
+ * @access "Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`." (https://vercel.com/geist/toggle) Ours: the title is the section's h2, or an h3 with `headingLevel` inside an ObjectPage's row, and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.
87
89
  */
88
- declare function SettingsSection({ title, description, actions, tone, children, className, save, footer, footerHint, lockedReason, unlock, ...props }: SettingsSectionProps): React.JSX.Element;
90
+ declare function SettingsSection({ title, headingLevel, description, actions, tone, children, className, save, footer, footerHint, lockedReason, unlock, ...props }: SettingsSectionProps): React.JSX.Element;
89
91
  type SettingsFieldBase = Omit<React.ComponentProps<typeof Field>, "children" | "orientation"> & {
90
92
  id: string;
91
93
  label: NonNullable<React.ReactNode>;
@@ -1 +1 @@
1
- {"version":3,"file":"settings-section.d.ts","sourceRoot":"","sources":["../../src/components/settings-section.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-section.d.ts","sourceRoot":"","sources":["../../src/components/settings-section.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,KAAK,EAAoD,MAAM,oBAAoB,CAAC;AAK7F,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAElF,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEtD,KAAK,YAAY,GAAG;IAClB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IACvF,mGAAmG;IACnG,WAAW,EAAE,MAAM,CAAC;IACpB,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACtB,CAAC;AAEF,KAAK,MAAM,GAAG;IACZ,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,GAAG;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,GAAG;IAC5B,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,yCAAyC;IACzC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,mIAAmI;IACnI,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,oHAAoH;IACpH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,uDAAuD;IACvD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,GAAG;IAC5B,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,2FAA2F;IAC3F,YAAY,EAAE,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC;IAC1C,wHAAwH;IACxH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,gFAAgF;IAChF,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,mIAAmI;IACnI,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,GACpD,CAAC,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,eAAe,CAAC,CAAC;AAEpE,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,GAAG,aAAa,CAAC;AAS7E;;;;;;;;;GASG;AACH,iBAAS,eAAe,CAAC,EACvB,KAAK,EACL,YAAgB,EAChB,WAAW,EACX,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,MAAM,EACN,UAAU,EACV,YAAY,EACZ,MAAM,EACN,GAAG,KAAK,EACT,EAAE,oBAAoB,qBA4DtB;AA0FD,KAAK,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC,GAAG;IAC9F,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,YAAY,EAAE,yBAAyB,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC;CACnF,CAAC;AAEF,KAAK,kBAAkB,GAAG,iBAAiB,GACzC,CACI;IACE,0EAA0E;IAC1E,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,YAAY,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IAC/C,UAAU,CAAC,EAAE,KAAK,CAAC;CACpB,GACD;IACE,yDAAyD;IACzD,OAAO,EAAE,QAAQ,CAAC;IAClB,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC;CACpB,GACD;IACE,uFAAuF;IACvF,OAAO,EAAE,QAAQ,CAAC;IAClB,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;CACpB,CACJ,CAAC;AAEJ;;;;;;;;;GASG;AACH,iBAAS,aAAa,CAAC,EACrB,EAAE,EACF,KAAK,EACL,IAAI,EACJ,KAAK,EACL,OAAwB,EACxB,QAAQ,EACR,QAAQ,EACR,OAAe,EACf,YAAyB,EACzB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,kBAAkB,qBAiCpB;AAED,KAAK,eAAe,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,iBAAiB,GAAG,eAAe,GAAG;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,KAAK,iBAAiB,GAAG,eAAe,GAAG;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrD,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,KAAK,kBAAkB,GAAG,eAAe,GAAG;IAC1C,uFAAuF;IACvF,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,YAAY,EAAE,yBAAyB,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC;IACjF,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,KAAK,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,KAAK,iBAAiB,GAClB;IACE,2EAA2E;IAC3E,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,SAAS,CAAC,iBAAiB,GAAG,iBAAiB,GAAG,kBAAkB,CAAC,EAAE,CAAC;CAC/E,GACD;IACE,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC,iBAAiB,GAAG,kBAAkB,CAAC,EAAE,CAAC;CAC3D,CAAC;AAyCN;;;;;;;;;GASG;AACH,iBAAS,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,iBAAiB,qBAS7D;AAkDD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -22,13 +22,14 @@ const toneClassNames = {
22
22
  * @instead Read-only facts of an object are a SettingsFactsSection; a table or a list of records is a TableCard; Theme and Language live in the account menu; a record's edit in a list is a RowEditForm.
23
23
  * @behaviour "Groups related form controls inside a bordered card with optional footer actions." (https://vercel.com/geist/fieldset) Ours: one setting per card, a single SettingsField with the description its only help, unless the card's description covers several settings: then they are its SettingsRows, switches and selects together. A typed value (a name, a URL, a server, a port, a key) gets its own card. A semantic subgroup of related controls inside a field, such as radios or checkboxes, is a `FieldSet` with a `FieldLegend`. Several settings in one card are declared by SettingsRows, never by classes at the call site. "Use Toggle for a single boolean setting where ON takes effect immediately, like `Password Protection` or `Auto-Cancel Builds`." (https://vercel.com/geist/toggle) "Pair with a form footer only when the setting needs an explicit `Save` step." (https://vercel.com/geist/toggle) "Disable Toggle only when the action is impossible (missing plan, locked policy); pair with helper text or a `Tooltip` that names the resolver." (https://vercel.com/geist/toggle) Ours: a switch never applies on change; it is a row of the card, a draft until the footer's Save, as Vercel's settings cards are. A switch blocked from above is shown off and disabled, the footer saying why and never a tooltip. Required: the title and the description. The header's actions stand at the title's right; on a card narrower than 28 rem they keep the title's row and the description runs under both, as Vercel's cards read on a phone, and when the title's longest word would not fit beside them they move under the title, so they never cover it. The footer's left line (`footerHint`, `save.hint`) is optional and specific to the card, never a generic line repeated on every card: a limit, what a value is for, a plan it needs, a link; absent, it is nothing, and a card with neither a line nor a button has no footer. Ours: `save`: a typed value, one card with its own Save in the footer, always visible. The section owns the changed state: Save stays disabled until a field differs from what is saved and says `pendingLabel` while saving with Cancel beside it; a completed save calls `saved`, and the product raises one toast from its catalogue ("Completion toasts follow `{Noun} {past-participle}`: `Blob deleted`, `Domain added`, `Environment variable saved`. Never include `successfully`; the action name implies it." https://vercel.com/geist/toast), and Save returns to disabled, with no saved state in the footer. Ours: the section never raises a toast itself. A failed save keeps every value and shows under its field, or above the footer when no field owns it. `tone` marks a state with a command (a failed payment, a trial ending): a 1px border and a footer tinted in the hue with its line in it, the line saying the condition in words; title, line, fields and buttons stay neutral, an outline secondary then a default primary. A button takes the hue of its command, not of the card: `destructive` (red) for a permanent loss (Delete), `warning` (amber) for a disruptive command that can be undone (Pause, Archive). A delete card is `tone="error"` with the object's summary as its body; an archive card is neutral with a `warning` button in the footer. "Use a Note for inline contextual feedback next to the field, card, or section it describes: a region change warning above a region picker, a rate-limit notice next to a usage gauge." (https://vercel.com/geist/note) "One Note per concept." (https://vercel.com/geist/note) Ours: a message about the fields inside is a MessageNotice in the body, the card staying neutral. "Disabled checkboxes still need a Tooltip naming the reason; a greyed box with no explanation reads as a bug." (https://vercel.com/geist/checkbox) Ours: `lockedReason` (Geist's disabled wall) is the reason, written as the footer's line, not in a tooltip; it keeps the fields in view, inert with muted text, under a not-allowed cursor, the title and line unchanged; `unlock` is the way to get access, left out when nothing the person does unlocks it. A locked section has no `save` and no header `actions`.
24
24
  * @words "Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input) Ours: the description is that helper text for the whole card, and no field has its own. "Render an optional one-sentence description as a sibling under the label that explains ON only. Don’t describe OFF; it’s the negation." (https://vercel.com/geist/toggle) Ours: a header-switch card's description says what turning it on does. The title names the values ("Personal details"); the description says what changing them does, in one line; the footer line is a Learn more link, a limit ("Use 32 characters at most."), what stays unaffected, or what is blocked and why ("Ask an owner to change this."); Save and Saving come from the product's catalogue, and so does the toast a `saved` callback raises; a delete card's description opens "Permanently delete".
25
- * @access "Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`." (https://vercel.com/geist/toggle) Ours: the title is the section's h2 and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.
25
+ * @access "Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`." (https://vercel.com/geist/toggle) Ours: the title is the section's h2, or an h3 with `headingLevel` inside an ObjectPage's row, and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.
26
26
  */
27
- function SettingsSection({ title, description, actions, tone, children, className, save, footer, footerHint, lockedReason, unlock, ...props }) {
27
+ function SettingsSection({ title, headingLevel = 2, description, actions, tone, children, className, save, footer, footerHint, lockedReason, unlock, ...props }) {
28
28
  const titleId = React.useId();
29
+ const Heading = headingLevel === 3 ? "h3" : "h2";
29
30
  const locked = lockedReason !== undefined;
30
31
  const fields = children != null ? (_jsx(CardContent, { children: _jsx(FieldGroup, { "data-slot": "settings-section-fields", inert: locked, className: cn(locked && "**:text-muted-foreground"), children: children }) })) : null;
31
- return (_jsxs(Card, { render: _jsx("section", { ...props, "data-slot": "settings-section", "data-tone": tone, "data-locked": locked || undefined }), className: cn("min-w-0", tone && toneClassNames[tone], locked && "cursor-not-allowed *:data-[slot=card-footer]:cursor-default", className), children: [_jsxs(CardHeader, { narrowAction: "title-row", className: cn(!title && "has-data-[slot=card-description]:grid-rows-none"), children: [title ? (_jsx(CardTitle, { children: _jsx("h2", { id: titleId, children: title }) })) : null, _jsx(CardDescription, { children: description }), actions ? _jsx(CardAction, { children: actions }) : null] }), save ? (_jsx(SettingsSaveForm, { save: save, titleId: titleId, children: fields })) : (_jsxs(_Fragment, { children: [fields, _jsx(FooterStrip, { hint: locked ? lockedReason : footerHint, hintSlot: "settings-section-hint", children: locked ? unlock : footer })] }))] }));
32
+ return (_jsxs(Card, { render: _jsx("section", { ...props, "data-slot": "settings-section", "data-tone": tone, "data-locked": locked || undefined }), className: cn("min-w-0", tone && toneClassNames[tone], locked && "cursor-not-allowed *:data-[slot=card-footer]:cursor-default", className), children: [_jsxs(CardHeader, { narrowAction: "title-row", className: cn(!title && "has-data-[slot=card-description]:grid-rows-none"), children: [title ? (_jsx(CardTitle, { children: _jsx(Heading, { id: titleId, children: title }) })) : null, _jsx(CardDescription, { children: description }), actions ? _jsx(CardAction, { children: actions }) : null] }), save ? (_jsx(SettingsSaveForm, { save: save, titleId: titleId, children: fields })) : (_jsxs(_Fragment, { children: [fields, _jsx(FooterStrip, { hint: locked ? lockedReason : footerHint, hintSlot: "settings-section-hint", children: locked ? unlock : footer })] }))] }));
32
33
  }
33
34
  function controlPropsOf({ id, info, error, invalid, disabled, required, }) {
34
35
  return {
@@ -141,10 +141,10 @@ export const USAGE = [
141
141
  family: "Compositions",
142
142
  summary: "One object's page: the object card with its name, commands, facts, rows that open and one link elsewhere, then its sections as cards.",
143
143
  when: "One thing a person opened from a list and now reads or acts on: a customer, a partner, an Installation, a Library entry.",
144
- instead: '"Use Context Card to reveal entity metadata on hover or focus: a user, a deployment, a project, an API key." (https://vercel.com/geist/context-card) Ours: that hover is a `HoverCard`, never this page. A list of records is a CollectionPage; a page of settings only is a SettingsPage, whose cards are SettingsSections; an Agent opens on its AgentProfileCard, the documented exception. A card of values a person saves is a setting card, never this one.',
145
- behaviour: "\"For a static key/value metadata block on a detail page, use `Description`.\" (https://vercel.com/geist/entity) \"The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`.\" (https://vercel.com/geist/entity) \"Lead the left column with a scannable identifier: an `Avatar` or icon, a Title Case label, then sentence-case secondary metadata (`Member since Mar 14, 2026`).\" (https://vercel.com/geist/entity) \"Don’t put interactive controls in the title slot. Buttons, menus, and links belong in the content (`<dd>`) or in the parent layout, not the label (`<dt>`).\" (https://vercel.com/geist/description) Ours: as Vercel's deployment page (Deployment Details, then its steps), the object card is the first card of the page: a header bar with the name at the start and the object's commands at the end (a secondary, then the primary as the filled button, then the three dots, in `PageActions`' order, on the name's row while the name keeps 128 px, as on a phone, and under it otherwise; the primary is the one thing the object waits on its viewer for, such as approving a company that waits for approval, beside its alternative as the secondary, and an object with nothing waiting has none), for a company, the compact mark at 64 stands beside the name and optional line in the header, followed by full-width facts with four columns from `lg` and two below; other object kinds keep their mark and line beside their facts in the existing preview treatment (at least one fact is required: an object is never shown without what it is), each a muted label over its value in body text, then an optional footer with a hint at the start and one link at the end. Optional `entries` follow in a card of their own 12 px under it: rows that open one by one, each with its chevron first (it turns down when open), its title, and its summary at the trailing edge, as Vercel's Build Logs and Deployment Checks rows; an entry marked `defaultOpen` opens with the page, for a link that names it. The footer takes a link only, so no Save or other command of the object fits in it; the object's changes live in its sections, each a setting card with its own footer. The sections follow, 24 apart, each drawing its own states. The card is neutral; colour belongs to the company's compact identity, a semantic fact value, or an entry's status summary, with no coloured card ground.",
144
+ instead: "\"Use Context Card to reveal entity metadata on hover or focus: a user, a deployment, a project, an API key.\" (https://vercel.com/geist/context-card) Ours: that hover is a `HoverCard`, never this page. A list of records is a CollectionPage; a page of settings only is a SettingsPage, whose cards are SettingsSections; an Agent's Edit page in Nadia's window opens on its AgentProfileCard, the documented exception. A card of values a person saves is a setting card, never this one.",
145
+ behaviour: "\"For a static key/value metadata block on a detail page, use `Description`.\" (https://vercel.com/geist/entity) \"The right column holds at most one or two controls. If the row needs more, move secondary actions into a `Dots Menu`.\" (https://vercel.com/geist/entity) \"Lead the left column with a scannable identifier: an `Avatar` or icon, a Title Case label, then sentence-case secondary metadata (`Member since Mar 14, 2026`).\" (https://vercel.com/geist/entity) \"Don’t put interactive controls in the title slot. Buttons, menus, and links belong in the content (`<dd>`) or in the parent layout, not the label (`<dt>`).\" (https://vercel.com/geist/description) Ours: as Vercel's deployment page (Deployment Details, then its steps), the object card is the first card of the page: a header bar with the name at the start and the object's commands at the end (a secondary, then the primary as the filled button, then the three dots, in `PageActions`' order, on the name's row while the name keeps 128 px, as on a phone, and under it otherwise; the primary is the one thing the object waits on its viewer for, such as approving a company that waits for approval, beside its alternative as the secondary, and an object with nothing waiting has none), for a company, the compact mark at 64 stands beside the name and optional line in the header, followed by full-width facts in four columns once they have 36rem and two below; other object kinds keep their mark and line beside their facts in the existing preview treatment (at least one fact is required: an object is never shown without what it is), each a muted label over its value in body text, then an optional footer with a hint at the start and one link at the end. Optional `entries` follow in a card of their own 12 px under it: rows that open one by one, each with its chevron first (it turns down when open), its title, and its summary at the trailing edge, as Vercel's Build Logs and Deployment Checks rows; an entry marked `defaultOpen` opens with the page, for a link that names it. The footer takes a link only, so no Save or other command of the object fits in it; the object's changes live in its sections, each a setting card with its own footer. The sections follow, 24 apart, each drawing its own states. The card is neutral; colour belongs to the company's compact identity, a semantic fact value, or an entry's status summary, with no coloured card ground.",
146
146
  words: '"Keep right-column buttons Verb + Noun (`Remove Member`, `Resend Invite`). Bare verbs like `Remove` or `Confirm` lose context once the row scrolls offscreen." (https://vercel.com/geist/entity) "Title slot is Title Case noun (`Last Deployed`, `Build Duration`); content is sentence case unless the value is a literal identifier, ID, or timestamp that should be preserved verbatim." (https://vercel.com/geist/description) Ours: sentence case throughout. The name as the object is called everywhere else; the line says what it is and whose ("Customer of Partner Alpha · since 3 August 2026"); a fact\'s label is a noun ("Plan"), its value the figure; an entry\'s title is a noun phrase; the hint is one sentence ("To update it, push to the main branch."); the link names where it goes ("Deployments"); the menu\'s trigger reads "More for {name}".',
147
- access: '"Geist renders `<dl>`/`<dt>`/`<dd>` so screen readers announce each key/value pair as a definition." (https://vercel.com/geist/description) "Don’t wrap the component in extra paragraphs that break the list semantics." (https://vercel.com/geist/description) Ours: with `headingProps` the name is the page\'s h1; without them it is text, for a product whose chrome already titles the page. The mark is decorative beside the facts. Each entry is a button with `aria-expanded` that controls its panel.',
147
+ access: '"Geist renders `<dl>`/`<dt>`/`<dd>` so screen readers announce each key/value pair as a definition." (https://vercel.com/geist/description) "Don’t wrap the component in extra paragraphs that break the list semantics." (https://vercel.com/geist/description) Ours: with `headingProps` the name is the page\'s h1; without them it is text, for a product whose chrome already titles the page. The mark is decorative beside the facts. Each entry is an h2 heading holding a button with `aria-expanded` that controls its panel.',
148
148
  },
149
149
  {
150
150
  name: "ObjectSection",
@@ -232,7 +232,7 @@ export const USAGE = [
232
232
  instead: "Read-only facts of an object are a SettingsFactsSection; a table or a list of records is a TableCard; Theme and Language live in the account menu; a record's edit in a list is a RowEditForm.",
233
233
  behaviour: '"Groups related form controls inside a bordered card with optional footer actions." (https://vercel.com/geist/fieldset) Ours: one setting per card, a single SettingsField with the description its only help, unless the card\'s description covers several settings: then they are its SettingsRows, switches and selects together. A typed value (a name, a URL, a server, a port, a key) gets its own card. A semantic subgroup of related controls inside a field, such as radios or checkboxes, is a `FieldSet` with a `FieldLegend`. Several settings in one card are declared by SettingsRows, never by classes at the call site. "Use Toggle for a single boolean setting where ON takes effect immediately, like `Password Protection` or `Auto-Cancel Builds`." (https://vercel.com/geist/toggle) "Pair with a form footer only when the setting needs an explicit `Save` step." (https://vercel.com/geist/toggle) "Disable Toggle only when the action is impossible (missing plan, locked policy); pair with helper text or a `Tooltip` that names the resolver." (https://vercel.com/geist/toggle) Ours: a switch never applies on change; it is a row of the card, a draft until the footer\'s Save, as Vercel\'s settings cards are. A switch blocked from above is shown off and disabled, the footer saying why and never a tooltip. Required: the title and the description. The header\'s actions stand at the title\'s right; on a card narrower than 28 rem they keep the title\'s row and the description runs under both, as Vercel\'s cards read on a phone, and when the title\'s longest word would not fit beside them they move under the title, so they never cover it. The footer\'s left line (`footerHint`, `save.hint`) is optional and specific to the card, never a generic line repeated on every card: a limit, what a value is for, a plan it needs, a link; absent, it is nothing, and a card with neither a line nor a button has no footer. Ours: `save`: a typed value, one card with its own Save in the footer, always visible. The section owns the changed state: Save stays disabled until a field differs from what is saved and says `pendingLabel` while saving with Cancel beside it; a completed save calls `saved`, and the product raises one toast from its catalogue ("Completion toasts follow `{Noun} {past-participle}`: `Blob deleted`, `Domain added`, `Environment variable saved`. Never include `successfully`; the action name implies it." https://vercel.com/geist/toast), and Save returns to disabled, with no saved state in the footer. Ours: the section never raises a toast itself. A failed save keeps every value and shows under its field, or above the footer when no field owns it. `tone` marks a state with a command (a failed payment, a trial ending): a 1px border and a footer tinted in the hue with its line in it, the line saying the condition in words; title, line, fields and buttons stay neutral, an outline secondary then a default primary. A button takes the hue of its command, not of the card: `destructive` (red) for a permanent loss (Delete), `warning` (amber) for a disruptive command that can be undone (Pause, Archive). A delete card is `tone="error"` with the object\'s summary as its body; an archive card is neutral with a `warning` button in the footer. "Use a Note for inline contextual feedback next to the field, card, or section it describes: a region change warning above a region picker, a rate-limit notice next to a usage gauge." (https://vercel.com/geist/note) "One Note per concept." (https://vercel.com/geist/note) Ours: a message about the fields inside is a MessageNotice in the body, the card staying neutral. "Disabled checkboxes still need a Tooltip naming the reason; a greyed box with no explanation reads as a bug." (https://vercel.com/geist/checkbox) Ours: `lockedReason` (Geist\'s disabled wall) is the reason, written as the footer\'s line, not in a tooltip; it keeps the fields in view, inert with muted text, under a not-allowed cursor, the title and line unchanged; `unlock` is the way to get access, left out when nothing the person does unlocks it. A locked section has no `save` and no header `actions`.',
234
234
  words: '"Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input) Ours: the description is that helper text for the whole card, and no field has its own. "Render an optional one-sentence description as a sibling under the label that explains ON only. Don’t describe OFF; it’s the negation." (https://vercel.com/geist/toggle) Ours: a header-switch card\'s description says what turning it on does. The title names the values ("Personal details"); the description says what changing them does, in one line; the footer line is a Learn more link, a limit ("Use 32 characters at most."), what stays unaffected, or what is blocked and why ("Ask an owner to change this."); Save and Saving come from the product\'s catalogue, and so does the toast a `saved` callback raises; a delete card\'s description opens "Permanently delete".',
235
- access: "\"Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`.\" (https://vercel.com/geist/toggle) Ours: the title is the section's h2 and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.",
235
+ access: "\"Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`.\" (https://vercel.com/geist/toggle) Ours: the title is the section's h2, or an h3 with `headingLevel` inside an ObjectPage's row, and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.",
236
236
  },
237
237
  {
238
238
  name: "Button",
@@ -1695,7 +1695,7 @@ export const USAGE = [
1695
1695
  instead: "“Single Collapse for one optional block. `CollapseGroup` for a related set; switch to `Tabs` when the items are sibling views, not optional drill-downs.” (https://vercel.com/geist/collapse) Ours: one piece of supporting detail is `Disclosure`, and a single optional block is `Collapsible`.",
1696
1696
  behaviour: "“Default state is closed unless the first-time visitor must read the content to act.” (https://vercel.com/geist/collapse) “Inside a `CollapseGroup`, allow only one panel open at a time when items are mutually exclusive; allow multiple when items are independent.” (https://vercel.com/geist/collapse) “Animate the open/close transition; jump-cuts make the page feel like it teleported.” (https://vercel.com/geist/collapse) “Don’t nest Collapse more than one level deep. Two-level nesting hides too much and breaks the keyboard tab path.” (https://vercel.com/geist/collapse) Ours: a flat list divided by 1 px lines, closed at the top and under every section, with no fill, no card and no hover change. A section is a heading row with the title at the start and a 16 px chevron at the end that points right while closed and down while open. `size` is `default` (a 24 px semibold title, an 84 px row) or `small` (a 16 px medium title, a 48 px row). Colour is neutral only, in every state. Exclusive sections open one at a time and the open one can be closed; independent ones stay open together with `multiple`. The panel animates its height, and under reduced motion it jumps. An accordion never nests in another.",
1697
1697
  words: "“Heading is Title Case and names the topic, not the action (`Advanced Settings`, not `Show Advanced Settings`).” (https://vercel.com/geist/collapse) “Body is sentence case prose with normal section formatting; treat the panel as a small page, not a tooltip.” (https://vercel.com/geist/collapse) “Don’t put primary destructive actions inside a closed Collapse; the user has to click twice to reach the warning.” (https://vercel.com/geist/collapse) Ours: the trigger is required and names its topic as a noun phrase or a question a person asks, in sentence case, not Title Case: *Advanced settings*, never *Show advanced settings*.",
1698
- access: "“The trigger is a `<button>` with `aria-expanded` that flips on toggle and `aria-controls` pointing at the panel id.” (https://vercel.com/geist/collapse) “Enter and Space toggle. Don’t bind any other key globally; arrow keys move focus inside the panel content.” (https://vercel.com/geist/collapse) “Render the panel content in the DOM when closed (with `hidden` or visibility) so search and find-in-page still hit it; lazy-render only for expensive content.” (https://vercel.com/geist/collapse) Ours: a closed panel stays in the page, hidden until found, so find-in-page opens it; pass `hiddenUntilFound={false}` on a heavy panel to mount it only when open. Headings keep the page's outline.",
1698
+ access: "“The trigger is a `<button>` with `aria-expanded` that flips on toggle and `aria-controls` pointing at the panel id.” (https://vercel.com/geist/collapse) “Enter and Space toggle. Don’t bind any other key globally; arrow keys move focus inside the panel content.” (https://vercel.com/geist/collapse) “Render the panel content in the DOM when closed (with `hidden` or visibility) so search and find-in-page still hit it; lazy-render only for expensive content.” (https://vercel.com/geist/collapse) Ours: a closed panel stays in the page, hidden until found, so find-in-page opens it; pass `hiddenUntilFound={false}` on a heavy panel to mount it only when open. A trigger's heading is an h3, and `level` sets the one that keeps the page's outline.",
1699
1699
  },
1700
1700
  {
1701
1701
  name: "AspectRatio",
@@ -1756,7 +1756,7 @@ export const USAGE = [
1756
1756
  name: "HiveScene",
1757
1757
  module: "hive-scene",
1758
1758
  family: "Other",
1759
- summary: "Alveare's entry scene: its picture, its logo and six Agent orbs around the words.",
1759
+ summary: "Alveare's entry scene: its picture, its mark and six Agent orbs around the words.",
1760
1760
  when: "Alveare's entry screens, on its desktop and on Alveare Server: joining, loading, a failure.",
1761
1761
  instead: "Nadia's entry screens are `EntryScene`. A product page never stands on a scene.",
1762
1762
  behaviour: "`join` puts the words in the hexagon's middle, `loading` draws the orbs in with no words, `still` shows no Agent and no work. Only the orbs and the particles move; reduced motion stops both. Black in every theme. The scene sets the width its words are drawn at on itself as `--hive-words-width`, so the app's picture keeps clear of them, and draws no honeycomb near them.",
@@ -653,41 +653,36 @@
653
653
  }
654
654
 
655
655
  /*
656
- * Alveare's own logo at the upper left, where Nadia's and the Portal's entry
657
- * screens put the nadicode wordmark, at the wordmark's height and inset. The
658
- * icon's tile is 824 of its 1024 units; the image box is sized so the tile,
659
- * not the file's margin, takes the wordmark's height. An app with window
660
- * controls over the scene sets `--hive-chrome-clearance` to their height, which
661
- * the narrow inset clears.
656
+ * Alveare's own mark at the upper left, where Nadia's and the Portal's entry
657
+ * screens put the nadicode wordmark, at the wordmark's height and inset: the
658
+ * ribbon alone, since the icon's black tile would vanish into the black scene
659
+ * and leave the ribbon a third of the height. An app with window controls over
660
+ * the scene sets `--hive-chrome-clearance` to their height, which the narrow
661
+ * inset clears.
662
662
  */
663
663
  .nc-hive-logo {
664
- --hive-logo-tile: 24px;
664
+ --hive-logo-height: 24px;
665
665
  --hive-logo-inset: var(--nc-lg);
666
- --hive-logo-box: calc(var(--hive-logo-tile) * 1024 / 824);
667
- --hive-logo-margin: calc(var(--hive-logo-box) * 100 / 1024);
668
666
  position: absolute;
669
667
  z-index: 2;
670
- top: calc(
671
- max(var(--hive-logo-inset), var(--hive-chrome-clearance, 0px)) -
672
- var(--hive-logo-margin)
673
- );
674
- left: calc(var(--hive-logo-inset) - var(--hive-logo-margin));
675
- width: var(--hive-logo-box);
676
- height: var(--hive-logo-box);
668
+ top: max(var(--hive-logo-inset), var(--hive-chrome-clearance, 0px));
669
+ left: var(--hive-logo-inset);
670
+ width: auto;
671
+ height: var(--hive-logo-height);
677
672
  pointer-events: none;
678
673
  user-select: none;
679
674
  }
680
675
 
681
676
  @media (min-width: 640px) {
682
677
  .nc-hive-logo {
683
- --hive-logo-tile: 32px;
678
+ --hive-logo-height: 32px;
684
679
  }
685
680
  }
686
681
 
687
682
  @media (min-width: 768px) {
688
683
  .nc-hive-logo {
689
684
  --hive-logo-inset: var(--nc-2xl);
690
- top: calc(var(--hive-logo-inset) - var(--hive-logo-margin));
685
+ top: var(--hive-logo-inset);
691
686
  }
692
687
  }
693
688
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "12.1.163",
3
+ "version": "12.1.165",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -84,7 +84,7 @@
84
84
  "@base-ui/react": "^1.9.0",
85
85
  "@iconify-icons/logos": "^2.0.3",
86
86
  "@iconify/react": "^6.0.2",
87
- "@nadicodeai/design-system": "12.1.163",
87
+ "@nadicodeai/design-system": "12.1.165",
88
88
  "@tanstack/react-table": "^9.3.1",
89
89
  "@vgpu/wgsl": "0.6.0",
90
90
  "class-variance-authority": "^0.7.1",