@assure-one/design-system 1.36.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- Generated by `pnpm docs:catalogue` from api/*.api.md and docs/components.registry.json. Do not edit by hand; edit the registry and regenerate. -->
4
4
 
5
- Every public component of `@assure-one/design-system`, in one place: **547 component exports** — 166 component families with 228 compound parts, and 153 icons — plus the hooks, utilities, tokens and testing helpers the package exports. The list is derived from the API reports, so a public component cannot be missing from this page (`pnpm docs:catalogue --check` runs in `pnpm test:contracts`).
5
+ Every public component of `@assure-one/design-system`, in one place: **561 component exports** — 180 component families with 228 compound parts, and 153 icons — plus the hooks, utilities, tokens and testing helpers the package exports. The list is derived from the API reports, so a public component cannot be missing from this page (`pnpm docs:catalogue --check` runs in `pnpm test:contracts`).
6
6
 
7
7
  **How to use this page.** Start from the ["Pick a component"](#pick-a-component) table with the UI need you have, or from ["Never hand-roll"](#never-hand-roll) with the raw element you were about to write; links land on the category section that holds the row. Every row links to the story that shows the states. The short rulebook for agents and new contributors is [`docs/for-ai-agents.md`](./for-ai-agents.md).
8
8
 
@@ -46,7 +46,7 @@ The UI need on the left, the design-system answer on the right. When two compone
46
46
  | Navigate somewhere with a button look | [LinkButton](#actions) | Renders an `<a href>`; `Button asChild` around your router's `Link` is the alternative. |
47
47
  | Submit a form | [SubmitButton](#actions) | Full-width by default; `type="submit"` and pending state handled. |
48
48
  | Make something that is not a button clickable | [Pressable](#actions) | Keyboard, focus ring, disabled handling, no button chrome. Never `<div onClick>`. |
49
- | Confirm a destructive action | [ConfirmActionButton](#actions), [AlertDialog](#overlays) | `ConfirmActionButton` wraps the dialog around any trigger; `AlertDialog` when you compose the copy yourself. |
49
+ | Confirm a destructive action | [ConfirmActionButton](#actions), [ConfirmDialog](#overlays), [ConfirmHost](#overlays) | `ConfirmActionButton` wraps the dialog around any trigger; `ConfirmDialog` when you control `open` or need a form field in the body; `useConfirm()` / `usePrompt()` to `await` an answer from an event handler (needs `DesignSystemProvider confirm` or a `ConfirmHost`). |
50
50
  | Act on selected rows | [BulkActionBar](#actions) | Floating bar with the count and the row actions. |
51
51
  | Keep Save / Cancel visible at the bottom of a long form | [StickyActionBar](#actions) | |
52
52
  | Label + help + error around any control | [Field](#forms) | `Label`, `FieldDescription`, `FieldError` inside; controls bind automatically. `Fieldset` groups several. `FieldControl` wires a non-DS control. |
@@ -76,7 +76,7 @@ The UI need on the left, the design-system answer on the right. When two compone
76
76
  | A global command / search box | [CommandPalette](#overlays), [KeyboardShortcutsDialog](#overlays) | |
77
77
  | Switch between views | [Tabs](#navigation), [ChannelTabs](#navigation), [BottomNav](#navigation) | `BottomNav` is the mobile tab bar. |
78
78
  | Where am I | [Breadcrumb](#navigation), [PageHeader](#layout), [AppHeader](#shell-screens) | |
79
- | Page through results | [Pagination](#navigation) | `DataTablePagination` inside a `DataTable`. |
79
+ | Page through results | [Pagination](#navigation) | `DataTablePagination` is the same pager with the table's 25-row default; `pageSizeOptions` adds a rows-per-page picker. |
80
80
  | A tree or a rail of items | [FolderTree](#navigation), [ClientRailItem](#navigation) | |
81
81
  | Space things out | [Stack](#layout), [Inline](#layout) | Tokenised gap and alignment; never ad-hoc `flex gap-*` in product code. |
82
82
  | A bordered box or card | [Surface](#layout), [Card](#layout) | `Card` adds header/title/description/footer parts and an interactive variant. |
@@ -112,7 +112,7 @@ Things you press. Every clickable control is one of these; a `<button>`, `<a rol
112
112
  | **SubmitButton**<br>since 0.0.0 | The primary submit of a form: `type="submit"`, full width by default (`fullWidth={false}` inline), shows `pendingText` while the form's `useFormStatus` is pending. | The button is not a form submit or you need a secondary action next to the submit (`Button`). | `<button type="submit">`, `<input type="submit">` | [Button](#actions), [Field](#forms) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/submit-button.stories.tsx) |
113
113
  | **Pressable** (experimental)<br>since 1.35.0 | A clickable region without button chrome: a card, a row, a tile. Renders a `<button>` (or `asChild`) with keyboard activation, focus ring and disabled handling. | A visible button is meant (`Button`) or the region contains its own interactive controls (use `Card variant="interactive"` with an explicit action). | `<div onClick>`, `<span role="button">`, `<li onClick>` | [Button](#actions), [Card](#layout) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/pressable.stories.tsx) |
114
114
  | **CopyButton**<br>since 0.0.0 | Copy a value to the clipboard with check-mark feedback (ids, codes, links). | The copy needs a confirmation toast or copies rich content — compose `IconButton` + `useToast`. | `navigator.clipboard.writeText + useState` | [IconButton](#actions), [ToastProvider](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/copy-button.stories.tsx) |
115
- | **ConfirmActionButton**<br>since 0.3.0 | A destructive or irreversible action that needs a confirmation step: wraps `AlertDialog` around any trigger and retires `window.confirm()`. | The confirmation needs a form or custom body (`AlertDialog` composed directly) or the action is reversible (act, then offer undo in a toast). | `window.confirm()`, `useState + AlertDialog boilerplate` | [AlertDialog](#overlays), [DangerAction](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/confirm-action-button.stories.tsx) |
115
+ | **ConfirmActionButton**<br>since 0.3.0 | A destructive or irreversible action that needs a confirmation step: a trigger plus `ConfirmDialog`, retiring `window.confirm()`. `destructive={false}` (alias of `intent="brand"`) for a non-destructive confirm. | The confirmation is imperative (`useConfirm`) or the action is reversible (act, then offer undo in a toast). | `window.confirm()`, `useState + AlertDialog boilerplate` | [ConfirmDialog](#overlays), [AlertDialog](#overlays), [DangerAction](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/confirm-action-button.stories.tsx) |
116
116
  | **Intent actions**<br>parts: `SecondaryAction`, `DangerAction`, `LinkAction`, `IconAction`<br>since 0.3.0 | Intent-named `Button` wrappers for product code that reads by role: primary, secondary, danger, link-styled, icon-only. | You need the full variant × intent matrix or a size outside the defaults (`Button`, `IconButton`). | — | [Button](#actions), [IconButton](#actions), [LinkButton](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/intent-actions.stories.tsx) |
117
117
  | **BulkActionBar**<br>parts: `BulkActionBarAction`, `BulkActionBarSeparator`<br>since 0.15.0 | A floating bar that appears when rows are selected: selection count, actions, separators, clear. | Actions apply to one record (row menu via `DropdownMenu`) or belong to the page (`PageHeader` actions). | — | [DataTable](#data-display), [StickyActionBar](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/bulk-action-bar.stories.tsx) |
118
118
  | **StickyActionBar**<br>since 1.3.0 | Save / Cancel that stays visible at the bottom of a long form or settings page, with an optional hint and mobile-nav offset. | The form fits the viewport (put the `SubmitButton` at the end) or the actions belong to a dialog (`DialogFooter`). | `<div class="sticky bottom-0">` | [SubmitButton](#actions), [BulkActionBar](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/sticky-action-bar.stories.tsx) |
@@ -165,6 +165,8 @@ Pick one or many from a set: dropdowns, comboboxes, toggle groups, chips and fil
165
165
 
166
166
  | Component | Use when | Don't use when | Replaces raw HTML | Related | Links |
167
167
  | --- | --- | --- | --- | --- | --- |
168
+ | **PeoplePicker** (experimental)<br>since unreleased | Pick a person or people from the firm's roster (W7-10): `people`, single or `multiple`, avatars with an optional second line, an "assign to me" shortcut from `currentUserId`, and an `unassignedLabel` row that reports `null`. Search, keyboard, `Field` binding and form submission come from `Combobox`. | The options are not people (`Combobox`, `MultiSelect`), or a plain roster select with no roster affordances is enough (`Select`). `TeamMemberSelect` is the predecessor it replaces. | `hand-rolled assignee popover with checkboxes` | [Combobox](#selection), [MultiSelect](#selection), [Avatar](#data-display), [TeamMemberSelect](#selection) | [story](https://github.com/Assure-One/design-system/blob/main/src/patterns/pickers/people-picker.stories.tsx) |
169
+ | **SegmentedControl** (experimental)<br>since unreleased | One of a few mutually exclusive views or scopes, shown side by side (W7-17): `options` with an optional `count` per segment, `size` on the control scale, radio semantics and arrow-key movement from `ToggleGroup`. The active segment cannot be cleared by clicking it again. | The set is long or open-ended (`Select`, `Combobox`), more than one may be active (`ToggleGroup type="multiple"`), or the segments switch page regions rather than a value (`Tabs`). | `pill Tabs used as a filter`, `<div> of <button> with a manual active class` | [ToggleGroup](#selection), [Tabs](#navigation), [Select](#selection), [MultiFilterPill](#selection) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/segmented-control.stories.tsx) |
168
170
  | **Select**<br>parts: `SelectRoot`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectItem`, `SelectGroup`, `SelectLabel`, `SelectSeparator`, `SelectScrollUpButton`, `SelectScrollDownButton`<br>since 0.0.0 | One of a short static list in a dropdown: the sealed `Select` takes `options`; the `Select*` parts compose custom items. Empty value is a real empty (no sentinel option), `size`, `classNames`, Field binding. | The user should type to filter, the list is long or async (`Combobox`), several values (`MultiSelect`), or a few options that can all be visible (`RadioGroup`, `ToggleGroup`). | `<select>`, `<option>` | [Combobox](#selection), [MultiSelect](#selection), [ClientSelect](#selection), [TeamMemberSelect](#selection) | — |
169
171
  | **Combobox** (experimental)<br>also: `DEFAULT_COMBOBOX_MESSAGES`<br>since unreleased | A searchable pick: one input, a portalled listbox, the `Option<T>` model (`{ value, label }`), async loading and empty messages, single or `multiple`. | A short static list (`Select`) or free text with suggestions that need not match (`Input` + `Popover`). | `<input list> + <datalist>`, `<select> with a search box` | [Select](#selection), [MultiSelect](#selection), [SearchSelect](#selection) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/combobox.stories.tsx) |
170
172
  | **MultiSelect** (experimental)<br>since unreleased | Several of many options with search: `Combobox` in `multiple` mode with selected chips. | A handful of options that should all be visible (`MultiSelectField`) or one value (`Combobox`, `Select`). | `<select multiple>` | [Combobox](#selection), [MultiSelectField](#forms), [Chip](#selection) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/multi-select.stories.tsx) |
@@ -192,7 +194,8 @@ Tell the user what is happening: status messages, progress, loading and empty st
192
194
  | **ProgressRing**<br>also: `progressRingVariants`<br>since 0.0.0 | A circular meter for a card or tile, with the same `intent` and value-driven colour rule as `ProgressBar`. | A wide layout (`ProgressBar`) or a donut of several series (`DonutChart`). | — | [ProgressBar](#feedback), [DonutChart](#media) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/progress-ring.stories.tsx) |
193
195
  | **SegmentedProgress**<br>since 1.2.0 | Progress through a known number of steps as filled segments (onboarding, checklists). | The steps have names (`Stepper`) or the value is continuous (`ProgressBar`). | — | [Stepper](#navigation), [ProgressBar](#feedback), [SuiteProgress](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/segmented-progress.stories.tsx) |
194
196
  | **SuiteProgress**<br>also: `suiteProgressFillVariants`<br>since 1.34.0 | The suite's discrete segmented meter with a percent readout, tinted per product or `intent`. | A generic segmented meter (`SegmentedProgress`) or a continuous one (`ProgressBar`). | — | [SegmentedProgress](#feedback), [ProgressBar](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/suite-progress.stories.tsx) |
195
- | **EmptyState**<br>since 0.0.0 | A list or panel has nothing to show: icon, title, description and one action. | The feature does not exist yet (`ComingSoon`) or content is loading (`Skeleton`). | `centred div with an icon and grey text` | [ComingSoon](#feedback), [LoadingRows](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/empty-state.stories.tsx) |
197
+ | **EmptyState**<br>since 0.0.0 | A list or panel has nothing to show: icon, title, description and one action. | The feature does not exist yet (`ComingSoon`) or content is loading (`Skeleton`). | `centred div with an icon and grey text` | [ComingSoon](#feedback), [LoadingRows](#feedback), [ErrorState](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/empty-state.stories.tsx) |
198
+ | **ErrorState**<br>since 1.38.0 | A list or panel failed to load: danger icon tile, title, description and a retry button (`onRetry`). `size="compact"` inside a table. | There is simply nothing to show (`EmptyState`) or the error belongs to a form field (`FieldError`). | `centred div with a warning icon and a Try again button` | [EmptyState](#feedback), [TableError](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/error-state.stories.tsx) |
196
199
  | **ComingSoon**<br>since 0.0.0 | A placeholder for a feature that is not available yet: icon, title, description and a feature list. | The feature exists but has no data (`EmptyState`). | — | [EmptyState](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/coming-soon.stories.tsx) |
197
200
  | **AttentionItem**<br>since 1.2.0 | One row of an attention queue: icon, title, description, service tone and trailing action. | A notification (`NotificationPanel` items) or an activity event (`ActivityList` items). | — | [NotificationPanel](#data-display), [ActivityList](#data-display), [KpiCard](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/attention-item.stories.tsx) |
198
201
  | **MissingDocumentsPanel**<br>since 1.4.0 | The firm-side panel listing documents a client has not provided, with a Request action. | The client-side checklist (`DocumentChecklist`). | — | [DocumentChecklist](#data-display), [DocumentRequestDetail](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/missing-documents-panel.stories.tsx) |
@@ -205,11 +208,13 @@ Layers above the page: dialogs, sheets, menus, popovers and tooltips. All portal
205
208
 
206
209
  | Component | Use when | Don't use when | Replaces raw HTML | Related | Links |
207
210
  | --- | --- | --- | --- | --- | --- |
211
+ | **ConfirmDialog** (experimental)<br>since unreleased | The confirmation pattern (target architecture §34): `title`, `description`, optional body content (a form field the decision depends on), `intent` (`danger` default — focus starts on Cancel; `brand` / `neutral` / `success` render the action through the Button recipe), async `onConfirm` with a built-in pending state, a rejection or a resolved `false` keeps it open and shows the error inline. Labels default to the `confirm` messages namespace. | A one-line confirm around a trigger (`ConfirmActionButton`, which is this pattern with a `trigger`) or an imperative `await` from an event handler (`useConfirm`). | `window.confirm()`, `useState + AlertDialog + pending flag boilerplate` | [ConfirmActionButton](#actions), [AlertDialog](#overlays), [ConfirmHost](#overlays) | [story](https://github.com/Assure-One/design-system/blob/main/src/patterns/confirm/confirm-dialog.stories.tsx) |
212
+ | **ConfirmHost** (experimental)<br>also: `useConfirm`, `usePrompt`<br>since unreleased | Imperative confirmation: `const confirm = useConfirm(); if (await confirm({ title, intent: "danger" })) …` resolves `true` / `false`; `usePrompt()` resolves the entered string or `null`. Mount one `ConfirmHost` high in the tree (`DesignSystemProvider confirm` does) and every hook below shares its queue; without a host, or on the server, a request resolves as cancelled. | The confirmation is part of the markup (`ConfirmDialog`, `ConfirmActionButton`) or needs a custom body beyond one input (`ConfirmDialog` with children). | `window.confirm()`, `window.prompt()`, `PromptDialog.ask() singletons` | [ConfirmDialog](#overlays), [DesignSystemProvider](#shell-screens) | [story](https://github.com/Assure-One/design-system/blob/main/src/patterns/confirm/use-confirm.stories.tsx) |
208
213
  | **Dialog**<br>parts: `DialogTrigger`, `DialogPortal`, `DialogOverlay`, `DialogContent`, `DialogHeader`, `DialogTitle`, `DialogDescription`, `DialogBody`, `DialogFooter`, `DialogClose`<br>since 0.0.0 | A modal task or message: focus trap, Escape, overlay, `DialogTitle` required for the accessible name; `size` up to `xl` (or the `--ds-dialog-width` variable), `height`, and `DialogBody` as the scrolling region between header and footer. | A confirmation that must be answered (`AlertDialog`), a side panel (`Sheet`), a mobile-friendly modal (`ResponsiveDialog`) or non-modal content (`Popover`). | `<dialog>`, `fixed inset-0 div` | [AlertDialog](#overlays), [Sheet](#overlays), [ResponsiveDialog](#overlays), [CommandPalette](#overlays) | [docs](https://github.com/Assure-One/design-system/blob/main/docs/adr/012-overlay-presence-motion.md) |
209
214
  | **AlertDialog**<br>parts: `AlertDialogTrigger`, `AlertDialogPortal`, `AlertDialogOverlay`, `AlertDialogContent`, `AlertDialogHeader`, `AlertDialogTitle`, `AlertDialogDescription`, `AlertDialogFooter`, `AlertDialogAction`, `AlertDialogCancel`<br>since 0.0.0 | A decision the user must make before continuing (delete, discard): no outside-click dismiss, explicit Action and Cancel. | A dismissible task (`Dialog`) or a one-line confirm around a trigger (`ConfirmActionButton`). | `window.confirm()` | [Dialog](#overlays), [ConfirmActionButton](#actions) | — |
210
215
  | **Sheet**<br>parts: `SheetTrigger`, `SheetPortal`, `SheetOverlay`, `SheetContent`, `SheetHeader`, `SheetTitle`, `SheetDescription`, `SheetBody`, `SheetFooter`, `SheetClose`<br>since 0.0.0 | A panel sliding in from an edge for a secondary task or detail: `side`, sizes, the Dialog accessibility model, `SheetBody` as the scrolling region between header and footer. | Centred content (`Dialog`) or a persistent split view (`MasterDetailLayout`). | `fixed right-0 h-full div` | [SideDrawer](#overlays), [Dialog](#overlays), [ResponsiveDialog](#overlays) | — |
211
- | **SideDrawer**<br>since 0.0.0 | Only in code that already uses it: the earlier slide-in panel API (`open`, `onClose`, `title`, `width`). | New code — `Sheet` has the same behaviour with composable parts. | — | [Sheet](#overlays) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/side-drawer.stories.tsx) |
212
- | **ResponsiveDialog**<br>since 1.3.0 | A modal that should be a `Dialog` on desktop and a bottom `Sheet` below the `sm` breakpoint, decided after mount. | The presentation must be fixed (`Dialog`, `Sheet`). | — | [Dialog](#overlays), [Sheet](#overlays) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/responsive-dialog.stories.tsx) |
216
+ | **SideDrawer** (deprecated)<br>since 0.0.0 | Only in code that already uses it: the earlier slide-in panel API (`open`, `onClose`, `title`, `width`). | New code — `Sheet` has the same behaviour with composable parts. | — | [Sheet](#overlays) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/side-drawer.stories.tsx) |
217
+ | **ResponsiveDialog** (experimental)<br>since 1.3.0 | A modal that should be a `Dialog` on desktop and a bottom `Sheet` below the `sm` breakpoint, decided after mount. | The presentation must be fixed (`Dialog`, `Sheet`). | — | [Dialog](#overlays), [Sheet](#overlays) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/responsive-dialog.stories.tsx) |
213
218
  | **Popover**<br>parts: `PopoverTrigger`, `PopoverAnchor`, `PopoverPortal`, `PopoverContent`, `PopoverClose`<br>since 0.0.0 | Interactive content anchored to a trigger: a small form, a picker, a filter panel. | A short non-interactive label (`Tooltip`), a preview on hover (`HoverCard`) or a list of actions (`DropdownMenu`). | `absolute-positioned div toggled by state` | [Tooltip](#overlays), [HoverCard](#overlays), [DropdownMenu](#overlays) | — |
214
219
  | **HoverCard**<br>parts: `HoverCardTrigger`, `HoverCardPortal`, `HoverCardContent`<br>since 0.0.0 | A rich preview when hovering a link or name (a person card, a record summary), for sighted pointer users. | The content is essential (it is hover-only) or interactive (`Popover`). | — | [Popover](#overlays), [Tooltip](#overlays) | — |
215
220
  | **Tooltip**<br>parts: `TooltipProvider`, `TooltipTrigger`, `TooltipPortal`, `TooltipContent`<br>since 0.0.0 | A short label for a control on hover and focus; the sealed `Tooltip` takes `content`, the parts compose. | The text is essential to use the control (make it visible) or interactive (`Popover`). | `title="…"` | [IconButton](#actions), [Popover](#overlays), [Kbd](#typography) | — |
@@ -227,7 +232,7 @@ Move between places: tabs, breadcrumbs, pagination, steppers, trees and rails.
227
232
  | **Tabs**<br>parts: `TabsList`, `TabsTrigger`, `TabsContent`<br>since 0.0.0 | Switch between panels of one page; roving focus, `value`/`onValueChange`. | The switch changes a mode rather than showing another panel (`ToggleGroup`), or it is the mobile app-level bar (`BottomNav`). | `<ul role="tablist">`, `buttons toggling useState panels` | [ToggleGroup](#selection), [ChannelTabs](#navigation), [BottomNav](#navigation) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/tabs.stories.tsx) |
228
233
  | **ChannelTabs**<br>since 1.5.0 | Pill tabs switching between communication channels on a thread, each with a toned status dot and unread count; fully controlled. | Generic panels (`Tabs`). | — | [Tabs](#navigation), [StatusDot](#data-display), [MessageBubble](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/channel-tabs.stories.tsx) |
229
234
  | **Breadcrumb**<br>parts: `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, `BreadcrumbSeparator`<br>since 0.0.0 | The path to the current page; `BreadcrumbPage` marks the current one, `BreadcrumbLink asChild` wraps your router link. | The page title itself (`PageHeader`) or the app-level bar (`AppHeaderBreadcrumb` inside `AppHeader`). | `<nav aria-label="breadcrumb"><ol>` | [PageHeader](#layout), [AppHeader](#shell-screens) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/breadcrumb.stories.tsx) |
230
- | **Pagination**<br>since 0.0.0 | Page controls for a paged list: current/total pages, sibling count, optional total items. | Inside a `DataTable` (`DataTablePagination`) or infinite scroll. | `<nav> of page number buttons` | [DataTable](#data-display), [DataTableView](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/pagination.stories.tsx) |
235
+ | **Pagination**<br>since 0.0.0 | Page controls for a paged list: current/total pages, sibling count, optional total items. | Infinite scroll. Inside a `DataTable`, `DataTablePagination` is the same component with the table defaults. | `<nav> of page number buttons` | [DataTable](#data-display), [DataTableView](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/pagination.stories.tsx) |
231
236
  | **Stepper**<br>since 0.0.0 | Named steps of a multi-step flow, horizontal or vertical, with the current step marked. | Unnamed progress (`SegmentedProgress`) or a timeline of past events (`EngagementTimeline`). | — | [SegmentedProgress](#feedback), [EngagementTimeline](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/stepper.stories.tsx) |
232
237
  | **BottomNav**<br>since 1.2.0 | The mobile tab bar at the bottom of the app: tabs with icons and badges, controlled `value`. | Desktop navigation (`Sidebar`) or in-page panels (`Tabs`). | — | [Sidebar](#shell-screens), [Tabs](#navigation), [StickyActionBar](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/bottom-nav.stories.tsx) |
233
238
  | **FolderTree**<br>since 1.2.0 | A collapsible tree of folders with an active node, default-open ids and selection callback. | A flat list (`ClientRailItem`) or a file list (`DocumentList`). | — | [DocumentsWorkspaceLayout](#layout), [ClientRailItem](#navigation), [Collapsible](#layout) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/folder-tree.stories.tsx) |
@@ -239,6 +244,7 @@ Arrange content: stacks, surfaces, cards, separators, section and page framing.
239
244
 
240
245
  | Component | Use when | Don't use when | Replaces raw HTML | Related | Links |
241
246
  | --- | --- | --- | --- | --- | --- |
247
+ | **SectionCard**<br>since 1.38.0 | A titled panel: `title`, optional `description`, trailing `actions`, body and optional `footer` — `Card`'s header/body/footer composed once. `flush` for a body that owns its row insets. | The surface has no heading (`Card`) or it is a whole page header (`PageHeader`). | `section with a border, a heading row and a padded body` | [Card](#layout), [PageHeader](#layout), [Surface](#layout) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/section-card.stories.tsx) |
242
248
  | **Stack** (experimental)<br>since 1.33.0 | A vertical (or `direction="row"`) flex container that owns the gap between its children with tokenised `gap` and alignment. | A wrapping horizontal row (`Inline`) or a bordered box (`Surface`). | `<div class="flex flex-col gap-4">` | [Inline](#layout), [Surface](#layout) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/layout/stack.stories.tsx) |
243
249
  | **Inline** (experimental)<br>since 1.33.0 | A horizontal wrapping row with children centred on the baseline and a tokenised gap: a row of chips, a button row, meta items. | A column (`Stack`) or a toolbar of controls that must share one control size (`Toolbar`). | `<div class="flex flex-wrap items-center gap-2">` | [Stack](#layout), [Toolbar](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/layout/inline.stories.tsx) |
244
250
  | **Surface** (experimental)<br>since 1.33.0 | The bordered box content sits on: surface background, 1px rule, radius, `padding` role (none/sm/md/lg). | You need header/title/footer parts or an interactive variant (`Card`). | `<div class="rounded-xl border bg-white p-4">` | [Card](#layout), [Stack](#layout) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/layout/surface.stories.tsx) |
@@ -280,10 +286,15 @@ Show records and status: tables, key/value grids, badges, dots, avatars, lists a
280
286
 
281
287
  | Component | Use when | Don't use when | Replaces raw HTML | Related | Links |
282
288
  | --- | --- | --- | --- | --- | --- |
289
+ | **InfoHint** (experimental)<br>since unreleased | The ⓘ beside a label or a figure (W7-15): `label` names what the hint is about, `children` is the explanation, `presentation="tooltip"` (default) or `"popover"` for an explanation with a paragraph or a link. The trigger is a real `IconButton`, so the hint is reachable by keyboard and by touch. | The text belongs in the layout (`FieldDescription` under a field) or the surface is a rich hover preview (`HoverCard`). | `<svg title>`, `<span title>` | [Tooltip](#overlays), [Popover](#overlays), [IconButton](#actions), [FieldDescription](#forms) | [story](https://github.com/Assure-One/design-system/blob/main/src/patterns/display/info-hint.stories.tsx) |
290
+ | **AvatarGroup**<br>since 1.38.0 | An overlapping stack of `Avatar`s with a `+N` overflow bubble: `max` caps the faces, `total` carries the real count, `size` cascades from Avatar's scale. | A single person (`Avatar`) or a list that needs names (`DescriptionList`). | `flex row of avatars with negative margins and a +N circle` | [Avatar](#data-display), [TeamMemberSelect](#selection) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/avatar-group.stories.tsx) |
283
291
  | **StarRating**<br>also: `starRatingVariants`<br>since 0.0.0 | A display-only rating: fractional stars, `max`, sized variants. | Capturing a rating (compose `RadioGroup` or `ToggleGroup` with star icons). | — | [Badge](#data-display), [KpiCard](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/star-rating.stories.tsx) |
284
292
  | **Table**<br>parts: `TableHeader`, `TableBody`, `TableFooter`, `TableRow`, `TableHead`, `TableCell`, `TableCaption`<br>since 0.0.0 | A bare semantic table with the design system's row, header and caption styling. | A records table with toolbar, sorting and pagination (`DataTable`, `DataTableView`) or an editable matrix (`Grid`). | `<table>`, `<tr>`, `<td>`, `<th>` | [DataTable](#data-display), [DataTableView](#data-display), [MetadataGrid](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/table.stories.tsx) |
285
- | **DataTable**<br>parts: `DataTableToolbar`, `DataTableSearch`, `DataTableSpacer`, `DataTableResultsCount`, `DataTableHead`, `DataTableHeader`, `DataTableBody`, `DataTableRow`, `DataTableCell`, `DataTableCellName`, `DataTableCellMono`, `DataTableCellId`, `DataTableCellDue`, `DataTableCheckbox`, `DataTablePagination`<br>since 0.3.0 | The composable records table: card frame, toolbar with search and count, sortable headers, typed cells (name, mono, id, due), row checkbox, pagination. | A config-driven table is enough (`DataTableView`) or the table is a plain semantic one (`Table`). | `<table> + hand-rolled toolbar and pager` | [DataTableView](#data-display), [Table](#data-display), [BulkActionBar](#actions), [LoadingRows](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table.stories.tsx) |
286
- | **DataTableView**<br>parts: `StagePill`, `Assignee`, `MoneyCell`, `TagsCell`, `Dash`<br>since 1.6.0 | A list screen as configuration: `columns` + `data` (+ filters, search keys, sort); owns search/filter/sort/pagination state. Cell renderers `StagePill`, `Assignee`, `MoneyCell`, `TagsCell`, `Dash` for `column.render`. | You need custom table composition (`DataTable`). | — | [DataTable](#data-display), [DisplayMenu](#actions), [Toolbar](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table-view.stories.tsx) |
293
+ | **DataTable**<br>parts: `DataTableToolbar`, `DataTableSearch`, `DataTableSpacer`, `DataTableResultsCount`, `DataTableHead`, `DataTableHeader`, `DataTableBody`, `DataTableRow`, `DataTableCell`, `DataTableCellName`, `DataTableCellMono`, `DataTableCellId`, `DataTableCellDue`, `DataTableCheckbox`, `DataTablePagination`<br>since 0.3.0 | The composable records table: card frame, toolbar with search and count, sortable headers, typed cells (name, mono, id, due), row checkbox, pagination. | A config-driven table is enough (`DataTableView`) or the table is a plain semantic one (`Table`). | `<table> + hand-rolled toolbar and pager` | [DataTableView](#data-display), [Table](#data-display), [BulkActionBar](#actions), [LoadingRows](#feedback), [TableLoading](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table.stories.tsx) |
294
+ | **TableLoading** (experimental)<br>since 1.38.0 | The `<tbody aria-busy>` of a data table while its rows load: skeleton rows sized to the columns. Slots in place of `DataTableBody`. | A list outside a table (`LoadingRows`) or a single shape (`Skeleton`). | `<tbody> of hand-rolled skeleton <td>s` | [TableEmpty](#data-display), [TableError](#data-display), [DataTable](#data-display), [LoadingRows](#feedback) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table-states.stories.tsx) |
295
+ | **TableEmpty** (experimental)<br>since 1.38.0 | The `<tbody>` of a data table with no rows: one full-width row holding a compact `EmptyState`. | An empty panel outside a table (`EmptyState`). | `<tr><td colSpan> with centred grey text` | [TableLoading](#data-display), [TableError](#data-display), [EmptyState](#feedback), [DataTable](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table-states.stories.tsx) |
296
+ | **TableError** (experimental)<br>since 1.38.0 | The `<tbody>` of a data table whose rows failed to load: one full-width row holding a compact `ErrorState` with retry. | An error panel outside a table (`ErrorState`). | `<tr><td colSpan> with an error message and a retry button` | [TableLoading](#data-display), [TableEmpty](#data-display), [ErrorState](#feedback), [DataTable](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table-states.stories.tsx) |
297
+ | **DataTableView**<br>parts: `StagePill` (deprecated), `Assignee` (deprecated), `MoneyCell` (deprecated), `TagsCell`, `Dash` (deprecated)<br>since 1.6.0 | A list screen as configuration: `columns` + `data` (+ filters, search keys, sort); owns search/filter/sort/pagination state. Cell renderers `StagePill`, `Assignee`, `MoneyCell`, `TagsCell`, `Dash` for `column.render`. | You need custom table composition (`DataTable`). | — | [DataTable](#data-display), [DisplayMenu](#actions), [Toolbar](#actions) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table-view.stories.tsx) |
287
298
  | **MetadataGrid**<br>parts: `DataItem`<br>since 0.4.1 | Label / value pairs on a detail surface as a semantic `<dl>`; `DataItem span={2}` for full-row values. | Tabular records (`Table`) or a stat tile (`KpiCard`). | `<dl>`, `two-column label/value divs` | [DetailGrid](#layout), [Table](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/metadata-grid.stories.tsx) |
288
299
  | **KpiCard**<br>parts: `SelectableKpiCard`<br>since 0.4.1 | A single-stat dashboard tile: label, value, optional tone, icon and hint; `SelectableKpiCard` when tiles act as filters. | A number inside running content (`Stat`) or a chart (`DonutChart`). | — | [Stat](#typography), [DashGrid](#layout), [Card](#layout) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/kpi-card.stories.tsx) |
289
300
  | **Badge**<br>also: `badgeVariants`, `resolveBadgeAppearance`<br>since 0.0.0 | A short static label or count: `variant` (solid, soft, outline) × `intent`. | A status with a shared vocabulary (`StatusBadge`), a removable token (`Chip`) or a machine-suggested intent (`IntentBadge`). | `<span class="rounded-full px-2 text-xs">` | [StatusBadge](#data-display), [Chip](#selection), [IntentBadge](#data-display), [StatusDot](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/badge.stories.tsx) |
@@ -311,6 +322,8 @@ Show records and status: tables, key/value grids, badges, dots, avatars, lists a
311
322
  | **TimeLogger**<br>parts: `TimeLoggerHeader`, `TimeLoggerTimer`, `TimeLoggerContextRow`, `TimeLoggerField`, `TimeLoggerBillable`, `TimeLoggerNotes`, `TimeLoggerEntryList`, `TimeLoggerEntry`, `TimeLoggerActions`, `TimeLoggerFooter`<br>also: `formatClock`, `formatDuration`, `parseDuration`, `formatCurrency`, `useStopwatch`<br>since 0.15.0 | The compact time-entry panel: compose only the rows a surface needs (timer, context, billable, notes, entries); `useStopwatch` and the duration formatters drive it. | A single duration field (`Input` + `parseDuration`). | — | [Popover](#overlays), [NumberInput](#forms) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/time-logger.stories.tsx) |
312
323
  | **Proposal pricing**<br>parts: `ProposalServiceRow`, `ProposalAddOn`, `ProposalBillingTerms`, `ProposalPricingSummary`<br>since 1.12.0 | The Services & Pricing blocks of a proposal preview: package card, service rows, add-ons, billing terms, summary; inherit the firm accent inside `AgreementViewer`. | Anything outside a proposal (`Card`, `MetadataGrid`). | — | [AgreementViewer](#shell-screens), [ProposalSignatureBlock](#forms), [ProposalSignerList](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/proposal-pricing.stories.tsx) |
313
324
  | **Proposal content**<br>parts: `ProposalNote`, `ProposalCustomPage`<br>since 1.12.0 | The content blocks of a proposal: signer list, notes, custom pages. | Anything outside a proposal. | — | [AgreementViewer](#shell-screens), [ProposalPackageCard](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/proposal-content.stories.tsx) |
325
+ | **DataTable (compound)** (experimental)<br>since unreleased | A records table driven by `useDataTable`: the toolbar with a labelled search, filters and a column-visibility menu, the table on the `Table*` parts with sort and selection wired to the controller, bulk actions, the merged pager and the built-in loading / empty / error bodies. `classNames.search` and `--ds-data-table-search-width` size the search field. | A table with no state (the `Table` parts alone), the hand-written `DataTable*` parts a product already composes, or the config-driven convenience (`DataTableView`). | `hand-rolled toolbar + <table> + pager around per-table useState` | [useDataTable](#hooks-utilities), [Table](#data-display), [DataTable](#data-display), [DataTableView](#data-display), [Pagination](#navigation), [BulkActionBar](#actions), [TableLoading](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/patterns/data/data-table.stories.tsx) · [docs](https://github.com/Assure-One/design-system/blob/main/docs/data-tables.md) |
326
+ | **EmptyValue** (experimental)<br>since unreleased | A table or detail cell has no value: renders the em dash placeholder consistently. | The value is genuinely empty text a user typed — render it as-is. | `<span>—</span>` | — | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/data-table-view.stories.tsx) |
314
327
 
315
328
  ## Media
316
329
 
@@ -368,13 +381,14 @@ The application frame and full-screen composites: shell, sidebar, header, brand
368
381
  | Component | Use when | Don't use when | Replaces raw HTML | Related | Links |
369
382
  | --- | --- | --- | --- | --- | --- |
370
383
  | **Shell**<br>parts: `Main`, `Content`<br>since 0.3.0 | The application frame: `Shell` holds the `Sidebar` and `Main`; `Main` holds `AppHeader` and `Content`. | A public or marketing page (`Section`). | `<div class="flex h-screen">` | [Sidebar](#shell-screens), [AppHeader](#shell-screens), [BrandScope](#shell-screens) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/shell.stories.tsx) |
371
- | **Sidebar**<br>parts: `SidebarProvider`, `SidebarTrigger`, `SidebarBrand`, `SidebarBrandText`, `SidebarSection`, `SidebarLinkGroup`, `SidebarLink`, `SidebarLinkLabel`, `SidebarLinkBadge`, `SidebarLinkAction`, `SidebarPinButton`, `SidebarUser`, `SidebarFooter`<br>also: `sidebarLinkBadgeVariants`, `useSidebarState`, `useSidebarPeekLock`<br>since 0.3.0 | The app navigation rail: expanded/collapsed/peek states from `SidebarProvider`, brand, sections, link groups with badges and actions, user and footer. | Mobile (`BottomNav`) or a rail of records (`ClientRailItem`). | `<aside> + <nav> hand-rolled` | [Shell](#shell-screens), [SidebarBrandSwitcher](#shell-screens), [BottomNav](#navigation) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/sidebar.stories.tsx) |
384
+ | **Sidebar**<br>parts: `SidebarProvider`, `SidebarTrigger`, `SidebarBrand`, `SidebarBrandText`, `SidebarSection`, `SidebarLinkGroup`, `SidebarLink`, `SidebarLinkLabel`, `SidebarLinkBadge`, `SidebarLinkAction`, `SidebarPinButton`, `SidebarUser`, `SidebarFooter`<br>also: `sidebarLinkBadgeVariants`, `useSidebarState`, `useSidebarPeekLock`<br>since 0.3.0 | The app navigation rail: expanded/collapsed/peek states from `SidebarProvider`, brand, sections, link groups with badges and actions, user and footer. | Mobile (`BottomNav`) or a rail of records (`ClientRailItem`). | `<aside> + <nav> hand-rolled` | [Shell](#shell-screens), [SidebarBrandSwitcher](#shell-screens), [BottomNav](#navigation), [SidebarDrawer](#shell-screens) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/sidebar.stories.tsx) |
372
385
  | **SidebarBrandSwitcher**<br>parts: `SidebarBrandSwitcherTile`<br>since 0.11.2 | Switch between Assure products from the sidebar brand slot: tiles for available, current and coming-soon products. | A single-product app (`SidebarBrand`). | — | [Sidebar](#shell-screens), [BrandScope](#shell-screens), [Logo](#media) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/sidebar-brand-switcher.stories.tsx) |
373
386
  | **AppHeader**<br>parts: `AppHeaderBreadcrumb`, `AppHeaderTitle`, `AppHeaderSearch`, `AppHeaderActions`<br>since 0.3.0 | The sticky 56px top bar inside `Main`: breadcrumb, title, search and actions slots in any order. | The page's own title block (`PageHeader`). | — | [Shell](#shell-screens), [PageHeader](#layout), [NewMenu](#actions), [NotificationPanel](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/app-header.stories.tsx) |
374
- | **DesignSystemProvider** (experimental)<br>also: `useDsMessages`<br>since unreleased | Mount once in the root layout to configure the whole design system: `messages` overrides for the generic strings components render, `locale` (default `en-US`, pass the one your app knows server-side), `dir`, the portal container, the router `linkComponent` and `imageComponent` for `LinkButton` and `Logo`, and the tooltip provider. `useDsMessages(namespace, override?)` reads the resolved strings inside your own components. | You are on Next.js — `NextDesignSystemProvider` from `/next` fills in the adapters. Theming a subtree is `ThemeScope` / `BrandScope`, not a nested provider. | `hand-rolled i18n or router context for design-system strings and links` | [ThemeScope](#shell-screens), [BrandScope](#shell-screens), [Tooltip](#overlays), [LinkButton](#actions), [Logo](#media) | [story](https://github.com/Assure-One/design-system/blob/main/src/foundation/provider/design-system-provider.stories.tsx) |
387
+ | **DesignSystemProvider** (experimental)<br>also: `useDsMessages`<br>since unreleased | Mount once in the root layout to configure the whole design system: `messages` overrides for the generic strings components render, `locale` (default `en-US`, pass the one your app knows server-side), `dir`, the portal container, the router `linkComponent` and `imageComponent` for `LinkButton` and `Logo`, the tooltip provider, and opt-in `toasts` / `confirm` regions. `useDsMessages(namespace, override?)` reads the resolved strings inside your own components. | You are on Next.js — `NextDesignSystemProvider` from `/next` fills in the adapters. Theming a subtree is `ThemeScope` / `BrandScope`, not a nested provider. | `hand-rolled i18n or router context for design-system strings and links` | [ThemeScope](#shell-screens), [BrandScope](#shell-screens), [Tooltip](#overlays), [LinkButton](#actions), [Logo](#media) | [story](https://github.com/Assure-One/design-system/blob/main/src/foundation/provider/design-system-provider.stories.tsx) |
375
388
  | **ThemeScope** (experimental)<br>since unreleased | A subtree that renders with its own colour `scheme`, `brand`, `density`, `dir` or runtime brand theme: stamps the `data-ds-*` attributes on its element and registers them so portalled overlays opened from inside (Dialog, Popover, menus) come up in the same theme; nested scopes merge. | The whole app shares one theme (set the attributes on the document root) or only the product brand changes (`BrandScope`). | `<div data-ds-scheme="dark"> whose dialogs come up in the root theme` | [BrandScope](#shell-screens), [DesignSystemProvider](#shell-screens), [Dialog](#overlays), [Popover](#overlays) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/behavior/portal.stories.tsx) · [docs](https://github.com/Assure-One/design-system/blob/main/docs/integration/css.md) |
376
389
  | **BrandScope**<br>parts: `BrandScopeProvider`<br>also: `BRAND_PRODUCTS`, `brandLabel`, `brandScope`, `useBrandScope`<br>since 1.18.0 | Theme a subtree as a product: stamps `data-brand` and provides it so portalled surfaces re-stamp themselves; `brandScope(product)` for the attribute alone. | Colouring by service line (`serviceToneStyle`) or by status (`intent`). | — | [Shell](#shell-screens), [SidebarBrandSwitcher](#shell-screens) | [docs](https://github.com/Assure-One/design-system/blob/main/docs/integration/css.md) |
377
390
  | **AgreementViewer**<br>parts: `AgreementPaneHeading`<br>since 1.12.0 | The client-facing agreement / proposal viewer: cover, steps, firm accent scope for the proposal blocks. | Previewing a PDF (`PdfPreview`). | — | [ProposalPackageCard](#data-display), [ProposalSignatureBlock](#forms), [ProposalSignerList](#data-display) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/agreement-viewer.stories.tsx) |
391
+ | **SidebarDrawer** (experimental)<br>since 1.38.0 | The sidebar nav off-canvas on small viewports: the same tree in a left-hand Sheet, with the focus trap, scroll lock and dismissal the overlay parts already provide. | Desktop widths (`Sidebar`) or a bottom tab bar (`BottomNav`). | — | [Sidebar](#shell-screens), [Sheet](#overlays), [Shell](#shell-screens) | [story](https://github.com/Assure-One/design-system/blob/main/src/composites/sidebar.stories.tsx) |
378
392
 
379
393
  ## Hooks/utilities
380
394
 
@@ -383,6 +397,7 @@ Non-rendering exports: hooks, class-name helpers, formatters and token objects.
383
397
  | Component | Use when | Don't use when | Replaces raw HTML | Related | Links |
384
398
  | --- | --- | --- | --- | --- | --- |
385
399
  | **cn**<br>since 0.0.0 | Merge class names (clsx + tailwind-merge) when composing `className`; consumer classes still win by cascade, `cn` only dedupes. | Overriding a component part — pass `className`/`classNames` instead of rebuilding its classes. | — | [Button](#actions) | [docs](https://github.com/Assure-One/design-system/blob/main/docs/integration/css.md) |
400
+ | **Data-table controller** (experimental)<br>also: `compareSortValues`, `nextSortDirection`<br>since unreleased | Building a data table: owns sorting, pagination, search, selection, column visibility and filters (each controllable or uncontrolled), derives the rows to render, and in `manual` mode only emits state for a server-driven table. | A static table with no state (the `Table` parts alone), or the data-driven convenience (`DataTableView`) once it is rebuilt on the hook. | — | [Table](#data-display), [DataTable](#data-display), [DataTableView](#data-display), [Pagination](#navigation) | [story](https://github.com/Assure-One/design-system/blob/main/src/primitives/behavior/data-table/use-data-table.stories.tsx) · [docs](https://github.com/Assure-One/design-system/blob/main/docs/data-tables.md) |
386
401
  | **useFieldControl** (experimental)<br>since 1.32.0 | Building your own form control that should bind to `Field` like the design-system ones: returns ids, `aria-*`, invalid/disabled/required wiring; explicit props win. | Wrapping an existing element once (`FieldControl`). | — | [Field](#forms), [FieldControl](#forms) | [docs](https://github.com/Assure-One/design-system/blob/main/docs/adr/006-field-native-form-participation.md) |
387
402
  | **Date utilities**<br>also: `displayToIso`, `applyMask`, `applyYearMask`, `isoToDate`, `dateToIso`, `isoToYear`, `yearToIso`, `DATE_DISPLAY_PLACEHOLDER`, `YEAR_DISPLAY_PLACEHOLDER`<br>since 0.11.0 | Convert between ISO `YYYY-MM-DD`, the `MM/DD/YYYY` display format and JS `Date` the way `DatePicker` does, and apply its typing masks. | Locale-aware formatting for display text (`Intl.DateTimeFormat`). | — | [DatePicker](#forms), [DateRangePicker](#forms) | — |
388
403
  | **Country codes**<br>also: `getFlagEmoji`, `parsePhoneForEditing`<br>since 1.1.0 | The ISO country / dial-code table behind `PhoneCountryInput`, a flag emoji fallback, and splitting a stored phone string for editing. | Full phone validation (bring libphonenumber). | — | [PhoneField](#forms), [PhoneCountryInput](#forms) | — |
@@ -423,6 +438,7 @@ The raw element or pattern on the left already has a design-system component. Wr
423
438
  | `<div onClick>` | [Button](#actions), [Pressable](#actions) |
424
439
  | `<div role="alert">` | [Alert](#feedback) |
425
440
  | `<div role="group">` | [Fieldset](#forms) |
441
+ | `<div> of <button> with a manual active class` | [SegmentedControl](#selection) |
426
442
  | `<dl>` | [MetadataGrid](#data-display) |
427
443
  | `<fieldset>` | [Fieldset](#forms) |
428
444
  | `<h1>` | [Heading](#typography) |
@@ -474,14 +490,20 @@ The raw element or pattern on the left already has a design-system component. Wr
474
490
  | `<span class="rounded-full px-2 text-xs">` | [Badge](#data-display) |
475
491
  | `<span class="text-sm text-gray-500">` | [Text](#typography) |
476
492
  | `<span role="button">` | [Pressable](#actions) |
493
+ | `<span title>` | [InfoHint](#data-display) |
494
+ | `<span>—</span>` | [EmptyValue](#data-display) |
495
+ | `<svg title>` | [InfoHint](#data-display) |
477
496
  | `<svg>` | [Icons](#icons) |
478
497
  | `<table>` | [Table](#data-display) |
479
498
  | `<table> + hand-rolled toolbar and pager` | [DataTable](#data-display) |
480
499
  | `<table> of <input>s` | [Grid](#forms) |
500
+ | `<tbody> of hand-rolled skeleton <td>s` | [TableLoading](#data-display) |
481
501
  | `<td>` | [Table](#data-display) |
482
502
  | `<textarea>` | [Textarea](#forms) |
483
503
  | `<th>` | [Table](#data-display) |
484
504
  | `<tr>` | [Table](#data-display) |
505
+ | `<tr><td colSpan> with an error message and a retry button` | [TableError](#data-display) |
506
+ | `<tr><td colSpan> with centred grey text` | [TableEmpty](#data-display) |
485
507
  | `<ul role="tablist">` | [Tabs](#navigation) |
486
508
  | `<ul> of hand-styled feed rows` | [ActivityList](#data-display) |
487
509
  | `<ul> shown on click` | [DropdownMenu](#overlays) |
@@ -491,33 +513,42 @@ The raw element or pattern on the left already has a design-system component. Wr
491
513
  | `animate-spin svg` | [Spinner](#feedback) |
492
514
  | `Array.from({ length }).map(<Skeleton/>)` | [LoadingRows](#feedback) |
493
515
  | `buttons toggling useState panels` | [Tabs](#navigation) |
516
+ | `centred div with a warning icon and a Try again button` | [ErrorState](#feedback) |
494
517
  | `centred div with an icon and grey text` | [EmptyState](#feedback) |
495
518
  | `class="sr-only"` | [VisuallyHidden](#layout) |
496
519
  | `coloured bordered div` | [Alert](#feedback) |
497
520
  | `drop-zone div with onDrop` | [FileUpload](#forms) |
498
521
  | `fixed inset-0 div` | [Dialog](#overlays) |
499
522
  | `fixed right-0 h-full div` | [Sheet](#overlays) |
523
+ | `flex row of avatars with negative margins and a +N circle` | [AvatarGroup](#data-display) |
500
524
  | `group of <button aria-pressed>` | [ToggleGroup](#selection) |
525
+ | `hand-rolled assignee popover with checkboxes` | [PeoplePicker](#selection) |
501
526
  | `hand-rolled i18n or router context for design-system strings and links` | [DesignSystemProvider](#shell-screens) |
502
527
  | `hand-rolled toast portal` | [ToastProvider](#feedback) |
528
+ | `hand-rolled toolbar + <table> + pager around per-table useState` | [DataTable (compound)](#data-display) |
503
529
  | `hard-coded top-[56px] sticky offsets` | [StickyStack](#layout) |
504
530
  | `lucide-react` | [Icons](#icons) |
505
531
  | `navigator.clipboard.writeText + useState` | [CopyButton](#actions) |
506
532
  | `nested div with width:%` | [ProgressBar](#feedback) |
507
533
  | `onContextMenu + positioned div` | [ContextMenu](#overlays) |
508
534
  | `padding-top percentage hack` | [AspectRatio](#layout) |
535
+ | `pill Tabs used as a filter` | [SegmentedControl](#selection) |
536
+ | `PromptDialog.ask() singletons` | [ConfirmHost](#overlays) |
537
+ | `section with a border, a heading row and a padded body` | [SectionCard](#layout) |
509
538
  | `six <input maxlength="1">` | [OTPInput](#forms) |
510
539
  | `stack of <details>` | [Accordion](#layout) |
511
540
  | `title="…"` | [Tooltip](#overlays) |
512
541
  | `two <input type="date">` | [DateRangePicker](#forms) |
513
542
  | `two-column label/value divs` | [MetadataGrid](#data-display) |
543
+ | `useState + AlertDialog + pending flag boilerplate` | [ConfirmDialog](#overlays) |
514
544
  | `useState + AlertDialog boilerplate` | [ConfirmActionButton](#actions) |
515
545
  | `useState toggle` | [Collapsible](#layout) |
516
- | `window.confirm()` | [ConfirmActionButton](#actions), [AlertDialog](#overlays) |
546
+ | `window.confirm()` | [ConfirmActionButton](#actions), [ConfirmDialog](#overlays), [ConfirmHost](#overlays), [AlertDialog](#overlays) |
547
+ | `window.prompt()` | [ConfirmHost](#overlays) |
517
548
 
518
549
  ## Deprecated aliases and their replacements
519
550
 
520
- Every deprecated name keeps rendering exactly what it did (zero visual diff) until 3.0. The codemod column names the transform in [`codemods/README.md`](../codemods/README.md) that rewrites call sites (`node node_modules/@assure-one/design-system/codemods/run.mjs <id> src`); a dash means the change is a hand edit. Deprecated exports in the API report: `ArrowRightSmallIcon`, `CloseIcon`, `CountryFlag`, `CountrySelect`, `FormError`, `FormSection`, `FormSuccess`, `PhoneCountryInput`, `PhoneInput`, `SearchSelect`.
551
+ Every deprecated name keeps rendering exactly what it did (zero visual diff) until 3.0. The codemod column names the transform in [`codemods/README.md`](../codemods/README.md) that rewrites call sites (`node node_modules/@assure-one/design-system/codemods/run.mjs <id> src`); a dash means the change is a hand edit. Deprecated exports in the API report: `ArrowRightSmallIcon`, `Assignee`, `CloseIcon`, `CountryFlag`, `CountrySelect`, `Dash`, `FormError`, `FormSection`, `FormSuccess`, `MoneyCell`, `PhoneCountryInput`, `PhoneInput`, `SearchSelect`, `SideDrawer`, `StagePill`.
521
552
 
522
553
  | Deprecated | Use instead | Codemod | Contract |
523
554
  | --- | --- | --- | --- |
@@ -533,6 +564,8 @@ Every deprecated name keeps rendering exactly what it did (zero visual diff) unt
533
564
  | `Input` / `Textarea` / `SearchInput` `inputSize` | `size` | CM-07 | C-INPUT-SIZE |
534
565
  | `InputSizeAlias` `compact` / `default` / `comfortable` | `sm` / `md` / `lg` | — | C-INPUT-SIZE |
535
566
  | `Select` `triggerClassName` / `contentClassName` | `classNames={{ trigger, content }}` | — | C-SELECT-CLASSNAMES |
567
+ | `Dash` (DataTableView cell) | `EmptyValue` | — | — |
568
+ | `StagePill` / `Assignee` / `MoneyCell` / `TableTone` (DataTableView product cells) | Product-owned renderers in `column.render` (`StatusBadge`, `Avatar`, `Intl.NumberFormat`, `EmptyValue`); hand-over to TAX in W8-13 | — | — |
536
569
  | `Select searchable` | `Combobox` | — | — |
537
570
  | `Select` sentinel option values standing in for "no value" | A real empty value (`value=""`, `clearable`) | CM-20 (finder) | C-SELECT-EMPTY |
538
571
  | `SearchSelect` (`{ id, label }` options) | `Combobox` with `Option` (`{ value, label }`) | CM-08 | C-SEARCHSELECT |