@nadicodeai/ui 12.1.148 → 12.1.149

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.
@@ -20,7 +20,7 @@ export type MessageNoticeProps = {
20
20
  *
21
21
  * @family Feedback
22
22
  * @when "Display text that requires attention or provides additional information." (https://vercel.com/geist/note) "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) "Choose `variant` by meaning: `error` for a problem the user must fix, `warning` for a consequence to acknowledge, `success` for a passed check, `secondary` for neutral information." (https://vercel.com/geist/note) Ours: a message beside the field, card or section it describes, under the control whose write failed (`action`), or atop the section whose condition lasts (`section`). The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` (a passed check or a state the product manages for the reader, drawn in the accent blue) and `neutral` is `secondary`; there is no violet or cyan.
23
- * @instead "Pick `Banner` when the message is page-level or system-wide and needs a CTA, `Toast` for transient acknowledgments, `Modal` for destructive confirmations." (https://vercel.com/geist/note) Ours: `Banner` is `NoticeBanner`, `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a field's wrong value use `FieldError`. For a failed read use `EmptyState failed`.
23
+ * @instead "Pick `Banner` when the message is page-level or system-wide and needs a CTA, `Toast` for transient acknowledgments, `Modal` for destructive confirmations." (https://vercel.com/geist/note) Ours: `Banner` is `NoticeBanner`, for a condition of the page's own object, and a system-wide condition is a notification in the product's inbox, never a banner; `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a field's wrong value use `FieldError`. For a failed read use `EmptyState failed`.
24
24
  * @behaviour "A Note is persistent until the underlying state changes; don’t add an ad hoc dismiss control because it competes with the message." (https://vercel.com/geist/note) "One Note per concept. Stacking three Notes on a card means the page architecture, not the Note copy, is wrong." (https://vercel.com/geist/note) "The optional `NoteAction` holds a single inline CTA. Don’t pair it with a second button." (https://vercel.com/geist/note) Ours: `Alert` is its primitive. Tone `destructive` by default, `warning`, `info` or `neutral`; there is no `success` tone. Colour sits on the line, the text and the mark; the ground stays clear, and the action stays neutral. `section` is the framed note, a line 36 px high with its mark and sentence on one row and the action at its trailing edge (under 768 px the action takes its own row, full width), with or without an action; `action` is the unframed passage, its mark and sentence on one row with the action link inside the sentence, after a space. The title and the body run on as one passage, the title closed by a full stop when it has none of its own, so the two never read as one sentence; the title leads in bold (semibold in a note, medium in a passage) only when a body follows it, and stands at regular weight alone. A message worded for a notice has one action, a small default button in a section and an underlined 14 px link in the passage, and at most a second one after it (Nadia's *Ask Nadia* after *Try again*), an outline button in a section and a second link in the passage; a third is not shown. Long words wrap, nothing truncates. A successful retry removes it. Required: the catalogue `message`, so the sentence and its mark are always drawn.
25
25
  * @words "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) "`NoteContent` is one sentence in active voice that names the impact: `Changing this region restarts all functions.`" (https://vercel.com/geist/note) "No `variant="info"` exists; omit `variant` for the default info icon or use `variant="secondary"` for neutral copy." (https://vercel.com/geist/note) "Single-fragment labels take no period; full descriptive sentences in the body do." (https://vercel.com/geist/note) Ours: words come from the catalogue only. The message's title stands in for `NoteLabel` and `NoteContent`, in sentence case, and `info` exists as Geist's blue `success`. The action is labelled with its result: *Try again*, *Sign in*. When the message carries an action, its body does not repeat it: the link is the step, so the body ends before "Try again".
26
26
  * @access `action`: `role="alert"` (`status` for info and neutral). `section`: `role="status"`, `aria-live="polite"`, atomic. The mark is hidden. Focus stays where the person was.
@@ -1 +1 @@
1
- {"version":3,"file":"message-notice.d.ts","sourceRoot":"","sources":["../../src/components/message-notice.tsx"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,UAAU,IAAI,iBAAiB,EACrC,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE1E,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAalC;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,IAAoB,EACpB,SAAS,GACV,EAAE,kBAAkB,+BAuEpB"}
1
+ {"version":3,"file":"message-notice.d.ts","sourceRoot":"","sources":["../../src/components/message-notice.tsx"],"names":[],"mappings":"AAKA,OAAO,EAKL,KAAK,UAAU,IAAI,iBAAiB,EACrC,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE1E,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAWlC;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,IAAoB,EACpB,SAAS,GACV,EAAE,kBAAkB,+BAuEpB"}
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { OctagonAlert } from "lucide-react";
4
4
  import { Alert } from "./alert.js";
5
- import { NOTICE_EDGE, NoticeLink, NoticeMark, } from "../internal/notice.js";
5
+ import { closedSentence, NOTICE_EDGE, NoticeLink, NoticeMark, } from "../internal/notice.js";
6
6
  import { cn } from "../lib/utils.js";
7
7
  import { PageCommandButton } from "./page-actions.js";
8
8
  import { bodyBeyondTitle } from "./product-message.js";
@@ -13,13 +13,12 @@ const TONE_TEXT = {
13
13
  destructive: "text-destructive-soft-foreground",
14
14
  };
15
15
  const LEAD = { action: "font-medium", section: "font-semibold" };
16
- const closedSentence = (title) => (/[.!?:…]$/u.test(title) ? title : `${title}.`);
17
16
  /**
18
17
  * A catalogue message about one thing on the screen.
19
18
  *
20
19
  * @family Feedback
21
20
  * @when "Display text that requires attention or provides additional information." (https://vercel.com/geist/note) "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) "Choose `variant` by meaning: `error` for a problem the user must fix, `warning` for a consequence to acknowledge, `success` for a passed check, `secondary` for neutral information." (https://vercel.com/geist/note) Ours: a message beside the field, card or section it describes, under the control whose write failed (`action`), or atop the section whose condition lasts (`section`). The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` (a passed check or a state the product manages for the reader, drawn in the accent blue) and `neutral` is `secondary`; there is no violet or cyan.
22
- * @instead "Pick `Banner` when the message is page-level or system-wide and needs a CTA, `Toast` for transient acknowledgments, `Modal` for destructive confirmations." (https://vercel.com/geist/note) Ours: `Banner` is `NoticeBanner`, `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a field's wrong value use `FieldError`. For a failed read use `EmptyState failed`.
21
+ * @instead "Pick `Banner` when the message is page-level or system-wide and needs a CTA, `Toast` for transient acknowledgments, `Modal` for destructive confirmations." (https://vercel.com/geist/note) Ours: `Banner` is `NoticeBanner`, for a condition of the page's own object, and a system-wide condition is a notification in the product's inbox, never a banner; `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a field's wrong value use `FieldError`. For a failed read use `EmptyState failed`.
23
22
  * @behaviour "A Note is persistent until the underlying state changes; don’t add an ad hoc dismiss control because it competes with the message." (https://vercel.com/geist/note) "One Note per concept. Stacking three Notes on a card means the page architecture, not the Note copy, is wrong." (https://vercel.com/geist/note) "The optional `NoteAction` holds a single inline CTA. Don’t pair it with a second button." (https://vercel.com/geist/note) Ours: `Alert` is its primitive. Tone `destructive` by default, `warning`, `info` or `neutral`; there is no `success` tone. Colour sits on the line, the text and the mark; the ground stays clear, and the action stays neutral. `section` is the framed note, a line 36 px high with its mark and sentence on one row and the action at its trailing edge (under 768 px the action takes its own row, full width), with or without an action; `action` is the unframed passage, its mark and sentence on one row with the action link inside the sentence, after a space. The title and the body run on as one passage, the title closed by a full stop when it has none of its own, so the two never read as one sentence; the title leads in bold (semibold in a note, medium in a passage) only when a body follows it, and stands at regular weight alone. A message worded for a notice has one action, a small default button in a section and an underlined 14 px link in the passage, and at most a second one after it (Nadia's *Ask Nadia* after *Try again*), an outline button in a section and a second link in the passage; a third is not shown. Long words wrap, nothing truncates. A successful retry removes it. Required: the catalogue `message`, so the sentence and its mark are always drawn.
24
23
  * @words "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) "`NoteContent` is one sentence in active voice that names the impact: `Changing this region restarts all functions.`" (https://vercel.com/geist/note) "No `variant="info"` exists; omit `variant` for the default info icon or use `variant="secondary"` for neutral copy." (https://vercel.com/geist/note) "Single-fragment labels take no period; full descriptive sentences in the body do." (https://vercel.com/geist/note) Ours: words come from the catalogue only. The message's title stands in for `NoteLabel` and `NoteContent`, in sentence case, and `info` exists as Geist's blue `success`. The action is labelled with its result: *Try again*, *Sign in*. When the message carries an action, its body does not repeat it: the link is the step, so the body ends before "Try again".
25
24
  * @access `action`: `role="alert"` (`status` for info and neutral). `section`: `role="status"`, `aria-live="polite"`, atomic. The mark is hidden. Focus stays where the person was.
@@ -3,30 +3,33 @@ import type { LucideIcon } from "lucide-react";
3
3
  import { type NoticeTone } from "../internal/notice.js";
4
4
  import type { PageCommand } from "./page-actions.js";
5
5
  export type NoticeBannerTone = NoticeTone;
6
- export type NoticeBannerLiveRegion = "off" | "polite";
6
+ export type NoticeBannerLiveRegion = "off" | "polite" | "assertive";
7
7
  export type NoticeBannerProps = {
8
8
  /** The one fix the page offers, drawn as an underlined link. Required: a condition is shown with its fix. */
9
9
  action: PageCommand;
10
10
  className?: string;
11
- description?: ReactNode;
11
+ /** One more sentence the title leaves out, run on after it; not shown when it repeats the title. */
12
+ description?: string;
13
+ /** What runs under the passage on a row of its own: a progress bar, a failed retry's line. */
12
14
  detail?: ReactNode;
13
15
  /** Replaces the tone's mark with another lucide icon. */
14
16
  icon?: LucideIcon;
15
17
  /** One or two words naming the topic, leading the title: "Billing", "Slack". */
16
18
  label?: string;
17
19
  liveRegion: NoticeBannerLiveRegion;
18
- title: ReactNode;
20
+ /** The one sentence naming the condition, as the product's catalogue words it. */
21
+ title: string;
19
22
  tone: NoticeBannerTone;
20
23
  } & Omit<ComponentProps<"div">, "children" | "title">;
21
24
  /**
22
- * A condition of the whole page, the account or the service, with its fix.
25
+ * A condition of the page's own object, with the fix the page offers.
23
26
  *
24
27
  * @family Feedback
25
- * @when "A prominent message that spans the full width of its container to announce important information." (https://vercel.com/geist/banner) "Used for temporary, project-wide notifications that require resolution" (https://vercel.com/geist/project-banner) "Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys." (https://vercel.com/geist/project-banner) "Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices." (https://vercel.com/geist/project-banner) Ours: a condition of the whole page, the account or the service that the page itself can resolve, with that resolving action on the banner. The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` and `neutral` is `gray`. One sits above the page's content, under its title.
26
- * @instead "Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations." (https://vercel.com/geist/project-banner) Ours: there is no announcement strip. `Note` is `MessageNotice` (`placement="section"`), `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a measured level use a `KpiCard` with its tone; crossing a threshold is a notification in the inbox, not a banner.
27
- * @behaviour "Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`." (https://vercel.com/geist/project-banner) "Show one Project Banner at a time. Stacking competing banners drowns the most urgent state." (https://vercel.com/geist/project-banner) "Always pass a `callToAction` that resolves the state. A banner with no route is a dead end." (https://vercel.com/geist/project-banner) Ours: a strip as wide as its container: a filled ground with a line on its top and bottom edge only, no corners, 40 px high and centred, with the mark, the sentence and the fix on one row; under 768 px the fix drops under the sentence, aligned with its text. Colour sits on the whole strip (ground, both lines, mark and text); the fix is an underlined link in the darkest step of the same hue (neutral: `text-foreground`) and returns to the strip's text on hover. Neutral and info take the Info mark, warning and destructive the TriangleAlert. `action` is the `callToAction`: one command, never two, never a ready-made button, and there is no close button. Required: `action`, `title`, `tone` and `liveRegion`; the mark is always drawn, and `icon` swaps the tone's mark for another lucide icon.
28
- * @words "`label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles." (https://vercel.com/geist/project-banner) "`callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`." (https://vercel.com/geist/project-banner) "Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`)." (https://vercel.com/geist/project-banner) "Don’t encode severity in the copy with emoji or interjections; the variant carries that signal." (https://vercel.com/geist/project-banner) "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) Ours: the `title` is the `label`: the one sentence, naming the condition, its impact and the object. A `description` only adds what the title leaves out, in one more sentence. Our `label` is the `NoteLabel` topic prefix. The action is sentence case, verb and noun, pointing at the resolver: "Open Slack settings", "Update card". No "Please". The words come from the product's catalogue code.
29
- * @access `liveRegion="polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark, given or not, is hidden.
28
+ * @when "A prominent message that spans the full width of its container to announce important information." (https://vercel.com/geist/banner) "Used for temporary, project-wide notifications that require resolution" (https://vercel.com/geist/project-banner) "Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys." (https://vercel.com/geist/project-banner) "Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices." (https://vercel.com/geist/project-banner) Ours: a condition of the page's own object that the page itself resolves, with that resolving action on the banner: a past-due subscription on its billing page, a failed refresh of the page's own reading. The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` and `neutral` is `gray`. One sits above the page's content, under its title.
29
+ * @instead "Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations." (https://vercel.com/geist/project-banner) Ours: there is no announcement strip. `Note` is `MessageNotice` (`placement="section"`), `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a measured level use a `KpiCard` with its tone; crossing a threshold is a notification in the inbox, not a banner. A condition of the system, the setup or the staff (a connection, a stored secret, a failing job, anything a staff member fixes in settings) is a notification in the product's inbox, never a banner on a page: "The Vercel dashboard displays a popover, which contains all relevant notifications" (https://vercel.com/docs/notifications), and the Portal's System health raises it through Knock to the bell at the sidebar's foot.
30
+ * @behaviour "Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`." (https://vercel.com/geist/project-banner) "Show one Project Banner at a time. Stacking competing banners drowns the most urgent state." (https://vercel.com/geist/project-banner) "Always pass a `callToAction` that resolves the state. A banner with no route is a dead end." (https://vercel.com/geist/project-banner) Ours: a strip as wide as its container: a filled ground with a line on its top and bottom edge only, no corners, 40 px high and centred, with the mark, the sentence and the fix on one row; under 768 px the fix drops under the sentence, aligned with its text. The title and the description run on as one passage: the title closed by a full stop when it has none of its own, leading in semibold when a description follows and at regular weight alone, the description after it on the same line, and a description that repeats the title not shown. `detail` takes its own row under the passage. Colour sits on the whole strip (ground, both lines, mark and text); the fix is an underlined link in the darkest step of the same hue (neutral: `text-foreground`) and returns to the strip's text on hover. Neutral and info take the Info mark, warning and destructive the TriangleAlert. `action` is the `callToAction`: one command, never two, never a ready-made button, and there is no close button. Required: `action`, `title`, `tone` and `liveRegion`; the mark is always drawn, and `icon` swaps the tone's mark for another lucide icon.
31
+ * @words "`label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles." (https://vercel.com/geist/project-banner) "`callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`." (https://vercel.com/geist/project-banner) "Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`)." (https://vercel.com/geist/project-banner) "Don’t encode severity in the copy with emoji or interjections; the variant carries that signal." (https://vercel.com/geist/project-banner) "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) Ours: the `title` is the `label`: the one sentence, naming the condition, its impact and the object. A `description` only adds what the title leaves out, in one more sentence. Our `label` is the `NoteLabel` topic prefix. The action is sentence case, verb and noun, pointing at the resolver: "Update payment method", "Try again". No "Please". The words come from the product's catalogue code.
32
+ * @access `liveRegion="assertive"` gives `role="alert"`, for a failure the person just caused; `"polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark, given or not, is hidden.
30
33
  */
31
34
  export declare function NoticeBanner({ action, className, description, detail, icon, label, liveRegion, title, tone, ...props }: NoticeBannerProps): import("react").JSX.Element;
32
35
  //# sourceMappingURL=notice-banner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notice-banner.d.ts","sourceRoot":"","sources":["../../src/components/notice-banner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAC1C,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEtD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6GAA6G;IAC7G,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,yDAAyD;IACzD,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,sBAAsB,CAAC;IACnC,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,gBAAgB,CAAC;CACxB,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC;AAGtD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,WAAW,EACX,MAAM,EACN,IAAI,EACJ,KAAK,EACL,UAAU,EACV,KAAK,EACL,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,iBAAiB,+BA4CnB"}
1
+ {"version":3,"file":"notice-banner.d.ts","sourceRoot":"","sources":["../../src/components/notice-banner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAC1C,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEpE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6GAA6G;IAC7G,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,yDAAyD;IACzD,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,sBAAsB,CAAC;IACnC,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,gBAAgB,CAAC;CACxB,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC;AAKtD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,WAAW,EACX,MAAM,EACN,IAAI,EACJ,KAAK,EACL,UAAU,EACV,KAAK,EACL,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,iBAAiB,+BAkDnB"}
@@ -1,19 +1,22 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Alert, AlertDescription, AlertTitle } from "./alert.js";
3
- import { NOTICE_EDGE, NoticeLink, NoticeMark } from "../internal/notice.js";
3
+ import { closedSentence, NOTICE_EDGE, NoticeLink, NoticeMark, } from "../internal/notice.js";
4
4
  import { cn } from "../lib/utils.js";
5
+ import { bodyBeyondTitle } from "./product-message.js";
6
+ const LIVE_REGION_ROLE = { assertive: "alert", polite: "status", off: "note" };
5
7
  // eslint-disable-next-line no-warning-comments -- the block quotes Geist's banner rule word for word (https://vercel.com/geist/banner); "temporary" there is prose, not a marker
6
8
  /**
7
- * A condition of the whole page, the account or the service, with its fix.
9
+ * A condition of the page's own object, with the fix the page offers.
8
10
  *
9
11
  * @family Feedback
10
- * @when "A prominent message that spans the full width of its container to announce important information." (https://vercel.com/geist/banner) "Used for temporary, project-wide notifications that require resolution" (https://vercel.com/geist/project-banner) "Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys." (https://vercel.com/geist/project-banner) "Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices." (https://vercel.com/geist/project-banner) Ours: a condition of the whole page, the account or the service that the page itself can resolve, with that resolving action on the banner. The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` and `neutral` is `gray`. One sits above the page's content, under its title.
11
- * @instead "Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations." (https://vercel.com/geist/project-banner) Ours: there is no announcement strip. `Note` is `MessageNotice` (`placement="section"`), `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a measured level use a `KpiCard` with its tone; crossing a threshold is a notification in the inbox, not a banner.
12
- * @behaviour "Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`." (https://vercel.com/geist/project-banner) "Show one Project Banner at a time. Stacking competing banners drowns the most urgent state." (https://vercel.com/geist/project-banner) "Always pass a `callToAction` that resolves the state. A banner with no route is a dead end." (https://vercel.com/geist/project-banner) Ours: a strip as wide as its container: a filled ground with a line on its top and bottom edge only, no corners, 40 px high and centred, with the mark, the sentence and the fix on one row; under 768 px the fix drops under the sentence, aligned with its text. Colour sits on the whole strip (ground, both lines, mark and text); the fix is an underlined link in the darkest step of the same hue (neutral: `text-foreground`) and returns to the strip's text on hover. Neutral and info take the Info mark, warning and destructive the TriangleAlert. `action` is the `callToAction`: one command, never two, never a ready-made button, and there is no close button. Required: `action`, `title`, `tone` and `liveRegion`; the mark is always drawn, and `icon` swaps the tone's mark for another lucide icon.
13
- * @words "`label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles." (https://vercel.com/geist/project-banner) "`callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`." (https://vercel.com/geist/project-banner) "Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`)." (https://vercel.com/geist/project-banner) "Don’t encode severity in the copy with emoji or interjections; the variant carries that signal." (https://vercel.com/geist/project-banner) "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) Ours: the `title` is the `label`: the one sentence, naming the condition, its impact and the object. A `description` only adds what the title leaves out, in one more sentence. Our `label` is the `NoteLabel` topic prefix. The action is sentence case, verb and noun, pointing at the resolver: "Open Slack settings", "Update card". No "Please". The words come from the product's catalogue code.
14
- * @access `liveRegion="polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark, given or not, is hidden.
12
+ * @when "A prominent message that spans the full width of its container to announce important information." (https://vercel.com/geist/banner) "Used for temporary, project-wide notifications that require resolution" (https://vercel.com/geist/project-banner) "Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys." (https://vercel.com/geist/project-banner) "Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices." (https://vercel.com/geist/project-banner) Ours: a condition of the page's own object that the page itself resolves, with that resolving action on the banner: a past-due subscription on its billing page, a failed refresh of the page's own reading. The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` and `neutral` is `gray`. One sits above the page's content, under its title.
13
+ * @instead "Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations." (https://vercel.com/geist/project-banner) Ours: there is no announcement strip. `Note` is `MessageNotice` (`placement="section"`), `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a measured level use a `KpiCard` with its tone; crossing a threshold is a notification in the inbox, not a banner. A condition of the system, the setup or the staff (a connection, a stored secret, a failing job, anything a staff member fixes in settings) is a notification in the product's inbox, never a banner on a page: "The Vercel dashboard displays a popover, which contains all relevant notifications" (https://vercel.com/docs/notifications), and the Portal's System health raises it through Knock to the bell at the sidebar's foot.
14
+ * @behaviour "Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`." (https://vercel.com/geist/project-banner) "Show one Project Banner at a time. Stacking competing banners drowns the most urgent state." (https://vercel.com/geist/project-banner) "Always pass a `callToAction` that resolves the state. A banner with no route is a dead end." (https://vercel.com/geist/project-banner) Ours: a strip as wide as its container: a filled ground with a line on its top and bottom edge only, no corners, 40 px high and centred, with the mark, the sentence and the fix on one row; under 768 px the fix drops under the sentence, aligned with its text. The title and the description run on as one passage: the title closed by a full stop when it has none of its own, leading in semibold when a description follows and at regular weight alone, the description after it on the same line, and a description that repeats the title not shown. `detail` takes its own row under the passage. Colour sits on the whole strip (ground, both lines, mark and text); the fix is an underlined link in the darkest step of the same hue (neutral: `text-foreground`) and returns to the strip's text on hover. Neutral and info take the Info mark, warning and destructive the TriangleAlert. `action` is the `callToAction`: one command, never two, never a ready-made button, and there is no close button. Required: `action`, `title`, `tone` and `liveRegion`; the mark is always drawn, and `icon` swaps the tone's mark for another lucide icon.
15
+ * @words "`label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles." (https://vercel.com/geist/project-banner) "`callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`." (https://vercel.com/geist/project-banner) "Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`)." (https://vercel.com/geist/project-banner) "Don’t encode severity in the copy with emoji or interjections; the variant carries that signal." (https://vercel.com/geist/project-banner) "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) Ours: the `title` is the `label`: the one sentence, naming the condition, its impact and the object. A `description` only adds what the title leaves out, in one more sentence. Our `label` is the `NoteLabel` topic prefix. The action is sentence case, verb and noun, pointing at the resolver: "Update payment method", "Try again". No "Please". The words come from the product's catalogue code.
16
+ * @access `liveRegion="assertive"` gives `role="alert"`, for a failure the person just caused; `"polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark, given or not, is hidden.
15
17
  */
16
18
  export function NoticeBanner({ action, className, description, detail, icon, label, liveRegion, title, tone, ...props }) {
17
- const isLive = liveRegion === "polite";
18
- return (_jsxs(Alert, { "aria-atomic": isLive ? "true" : undefined, "aria-live": isLive ? "polite" : undefined, className: cn("flex min-h-10 flex-col items-start gap-2 rounded-none border-x-0 px-6 py-2 md:flex-row md:items-center md:justify-center", tone === "neutral" && "bg-muted text-muted-foreground", NOTICE_EDGE[tone], className), "data-live-region": liveRegion, "data-notice-banner": true, "data-tone": tone, role: isLive ? "status" : "note", variant: tone === "neutral" ? "default" : tone, ...props, children: [_jsxs("div", { className: "flex min-w-0 items-start gap-2", children: [_jsx("span", { className: "flex h-5 shrink-0 items-center [&_svg]:size-4", children: _jsx(NoticeMark, { icon: icon, tone: tone }) }), _jsxs("div", { className: "grid min-w-0 text-body-sm", children: [_jsxs(AlertTitle, { className: "font-normal", children: [label ? (_jsxs(_Fragment, { children: [_jsx("strong", { "data-notice-label": true, children: label }), " "] })) : null, title] }), description || detail ? (_jsxs(AlertDescription, { className: "flex min-w-0 flex-col gap-2 text-current", children: [description ? _jsx("div", { "data-notice-description": true, children: description }) : null, detail ? _jsx("div", { "data-notice-detail": true, children: detail }) : null] })) : null] })] }), _jsx(NoticeLink, { className: "pl-6 md:pl-0", command: action, place: "strip", tone: tone })] }));
19
+ const isLive = liveRegion !== "off";
20
+ const body = bodyBeyondTitle({ title, body: description ?? "" });
21
+ return (_jsxs(Alert, { "aria-atomic": isLive ? "true" : undefined, "aria-live": isLive ? liveRegion : undefined, className: cn("flex min-h-10 flex-col items-start gap-2 rounded-none border-x-0 px-6 py-2 md:flex-row md:items-center md:justify-center", tone === "neutral" && "bg-muted text-muted-foreground", NOTICE_EDGE[tone], className), "data-live-region": liveRegion, "data-notice-banner": true, "data-tone": tone, role: LIVE_REGION_ROLE[liveRegion], variant: tone === "neutral" ? "default" : tone, ...props, children: [_jsxs("div", { className: "flex min-w-0 items-start gap-2", children: [_jsx("span", { className: "flex h-5 shrink-0 items-center [&_svg]:size-4", children: _jsx(NoticeMark, { icon: icon, tone: tone }) }), _jsxs("div", { className: "grid min-w-0 gap-2 text-body-sm", children: [_jsxs(AlertTitle, { className: "font-normal break-words", children: [label ? (_jsxs(_Fragment, { children: [_jsx("strong", { "data-notice-label": true, children: label }), " "] })) : null, body ? _jsx("span", { className: "font-semibold", children: closedSentence(title) }) : title, body ? (_jsxs(_Fragment, { children: [" ", _jsx("span", { "data-notice-description": true, children: body })] })) : null] }), detail ? (_jsx(AlertDescription, { className: "min-w-0 text-current", "data-notice-detail": true, children: detail })) : null] })] }), _jsx(NoticeLink, { className: "pl-6 md:pl-0", command: action, place: "strip", tone: tone })] }));
19
22
  }
@@ -28,7 +28,7 @@ export declare function wordMessage(parts: {
28
28
  actions?: readonly MessageAction[];
29
29
  }): ResolvedMessage;
30
30
  /** The body a surface shows: none when it would repeat the title. */
31
- export declare function bodyBeyondTitle(message: ResolvedMessage): string | null;
31
+ export declare function bodyBeyondTitle(message: Pick<ResolvedMessage, "title" | "body">): string | null;
32
32
  /** The title and the body as one line of sentences: "Couldn't pause Discord. The Gateway didn't answer." */
33
33
  export declare function messageSentences(message: ResolvedMessage): string;
34
34
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"product-message.d.ts","sourceRoot":"","sources":["../../src/components/product-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;AAEtE,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI;IACzD,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC;AAExC,OAAO,CAAC,MAAM,MAAM,EAAE,OAAO,MAAM,CAAC;AAEpC,uGAAuG;AACvG,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;CACzB,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACpC,GAAG,eAAe,CAGlB;AAED,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAGvE;AAID,4GAA4G;AAC5G,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAKjE"}
1
+ {"version":3,"file":"product-message.d.ts","sourceRoot":"","sources":["../../src/components/product-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;AAEtE,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI;IACzD,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC;AAExC,OAAO,CAAC,MAAM,MAAM,EAAE,OAAO,MAAM,CAAC;AAEpC,uGAAuG;AACvG,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;CACzB,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACpC,GAAG,eAAe,CAGlB;AAED,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAG/F;AAID,4GAA4G;AAC5G,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAKjE"}
@@ -3,6 +3,8 @@ import { type PageCommand } from "../components/page-actions.js";
3
3
  export type NoticeTone = "neutral" | "info" | "warning" | "destructive";
4
4
  /** The hue of a notice's edge: a light step of its text colour, neutral for the plain tone. */
5
5
  export declare const NOTICE_EDGE: Record<NoticeTone, string>;
6
+ /** A notice's title as the first of two sentences: closed by a full stop when it has no mark of its own. */
7
+ export declare const closedSentence: (title: string) => string;
6
8
  /** The mark a tone draws: Info for neutral and info, the triangle for warning and destructive. */
7
9
  export declare function NoticeMark({ icon, tone }: {
8
10
  icon?: LucideIcon | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"notice.d.ts","sourceRoot":"","sources":["../../src/internal/notice.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAiB,MAAM,cAAc,CAAC;AAEpE,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,2BAA2B,CAAC;AAGhF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;AAExE,+FAA+F;AAC/F,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAKlD,CAAC;AAEF,kGAAkG;AAClG,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,+BAG7F;AAgBD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,OAAO,EACP,GAAG,KAAK,EACT,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;CACtB,GAAG,CAAC;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,+BAc/D"}
1
+ {"version":3,"file":"notice.d.ts","sourceRoot":"","sources":["../../src/internal/notice.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAiB,MAAM,cAAc,CAAC;AAEpE,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,2BAA2B,CAAC;AAGhF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;AAExE,+FAA+F;AAC/F,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAKlD,CAAC;AAEF,4GAA4G;AAC5G,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,MACA,CAAC;AAEhD,kGAAkG;AAClG,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,+BAG7F;AAgBD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,OAAO,EACP,GAAG,KAAK,EACT,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;CACtB,GAAG,CAAC;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,+BAc/D"}
@@ -9,6 +9,8 @@ export const NOTICE_EDGE = {
9
9
  warning: "border-warning-soft-foreground/25",
10
10
  destructive: "border-destructive-soft-foreground/25",
11
11
  };
12
+ /** A notice's title as the first of two sentences: closed by a full stop when it has no mark of its own. */
13
+ export const closedSentence = (title) => /[.!?:…]$/u.test(title) ? title : `${title}.`;
12
14
  /** The mark a tone draws: Info for neutral and info, the triangle for warning and destructive. */
13
15
  export function NoticeMark({ icon, tone }) {
14
16
  const Mark = icon ?? (tone === "warning" || tone === "destructive" ? TriangleAlert : Info);
@@ -71,7 +71,7 @@ export const FEEDBACK = {
71
71
  ]), placement: "action" }), _jsx(MessageNotice, { message: sampleMessage("Billing is paused", "Agents stop at the end of the cycle.", [
72
72
  { label: "Update payment", onClick: nothing },
73
73
  ]), placement: "section", tone: "warning" }), _jsx(MessageNotice, { message: sampleMessage("Orders is read-only for you", "Ask an owner of Acme to change who can write to it."), placement: "section", tone: "info" })] })),
74
- NoticeBanner: () => (_jsxs("div", { className: "grid max-w-lg gap-6", children: [_jsx(Captioned, { caption: "Warning, with a label and a command", children: _jsx(NoticeBanner, { action: { label: "Open Slack settings", onClick: nothing }, description: "Agents can't post to Slack until it is connected again.", label: "Slack", liveRegion: "off", title: "Slack is disconnected", tone: "warning" }) }), _jsx(Captioned, { caption: "Destructive, with its own icon and a link", children: _jsx(NoticeBanner, { action: { label: "Update payment method", link: _jsx("a", { href: "#billing" }) }, description: "Agents stop at the end of the billing cycle.", icon: CreditCard, label: "Billing", liveRegion: "polite", title: "Your last payment failed", tone: "destructive" }) })] })),
74
+ NoticeBanner: () => (_jsxs("div", { className: "grid max-w-lg gap-6", children: [_jsx(Captioned, { caption: "Warning, with a label and a command", children: _jsx(NoticeBanner, { action: { label: "Try again", onClick: nothing }, description: "They show the reading from 10:42.", label: "Usage", liveRegion: "off", title: "The figures couldn't be refreshed", tone: "warning" }) }), _jsx(Captioned, { caption: "Destructive, with its own icon and a link", children: _jsx(NoticeBanner, { action: { label: "Update payment method", link: _jsx("a", { href: "#billing" }) }, description: "Agents stop at the end of the billing cycle.", icon: CreditCard, label: "Billing", liveRegion: "polite", title: "Your last payment failed", tone: "destructive" }) })] })),
75
75
  PendingLabel: PendingLabelSpecimen,
76
76
  Skeleton: () => (_jsxs(SkeletonRegion, { busy: true, className: "grid max-w-sm gap-3", children: [_jsx(Skeleton, { boxHeight: 20, height: 16, width: "75%" }), _jsx(Skeleton, { height: 16, width: 160 }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { height: 32, shape: "circle", width: 32 }), _jsx(Skeleton, { height: 48, shape: "squared", width: 48 })] }), _jsx(Skeleton, { height: 100, width: "100%", children: null }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { children: _jsx(Button, { children: "Save changes" }) }), _jsx(Skeleton, { show: false, children: _jsx(Button, { children: "Save changes" }) })] })] })),
77
77
  SkeletonRegion: SkeletonRegionSpecimen,
@@ -1307,7 +1307,7 @@ export const USAGE = [
1307
1307
  family: "Feedback",
1308
1308
  summary: "A catalogue message about one thing on the screen.",
1309
1309
  when: '"Display text that requires attention or provides additional information." (https://vercel.com/geist/note) "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) "Choose `variant` by meaning: `error` for a problem the user must fix, `warning` for a consequence to acknowledge, `success` for a passed check, `secondary` for neutral information." (https://vercel.com/geist/note) Ours: a message beside the field, card or section it describes, under the control whose write failed (`action`), or atop the section whose condition lasts (`section`). The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` (a passed check or a state the product manages for the reader, drawn in the accent blue) and `neutral` is `secondary`; there is no violet or cyan.',
1310
- instead: '"Pick `Banner` when the message is page-level or system-wide and needs a CTA, `Toast` for transient acknowledgments, `Modal` for destructive confirmations." (https://vercel.com/geist/note) Ours: `Banner` is `NoticeBanner`, `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a field\'s wrong value use `FieldError`. For a failed read use `EmptyState failed`.',
1310
+ instead: "\"Pick `Banner` when the message is page-level or system-wide and needs a CTA, `Toast` for transient acknowledgments, `Modal` for destructive confirmations.\" (https://vercel.com/geist/note) Ours: `Banner` is `NoticeBanner`, for a condition of the page's own object, and a system-wide condition is a notification in the product's inbox, never a banner; `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a field's wrong value use `FieldError`. For a failed read use `EmptyState failed`.",
1311
1311
  behaviour: '"A Note is persistent until the underlying state changes; don’t add an ad hoc dismiss control because it competes with the message." (https://vercel.com/geist/note) "One Note per concept. Stacking three Notes on a card means the page architecture, not the Note copy, is wrong." (https://vercel.com/geist/note) "The optional `NoteAction` holds a single inline CTA. Don’t pair it with a second button." (https://vercel.com/geist/note) Ours: `Alert` is its primitive. Tone `destructive` by default, `warning`, `info` or `neutral`; there is no `success` tone. Colour sits on the line, the text and the mark; the ground stays clear, and the action stays neutral. `section` is the framed note, a line 36 px high with its mark and sentence on one row and the action at its trailing edge (under 768 px the action takes its own row, full width), with or without an action; `action` is the unframed passage, its mark and sentence on one row with the action link inside the sentence, after a space. The title and the body run on as one passage, the title closed by a full stop when it has none of its own, so the two never read as one sentence; the title leads in bold (semibold in a note, medium in a passage) only when a body follows it, and stands at regular weight alone. A message worded for a notice has one action, a small default button in a section and an underlined 14 px link in the passage, and at most a second one after it (Nadia\'s *Ask Nadia* after *Try again*), an outline button in a section and a second link in the passage; a third is not shown. Long words wrap, nothing truncates. A successful retry removes it. Required: the catalogue `message`, so the sentence and its mark are always drawn.',
1312
1312
  words: '"`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) "`NoteContent` is one sentence in active voice that names the impact: `Changing this region restarts all functions.`" (https://vercel.com/geist/note) "No `variant="info"` exists; omit `variant` for the default info icon or use `variant="secondary"` for neutral copy." (https://vercel.com/geist/note) "Single-fragment labels take no period; full descriptive sentences in the body do." (https://vercel.com/geist/note) Ours: words come from the catalogue only. The message\'s title stands in for `NoteLabel` and `NoteContent`, in sentence case, and `info` exists as Geist\'s blue `success`. The action is labelled with its result: *Try again*, *Sign in*. When the message carries an action, its body does not repeat it: the link is the step, so the body ends before "Try again".',
1313
1313
  access: '`action`: `role="alert"` (`status` for info and neutral). `section`: `role="status"`, `aria-live="polite"`, atomic. The mark is hidden. Focus stays where the person was.',
@@ -1316,12 +1316,12 @@ export const USAGE = [
1316
1316
  name: "NoticeBanner",
1317
1317
  module: "notice-banner",
1318
1318
  family: "Feedback",
1319
- summary: "A condition of the whole page, the account or the service, with its fix.",
1320
- when: '"A prominent message that spans the full width of its container to announce important information." (https://vercel.com/geist/banner) "Used for temporary, project-wide notifications that require resolution" (https://vercel.com/geist/project-banner) "Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys." (https://vercel.com/geist/project-banner) "Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices." (https://vercel.com/geist/project-banner) Ours: a condition of the whole page, the account or the service that the page itself can resolve, with that resolving action on the banner. The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` and `neutral` is `gray`. One sits above the page\'s content, under its title.',
1321
- instead: '"Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations." (https://vercel.com/geist/project-banner) Ours: there is no announcement strip. `Note` is `MessageNotice` (`placement="section"`), `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a measured level use a `KpiCard` with its tone; crossing a threshold is a notification in the inbox, not a banner.',
1322
- behaviour: '"Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`." (https://vercel.com/geist/project-banner) "Show one Project Banner at a time. Stacking competing banners drowns the most urgent state." (https://vercel.com/geist/project-banner) "Always pass a `callToAction` that resolves the state. A banner with no route is a dead end." (https://vercel.com/geist/project-banner) Ours: a strip as wide as its container: a filled ground with a line on its top and bottom edge only, no corners, 40 px high and centred, with the mark, the sentence and the fix on one row; under 768 px the fix drops under the sentence, aligned with its text. Colour sits on the whole strip (ground, both lines, mark and text); the fix is an underlined link in the darkest step of the same hue (neutral: `text-foreground`) and returns to the strip\'s text on hover. Neutral and info take the Info mark, warning and destructive the TriangleAlert. `action` is the `callToAction`: one command, never two, never a ready-made button, and there is no close button. Required: `action`, `title`, `tone` and `liveRegion`; the mark is always drawn, and `icon` swaps the tone\'s mark for another lucide icon.',
1323
- words: '"`label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles." (https://vercel.com/geist/project-banner) "`callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`." (https://vercel.com/geist/project-banner) "Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`)." (https://vercel.com/geist/project-banner) "Don’t encode severity in the copy with emoji or interjections; the variant carries that signal." (https://vercel.com/geist/project-banner) "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) Ours: the `title` is the `label`: the one sentence, naming the condition, its impact and the object. A `description` only adds what the title leaves out, in one more sentence. Our `label` is the `NoteLabel` topic prefix. The action is sentence case, verb and noun, pointing at the resolver: "Open Slack settings", "Update card". No "Please". The words come from the product\'s catalogue code.',
1324
- access: '`liveRegion="polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark, given or not, is hidden.',
1319
+ summary: "A condition of the page's own object, with the fix the page offers.",
1320
+ when: '"A prominent message that spans the full width of its container to announce important information." (https://vercel.com/geist/banner) "Used for temporary, project-wide notifications that require resolution" (https://vercel.com/geist/project-banner) "Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys." (https://vercel.com/geist/project-banner) "Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices." (https://vercel.com/geist/project-banner) Ours: a condition of the page\'s own object that the page itself resolves, with that resolving action on the banner: a past-due subscription on its billing page, a failed refresh of the page\'s own reading. The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` and `neutral` is `gray`. One sits above the page\'s content, under its title.',
1321
+ instead: '"Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations." (https://vercel.com/geist/project-banner) Ours: there is no announcement strip. `Note` is `MessageNotice` (`placement="section"`), `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a measured level use a `KpiCard` with its tone; crossing a threshold is a notification in the inbox, not a banner. A condition of the system, the setup or the staff (a connection, a stored secret, a failing job, anything a staff member fixes in settings) is a notification in the product\'s inbox, never a banner on a page: "The Vercel dashboard displays a popover, which contains all relevant notifications" (https://vercel.com/docs/notifications), and the Portal\'s System health raises it through Knock to the bell at the sidebar\'s foot.',
1322
+ behaviour: '"Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`." (https://vercel.com/geist/project-banner) "Show one Project Banner at a time. Stacking competing banners drowns the most urgent state." (https://vercel.com/geist/project-banner) "Always pass a `callToAction` that resolves the state. A banner with no route is a dead end." (https://vercel.com/geist/project-banner) Ours: a strip as wide as its container: a filled ground with a line on its top and bottom edge only, no corners, 40 px high and centred, with the mark, the sentence and the fix on one row; under 768 px the fix drops under the sentence, aligned with its text. The title and the description run on as one passage: the title closed by a full stop when it has none of its own, leading in semibold when a description follows and at regular weight alone, the description after it on the same line, and a description that repeats the title not shown. `detail` takes its own row under the passage. Colour sits on the whole strip (ground, both lines, mark and text); the fix is an underlined link in the darkest step of the same hue (neutral: `text-foreground`) and returns to the strip\'s text on hover. Neutral and info take the Info mark, warning and destructive the TriangleAlert. `action` is the `callToAction`: one command, never two, never a ready-made button, and there is no close button. Required: `action`, `title`, `tone` and `liveRegion`; the mark is always drawn, and `icon` swaps the tone\'s mark for another lucide icon.',
1323
+ words: '"`label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles." (https://vercel.com/geist/project-banner) "`callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`." (https://vercel.com/geist/project-banner) "Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`)." (https://vercel.com/geist/project-banner) "Don’t encode severity in the copy with emoji or interjections; the variant carries that signal." (https://vercel.com/geist/project-banner) "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) Ours: the `title` is the `label`: the one sentence, naming the condition, its impact and the object. A `description` only adds what the title leaves out, in one more sentence. Our `label` is the `NoteLabel` topic prefix. The action is sentence case, verb and noun, pointing at the resolver: "Update payment method", "Try again". No "Please". The words come from the product\'s catalogue code.',
1324
+ access: '`liveRegion="assertive"` gives `role="alert"`, for a failure the person just caused; `"polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark, given or not, is hidden.',
1325
1325
  },
1326
1326
  {
1327
1327
  name: "PendingLabel",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "12.1.148",
3
+ "version": "12.1.149",
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.148",
87
+ "@nadicodeai/design-system": "12.1.149",
88
88
  "@tanstack/react-table": "^9.3.1",
89
89
  "@vgpu/wgsl": "0.6.0",
90
90
  "class-variance-authority": "^0.7.1",