@nadicodeai/ui 12.1.131 → 12.1.132

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.
@@ -44,7 +44,7 @@ export type ConfirmDialogProps = {
44
44
  * @family Compositions
45
45
  * @when "Reach for this over `Modal` when the action is destructive and warrants friction: delete, rotate, revoke, disconnect, downgrade, disable a security setting. The typed gate forces deliberate intent." (https://vercel.com/geist/destructive-action-modal) "Use it for reversible destructive actions too, when the consequence is serious enough to warrant a pause — disabling deployment protection, revoking a shared token. Keep the typed gate; drop `irreversibleDescription`." (https://vercel.com/geist/destructive-action-modal) "For high-stakes destructive actions (delete production resource, rotate signing key, downgrade plan), gate the primary button on a typed match of the resource name." (https://vercel.com/geist/modal) Ours: `ConfirmDialog` is Geist's DestructiveActionModal: remove a mailbox, delete an Agent, with `verify` as the typed gate. It asks for the record's name before the confirm enables on a high-stakes action (delete, rotate, revoke, disconnect, downgrade, a protection switched off), even a reversible one; `irreversible` names what cannot be undone and is left out when the action can be reversed.
46
46
  * @instead "Don't use for routine confirmations (save draft, discard changes, close without saving). The typed gate reads as melodrama when the stakes are low — use a plain `Modal` instead." (https://vercel.com/geist/destructive-action-modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a routine confirmation (discard a draft) takes neither `verify` nor `irreversible`; an action that can be undone runs at once and offers its undo in a toast; a form of a few fields is a `FormDialog`; a choice from a catalogue is a `CatalogDrawer`.
47
- * @behaviour "The verification input gets focus on open so the user can start typing immediately. Submit stays disabled until the value matches `verificationPhrase` exactly." (https://vercel.com/geist/destructive-action-modal) "Enter submits only when the gate is open; it's a no-op otherwise. Cancel, outside-click, and Escape all dismiss." (https://vercel.com/geist/destructive-action-modal) "`loading` disables both buttons. The caller owns `open` — do not self-dismiss from `onConfirm`. Close the modal after the API settles (success or error), or keep it open on error so the user can retry." (https://vercel.com/geist/destructive-action-modal) "Default focus to `Cancel` on any destructive Modal. Enter must never trigger the destructive action without a typed confirmation." (https://vercel.com/geist/modal) "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: `title`, `description`, `confirmLabel` and `cancelLabel` are required; `irreversible` and `verify` are optional, and the absence of `irreversible` is what marks the action reversible. Geist's `irreversibleDescription` is `irreversible`, `verificationPhrase` and `verificationLabel` are `verify.phrase` and `verify.prompt`, and `error` is the catalogue's message. 480 px wide over a scrim. The title and the description, then the body in a 24 px column: the `irreversible` note, the `verify` field, the failure under it. `irreversible` is a flat red note with a red mark and red words, not a band over the footer; besides it the only red is the failure and the enabled destructive confirm. While `loading` the field turns read-only and keeps focus, Escape does not close it, and the confirm says `confirmPendingLabel`, which falls back to the confirm's label. A press outside does not close it, so a stray click never discards a typed phrase or an action in flight; Escape and Cancel do. The footer is a bar that stays at the bottom while a tall confirmation scrolls, and a row on a phone too.
47
+ * @behaviour "The verification input gets focus on open so the user can start typing immediately. Submit stays disabled until the value matches `verificationPhrase` exactly." (https://vercel.com/geist/destructive-action-modal) "Enter submits only when the gate is open; it's a no-op otherwise. Cancel, outside-click, and Escape all dismiss." (https://vercel.com/geist/destructive-action-modal) "`loading` disables both buttons. The caller owns `open` — do not self-dismiss from `onConfirm`. Close the modal after the API settles (success or error), or keep it open on error so the user can retry." (https://vercel.com/geist/destructive-action-modal) "Default focus to `Cancel` on any destructive Modal. Enter must never trigger the destructive action without a typed confirmation." (https://vercel.com/geist/modal) "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: `title`, `description`, `confirmLabel` and `cancelLabel` are required; `irreversible` and `verify` are optional, and the absence of `irreversible` is what marks the action reversible. Geist's `irreversibleDescription` is `irreversible`, `verificationPhrase` and `verificationLabel` are `verify.phrase` and `verify.prompt`, and `error` is the catalogue's message. 480 px wide over a scrim. The title and the description, then the body in a 24 px column: the `irreversible` note, the `verify` field, the failure under it. `irreversible` is a flat red note with a red mark and red words, not a band over the footer; besides it the only red is the failure and the enabled destructive confirm. While `loading` the field turns read-only and keeps focus, Escape does not close it, and the confirm says `confirmPendingLabel`, which falls back to the confirm's label. A press outside does not close it, so a stray click never discards a typed phrase or an action in flight; Escape and Cancel do. The footer is a bar that stays at the bottom while a tall confirmation scrolls, and a row on a phone too. How long it stays open while work goes on follows DESIGN.md "System activity".
48
48
  * @words "`title` is Title Case, `Verb + Noun`, a statement — never a question. `Delete Project`, not `Delete this project?`." (https://vercel.com/geist/destructive-action-modal) "`description` is sentence case, names the consequence, and interpolates the specific resource when relevant. `<b>my-project</b> and all its deployments will be permanently deleted.` reads stronger than `This project and all its deployments will be deleted.`." (https://vercel.com/geist/destructive-action-modal) "`confirmLabel` matches the title 1:1. Never generic (`Confirm`, `OK`, `Continue`), never a bare verb (`Delete`)." (https://vercel.com/geist/destructive-action-modal) "`cancelLabel` defaults to `Cancel`. Override when Cancel is ambiguous, such as `Keep Turn Running` when the primary action is itself a cancellation." (https://vercel.com/geist/destructive-action-modal) "`verificationPhrase`: for entity deletes, type the **resource name itself** (`my-project`) and pair with `verificationLabel="project name"` so the prompt reads `To confirm, type the project name "my-project"`. That's the canonical signal that the user knows which thing they're acting on. Fall back to a lowercase verb phrase (`disable vercel authentication`) only when there's no entity to name." (https://vercel.com/geist/destructive-action-modal) "`irreversibleDescription` names the specific action and resource and ends with `cannot be undone.` — `Deleting my-project cannot be undone.` rather than the generic `This cannot be undone.`. Omit the prop entirely for reversible actions; the prop's absence is the signal, not a falsy value." (https://vercel.com/geist/destructive-action-modal) "`error` surfaces the API failure verbatim in Vercel voice: `Couldn't save settings. Try again.`. Never dump a raw error object." (https://vercel.com/geist/destructive-action-modal) "Pair the post-confirm success toast verb 1:1 with the primary button: `Delete Project` button, `Project deleted` toast. Never `Project removed`." (https://vercel.com/geist/destructive-action-modal) "Close irreversible bodies with `This cannot be undone.`; close cascade-only bodies with `Some effects cannot be undone.`. Don’t claim full irreversibility for a partial cascade." (https://vercel.com/geist/modal) Ours: the title is sentence case and names the record, "Remove pec@acme.it", and the confirm repeats the verb and the noun, "Remove mailbox", so the two share a verb and not every word; its success toast uses the same verb ("Mailbox removed"). The description names the record in medium weight.
49
49
  * @access "The verification input is associated with its prompt via `aria-labelledby` + `htmlFor`. Screen readers announce the full prompt (`To confirm, type "delete my-project"`) on focus." (https://vercel.com/geist/destructive-action-modal) "The Warning icon in the irreversibility band is `aria-hidden`; the sentence carries the meaning so nothing is announced twice." (https://vercel.com/geist/destructive-action-modal) "Focus stays inside the modal across an `error` transition so the user can retry without losing context. After success, return focus to the trigger." (https://vercel.com/geist/destructive-action-modal) "Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Keep the Cancel button literally `Cancel` so screen-reader users hear a stable dismissal label across destructive flows." (https://vercel.com/geist/modal) Ours: `role="alertdialog"` named by its title and described by its consequence; the note is `role="note"` with its icon hidden. Focus starts on Cancel, or in the field with `verify`.
50
50
  */
@@ -14,7 +14,7 @@ import { bodyBeyondTitle } from "./product-message.js";
14
14
  * @family Compositions
15
15
  * @when "Reach for this over `Modal` when the action is destructive and warrants friction: delete, rotate, revoke, disconnect, downgrade, disable a security setting. The typed gate forces deliberate intent." (https://vercel.com/geist/destructive-action-modal) "Use it for reversible destructive actions too, when the consequence is serious enough to warrant a pause — disabling deployment protection, revoking a shared token. Keep the typed gate; drop `irreversibleDescription`." (https://vercel.com/geist/destructive-action-modal) "For high-stakes destructive actions (delete production resource, rotate signing key, downgrade plan), gate the primary button on a typed match of the resource name." (https://vercel.com/geist/modal) Ours: `ConfirmDialog` is Geist's DestructiveActionModal: remove a mailbox, delete an Agent, with `verify` as the typed gate. It asks for the record's name before the confirm enables on a high-stakes action (delete, rotate, revoke, disconnect, downgrade, a protection switched off), even a reversible one; `irreversible` names what cannot be undone and is left out when the action can be reversed.
16
16
  * @instead "Don't use for routine confirmations (save draft, discard changes, close without saving). The typed gate reads as melodrama when the stakes are low — use a plain `Modal` instead." (https://vercel.com/geist/destructive-action-modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a routine confirmation (discard a draft) takes neither `verify` nor `irreversible`; an action that can be undone runs at once and offers its undo in a toast; a form of a few fields is a `FormDialog`; a choice from a catalogue is a `CatalogDrawer`.
17
- * @behaviour "The verification input gets focus on open so the user can start typing immediately. Submit stays disabled until the value matches `verificationPhrase` exactly." (https://vercel.com/geist/destructive-action-modal) "Enter submits only when the gate is open; it's a no-op otherwise. Cancel, outside-click, and Escape all dismiss." (https://vercel.com/geist/destructive-action-modal) "`loading` disables both buttons. The caller owns `open` — do not self-dismiss from `onConfirm`. Close the modal after the API settles (success or error), or keep it open on error so the user can retry." (https://vercel.com/geist/destructive-action-modal) "Default focus to `Cancel` on any destructive Modal. Enter must never trigger the destructive action without a typed confirmation." (https://vercel.com/geist/modal) "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: `title`, `description`, `confirmLabel` and `cancelLabel` are required; `irreversible` and `verify` are optional, and the absence of `irreversible` is what marks the action reversible. Geist's `irreversibleDescription` is `irreversible`, `verificationPhrase` and `verificationLabel` are `verify.phrase` and `verify.prompt`, and `error` is the catalogue's message. 480 px wide over a scrim. The title and the description, then the body in a 24 px column: the `irreversible` note, the `verify` field, the failure under it. `irreversible` is a flat red note with a red mark and red words, not a band over the footer; besides it the only red is the failure and the enabled destructive confirm. While `loading` the field turns read-only and keeps focus, Escape does not close it, and the confirm says `confirmPendingLabel`, which falls back to the confirm's label. A press outside does not close it, so a stray click never discards a typed phrase or an action in flight; Escape and Cancel do. The footer is a bar that stays at the bottom while a tall confirmation scrolls, and a row on a phone too.
17
+ * @behaviour "The verification input gets focus on open so the user can start typing immediately. Submit stays disabled until the value matches `verificationPhrase` exactly." (https://vercel.com/geist/destructive-action-modal) "Enter submits only when the gate is open; it's a no-op otherwise. Cancel, outside-click, and Escape all dismiss." (https://vercel.com/geist/destructive-action-modal) "`loading` disables both buttons. The caller owns `open` — do not self-dismiss from `onConfirm`. Close the modal after the API settles (success or error), or keep it open on error so the user can retry." (https://vercel.com/geist/destructive-action-modal) "Default focus to `Cancel` on any destructive Modal. Enter must never trigger the destructive action without a typed confirmation." (https://vercel.com/geist/modal) "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: `title`, `description`, `confirmLabel` and `cancelLabel` are required; `irreversible` and `verify` are optional, and the absence of `irreversible` is what marks the action reversible. Geist's `irreversibleDescription` is `irreversible`, `verificationPhrase` and `verificationLabel` are `verify.phrase` and `verify.prompt`, and `error` is the catalogue's message. 480 px wide over a scrim. The title and the description, then the body in a 24 px column: the `irreversible` note, the `verify` field, the failure under it. `irreversible` is a flat red note with a red mark and red words, not a band over the footer; besides it the only red is the failure and the enabled destructive confirm. While `loading` the field turns read-only and keeps focus, Escape does not close it, and the confirm says `confirmPendingLabel`, which falls back to the confirm's label. A press outside does not close it, so a stray click never discards a typed phrase or an action in flight; Escape and Cancel do. The footer is a bar that stays at the bottom while a tall confirmation scrolls, and a row on a phone too. How long it stays open while work goes on follows DESIGN.md "System activity".
18
18
  * @words "`title` is Title Case, `Verb + Noun`, a statement — never a question. `Delete Project`, not `Delete this project?`." (https://vercel.com/geist/destructive-action-modal) "`description` is sentence case, names the consequence, and interpolates the specific resource when relevant. `<b>my-project</b> and all its deployments will be permanently deleted.` reads stronger than `This project and all its deployments will be deleted.`." (https://vercel.com/geist/destructive-action-modal) "`confirmLabel` matches the title 1:1. Never generic (`Confirm`, `OK`, `Continue`), never a bare verb (`Delete`)." (https://vercel.com/geist/destructive-action-modal) "`cancelLabel` defaults to `Cancel`. Override when Cancel is ambiguous, such as `Keep Turn Running` when the primary action is itself a cancellation." (https://vercel.com/geist/destructive-action-modal) "`verificationPhrase`: for entity deletes, type the **resource name itself** (`my-project`) and pair with `verificationLabel="project name"` so the prompt reads `To confirm, type the project name "my-project"`. That's the canonical signal that the user knows which thing they're acting on. Fall back to a lowercase verb phrase (`disable vercel authentication`) only when there's no entity to name." (https://vercel.com/geist/destructive-action-modal) "`irreversibleDescription` names the specific action and resource and ends with `cannot be undone.` — `Deleting my-project cannot be undone.` rather than the generic `This cannot be undone.`. Omit the prop entirely for reversible actions; the prop's absence is the signal, not a falsy value." (https://vercel.com/geist/destructive-action-modal) "`error` surfaces the API failure verbatim in Vercel voice: `Couldn't save settings. Try again.`. Never dump a raw error object." (https://vercel.com/geist/destructive-action-modal) "Pair the post-confirm success toast verb 1:1 with the primary button: `Delete Project` button, `Project deleted` toast. Never `Project removed`." (https://vercel.com/geist/destructive-action-modal) "Close irreversible bodies with `This cannot be undone.`; close cascade-only bodies with `Some effects cannot be undone.`. Don’t claim full irreversibility for a partial cascade." (https://vercel.com/geist/modal) Ours: the title is sentence case and names the record, "Remove pec@acme.it", and the confirm repeats the verb and the noun, "Remove mailbox", so the two share a verb and not every word; its success toast uses the same verb ("Mailbox removed"). The description names the record in medium weight.
19
19
  * @access "The verification input is associated with its prompt via `aria-labelledby` + `htmlFor`. Screen readers announce the full prompt (`To confirm, type "delete my-project"`) on focus." (https://vercel.com/geist/destructive-action-modal) "The Warning icon in the irreversibility band is `aria-hidden`; the sentence carries the meaning so nothing is announced twice." (https://vercel.com/geist/destructive-action-modal) "Focus stays inside the modal across an `error` transition so the user can retry without losing context. After success, return focus to the trigger." (https://vercel.com/geist/destructive-action-modal) "Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Keep the Cancel button literally `Cancel` so screen-reader users hear a stable dismissal label across destructive flows." (https://vercel.com/geist/modal) Ours: `role="alertdialog"` named by its title and described by its consequence; the note is `role="note"` with its icon hidden. Focus starts on Cancel, or in the field with `verify`.
20
20
  */
@@ -10,7 +10,7 @@ export type FormDialogProps = FormSurfaceProps & {
10
10
  * @family Compositions
11
11
  * @when "Use Modal when a decision must block the rest of the page. For persistent associated context where the underlying page stays readable, use `Sheet` on desktop or `Drawer` on mobile." (https://vercel.com/geist/modal) Ours: a person adds a record through a few fields, or changes one or two values a command asks for: new customer, add a mailbox, add an MCP server.
12
12
  * @instead "Skip Modal for routine create flows that have a dedicated page; route to the page instead." (https://vercel.com/geist/modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a record already in a list edits in its row with `RowEditForm`; a choice from a catalogue is a `CatalogDrawer`; a setup in steps with a wait is a `FormDrawer` with `job="steps"`; a consequence is confirmed in a `ConfirmDialog`.
13
- * @behaviour "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. `FormDialogForm` puts the fields in the dialog's own scroll body and the actions in its fixed footer; no other overlay is nested inside. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close.
13
+ * @behaviour "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. `FormDialogForm` puts the fields in the dialog's own scroll body and the actions in its fixed footer; no other overlay is nested inside. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close. How long it stays open while work goes on follows DESIGN.md "System activity".
14
14
  * @words "`Modal.Title` is a Title Case statement, never a question. `Transfer Project` is correct; `Transfer Project?` is wrong." (https://vercel.com/geist/modal) "Primary button is `Verb + Noun` and matches the title verb (`Transfer Project` title pairs with `Transfer Project` button). Never `Confirm`, `OK`, or a bare verb on a destructive primary." (https://vercel.com/geist/modal) "Cancel literal stays `Cancel`. Acknowledgment-only Modals (after a key reveal, after a one-time-show) use `Done`, never `OK` or `Close`." (https://vercel.com/geist/modal) Ours: the title and the primary are sentence case, where Geist writes Title Case: the title names the job and its object, "New customer", "Add a mailbox"; the primary repeats it, "Create customer", "Add mailbox".
15
15
  * @access "Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Trap focus inside the Modal while it’s open and return focus to the trigger after close. Restore body scroll on the same tick the Modal unmounts." (https://vercel.com/geist/modal) "After an error inside the Modal, keep focus inside so the user can retry; after success, return focus to the trigger." (https://vercel.com/geist/modal) Ours: a modal dialog with a Close named by `closeLabel`; focus starts in its first field or `initialFocus` and returns to the opener or `finalFocus`. Escape and Close close it unless the save runs.
16
16
  */
@@ -11,7 +11,7 @@ import { guardUnsaved } from "../internal/unsaved-guard.js";
11
11
  * @family Compositions
12
12
  * @when "Use Modal when a decision must block the rest of the page. For persistent associated context where the underlying page stays readable, use `Sheet` on desktop or `Drawer` on mobile." (https://vercel.com/geist/modal) Ours: a person adds a record through a few fields, or changes one or two values a command asks for: new customer, add a mailbox, add an MCP server.
13
13
  * @instead "Skip Modal for routine create flows that have a dedicated page; route to the page instead." (https://vercel.com/geist/modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a record already in a list edits in its row with `RowEditForm`; a choice from a catalogue is a `CatalogDrawer`; a setup in steps with a wait is a `FormDrawer` with `job="steps"`; a consequence is confirmed in a `ConfirmDialog`.
14
- * @behaviour "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. `FormDialogForm` puts the fields in the dialog's own scroll body and the actions in its fixed footer; no other overlay is nested inside. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close.
14
+ * @behaviour "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. `FormDialogForm` puts the fields in the dialog's own scroll body and the actions in its fixed footer; no other overlay is nested inside. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close. How long it stays open while work goes on follows DESIGN.md "System activity".
15
15
  * @words "`Modal.Title` is a Title Case statement, never a question. `Transfer Project` is correct; `Transfer Project?` is wrong." (https://vercel.com/geist/modal) "Primary button is `Verb + Noun` and matches the title verb (`Transfer Project` title pairs with `Transfer Project` button). Never `Confirm`, `OK`, or a bare verb on a destructive primary." (https://vercel.com/geist/modal) "Cancel literal stays `Cancel`. Acknowledgment-only Modals (after a key reveal, after a one-time-show) use `Done`, never `OK` or `Close`." (https://vercel.com/geist/modal) Ours: the title and the primary are sentence case, where Geist writes Title Case: the title names the job and its object, "New customer", "Add a mailbox"; the primary repeats it, "Create customer", "Add mailbox".
16
16
  * @access "Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Trap focus inside the Modal while it’s open and return focus to the trigger after close. Restore body scroll on the same tick the Modal unmounts." (https://vercel.com/geist/modal) "After an error inside the Modal, keep focus inside so the user can retry; after success, return focus to the trigger." (https://vercel.com/geist/modal) Ours: a modal dialog with a Close named by `closeLabel`; focus starts in its first field or `initialFocus` and returns to the opener or `finalFocus`. Escape and Close close it unless the save runs.
17
17
  */
@@ -42,7 +42,7 @@ export type FormDrawerProps = FormSurfaceProps & ({
42
42
  * @family Compositions
43
43
  * @when Ours: choosing from a catalogue too long for a dialog (through `CatalogDrawer`), or setting something up in several steps with a wait: connect a messaging channel, Telegram's code.
44
44
  * @instead "Don’t use Sheet to confirm destructive actions. The default `modal=false` keeps the page interactive, which weakens severity for a delete or revoke." (https://vercel.com/geist/sheet) Ours: a new record from a few fields is a `FormDialog`; a record already in a list edits in its row with `RowEditForm`; a fact on the record's own page changes in place in its section; a consequence is confirmed in a `ConfirmDialog`; a phone's short job is a `Drawer`.
45
- * @behaviour "Sheet defaults to `modal=false` so toasts and other high-z elements stay reachable. Keep that default unless the sheet owns the screen." (https://vercel.com/geist/sheet) "Pick `side` from the trigger location: a row inspector slides from `right`, a global filter from `left`. Don’t change sides mid-session." (https://vercel.com/geist/sheet) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet's one width that no caller sets. The header holds the step ("Step 2 of 3", in mono) over the title, which stays the job's name, then the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs.
45
+ * @behaviour "Sheet defaults to `modal=false` so toasts and other high-z elements stay reachable. Keep that default unless the sheet owns the screen." (https://vercel.com/geist/sheet) "Pick `side` from the trigger location: a row inspector slides from `right`, a global filter from `left`. Don’t change sides mid-session." (https://vercel.com/geist/sheet) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet's one width that no caller sets. The header holds the step ("Step 2 of 3", in mono) over the title, which stays the job's name, then the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs. How long it stays open while work goes on follows DESIGN.md "System activity".
46
46
  * @words "Title is Title Case and names the entity (`Deployment Details`, `Member Profile`), not the page action." (https://vercel.com/geist/sheet) "Body is read-mostly: sentence case prose with Title Case sub-headings. Action buttons are optional; when present, follow `Verb + Noun`." (https://vercel.com/geist/sheet) Ours: the title is sentence case and names the job and its object: "Connect Telegram", "Add a skill". The step reads "Step N of M". The primary says what it does: "Connect", "Continue", never "OK".
47
47
  * @access "Trap focus inside the sheet while it’s open and return focus to the trigger row on close so keyboard users keep their place in the list." (https://vercel.com/geist/sheet) "Provide a visible close button labeled `Close` (or an icon button with `aria-label="Close"`) since clicking outside doesn’t dismiss." (https://vercel.com/geist/sheet) "Announce the sheet with `aria-labelledby` pointing at the title; pair it with `aria-describedby` only when the body is short and load-bearing." (https://vercel.com/geist/sheet) Ours: a modal dialog named by its title; focus returns to the opener on close, or to `finalFocus` when the opener is gone. The step is read before the title.
48
48
  */
@@ -12,7 +12,7 @@ import { cn } from "../lib/utils.js";
12
12
  * @family Compositions
13
13
  * @when Ours: choosing from a catalogue too long for a dialog (through `CatalogDrawer`), or setting something up in several steps with a wait: connect a messaging channel, Telegram's code.
14
14
  * @instead "Don’t use Sheet to confirm destructive actions. The default `modal=false` keeps the page interactive, which weakens severity for a delete or revoke." (https://vercel.com/geist/sheet) Ours: a new record from a few fields is a `FormDialog`; a record already in a list edits in its row with `RowEditForm`; a fact on the record's own page changes in place in its section; a consequence is confirmed in a `ConfirmDialog`; a phone's short job is a `Drawer`.
15
- * @behaviour "Sheet defaults to `modal=false` so toasts and other high-z elements stay reachable. Keep that default unless the sheet owns the screen." (https://vercel.com/geist/sheet) "Pick `side` from the trigger location: a row inspector slides from `right`, a global filter from `left`. Don’t change sides mid-session." (https://vercel.com/geist/sheet) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet's one width that no caller sets. The header holds the step ("Step 2 of 3", in mono) over the title, which stays the job's name, then the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs.
15
+ * @behaviour "Sheet defaults to `modal=false` so toasts and other high-z elements stay reachable. Keep that default unless the sheet owns the screen." (https://vercel.com/geist/sheet) "Pick `side` from the trigger location: a row inspector slides from `right`, a global filter from `left`. Don’t change sides mid-session." (https://vercel.com/geist/sheet) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet's one width that no caller sets. The header holds the step ("Step 2 of 3", in mono) over the title, which stays the job's name, then the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs. How long it stays open while work goes on follows DESIGN.md "System activity".
16
16
  * @words "Title is Title Case and names the entity (`Deployment Details`, `Member Profile`), not the page action." (https://vercel.com/geist/sheet) "Body is read-mostly: sentence case prose with Title Case sub-headings. Action buttons are optional; when present, follow `Verb + Noun`." (https://vercel.com/geist/sheet) Ours: the title is sentence case and names the job and its object: "Connect Telegram", "Add a skill". The step reads "Step N of M". The primary says what it does: "Connect", "Continue", never "OK".
17
17
  * @access "Trap focus inside the sheet while it’s open and return focus to the trigger row on close so keyboard users keep their place in the list." (https://vercel.com/geist/sheet) "Provide a visible close button labeled `Close` (or an icon button with `aria-label="Close"`) since clicking outside doesn’t dismiss." (https://vercel.com/geist/sheet) "Announce the sheet with `aria-labelledby` pointing at the title; pair it with `aria-describedby` only when the body is short and load-bearing." (https://vercel.com/geist/sheet) Ours: a modal dialog named by its title; focus returns to the opener on close, or to `finalFocus` when the opener is gone. The step is read before the title.
18
18
  */
@@ -18,6 +18,7 @@ type WaitingLineProps = Omit<React.ComponentProps<"div">, "children"> & ({
18
18
  * @family Feedback
19
19
  * @when A system wait the person asked for that runs past a second: a save, a connection, a
20
20
  * download without a count.
21
+ * In a record's row, `WaitingDetail` puts it under the row's detail line, which names the work.
21
22
  * @instead Under a second the `PendingLabel` alone. A known amount is a progress line with a count.
22
23
  * A page load is `Skeleton`. An Agent working is her orb and a sentence.
23
24
  * @behaviour Takes its 2 px from the start and stays empty until 1 s, so its arrival moves nothing.
@@ -25,9 +26,13 @@ type WaitingLineProps = Omit<React.ComponentProps<"div">, "children"> & ({
25
26
  * it breathes in opacity, across the whole track, instead of travelling.
26
27
  * @words None of its own. The control beside it carries the pending word; a standalone line takes a
27
28
  * `label` naming the work: *Connecting Telegram*.
28
- * @access With a label: `role="status"`, announced once after the second. `decorative` when the
29
- * control beside it already says it. The segment is hidden.
29
+ * @access With a label: `role="status"`, announced once after the second. `decorative` when a control or
30
+ * sentence beside it already names the work (DESIGN.md "System activity"). The segment is hidden.
30
31
  */
31
32
  declare function WaitingLine({ className, decorative, label, ...props }: WaitingLineProps): React.JSX.Element;
32
- export { WaitingLine, WAITING_LINE_DELAY_MS };
33
+ /** A record's wait in its row: the detail line naming the work, with the waiting line under it. */
34
+ declare function WaitingDetail({ work }: {
35
+ work: string;
36
+ }): React.JSX.Element;
37
+ export { WaitingDetail, WaitingLine, WAITING_LINE_DELAY_MS };
33
38
  //# sourceMappingURL=waiting-line.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"waiting-line.d.ts","sourceRoot":"","sources":["../../src/components/waiting-line.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B;;;;GAIG;AACH,QAAA,MAAM,qBAAqB,OAAO,CAAC;AAEnC,KAAK,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GACnE,CAAC;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhF;;;;;;;;;;;;;;;GAeG;AACH,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,UAAkB,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,qBA0BxF;AAED,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC"}
1
+ {"version":3,"file":"waiting-line.d.ts","sourceRoot":"","sources":["../../src/components/waiting-line.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B;;;;GAIG;AACH,QAAA,MAAM,qBAAqB,OAAO,CAAC;AAEnC,KAAK,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GACnE,CAAC;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhF;;;;;;;;;;;;;;;;GAgBG;AACH,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,UAAkB,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,qBA0BxF;AAED,mGAAmG;AACnG,iBAAS,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,qBAOhD;AAED,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { cn } from "../lib/utils.js";
5
5
  /**
@@ -14,6 +14,7 @@ const WAITING_LINE_DELAY_MS = 1000;
14
14
  * @family Feedback
15
15
  * @when A system wait the person asked for that runs past a second: a save, a connection, a
16
16
  * download without a count.
17
+ * In a record's row, `WaitingDetail` puts it under the row's detail line, which names the work.
17
18
  * @instead Under a second the `PendingLabel` alone. A known amount is a progress line with a count.
18
19
  * A page load is `Skeleton`. An Agent working is her orb and a sentence.
19
20
  * @behaviour Takes its 2 px from the start and stays empty until 1 s, so its arrival moves nothing.
@@ -21,8 +22,8 @@ const WAITING_LINE_DELAY_MS = 1000;
21
22
  * it breathes in opacity, across the whole track, instead of travelling.
22
23
  * @words None of its own. The control beside it carries the pending word; a standalone line takes a
23
24
  * `label` naming the work: *Connecting Telegram*.
24
- * @access With a label: `role="status"`, announced once after the second. `decorative` when the
25
- * control beside it already says it. The segment is hidden.
25
+ * @access With a label: `role="status"`, announced once after the second. `decorative` when a control or
26
+ * sentence beside it already names the work (DESIGN.md "System activity"). The segment is hidden.
26
27
  */
27
28
  function WaitingLine({ className, decorative = false, label, ...props }) {
28
29
  const [elapsed, setElapsed] = React.useState(false);
@@ -33,4 +34,8 @@ function WaitingLine({ className, decorative = false, label, ...props }) {
33
34
  const announced = elapsed && !decorative;
34
35
  return (_jsx("div", { ...props, "aria-label": announced ? label : undefined, className: cn("relative h-0.5 w-full overflow-hidden", className), "data-slot": "waiting-line", "data-waiting": elapsed || undefined, role: announced ? "status" : undefined, children: elapsed ? (_jsx("span", { "aria-hidden": "true", className: "nc-anim-wait absolute inset-y-0 start-0 block bg-current" })) : null }));
35
36
  }
36
- export { WaitingLine, WAITING_LINE_DELAY_MS };
37
+ /** A record's wait in its row: the detail line naming the work, with the waiting line under it. */
38
+ function WaitingDetail({ work }) {
39
+ return (_jsxs("span", { className: "grid gap-1.5", "data-slot": "waiting-detail", children: [_jsx("span", { children: work }), _jsx(WaitingLine, { decorative: true })] }));
40
+ }
41
+ export { WaitingDetail, WaitingLine, WAITING_LINE_DELAY_MS };
@@ -87,7 +87,7 @@ export const USAGE = [
87
87
  summary: "A consequence confirmed before it happens, in a blocking alert dialog.",
88
88
  when: '"Reach for this over `Modal` when the action is destructive and warrants friction: delete, rotate, revoke, disconnect, downgrade, disable a security setting. The typed gate forces deliberate intent." (https://vercel.com/geist/destructive-action-modal) "Use it for reversible destructive actions too, when the consequence is serious enough to warrant a pause — disabling deployment protection, revoking a shared token. Keep the typed gate; drop `irreversibleDescription`." (https://vercel.com/geist/destructive-action-modal) "For high-stakes destructive actions (delete production resource, rotate signing key, downgrade plan), gate the primary button on a typed match of the resource name." (https://vercel.com/geist/modal) Ours: `ConfirmDialog` is Geist\'s DestructiveActionModal: remove a mailbox, delete an Agent, with `verify` as the typed gate. It asks for the record\'s name before the confirm enables on a high-stakes action (delete, rotate, revoke, disconnect, downgrade, a protection switched off), even a reversible one; `irreversible` names what cannot be undone and is left out when the action can be reversed.',
89
89
  instead: '"Don\'t use for routine confirmations (save draft, discard changes, close without saving). The typed gate reads as melodrama when the stakes are low — use a plain `Modal` instead." (https://vercel.com/geist/destructive-action-modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a routine confirmation (discard a draft) takes neither `verify` nor `irreversible`; an action that can be undone runs at once and offers its undo in a toast; a form of a few fields is a `FormDialog`; a choice from a catalogue is a `CatalogDrawer`.',
90
- behaviour: '"The verification input gets focus on open so the user can start typing immediately. Submit stays disabled until the value matches `verificationPhrase` exactly." (https://vercel.com/geist/destructive-action-modal) "Enter submits only when the gate is open; it\'s a no-op otherwise. Cancel, outside-click, and Escape all dismiss." (https://vercel.com/geist/destructive-action-modal) "`loading` disables both buttons. The caller owns `open` — do not self-dismiss from `onConfirm`. Close the modal after the API settles (success or error), or keep it open on error so the user can retry." (https://vercel.com/geist/destructive-action-modal) "Default focus to `Cancel` on any destructive Modal. Enter must never trigger the destructive action without a typed confirmation." (https://vercel.com/geist/modal) "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: `title`, `description`, `confirmLabel` and `cancelLabel` are required; `irreversible` and `verify` are optional, and the absence of `irreversible` is what marks the action reversible. Geist\'s `irreversibleDescription` is `irreversible`, `verificationPhrase` and `verificationLabel` are `verify.phrase` and `verify.prompt`, and `error` is the catalogue\'s message. 480 px wide over a scrim. The title and the description, then the body in a 24 px column: the `irreversible` note, the `verify` field, the failure under it. `irreversible` is a flat red note with a red mark and red words, not a band over the footer; besides it the only red is the failure and the enabled destructive confirm. While `loading` the field turns read-only and keeps focus, Escape does not close it, and the confirm says `confirmPendingLabel`, which falls back to the confirm\'s label. A press outside does not close it, so a stray click never discards a typed phrase or an action in flight; Escape and Cancel do. The footer is a bar that stays at the bottom while a tall confirmation scrolls, and a row on a phone too.',
90
+ behaviour: '"The verification input gets focus on open so the user can start typing immediately. Submit stays disabled until the value matches `verificationPhrase` exactly." (https://vercel.com/geist/destructive-action-modal) "Enter submits only when the gate is open; it\'s a no-op otherwise. Cancel, outside-click, and Escape all dismiss." (https://vercel.com/geist/destructive-action-modal) "`loading` disables both buttons. The caller owns `open` — do not self-dismiss from `onConfirm`. Close the modal after the API settles (success or error), or keep it open on error so the user can retry." (https://vercel.com/geist/destructive-action-modal) "Default focus to `Cancel` on any destructive Modal. Enter must never trigger the destructive action without a typed confirmation." (https://vercel.com/geist/modal) "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: `title`, `description`, `confirmLabel` and `cancelLabel` are required; `irreversible` and `verify` are optional, and the absence of `irreversible` is what marks the action reversible. Geist\'s `irreversibleDescription` is `irreversible`, `verificationPhrase` and `verificationLabel` are `verify.phrase` and `verify.prompt`, and `error` is the catalogue\'s message. 480 px wide over a scrim. The title and the description, then the body in a 24 px column: the `irreversible` note, the `verify` field, the failure under it. `irreversible` is a flat red note with a red mark and red words, not a band over the footer; besides it the only red is the failure and the enabled destructive confirm. While `loading` the field turns read-only and keeps focus, Escape does not close it, and the confirm says `confirmPendingLabel`, which falls back to the confirm\'s label. A press outside does not close it, so a stray click never discards a typed phrase or an action in flight; Escape and Cancel do. The footer is a bar that stays at the bottom while a tall confirmation scrolls, and a row on a phone too. How long it stays open while work goes on follows DESIGN.md "System activity".',
91
91
  words: '"`title` is Title Case, `Verb + Noun`, a statement — never a question. `Delete Project`, not `Delete this project?`." (https://vercel.com/geist/destructive-action-modal) "`description` is sentence case, names the consequence, and interpolates the specific resource when relevant. `<b>my-project</b> and all its deployments will be permanently deleted.` reads stronger than `This project and all its deployments will be deleted.`." (https://vercel.com/geist/destructive-action-modal) "`confirmLabel` matches the title 1:1. Never generic (`Confirm`, `OK`, `Continue`), never a bare verb (`Delete`)." (https://vercel.com/geist/destructive-action-modal) "`cancelLabel` defaults to `Cancel`. Override when Cancel is ambiguous, such as `Keep Turn Running` when the primary action is itself a cancellation." (https://vercel.com/geist/destructive-action-modal) "`verificationPhrase`: for entity deletes, type the **resource name itself** (`my-project`) and pair with `verificationLabel="project name"` so the prompt reads `To confirm, type the project name "my-project"`. That\'s the canonical signal that the user knows which thing they\'re acting on. Fall back to a lowercase verb phrase (`disable vercel authentication`) only when there\'s no entity to name." (https://vercel.com/geist/destructive-action-modal) "`irreversibleDescription` names the specific action and resource and ends with `cannot be undone.` — `Deleting my-project cannot be undone.` rather than the generic `This cannot be undone.`. Omit the prop entirely for reversible actions; the prop\'s absence is the signal, not a falsy value." (https://vercel.com/geist/destructive-action-modal) "`error` surfaces the API failure verbatim in Vercel voice: `Couldn\'t save settings. Try again.`. Never dump a raw error object." (https://vercel.com/geist/destructive-action-modal) "Pair the post-confirm success toast verb 1:1 with the primary button: `Delete Project` button, `Project deleted` toast. Never `Project removed`." (https://vercel.com/geist/destructive-action-modal) "Close irreversible bodies with `This cannot be undone.`; close cascade-only bodies with `Some effects cannot be undone.`. Don’t claim full irreversibility for a partial cascade." (https://vercel.com/geist/modal) Ours: the title is sentence case and names the record, "Remove pec@acme.it", and the confirm repeats the verb and the noun, "Remove mailbox", so the two share a verb and not every word; its success toast uses the same verb ("Mailbox removed"). The description names the record in medium weight.',
92
92
  access: '"The verification input is associated with its prompt via `aria-labelledby` + `htmlFor`. Screen readers announce the full prompt (`To confirm, type "delete my-project"`) on focus." (https://vercel.com/geist/destructive-action-modal) "The Warning icon in the irreversibility band is `aria-hidden`; the sentence carries the meaning so nothing is announced twice." (https://vercel.com/geist/destructive-action-modal) "Focus stays inside the modal across an `error` transition so the user can retry without losing context. After success, return focus to the trigger." (https://vercel.com/geist/destructive-action-modal) "Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Keep the Cancel button literally `Cancel` so screen-reader users hear a stable dismissal label across destructive flows." (https://vercel.com/geist/modal) Ours: `role="alertdialog"` named by its title and described by its consequence; the note is `role="note"` with its icon hidden. Focus starts on Cancel, or in the field with `verify`.',
93
93
  },
@@ -109,7 +109,7 @@ export const USAGE = [
109
109
  summary: "A new record, or one or two values from a command, in a modal dialog.",
110
110
  when: '"Use Modal when a decision must block the rest of the page. For persistent associated context where the underlying page stays readable, use `Sheet` on desktop or `Drawer` on mobile." (https://vercel.com/geist/modal) Ours: a person adds a record through a few fields, or changes one or two values a command asks for: new customer, add a mailbox, add an MCP server.',
111
111
  instead: '"Skip Modal for routine create flows that have a dedicated page; route to the page instead." (https://vercel.com/geist/modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a record already in a list edits in its row with `RowEditForm`; a choice from a catalogue is a `CatalogDrawer`; a setup in steps with a wait is a `FormDrawer` with `job="steps"`; a consequence is confirmed in a `ConfirmDialog`.',
112
- behaviour: '"Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. `FormDialogForm` puts the fields in the dialog\'s own scroll body and the actions in its fixed footer; no other overlay is nested inside. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close.',
112
+ behaviour: '"Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. `FormDialogForm` puts the fields in the dialog\'s own scroll body and the actions in its fixed footer; no other overlay is nested inside. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close. How long it stays open while work goes on follows DESIGN.md "System activity".',
113
113
  words: '"`Modal.Title` is a Title Case statement, never a question. `Transfer Project` is correct; `Transfer Project?` is wrong." (https://vercel.com/geist/modal) "Primary button is `Verb + Noun` and matches the title verb (`Transfer Project` title pairs with `Transfer Project` button). Never `Confirm`, `OK`, or a bare verb on a destructive primary." (https://vercel.com/geist/modal) "Cancel literal stays `Cancel`. Acknowledgment-only Modals (after a key reveal, after a one-time-show) use `Done`, never `OK` or `Close`." (https://vercel.com/geist/modal) Ours: the title and the primary are sentence case, where Geist writes Title Case: the title names the job and its object, "New customer", "Add a mailbox"; the primary repeats it, "Create customer", "Add mailbox".',
114
114
  access: '"Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Trap focus inside the Modal while it’s open and return focus to the trigger after close. Restore body scroll on the same tick the Modal unmounts." (https://vercel.com/geist/modal) "After an error inside the Modal, keep focus inside so the user can retry; after success, return focus to the trigger." (https://vercel.com/geist/modal) Ours: a modal dialog with a Close named by `closeLabel`; focus starts in its first field or `initialFocus` and returns to the opener or `finalFocus`. Escape and Close close it unless the save runs.',
115
115
  },
@@ -120,7 +120,7 @@ export const USAGE = [
120
120
  summary: "The right-side sheet for a catalogue or a setup in steps, at one width.",
121
121
  when: "Ours: choosing from a catalogue too long for a dialog (through `CatalogDrawer`), or setting something up in several steps with a wait: connect a messaging channel, Telegram's code.",
122
122
  instead: "\"Don’t use Sheet to confirm destructive actions. The default `modal=false` keeps the page interactive, which weakens severity for a delete or revoke.\" (https://vercel.com/geist/sheet) Ours: a new record from a few fields is a `FormDialog`; a record already in a list edits in its row with `RowEditForm`; a fact on the record's own page changes in place in its section; a consequence is confirmed in a `ConfirmDialog`; a phone's short job is a `Drawer`.",
123
- behaviour: '"Sheet defaults to `modal=false` so toasts and other high-z elements stay reachable. Keep that default unless the sheet owns the screen." (https://vercel.com/geist/sheet) "Pick `side` from the trigger location: a row inspector slides from `right`, a global filter from `left`. Don’t change sides mid-session." (https://vercel.com/geist/sheet) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet\'s one width that no caller sets. The header holds the step ("Step 2 of 3", in mono) over the title, which stays the job\'s name, then the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs.',
123
+ behaviour: '"Sheet defaults to `modal=false` so toasts and other high-z elements stay reachable. Keep that default unless the sheet owns the screen." (https://vercel.com/geist/sheet) "Pick `side` from the trigger location: a row inspector slides from `right`, a global filter from `left`. Don’t change sides mid-session." (https://vercel.com/geist/sheet) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet\'s one width that no caller sets. The header holds the step ("Step 2 of 3", in mono) over the title, which stays the job\'s name, then the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs. How long it stays open while work goes on follows DESIGN.md "System activity".',
124
124
  words: '"Title is Title Case and names the entity (`Deployment Details`, `Member Profile`), not the page action." (https://vercel.com/geist/sheet) "Body is read-mostly: sentence case prose with Title Case sub-headings. Action buttons are optional; when present, follow `Verb + Noun`." (https://vercel.com/geist/sheet) Ours: the title is sentence case and names the job and its object: "Connect Telegram", "Add a skill". The step reads "Step N of M". The primary says what it does: "Connect", "Continue", never "OK".',
125
125
  access: '"Trap focus inside the sheet while it’s open and return focus to the trigger row on close so keyboard users keep their place in the list." (https://vercel.com/geist/sheet) "Provide a visible close button labeled `Close` (or an icon button with `aria-label="Close"`) since clicking outside doesn’t dismiss." (https://vercel.com/geist/sheet) "Announce the sheet with `aria-labelledby` pointing at the title; pair it with `aria-describedby` only when the body is short and load-bearing." (https://vercel.com/geist/sheet) Ours: a modal dialog named by its title; focus returns to the opener on close, or to `finalFocus` when the opener is gone. The step is read before the title.',
126
126
  },
@@ -1394,11 +1394,11 @@ export const USAGE = [
1394
1394
  module: "waiting-line",
1395
1395
  family: "Feedback",
1396
1396
  summary: "The one moving thing a system wait may show: a 2 px ink line, after a second.",
1397
- when: "A system wait the person asked for that runs past a second: a save, a connection, a download without a count.",
1397
+ when: "A system wait the person asked for that runs past a second: a save, a connection, a download without a count. In a record's row, `WaitingDetail` puts it under the row's detail line, which names the work.",
1398
1398
  instead: "Under a second the `PendingLabel` alone. A known amount is a progress line with a count. A page load is `Skeleton`. An Agent working is her orb and a sentence.",
1399
1399
  behaviour: "Takes its 2 px from the start and stays empty until 1 s, so its arrival moves nothing. No track colour; the segment is ink, never info blue, crossing at 32% width. Under reduced motion it breathes in opacity, across the whole track, instead of travelling.",
1400
1400
  words: "None of its own. The control beside it carries the pending word; a standalone line takes a `label` naming the work: *Connecting Telegram*.",
1401
- access: 'With a label: `role="status"`, announced once after the second. `decorative` when the control beside it already says it. The segment is hidden.',
1401
+ access: 'With a label: `role="status"`, announced once after the second. `decorative` when a control or sentence beside it already names the work (DESIGN.md "System activity"). The segment is hidden.',
1402
1402
  },
1403
1403
  {
1404
1404
  name: "AccountMenu",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "12.1.131",
3
+ "version": "12.1.132",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -83,7 +83,7 @@
83
83
  "@base-ui/react": "^1.9.0",
84
84
  "@iconify-icons/logos": "^2.0.3",
85
85
  "@iconify/react": "^6.0.2",
86
- "@nadicodeai/design-system": "12.1.131",
86
+ "@nadicodeai/design-system": "12.1.132",
87
87
  "@tanstack/react-table": "^9.3.1",
88
88
  "@vgpu/wgsl": "0.6.0",
89
89
  "class-variance-authority": "^0.7.1",