@actioneer/ads 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +98 -57
- package/README.md +19 -7
- package/components/answer.js +1 -1
- package/components/assistant-ui/composer-harness.js +13 -10
- package/components/body-page-header.d.ts +9 -4
- package/components/body-page-header.js +10 -10
- package/components/breadcrumbs.js +22 -22
- package/components/card.js +18 -18
- package/components/chart.d.ts +9 -0
- package/components/chart.js +738 -717
- package/components/chip.js +12 -12
- package/components/collection-header.js +4 -4
- package/components/connector-card.js +30 -30
- package/components/date-range-picker.js +1 -1
- package/components/detail-list.d.ts +28 -0
- package/components/detail-list.js +52 -0
- package/components/drawer.d.ts +38 -15
- package/components/drawer.js +150 -86
- package/components/empty-state.d.ts +3 -2
- package/components/empty-state.js +22 -22
- package/components/field.d.ts +16 -0
- package/components/field.js +63 -42
- package/components/file-dropzone.d.ts +15 -4
- package/components/file-dropzone.js +100 -64
- package/components/filter-bar.d.ts +44 -0
- package/components/filter-bar.js +89 -0
- package/components/index.d.ts +3 -0
- package/components/index.js +526 -513
- package/components/input-field.d.ts +1 -1
- package/components/input-field.js +24 -22
- package/components/modal.js +56 -53
- package/components/panel.js +26 -27
- package/components/sidebar.js +54 -54
- package/components/sparkline.d.ts +30 -0
- package/components/sparkline.js +69 -0
- package/demo/components/add-to-artifact.js +5 -2
- package/examples/README.md +4 -2
- package/examples/call-logs-screen.tsx +381 -0
- package/examples/campaign-analysis-screen.tsx +114 -72
- package/examples/campaigns-screen.tsx +218 -160
- package/examples/guardrails-settings-screen.tsx +123 -0
- package/fonts/geist-variable.woff2 +0 -0
- package/fonts.css +12 -17
- package/lib/icons.js +3 -3
- package/llms.txt +107 -39
- package/manifest.json +3100 -892
- package/package.json +1 -1
- package/styles.css +102 -59
- package/theme.css +81 -37
- package/fonts/aribau-grotesk-medium.woff2 +0 -0
- package/fonts/aribau-grotesk-regular.woff2 +0 -0
package/DESIGN.md
CHANGED
|
@@ -60,41 +60,43 @@ colors:
|
|
|
60
60
|
overlay: "color-mix(in srgb, var(--color-wg12) 50%, transparent)"
|
|
61
61
|
typography:
|
|
62
62
|
display:
|
|
63
|
-
fontFamily: "\"
|
|
63
|
+
fontFamily: "\"Season Mix\", serif"
|
|
64
64
|
fontSize: "24px"
|
|
65
|
-
fontWeight:
|
|
66
|
-
lineHeight: "
|
|
65
|
+
fontWeight: 400
|
|
66
|
+
lineHeight: "30px"
|
|
67
67
|
title:
|
|
68
|
-
fontFamily: "\"
|
|
69
|
-
fontSize: "
|
|
70
|
-
fontWeight:
|
|
71
|
-
lineHeight: "
|
|
68
|
+
fontFamily: "\"Season Mix\", serif"
|
|
69
|
+
fontSize: "20px"
|
|
70
|
+
fontWeight: 400
|
|
71
|
+
lineHeight: "28px"
|
|
72
72
|
headline:
|
|
73
|
-
fontFamily: "\"
|
|
74
|
-
fontSize: "
|
|
75
|
-
fontWeight:
|
|
76
|
-
lineHeight: "
|
|
73
|
+
fontFamily: "\"Season Mix\", serif"
|
|
74
|
+
fontSize: "18px"
|
|
75
|
+
fontWeight: 400
|
|
76
|
+
lineHeight: "26px"
|
|
77
77
|
body:
|
|
78
|
-
fontFamily: "\"
|
|
79
|
-
fontSize: "
|
|
78
|
+
fontFamily: "\"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif"
|
|
79
|
+
fontSize: "16px"
|
|
80
80
|
fontWeight: 400
|
|
81
|
-
lineHeight: "
|
|
81
|
+
lineHeight: "24px"
|
|
82
82
|
label:
|
|
83
|
-
fontFamily: "\"
|
|
84
|
-
fontSize: "
|
|
83
|
+
fontFamily: "\"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif"
|
|
84
|
+
fontSize: "14px"
|
|
85
85
|
fontWeight: 400
|
|
86
|
-
lineHeight: "
|
|
86
|
+
lineHeight: "20px"
|
|
87
87
|
mono:
|
|
88
88
|
fontFamily: "\"JetBrains Mono Variable\", ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", \"Courier New\", monospace"
|
|
89
|
-
fontSize: "
|
|
89
|
+
fontSize: "14px"
|
|
90
90
|
fontWeight: 400
|
|
91
|
-
lineHeight: "
|
|
91
|
+
lineHeight: "20px"
|
|
92
92
|
rounded:
|
|
93
93
|
xs: "2px"
|
|
94
94
|
sm: "4px"
|
|
95
95
|
md: "6px"
|
|
96
96
|
lg: "8px"
|
|
97
97
|
xl: "8px"
|
|
98
|
+
card: "14px"
|
|
99
|
+
window: "18px"
|
|
98
100
|
full: "9999px"
|
|
99
101
|
spacing:
|
|
100
102
|
xs: "4px"
|
|
@@ -179,16 +181,16 @@ components:
|
|
|
179
181
|
|
|
180
182
|
TASTE.md puts it in one line: On a quiet, neutral ground, colour and motion are spent like money — rarely, deliberately, and only where the eye should go.
|
|
181
183
|
|
|
182
|
-
ADS 1.0.
|
|
184
|
+
ADS 1.0.10 is a library first and a look second. 335 components across 10 families (Primitives / utilities, Foundations, Form controls, Overlays, Data display, Feedback, Navigation, Layout, AI Elements, Chat) ship from one barrel, and every product that consumes them inherits the judgment encoded in 56 semantic tokens and 17 principles rather than re-deciding it per screen.
|
|
183
185
|
|
|
184
186
|
The ground is warm grey and the ink is warm near-black. One hue is spent by default, the Studio teal CTA family, and four more carry semantic status. Everything else stays neutral. A consumer product may narrow that further, and one already does: Baby Sentinel drops the teal and runs every action on ink.
|
|
185
187
|
|
|
186
188
|
**Key characteristics:**
|
|
187
189
|
- Warm-grey canvas, white sheet, quiet tiles. Every surface belongs to exactly one plane
|
|
188
|
-
- One typeface at two real weights on a 5-step ladder (24px / 18px / 16px / 14px
|
|
190
|
+
- One typeface at two real weights on a 5-step ladder (24px / 20px / 18px / 16px / 14px), with mono reserved for literal code
|
|
189
191
|
- Fills and elevation separate surfaces roughly 75/25 against strokes
|
|
190
192
|
- Every surface defaults to `shadow-0`; elevation means "you can act on this"
|
|
191
|
-
- Radius runs 2px / 4px / 6px / 8px / 8px, with a pill reserved for chips and avatars
|
|
193
|
+
- Radius runs 2px / 4px / 6px / 8px / 8px / 14px / 18px, with a pill reserved for chips and avatars
|
|
192
194
|
|
|
193
195
|
## Colors
|
|
194
196
|
|
|
@@ -322,30 +324,30 @@ The warm-grey ground everything else stands on.
|
|
|
322
324
|
|
|
323
325
|
### Named rules
|
|
324
326
|
|
|
325
|
-
**The Fills Over Strokes Rule.** Delineate SURFACES (cards, panels, sidebars, page regions) with color contrast, elevation, and spacing — not borders. Keep no more than two persistent neutral layers in one composition: panels establish hierarchy; embedded items express state. Aim for ~75% shadow/fill, 25% strokes: form controls and floating menus keep a subtle border so they read as interactive;
|
|
327
|
+
**The Fills Over Strokes Rule.** Delineate SURFACES (cards, panels, sidebars, page regions) with color contrast, elevation, and spacing — not decorative borders. Keep no more than two persistent neutral layers in one composition: panels establish hierarchy; embedded items express state. Aim for ~75% shadow/fill, 25% strokes: form controls and floating menus keep a subtle border so they read as interactive. Two kinds of 1px WG4 line follow opposite rules (the window panel style, user-mandated 2026-11-12): STRUCTURAL hairlines that split the page into its parts — under a header bar, under a DrawerHeader and above a DrawerFooter, between the page and an attached Drawer, between the sidebar and the page — run full width, wall to wall; ROW dividers between items inside one region stay inset to the content.
|
|
326
328
|
|
|
327
329
|
## Typography
|
|
328
330
|
|
|
329
|
-
**Display font:**
|
|
330
|
-
**Body font:**
|
|
331
|
+
**Display font:** Season Mix
|
|
332
|
+
**Body font:** Geist
|
|
331
333
|
**Mono font:** JetBrains Mono Variable
|
|
332
334
|
|
|
333
|
-
**Character:**
|
|
335
|
+
**Character:** Season Mix sets heading roles (page, drawer, modal, section and chart titles); Geist carries body, labels, controls, rows and data values. Two real weights; hierarchy comes from size, ink strength and spacing, never a heavy weight.
|
|
334
336
|
|
|
335
337
|
### Hierarchy
|
|
336
338
|
|
|
337
|
-
- **Display** (
|
|
338
|
-
- **Title** (
|
|
339
|
-
- **Headline** (
|
|
340
|
-
- **Body** (400,
|
|
341
|
-
- **Label** (400,
|
|
342
|
-
- **Mono** (400,
|
|
339
|
+
- **Display** (400, 24px / 30px): page-level moments only.
|
|
340
|
+
- **Title** (400, 20px / 28px): page titles.
|
|
341
|
+
- **Headline** (400, 18px / 26px): emphasized body and section headings.
|
|
342
|
+
- **Body** (400, 16px / 24px): the default, all reading text and control labels.
|
|
343
|
+
- **Label** (400, 14px / 20px): the floor: captions, secondary text, table cells.
|
|
344
|
+
- **Mono** (400, 14px / 20px): literal source code, and nothing else.
|
|
343
345
|
|
|
344
346
|
### Named rules
|
|
345
347
|
|
|
346
|
-
**The
|
|
348
|
+
**The Two Face Rule.** Two faces with fixed jobs (Season Mix for headings, Geist for everything else), two real weights, one scale.
|
|
347
349
|
|
|
348
|
-
**The
|
|
350
|
+
**The 14px Floor Rule.** Nothing renders below `--text-s` (14px). Density comes from spacing and layout, never from shrinking type.
|
|
349
351
|
|
|
350
352
|
## Layout
|
|
351
353
|
|
|
@@ -353,7 +355,7 @@ The shell owns the frame and screens own their content. ADS targets landscape ta
|
|
|
353
355
|
|
|
354
356
|
### Named rules
|
|
355
357
|
|
|
356
|
-
**The Shell Owns the Frame Rule.** The
|
|
358
|
+
**The Shell Owns the Frame Rule.** The shell renders one app window (user-mandated 2026-11-12): a rounded-window (18px) surface with a 1px WG4 edge and shadow-window, inset 12px on the bg-surface (WG3) backdrop. The sidebar (bg-background) and the White PageBody sit inside it, split by one full-height WG4 hairline. Page headers are BodyPageHeader bars — 64px, 20px (text-xl) Medium title, actions trailing, full-width hairline below. A record's detail panel is an inline Drawer attached to the page: flush beside the content, one full-height hairline, no gap, radius or shadow. Screens never add their own outer padding, radius, card or shadow — a screen's root is flex h-full flex-col and fills the page.
|
|
357
359
|
|
|
358
360
|
**The One Thing Per Screen Rule.** A screen carries ONLY what the user needs to move forward: one title, the inputs, one primary action. Page, section, panel, modal, dialog, drawer, and popover headers are title-only by default; add a description only when the user explicitly asks for one. Never maximalist.
|
|
359
361
|
|
|
@@ -361,23 +363,26 @@ The shell owns the frame and screens own their content. ADS targets landscape ta
|
|
|
361
363
|
|
|
362
364
|
## Elevation & Depth
|
|
363
365
|
|
|
364
|
-
Flat by default with tonal layering. Depth comes from the plane system
|
|
366
|
+
Flat by default with tonal layering. Depth comes from the plane system: a grey backdrop, one app window resting on it, white page inside. Eight shadows only: `--shadow-0` (flat — panels, rows, controls, the attached Drawer), `--shadow-float` (toasts, toolbars, composer dock), `--shadow-overlay` (modals, dialogs, overlay drawers), the two table scroll-hint smudges, `--shadow-card` (resting cards), `--shadow-window` (the app window) and `--shadow-nav-active` (the active sidebar item).
|
|
365
367
|
|
|
366
368
|
### Shadow vocabulary
|
|
367
369
|
|
|
368
370
|
- **0** (`--shadow-0`): `none`
|
|
371
|
+
- **card** (`--shadow-card`): `0 1px 2px rgb(32 32 32 / 0.04), 0 8px 24px -12px rgb(32 32 32 / 0.10)`
|
|
369
372
|
- **float** (`--shadow-float`): `0 0 0 1px rgb(32 32 32 / 0.04), 0 2px 4px rgb(32 32 32 / 0.04), 0 8px 20px -4px rgb(32 32 32 / 0.10)`
|
|
373
|
+
- **nav-active** (`--shadow-nav-active`): `0 1px 2px rgb(32 32 32 / 0.08), 0 4px 12px -4px rgb(32 32 32 / 0.14)`
|
|
370
374
|
- **overlay** (`--shadow-overlay`): `0 0 0 1px rgb(32 32 32 / 0.04), 0 4px 8px rgb(32 32 32 / 0.04), 0 16px 36px -8px rgb(32 32 32 / 0.14)`
|
|
371
375
|
- **table-smudge-left** (`--shadow-table-smudge-left`): `8px 0 24px -14px rgb(32 32 32 / 0.05)`
|
|
372
376
|
- **table-smudge-right** (`--shadow-table-smudge-right`): `-8px 0 24px -14px rgb(32 32 32 / 0.05)`
|
|
377
|
+
- **window** (`--shadow-window`): `0 1px 2px rgb(32 32 32 / 0.05), 0 24px 48px -24px rgb(32 32 32 / 0.18)`
|
|
373
378
|
|
|
374
379
|
### Named rules
|
|
375
380
|
|
|
376
|
-
**The Elevation Is Actionability Rule.** ADS has
|
|
381
|
+
**The Elevation Is Actionability Rule.** ADS has eight shadow tokens: shadow-0 (flat, the default), shadow-float, shadow-overlay, the two table scroll-hint smudges, the two resting-surface lifts shadow-card and shadow-window, and shadow-nav-active for the active sidebar item (user-mandated 2026-11-12). Only a layer that floats above the page may carry float or overlay; resting cards (Card, stat/chart cards, ConnectorCard) carry shadow-card with rounded-card (14px) and a 1px WG4 edge; the app window carries shadow-window with rounded-window (18px); everything else in the page is flat.
|
|
377
382
|
|
|
378
383
|
## Shapes
|
|
379
384
|
|
|
380
|
-
Soft geometry on a
|
|
385
|
+
Soft geometry on a 7-step ladder: `xs` 2px, `sm` 4px, `md` 6px, `lg` 8px, `xl` 8px, `card` 14px, `window` 18px, plus a pill at `full` (9999px) for chips and avatars. `card` and `window` are surface radii for resting cards and the app window only. Tailwind's larger aliases (`2xl`, `3xl`) collapse onto the `lg` control step, so a stray `rounded-3xl` cannot exceed it.
|
|
381
386
|
|
|
382
387
|
### Named rules
|
|
383
388
|
|
|
@@ -385,7 +390,7 @@ Soft geometry on a 5-step ladder: `xs` 2px, `sm` 4px, `md` 6px, `lg` 8px, `xl` 8
|
|
|
385
390
|
|
|
386
391
|
## Components
|
|
387
392
|
|
|
388
|
-
The catalog is the contract:
|
|
393
|
+
The catalog is the contract: 335 components, 10 hooks and 98 utilities behind one barrel (`@actioneer/ads`). Import exact, unaliased names. Native elements are for semantic structure only: `<div>`, `<form>`, `<main>`, `<section>`. Never recreate a visual control.
|
|
389
394
|
|
|
390
395
|
### Sourcing a component
|
|
391
396
|
|
|
@@ -513,9 +518,9 @@ Hand-rolling a visual control, or importing a UI library at a call site, is neve
|
|
|
513
518
|
|
|
514
519
|
**The ADS First Rule.** Every UI decision stays synchronized with ADS. Search the full catalog before deciding a component is missing, and use the exact exported name from the public barrel. When the barrel genuinely has no primitive, the sanctioned fallback is a shadcn/ui component vendored into src/components/ui through the repo's components.json recipe — never a hand-rolled control and never a UI library imported at a call site. Enforced by `npm run lint:ads`.
|
|
515
520
|
|
|
516
|
-
**The Back Leads Rule.** A record or drill-down page (a campaign inside Voice campaigns, a connector inside Data Integrations) is titled by its Breadcrumbs trail — parent / record at
|
|
521
|
+
**The Back Leads Rule.** A record or drill-down page (a campaign inside Voice campaigns, a connector inside Data Integrations) is titled by its Breadcrumbs trail — parent / record at 18px, the header-bar title size, in the 64px header bar — with no back arrow and no repeated H1; the page's one primary action sits at the right end of the same row. A standalone page-level Back control, when one is needed outside a hierarchy, sits immediately before the title and never on the right.
|
|
517
522
|
|
|
518
|
-
**The Tabs Lead, Search Trails Rule.** When tabs and a search field control the same content, they share one responsive control row: the tab list leads with its triggers left-aligned at their natural width over a baseline that fades from WG3 to transparent, and search sits at the trailing edge. On collection screens the trailing controls are icon triggers — SearchDisclosure (expands into the field) then Filters — and tab labels are
|
|
523
|
+
**The Tabs Lead, Search Trails Rule.** When tabs and a search field control the same content, they share one responsive control row: the tab list leads with its triggers left-aligned at their natural width over a baseline that fades from WG3 to transparent, and search sits at the trailing edge. On collection screens the trailing controls are icon triggers — SearchDisclosure (expands into the field) then Filters — and tab labels are 16px with a quieter count after each label.
|
|
519
524
|
|
|
520
525
|
## Do's and Don'ts
|
|
521
526
|
|
|
@@ -526,8 +531,12 @@ Every line below is a `do` or `dont` recorded on a principle in `ads-manifest.js
|
|
|
526
531
|
- **Do** establish hierarchy with at most two persistent layers: bg-background for the screen ground and bg-card/bg-elevated for the primary surface. *(fills-over-strokes)*
|
|
527
532
|
- **Do** inside a white Panel or Card, keep rows and items transparent at rest; group them with spacing or inset dividers, use bg-muted for hover/selection, and reserve bg-surface for one continuous semantic recess such as an editor or table tray. *(fills-over-strokes)*
|
|
528
533
|
- **Do** use border-border for outline buttons and lightweight action rows; reserve border-input for form controls (input, select, textarea, checkbox, radio, segmented-control track) and floating menus (dropdown, popover, listboxes). *(fills-over-strokes)*
|
|
529
|
-
- **Do** keep strokes on focus rings, the outline Button/Badge/Chip variants, Kbd, Divider, the Tree connector rail,
|
|
530
|
-
- **Do**
|
|
534
|
+
- **Do** keep strokes on focus rings, the outline Button/Badge/Chip variants, Kbd, Divider, the Tree connector rail, functional color swatches, the WG4 edge of resting cards and the app window, and the structural hairlines. *(fills-over-strokes)*
|
|
535
|
+
- **Do** run structural hairlines edge to edge: the 64px header bar's bottom line, the DrawerHeader/DrawerFooter lines, the full-height line on an attached Drawer's leading edge, the sidebar's edge inside the app window. *(fills-over-strokes)*
|
|
536
|
+
- **Do** inset row dividers: put the padding on the container and border-b on each row, so the line stops at the content edge. *(fills-over-strokes)*
|
|
537
|
+
- **Do** keep panels, rows, chips, buttons, tabs, fields, thumbs, the attached Drawer and other in-page surfaces at shadow-0; separate them with fill, hairlines, or spacing. *(elevation-is-actionability)*
|
|
538
|
+
- **Do** give resting cards rounded-card + border border-border + shadow-card, and the app window rounded-window + border border-border + shadow-window. *(elevation-is-actionability)*
|
|
539
|
+
- **Do** lift the active sidebar item (its White fill) with shadow-nav-active; keep hover flat. *(elevation-is-actionability)*
|
|
531
540
|
- **Do** use shadow-float for floating layers that sit over content: toasts, toolbars, the chat composer dock, and any menu or popover that needs lift beyond its border. *(elevation-is-actionability)*
|
|
532
541
|
- **Do** use shadow-overlay for modals, dialogs, and overlay drawers, so a dialog always reads above a menu. *(elevation-is-actionability)*
|
|
533
542
|
- **Do** treat motion as part of every ADS component import: preserve the component's built-in motion, and import any composition-level preset from the ADS root barrel. *(motion-follows-guide)*
|
|
@@ -538,8 +547,9 @@ Every line below is a `do` or `dont` recorded on a principle in `ads-manifest.js
|
|
|
538
547
|
- **Do** import icons from the @/lib/icons registry; wrap a new Phosphor component with createIcon there before using it. *(icons-phosphor-regular)*
|
|
539
548
|
- **Do** let icons default to size='1em' so they scale with text; size with a size prop or size-* class. *(icons-phosphor-regular)*
|
|
540
549
|
- **Do** render weight='fill' for the active or selected state, and weight='bold' for the rare heavier stroke. *(icons-phosphor-regular)*
|
|
541
|
-
- **Do** make a screen root flex h-full flex-col and fill the
|
|
542
|
-
- **Do** let one place (the shell) own the
|
|
550
|
+
- **Do** make a screen root flex h-full flex-col and fill the page with Panel(s); the shell renders them flush. *(shell-owns-the-frame)*
|
|
551
|
+
- **Do** let one place (the shell) own the window, its radius, edge and shadow. *(shell-owns-the-frame)*
|
|
552
|
+
- **Do** open record details in an attached Drawer beside the list, inside the same white page. *(shell-owns-the-frame)*
|
|
543
553
|
- **Do** use rounded-dot for every indicator/status dot. *(square-status-dots)*
|
|
544
554
|
- **Do** use an existing ADS component by its exact exported name from the package barrel; compose existing components for layout-only patterns. *(ads-first)*
|
|
545
555
|
- **Do** search the whole catalog before concluding a component is missing — the documented specimens are a sample, not the inventory. *(ads-first)*
|
|
@@ -550,11 +560,11 @@ Every line below is a `do` or `dont` recorded on a principle in `ads-manifest.js
|
|
|
550
560
|
- **Do** prefer more, smaller steps over dense ones; ask one thing at a time. *(minimal-information)*
|
|
551
561
|
- **Do** derive instead of asking whenever possible (a name from a work email, the company from its domain). *(minimal-information)*
|
|
552
562
|
- **Do** prefer clear text-only buttons; add an icon only when it communicates essential meaning the label cannot carry alone, or for a compact conventional icon-only control. *(minimal-information)*
|
|
553
|
-
- **Do** open a multi-step create task launched from a collection (New campaign) as a Modal over that list: title-only header, one scrolling form (for New campaign: Campaign name, Caller numbers, Audience), and Cancel + Create together in the footer — the user never loses their place. Add a Stepper only when the task truly has separate steps.
|
|
563
|
+
- **Do** open a multi-step create task launched from a collection (New campaign) as a Modal over that list: title-only header, one scrolling form (for New campaign: Campaign name, Caller numbers, Audience), and Cancel + Create together in the footer — the user never loses their place. Add a Stepper only when the task truly has separate steps. Every modal is fixed-height (sm 320px, md/lg/xl 640px — the Modal default) so the frame never resizes: the header and footer stay put and ModalBody scrolls; see principle create-modals. Standalone onboarding flows render full-screen with a single content container holding the inputs and its own Back/Continue. *(minimal-information)*
|
|
554
564
|
- **Do** use @container on the pane and @lg:/@xl: variants on children inside components. *(responsive-container-fluid)*
|
|
555
565
|
- **Do** set pane widths in shells/pages through width tokens (thread-max-width, sidebar-width, aside-width, connector-card-min/-max). *(responsive-container-fluid)*
|
|
556
566
|
- **Do** cap prose at its measure; let tables/charts/tool cards break out wider. Use auto-fill + minmax(min, 1fr) for grids. *(responsive-container-fluid)*
|
|
557
|
-
- **Do** title a drill-down with Breadcrumbs (
|
|
567
|
+
- **Do** title a drill-down with Breadcrumbs (20px trail, the same size as the header-bar title: muted parent links, Medium current item) and put its primary action (e.g. Pause campaign) right-aligned on the same row. *(leading-back-navigation)*
|
|
558
568
|
- **Do** use PageHeader with onBack only for a standalone page that has no parent hierarchy to show. *(leading-back-navigation)*
|
|
559
569
|
- **Do** reserve the trailing header area for forward or page-level actions such as Add, Save, Pause, or Share. *(leading-back-navigation)*
|
|
560
570
|
- **Do** keep tab triggers left-aligned at their natural width, then place the scoped search opposite them in the same toolbar. *(tabs-search-opposed)*
|
|
@@ -565,34 +575,56 @@ Every line below is a `do` or `dont` recorded on a principle in `ads-manifest.js
|
|
|
565
575
|
- **Do** show row checkboxes only on hover/focus (and while checked or mixed); keep the header select-all checkbox always visible. *(collection-screens)*
|
|
566
576
|
- **Do** when a row's details are open, mark it with TableRow isActive (the soft-teal fade) — no radio and no selection column for that purpose. *(collection-screens)*
|
|
567
577
|
- **Do** put status in a Chip using business language (see status-language) and keep cell values at text-m. *(collection-screens)*
|
|
578
|
+
- **Do** give a rate column a small Progress meter (size sm, ~48px) before the right-aligned percentage, and give a record with a recent trend a "Last 7 days" column holding a dotless Sparkline (height 28, dot={false}); a record with no calls yet shows an em dash and "No calls yet" in secondary text. *(collection-screens)*
|
|
579
|
+
- **Do** show the owner as plain text — no avatar in the cell. *(collection-screens)*
|
|
568
580
|
- **Do** show the customer's workspace logo in the Sidebar brand slot (SidebarWorkspace) when the product runs inside a customer workspace. *(collection-screens)*
|
|
569
|
-
- **Do**
|
|
570
|
-
- **Do**
|
|
571
|
-
- **Do**
|
|
572
|
-
- **Do**
|
|
573
|
-
- **Do**
|
|
574
|
-
- **Do**
|
|
581
|
+
- **Do** compose DrawerHeader → DrawerKicker + DrawerTitle + DrawerMeta so status never floats on its own; the header's full-width hairline grounds it. *(record-detail-panels)*
|
|
582
|
+
- **Do** let DrawerBody scroll (it is overflow-y-auto) — never clip the panel with overflow hidden. *(record-detail-panels)*
|
|
583
|
+
- **Do** group numbers in small flat stat tiles (WG1 fill + 1px WG4 edge, rounded-card, 12px padding, no shadow, 8px apart) and a trend in its own chart tile. *(record-detail-panels)*
|
|
584
|
+
- **Do** list attributes as a DetailList: sentence-case labels ("Type of loan", never type_of_loan), values right-aligned and wrapping, Not stated in secondary grey when empty (tertiary fails AA at 16px). *(record-detail-panels)*
|
|
585
|
+
- **Do** count what a section holds in its title ("0 of 10") instead of a separate summary line. *(record-detail-panels)*
|
|
586
|
+
- **Do** put rarely-needed data (call metadata) in a Collapsible at the end of the body, collapsed. *(record-detail-panels)*
|
|
587
|
+
- **Do** add a DrawerFooter only when its action exists — Open full view only when the dedicated page exists. *(record-detail-panels)*
|
|
588
|
+
- **Do** spell out the scope under the tabs with a FilterBar: joined 32px segments showing their current values — period preset + resolved dates leading, a second filter (cohort) trailing. *(analytics-surfaces)*
|
|
589
|
+
- **Do** stat card: label (16px secondary) → number (text-4xl, 35px, tightened tracking) with its scope ("of 4,800 calls", 14px secondary) 4px apart, a Sparkline of its recent trend beside the number (right ~third of the card), then a Progress bar 12px below that fills the card width. *(analytics-surfaces)*
|
|
590
|
+
- **Do** chart card: title (18px Medium) + scope subtitle (14px secondary) on the left, the legend right-aligned on the same row, ~40px from the title block to the plot. *(analytics-surfaces)*
|
|
575
591
|
- **Do** bar charts print each bar's value; stacked bars print each segment that fits plus the stack total. Line charts print every point's value in the series colour (secondary grey for light amber/grey series). *(analytics-surfaces)*
|
|
592
|
+
- **Do** keep LineChart's default gradientFill: a wash under each observed line fading top-to-bottom from 20% of the series colour to nothing (forecasts stay unfilled). *(analytics-surfaces)*
|
|
576
593
|
- **Do** size charts so the cards end on the panel's 24px bottom inset. *(analytics-surfaces)*
|
|
577
594
|
- **Do** say Active, not Dialing; name the tab Active too (All · Draft · Active · Paused · Completed). *(status-language)*
|
|
578
595
|
- **Do** use Chip tones consistently for the same status everywhere (table cell, detail header, filters). *(status-language)*
|
|
579
|
-
- **Do** use the plain Chip appearance (square dot +
|
|
596
|
+
- **Do** use the plain Chip appearance (square dot + 16px text) where a column of filled chips would shout louder than the record names. *(status-language)*
|
|
597
|
+
- **Do** keep Chip labels Regular weight — 14px (text-s) in solid and outline chips, 16px (text-m) in plain ones. *(status-language)*
|
|
598
|
+
- **Do** use the Modal default height; pick size by width only (sm confirmation, md form, lg/xl dense content). *(create-modals)*
|
|
599
|
+
- **Do** put 'optional / you can change this later' notes in Field info, not in a helper line under the control. *(create-modals)*
|
|
600
|
+
- **Do** put a source switch (SegmentedControl size=sm, e.g. CSV upload | Empty audience) in Field actions on the label row. *(create-modals)*
|
|
601
|
+
- **Do** use FileDropzone layout='inline' (bare icon · label + hint · Browse) when the upload shares the form with other fields. *(create-modals)*
|
|
602
|
+
- **Do** let the user pick one saved record from a Table with selectionMode='single' (radio + soft-teal fade) under a search field, with the unit named once in the column header. *(create-modals)*
|
|
603
|
+
- **Do** render icons bare in muted grey: in upload strips, empty states, labels and list rows. *(create-modals)*
|
|
604
|
+
- **Do** give each group w-full; let SettingRow stretch to the panel width. *(settings-screens)*
|
|
605
|
+
- **Do** use the control that matches the setting: Switch for on/off, an outline Button showing the current value for pickers ("10:00 – 19:00"), a Badge for a fixed threshold. *(settings-screens)*
|
|
606
|
+
- **Do** keep the leading glyph bare and muted; rows separate with inset hairlines. *(settings-screens)*
|
|
580
607
|
|
|
581
608
|
### Don't:
|
|
582
609
|
|
|
583
610
|
- **Don't** add a border to a surface to separate or group it — use fill/elevation/spacing instead. *(fills-over-strokes)*
|
|
584
611
|
- **Don't** alternate persistent neutral fills inside one panel (for example white Panel → grey item → white child); flatten the item or promote the recess to the container. *(fills-over-strokes)*
|
|
585
612
|
- **Don't** give a filled control no stroke on the tinted canvas — it disappears; it needs a crisp edge. *(fills-over-strokes)*
|
|
613
|
+
- **Don't** stop a structural hairline short of the walls, or run a row divider full-bleed (divide-y on a container whose rows carry their own px-*). *(fills-over-strokes)*
|
|
586
614
|
- **Don't** put a shadow on an in-page surface for decoration or to signal that it is clickable. *(elevation-is-actionability)*
|
|
587
615
|
- **Don't** use raw shadow values, inset glows, or the removed numbered levels and elevation hook. *(elevation-is-actionability)*
|
|
588
616
|
- **Don't** invent a third floating level; stack order comes from float vs overlay. *(elevation-is-actionability)*
|
|
617
|
+
- **Don't** put shadow-card on a panel, a row, a detail-panel stat tile or the attached Drawer; put shadow-window on anything but the app window. *(elevation-is-actionability)*
|
|
589
618
|
- **Don't** invent raw spring values inside a component, recreate a global duration/easing token scale, use an unbounded all-property transition, or start an entrance at scale zero. *(motion-follows-guide)*
|
|
590
619
|
- **Don't** override or duplicate the motion already shipped inside an imported ADS component. *(motion-follows-guide)*
|
|
591
620
|
- **Don't** animate keyboard-initiated or 100×/day actions (e.g. a command-palette toggle). *(motion-follows-guide)*
|
|
592
621
|
- **Don't** add motion to a component only because it is visible; static structure and decorative chrome stay still. *(motion-follows-guide)*
|
|
593
622
|
- **Don't** import from an icon package directly, or install a second icon set. *(icons-phosphor-regular)*
|
|
594
623
|
- **Don't** leave an active nav item's icon at the regular stroke weight. *(icons-phosphor-regular)*
|
|
595
|
-
- **Don't**
|
|
624
|
+
- **Don't** set a glyph on a background tile, circle, or outlined square — icons sit bare in muted grey (avatars and brand logos keep their frames). *(icons-phosphor-regular)*
|
|
625
|
+
- **Don't** add outer padding, a radius or a shadow on a screen, or wrap a screen in its own card. *(shell-owns-the-frame)*
|
|
626
|
+
- **Don't** float a detail panel as a separate card with a strip of canvas between it and the list. *(shell-owns-the-frame)*
|
|
627
|
+
- **Don't** put the sidebar outside the window, directly on the backdrop. *(shell-owns-the-frame)*
|
|
596
628
|
- **Don't** use rounded-full on an indicator dot (the one exception is a Radio control's inner dot). *(square-status-dots)*
|
|
597
629
|
- **Don't** deep-import, alias, default/namespace-import, or hand-roll a local copy of a component. *(ads-first)*
|
|
598
630
|
- **Don't** import a visual component directly from the web or an npm UI library at a call site. *(ads-first)*
|
|
@@ -613,13 +645,22 @@ Every line below is a `do` or `dont` recorded on a principle in `ads-manifest.js
|
|
|
613
645
|
- **Don't** leave an empty band under a short table, or float Pagination mid-panel. *(collection-screens)*
|
|
614
646
|
- **Don't** use single-selection radios to mean 'this row is open'. *(collection-screens)*
|
|
615
647
|
- **Don't** show a checkbox on every resting row of a multi-select table. *(collection-screens)*
|
|
648
|
+
- **Don't** put a profile image beside every owner name, or draw an empty meter or a flat sparkline for a record with no data. *(collection-screens)*
|
|
616
649
|
- **Don't** open record details in a modal over the list you are scanning. *(collection-screens)*
|
|
617
650
|
- **Don't** mix attributes (owner) into the metric grid. *(record-detail-panels)*
|
|
618
|
-
- **Don't**
|
|
619
|
-
- **Don't**
|
|
651
|
+
- **Don't** repeat a fact: what the header says (status, time, length) never appears again in stat cards or write-back rows. *(record-detail-panels)*
|
|
652
|
+
- **Don't** add placeholder footer buttons (Open full view, Call again) for a record that has no page or action behind them. *(record-detail-panels)*
|
|
653
|
+
- **Don't** show raw field keys, monospace labels, or a dash pattern like "— not stated" for empty values. *(record-detail-panels)*
|
|
620
654
|
- **Don't** separate stats with vertical hairlines while their bars run into the next stat — proximity breaks. *(analytics-surfaces)*
|
|
621
655
|
- **Don't** hide numbers behind a hover tooltip. *(analytics-surfaces)*
|
|
622
656
|
- **Don't** give a legend its own row under the subtitle when it fits beside the title. *(analytics-surfaces)*
|
|
623
657
|
- **Don't** put the same spacing between a label and its value as between two separate cards. *(analytics-surfaces)*
|
|
658
|
+
- **Don't** set a Chip label in Medium; the tone, dot and edge already carry the emphasis. *(status-language)*
|
|
624
659
|
- **Don't** colour a status with the primary teal — it competes with the primary action and the selected-row fade. *(status-language)*
|
|
625
660
|
- **Don't** use different words for the same state in the tab, the chip and the filter. *(status-language)*
|
|
661
|
+
- **Don't** pass height='content' or let a modal resize as sections appear or disappear. *(create-modals)*
|
|
662
|
+
- **Don't** stack a tall drop target, a search, and an unlabeled list one after another inside a fixed-height form. *(create-modals)*
|
|
663
|
+
- **Don't** hand-roll a pick-one list with justify-between rows or an 'or' divider between alternatives. *(create-modals)*
|
|
664
|
+
- **Don't** put an icon on a grey tile, a circle, or an outlined square that adds nothing but a background. *(create-modals)*
|
|
665
|
+
- **Don't** cap a settings group at a fixed width (720px) and leave the right half of the panel empty. *(settings-screens)*
|
|
666
|
+
- **Don't** put a save button per group, or icons on tiles. *(settings-screens)*
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @actioneer/ads
|
|
2
2
|
|
|
3
3
|
The **Actioneer Design System**: React 19 components, Tailwind CSS v4 tokens,
|
|
4
|
-
bundled
|
|
4
|
+
bundled Geist body font, Season Mix heading tokens, and accessible interactions with built-in motion.
|
|
5
5
|
|
|
6
6
|
[Browse components in Storybook](https://actioneer-ads-storybook.himanshu-563.workers.dev).
|
|
7
7
|
|
|
@@ -48,8 +48,10 @@ Tailwind:
|
|
|
48
48
|
`tailwindcss`:
|
|
49
49
|
|
|
50
50
|
- the `@theme` **design tokens** (colors, typography, spacing, and radii),
|
|
51
|
-
- the **
|
|
52
|
-
|
|
51
|
+
- the **Geist** `@font-face` rule (served package-relative — no `/public` copy
|
|
52
|
+
needed). Headings use `--font-heading: "Season Mix"`; Season Mix is licensed
|
|
53
|
+
and not bundled, so declare its `@font-face` in your app from your licensed
|
|
54
|
+
file (without it, headings fall back to the platform serif), and
|
|
53
55
|
- a baked `@source "./**/*.{js,mjs}"` so Tailwind scans ADS's own class usage and
|
|
54
56
|
generates its utilities in your build.
|
|
55
57
|
|
|
@@ -166,13 +168,23 @@ composed, or copy one into your app and swap in your own data; the folder's
|
|
|
166
168
|
**Screen recipes:** when you build a screen CLOSE to a collection (a list of
|
|
167
169
|
records with a detail panel and a create modal) or a record's analytics page,
|
|
168
170
|
start from `CampaignsScreen` / `CampaignAnalysisScreen` and follow the
|
|
169
|
-
`collection-screens`, `record-detail-panels`, `analytics-surfaces
|
|
170
|
-
`status-language
|
|
171
|
-
|
|
171
|
+
`collection-screens`, `record-detail-panels`, `analytics-surfaces`,
|
|
172
|
+
`status-language`, `create-modals` and `settings-screens` principles
|
|
173
|
+
(`get_principles`) and the `collection-screen` / `record-analytics` /
|
|
174
|
+
`create-modal` / `record-call-logs` / `settings-screen` productions
|
|
175
|
+
(`get_ui_grammar`). A record's call logs start from `CallLogsScreen`; a
|
|
176
|
+
settings page from `GuardrailsSettingsScreen`. In short: rows fill the panel
|
|
172
177
|
with pagination at the bottom, row checkboxes on hover, `TableRow isActive` for
|
|
173
178
|
the open row, status under the detail title, outlined stat and chart cards with
|
|
174
179
|
legends in the title row and printed values, a 16px breadcrumb titling
|
|
175
|
-
drill-downs, business-language statuses, and fixed-height
|
|
180
|
+
drill-downs, business-language statuses, and fixed-height modals (sm 320px,
|
|
181
|
+
md–xl 640px). Inside a create modal (`NewCampaignModal`): optional guidance in
|
|
182
|
+
a `Field info` icon, a source switch in `Field actions`, an inline
|
|
183
|
+
`FileDropzone`, a single-select `Table` to reuse a saved record, and bare
|
|
184
|
+
icons with no tile behind them. Record panels: a grounded `DrawerHeader`
|
|
185
|
+
(`DrawerKicker`, `DrawerTitle`, `DrawerMeta`), a scrolling `DrawerBody` of
|
|
186
|
+
`DrawerSection`s, `DetailList` attributes with Not stated empties, each fact
|
|
187
|
+
once, and no footer unless its action exists. Settings groups fill the panel.
|
|
176
188
|
|
|
177
189
|
Shared motion presets are named exports from `@actioneer/ads`. Components already
|
|
178
190
|
include their own interaction motion; use the exported presets for additional
|
package/components/answer.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
var c = Object.defineProperty;
|
|
3
3
|
var l = (r, t, o) => t in r ? c(r, t, { enumerable: !0, configurable: !0, writable: !0, value: o }) : r[t] = o;
|
|
4
|
-
var
|
|
5
|
-
import { jsxs as
|
|
4
|
+
var n = (r, t, o) => l(r, typeof t != "symbol" ? t + "" : t, o);
|
|
5
|
+
import { jsxs as p, jsx as e } from "react/jsx-runtime";
|
|
6
6
|
import { useComposerRuntime as d, useComposer as u } from "@assistant-ui/react";
|
|
7
7
|
import "../../lib/cn.js";
|
|
8
8
|
import "../../lib/interactive.js";
|
|
@@ -40,6 +40,7 @@ import "../autocomplete.js";
|
|
|
40
40
|
import "../slider.js";
|
|
41
41
|
import "../segmented.js";
|
|
42
42
|
import "../filters.js";
|
|
43
|
+
import "../filter-bar.js";
|
|
43
44
|
import "../modal.js";
|
|
44
45
|
import "../drawer.js";
|
|
45
46
|
import "../popover.js";
|
|
@@ -60,6 +61,8 @@ import "../avatar.js";
|
|
|
60
61
|
import "../badge.js";
|
|
61
62
|
import "../chip.js";
|
|
62
63
|
import "../timeline.js";
|
|
64
|
+
import "../detail-list.js";
|
|
65
|
+
import "../sparkline.js";
|
|
63
66
|
import "../alert.js";
|
|
64
67
|
import "../surface-loader.js";
|
|
65
68
|
import "../pixel-blast-svg.js";
|
|
@@ -128,7 +131,7 @@ const m = "application/x-actioneer-harness", S = [
|
|
|
128
131
|
instructions: "Write a concise executive brief: lead with the decision or insight, use only decision-relevant evidence, and end with the recommended next action."
|
|
129
132
|
}
|
|
130
133
|
];
|
|
131
|
-
function
|
|
134
|
+
function Di() {
|
|
132
135
|
const r = d(), t = u((i) => i.attachments), o = new Set(
|
|
133
136
|
t.filter((i) => i.contentType === m).map((i) => i.name)
|
|
134
137
|
), s = (i) => {
|
|
@@ -136,8 +139,8 @@ function Si() {
|
|
|
136
139
|
new File([i.instructions], `${i.label}.harness`, { type: m })
|
|
137
140
|
);
|
|
138
141
|
};
|
|
139
|
-
return /* @__PURE__ */
|
|
140
|
-
/* @__PURE__ */ e(v, { children: /* @__PURE__ */
|
|
142
|
+
return /* @__PURE__ */ p(b, { children: [
|
|
143
|
+
/* @__PURE__ */ e(v, { children: /* @__PURE__ */ p(
|
|
141
144
|
"button",
|
|
142
145
|
{
|
|
143
146
|
type: "button",
|
|
@@ -156,7 +159,7 @@ function Si() {
|
|
|
156
159
|
]
|
|
157
160
|
}
|
|
158
161
|
) }),
|
|
159
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ p(y, { side: "top", align: "start", className: "w-56", autoFocusFirstItem: !1, children: [
|
|
160
163
|
/* @__PURE__ */ e(x, { children: "Add a harness" }),
|
|
161
164
|
S.map((i) => /* @__PURE__ */ e(
|
|
162
165
|
w,
|
|
@@ -171,9 +174,9 @@ function Si() {
|
|
|
171
174
|
] })
|
|
172
175
|
] });
|
|
173
176
|
}
|
|
174
|
-
class
|
|
177
|
+
class Ei {
|
|
175
178
|
constructor() {
|
|
176
|
-
|
|
179
|
+
n(this, "accept", m);
|
|
177
180
|
}
|
|
178
181
|
async add(t) {
|
|
179
182
|
return {
|
|
@@ -204,7 +207,7 @@ ${o}
|
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
209
|
export {
|
|
207
|
-
|
|
210
|
+
Di as ComposerHarness,
|
|
208
211
|
m as HARNESS_MIME,
|
|
209
|
-
|
|
212
|
+
Ei as HarnessAttachmentAdapter
|
|
210
213
|
};
|
|
@@ -6,10 +6,15 @@ export interface BodyPageHeaderProps extends Omit<React.HTMLAttributes<HTMLEleme
|
|
|
6
6
|
actions?: React.ReactNode;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Header bar for a PageBody destination (the window panel style,
|
|
10
|
+
* user-mandated 2026-11-12).
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* A 64px bar: the 18px page title at the leading edge, page actions (and any
|
|
13
|
+
* quiet "Updated 2m ago" meta) at the trailing edge, 24px side insets, and a
|
|
14
|
+
* full-width WG4 hairline under it that separates the bar from the page
|
|
15
|
+
* content. The hairline is structural, so it runs edge to edge; row dividers
|
|
16
|
+
* inside the content stay inset. The bar owns the 24px gap to the content
|
|
17
|
+
* below (mb-6), so content never pads its own top.
|
|
18
|
+
* Destination icons belong in the sidebar, not beside the title.
|
|
14
19
|
*/
|
|
15
20
|
export declare const BodyPageHeader: React.ForwardRefExoticComponent<BodyPageHeaderProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsxs as
|
|
3
|
-
import * as
|
|
4
|
-
import { cn as
|
|
5
|
-
const
|
|
2
|
+
import { jsxs as s, jsx as r } from "react/jsx-runtime";
|
|
3
|
+
import * as i from "react";
|
|
4
|
+
import { cn as o } from "../lib/cn.js";
|
|
5
|
+
const n = i.forwardRef(({ className: a, title: t, actions: e, ...d }, m) => /* @__PURE__ */ s(
|
|
6
6
|
"header",
|
|
7
7
|
{
|
|
8
8
|
ref: m,
|
|
9
9
|
"data-slot": "body-page-header",
|
|
10
|
-
className:
|
|
11
|
-
"flex shrink-0 items-center justify-between gap-4
|
|
10
|
+
className: o(
|
|
11
|
+
"mb-6 flex h-16 shrink-0 items-center justify-between gap-4 border-b border-border px-6",
|
|
12
12
|
a
|
|
13
13
|
),
|
|
14
|
-
...
|
|
14
|
+
...d,
|
|
15
15
|
children: [
|
|
16
|
-
/* @__PURE__ */ r("h1", { className: "min-w-0 truncate text-
|
|
16
|
+
/* @__PURE__ */ r("h1", { className: "m-0 min-w-0 truncate text-xl font-medium text-on-white-primary", children: t }),
|
|
17
17
|
e ? /* @__PURE__ */ r("div", { className: "flex shrink-0 items-center gap-2", children: e }) : null
|
|
18
18
|
]
|
|
19
19
|
}
|
|
20
20
|
));
|
|
21
|
-
|
|
21
|
+
n.displayName = "BodyPageHeader";
|
|
22
22
|
export {
|
|
23
|
-
|
|
23
|
+
n as BodyPageHeader
|
|
24
24
|
};
|