@mediaradar/design-components 0.9.0 → 0.11.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.
package/dist/index.d.cts CHANGED
@@ -17,6 +17,9 @@ import { VariantProps } from 'class-variance-authority';
17
17
  * not just a decorative hover effect. Both modes close on Escape and on any
18
18
  * outside click. The bubble is portaled to document.body and repositions
19
19
  * itself to stay clear of the right viewport edge.
20
+ * @a11y The trigger is a <button> reporting aria-expanded; the bubble is
21
+ * role="tooltip" and Escape dismisses it. It describes its anchor rather
22
+ * than naming it, so the anchor still needs its own accessible name.
20
23
  * @usage
21
24
  * ```tsx
22
25
  * <InfoTip text="Trims time periods to data that has finalized across the selected media formats." />
@@ -61,6 +64,10 @@ declare function InfoTip({ text, size, label, trigger }: InfoTipProps): react.JS
61
64
  * other close path discards the draft, so the trigger label never previews
62
65
  * an unapplied change. The pinned "selected" section persists across
63
66
  * searches and collapses when the search is cleared.
67
+ * @a11y Trigger is a <button> with aria-expanded and aria-haspopup; the menu is
68
+ * role="dialog", closed on Escape. Option rows are role="checkbox" with
69
+ * aria-checked, so each row is itself the control -- don't wrap them in
70
+ * another clickable element.
64
71
  * @usage
65
72
  * ```tsx
66
73
  * <AdvertiserQuickFilter options={advertisers} selected={selected} onChange={setSelected} />
@@ -159,6 +166,13 @@ declare function AdvertiserSearchPrompt({ label }: AdvertiserSearchPromptProps):
159
166
  * `stopPropagation` before firing `onChange` by default, so nesting this
160
167
  * inside a row that toggles on its own click can't fire the toggle twice;
161
168
  * pass `stopPropagation={false}` where the row should also see the click.
169
+ * @a11y The <button> itself carries role="checkbox" and aria-checked ("mixed"
170
+ * when indeterminate), so it IS the control -- never nest it inside
171
+ * another button or a row that is itself clickable. `ariaLabel` is
172
+ * required because the box renders no text. Where the whole row should be
173
+ * the control, use CheckBoxBox inside your own <button role="checkbox">
174
+ * instead: a <button> inside a <button> is invalid markup, and a <div
175
+ * onClick> wrapper is not keyboard-reachable at all.
162
176
  * @usage
163
177
  * ```tsx
164
178
  * <CheckBox checked={selected} ariaLabel="Select row" onChange={toggle} />
@@ -221,6 +235,10 @@ declare function CheckBox({ checked, indeterminate, onChange, ariaLabel, disable
221
235
  * the control has no correct option: nesting the interactive `CheckBox`
222
236
  * produces a button inside a button, and dropping to a `<div>` with a click
223
237
  * handler loses keyboard access entirely.
238
+ * @a11y Presentational only: aria-hidden, no focus stop, no click handling. The
239
+ * ancestor owns role="checkbox", aria-checked, the accessible name and the
240
+ * click. Use it exactly when that ancestor is itself the control; use
241
+ * CheckBox when the box is the control.
224
242
  * @usage
225
243
  * ```tsx
226
244
  * <button type="button" role="checkbox" aria-checked={on} onClick={toggle}>
@@ -257,6 +275,9 @@ declare function CheckBoxBox({ checked, indeterminate, disabled, className }: Ch
257
275
  * values, so a previous unsaved edit never lingers into the next open. Only
258
276
  * the Apply button commits -- Cancel, Escape, and outside-click all discard
259
277
  * the draft silently.
278
+ * @a11y Trigger is a <button> with aria-expanded and an aria-label from the
279
+ * caption; the panel is role="dialog" and Escape closes it. Focus is not
280
+ * moved into the panel, so it is reached by tabbing.
260
281
  * @usage
261
282
  * ```tsx
262
283
  * <DateRangeFilter caption="Date Range" defaultValue="Rolling 6 months" onChange={setRange} />
@@ -327,6 +348,11 @@ declare function DateRangeFilter({ caption, defaultValue, value: controlledValue
327
348
  * The text input carries an `aria-label` derived from `placeholder` — the
328
349
  * wrapping `<label>` has no visible text content (just an icon and the
329
350
  * input), so it grants the input no accessible name on its own.
351
+ * @a11y The <input> takes its accessible name from `ariaLabel`. The match-mode
352
+ * popover is a radio group (role="radio" + aria-checked) and its trigger
353
+ * reports aria-expanded. Escape closes the popover only, leaving focus in
354
+ * the field -- a consumer nesting this inside another dismissible layer
355
+ * must sequence the two dismissals itself.
330
356
  * @usage
331
357
  * ```tsx
332
358
  * <SearchBar value={query} onChange={setQuery} />
@@ -390,6 +416,9 @@ declare function SearchBar({ placeholder, value, onChange, variant, matchValue,
390
416
  * anchor rather than a framework router Link — this package has no router
391
417
  * peer dependency, and the two consuming apps disagree on one (react-router-dom
392
418
  * vs next/link); a plain anchor is the one thing that works unmodified in both.
419
+ * @a11y Rail items are buttons and take their accessible name from `ariaLabel`,
420
+ * since several render icon-only. Without it they announce as unnamed
421
+ * buttons.
393
422
  * @usage
394
423
  * ```tsx
395
424
  * <SectionRail title="Sports" subtitle="Your tracked leagues" viewAllLabel="View all" viewAllHref="/sports">
@@ -432,6 +461,10 @@ declare function SectionRail({ title, titleSerif, subtitle, viewAllLabel, viewAl
432
461
  * invalid HTML that breaks click targeting (confirmed against how
433
462
  * mr-clientapps-insights-studio's own equivalent, `ChipOption`, already
434
463
  * avoids exactly this by rendering its InfoTip as a sibling, not a child).
464
+ * @a11y Trigger is a <button> with aria-expanded and aria-haspopup; the menu is
465
+ * role="listbox" with role="option" rows carrying aria-selected. Escape
466
+ * closes it. Use the listbox semantics as given -- adding a second role to
467
+ * the wrapper breaks the option/listbox relationship.
435
468
  * @usage
436
469
  * ```tsx
437
470
  * <DataScopeFilter value={finalOnly} onChange={setFinalOnly} />
@@ -467,6 +500,11 @@ declare function DataScopeFilter({ value, onChange, align }: DataScopeFilterProp
467
500
  * `onChange` ever fires, so nothing would ever get selected. Selecting an
468
501
  * option commits immediately and closes -- there's no separate draft/Apply
469
502
  * step; Escape and outside-click just close without side effects.
503
+ * @a11y Trigger is a <button>; the popover is role="listbox" with role="option"
504
+ * rows carrying aria-selected. The trigger owns the accessible name via
505
+ * the caption. The popover is not a focus trap and does not move focus on
506
+ * open, so keyboard users tab into it; a consumer rendering it inside
507
+ * another dismissible layer has to sequence the two dismissals itself.
470
508
  * @usage
471
509
  * ```tsx
472
510
  * <SelectFilter caption="Rank" value={rankFilter} onChange={setRankFilter} options={['All', 'VP / Director', 'Manager', 'Coordinator']} />
@@ -598,6 +636,10 @@ declare const QUIET_ACTION_CLASS = "rounded-control text-[13px] font-medium text
598
636
  * recovery buttons (e.g. "Switch workspace") after the two named ones, for
599
637
  * empty states whose fix isn't about filters at all -- primary gets the
600
638
  * filled treatment, everything else the quiet one.
639
+ * @a11y The optional action is a real <button> with visible text as its
640
+ * accessible name; the illustration is aria-hidden. Nothing here announces
641
+ * automatically, so a consumer replacing results should manage its own
642
+ * live region if the change needs announcing.
601
643
  * @usage
602
644
  * ```tsx
603
645
  * <NoResultsEmptyState hasFilters={hasFilters} onClearFilters={clearFilters} onEditFilters={openFilterTray} />
@@ -689,6 +731,8 @@ interface SummaryGroup {
689
731
  * increase, including one added to an already-open or already
690
732
  * manually-collapsed nonempty group, silently undoing the user's own
691
733
  * collapse. Sub-groups render indented beneath their parent's own items.
734
+ * @a11y The card's toggle is a button reporting aria-expanded, with an aria-
735
+ * label since it renders icon-only. Decorative marks are aria-hidden.
692
736
  * @usage
693
737
  * ```tsx
694
738
  * <WorkspaceSelectedCard groups={[{ id: 'advertisers', label: 'Advertisers', items: selected, onRemove: removeOne, onRemoveAll: clearAll }]} />
@@ -731,6 +775,9 @@ declare function WorkspaceSelectedCard({ groups, testIdPrefix }: WorkspaceSelect
731
775
  * `aria-hidden="true"` throughout, since none of the boxes carry real
732
776
  * content for assistive tech to announce. The bar count and profile are a
733
777
  * fixed shape, not driven by `height`.
778
+ * @a11y role="presentation" with aria-hidden marks: a visual stand-in with no
779
+ * data, deliberately invisible to assistive tech. Don't add a caption
780
+ * expecting it to be announced.
734
781
  * @usage
735
782
  * ```tsx
736
783
  * <BarChartPlaceholder />
@@ -756,6 +803,9 @@ declare function BarChartPlaceholder({ height }: BarChartPlaceholderProps): reac
756
803
  * @behavior Purely presentational -- `role="presentation"` and
757
804
  * `aria-hidden="true"` throughout (inherited from `AxisFrame`). The series
758
805
  * count and shapes are fixed; `height` is the only variable.
806
+ * @a11y role="presentation" with aria-hidden marks: a visual stand-in with no
807
+ * data, deliberately invisible to assistive tech. Don't add a caption
808
+ * expecting it to be announced.
759
809
  * @usage
760
810
  * ```tsx
761
811
  * <LineChartPlaceholder />
@@ -780,6 +830,9 @@ declare function LineChartPlaceholder({ height }: LineChartPlaceholderProps): re
780
830
  * @behavior Purely presentational -- `role="presentation"` and
781
831
  * `aria-hidden="true"` throughout. `legendRows` controls the blank legend
782
832
  * only; the disc's seam count is a fixed shape.
833
+ * @a11y role="presentation" with aria-hidden marks: it is a visual stand-in with
834
+ * no data, deliberately invisible to assistive tech. Don't add a caption
835
+ * expecting it to be announced.
783
836
  * @usage
784
837
  * ```tsx
785
838
  * <PieChartPlaceholder />
@@ -809,6 +862,8 @@ declare function PieChartPlaceholder({ height, legendRows }: PieChartPlaceholder
809
862
  * `bg-subtle` fill the default-strength seam disappears and the stack reads
810
863
  * as one undivided block. Legend rows are reversed (bottom-up) when `axis`
811
864
  * is off, matching a bare stack's usual bottom-anchored reading order.
865
+ * @a11y role="presentation" with aria-hidden marks: a visual stand-in with no
866
+ * data, deliberately invisible to assistive tech.
812
867
  * @usage
813
868
  * ```tsx
814
869
  * <StackedColumnPlaceholder />
@@ -858,6 +913,10 @@ declare function StackedColumnPlaceholder({ height, width, legendRows, axis, }:
858
913
  * right-aligned to the anchor's right edge -- both meant for `anchorRef`
859
914
  * anchors near the viewport's right edge, where a centred box would run
860
915
  * off-screen or read awkwardly beside a narrow icon.
916
+ * @a11y Renders role="tooltip" and is wired to its anchor by aria-describedby,
917
+ * so the anchor must exist and keep a stable id. It describes rather than
918
+ * labels: it is announced in addition to the anchor's own name, not
919
+ * instead of it, so never put the only label for a control in here.
861
920
  * @usage
862
921
  * ```tsx
863
922
  * <Tooltip label="Full advertiser name" whenTruncated>
@@ -959,6 +1018,10 @@ declare function AdvertiserNoResults({ query, hint, }: AdvertiserNoResultsProps)
959
1018
  * between "Select all" and "Deselect" based on `allSelected`.
960
1019
  * @tokens rounded-control, text-text-link, hover:bg-subtle
961
1020
  * @dependencies lucide-react
1021
+ * @a11y A plain <button>, not a checkbox -- it performs a bulk action rather
1022
+ * than holding a checked state, so it deliberately carries no
1023
+ * role="checkbox" or aria-checked. Its icon is aria-hidden and the visible
1024
+ * text is the accessible name.
962
1025
  * @usage
963
1026
  * ```tsx
964
1027
  * {results.length > 5 && (
@@ -992,6 +1055,9 @@ declare function SelectAllVisible({ count, allSelected, onToggle, testIdPrefix }
992
1055
  * need. Self-hides at `count === 0` so a caller can render it unconditionally.
993
1056
  * @tokens rounded-control, text-text-tertiary, hover:text-text-primary
994
1057
  * @dependencies lucide-react
1058
+ * @a11y The disclosure header is a button reporting aria-expanded, and the
1059
+ * chevron is aria-hidden. It is a disclosure, not a selection control --
1060
+ * the rows inside own their own semantics.
995
1061
  * @usage
996
1062
  * ```tsx
997
1063
  * <SelectedSection count={selected.length} open={open} onToggle={() => setOpen((o) => !o)}>
@@ -1147,6 +1213,10 @@ interface SelectionPickerProps<T extends PickerRow> {
1147
1213
  * with both an `onChange` and the row's own `onClick` -- `CheckBox` stops
1148
1214
  * click propagation before firing `onChange`, which is exactly what lets it
1149
1215
  * sit inside a row that toggles on its own click without double-firing.
1216
+ * @a11y Search is an <input>; result rows and the account-list menu
1217
+ * (role="menu") are buttons. Escape closes the menu. Loading, empty and
1218
+ * error states announce through role="status", so a consumer should NOT
1219
+ * wrap this in its own live region -- that would double-announce.
1150
1220
  * @usage
1151
1221
  * ```tsx
1152
1222
  * <SelectionPicker
@@ -1234,6 +1304,9 @@ interface PublisherBreakdownListProps {
1234
1304
  * the kind of forked-with-extra-indirection outcome this package's README
1235
1305
  * calls out as not actually shared. Per that guidance, this component stays
1236
1306
  * the flat-list case only; mr-clientapps' accordion stays where it is, un-migrated.
1307
+ * @a11y Rows are buttons. One row manages tabIndex directly and a row tooltip
1308
+ * uses role="tooltip", dismissed on Escape. The tooltip describes rather
1309
+ * than names, so never put a row's only label in it.
1237
1310
  * @usage
1238
1311
  * ```tsx
1239
1312
  * <PublisherBreakdownList rows={publishers} defaultVisibleCount={10} />
@@ -1275,6 +1348,9 @@ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantPr
1275
1348
  * and relies on its per-variant hover/brightness treatment instead. `loading`
1276
1349
  * implies `disabled` (and sets `aria-busy`), since a control mid-submit
1277
1350
  * shouldn't accept another click.
1351
+ * @a11y Renders a native <button>, so it keeps native keyboard behaviour.
1352
+ * `loading` sets aria-busy, and the spinner is aria-hidden. Icon-only
1353
+ * usage needs an aria-label from the caller -- nothing here supplies one.
1278
1354
  * @usage
1279
1355
  * ```tsx
1280
1356
  * <Button variant="primary" size="md">Save changes</Button>
@@ -1300,6 +1376,9 @@ interface FilterDropdownFooterProps {
1300
1376
  * visible. Shared by the Media/Advertiser/Date/Group By/Time Increment quick
1301
1377
  * filters on Sports Dashboard, Publisher Intel, and Opportunities.
1302
1378
  * @tokens border-border-default
1379
+ * @a11y Clear and Apply are real Buttons with visible text as their accessible
1380
+ * names, in that DOM order. It adds no roles or live regions of its own --
1381
+ * the menu that contains it owns dismissal and focus.
1303
1382
  * @usage
1304
1383
  * ```tsx
1305
1384
  * <FilterDropdownFooter onApply={handleApply} onClear={handleClear} />
@@ -1312,22 +1391,53 @@ interface NameListModalProps {
1312
1391
  initialName: string;
1313
1392
  submitLabel: string;
1314
1393
  onCancel: () => void;
1315
- onSubmit: (name: string) => void;
1394
+ /**
1395
+ * Called with the trimmed name, and the state of `options` when any were
1396
+ * given. A handler that only takes the name stays valid -- TypeScript lets
1397
+ * a function ignore trailing parameters -- so existing callers are
1398
+ * unaffected.
1399
+ */
1400
+ onSubmit: (name: string, checked: Record<string, boolean>) => void;
1401
+ /**
1402
+ * Relabels the name field, for dialogs that name something other than a
1403
+ * list (e.g. "View name").
1404
+ */
1405
+ fieldLabel?: string;
1406
+ /** Placeholder for the name field, paired with `fieldLabel`. */
1407
+ placeholder?: string;
1408
+ /**
1409
+ * Optional checkboxes below the name field -- e.g. "Set as default" or
1410
+ * "Enable email alerts". Their state is handed to `onSubmit` as the second
1411
+ * argument, keyed by `key`. `initial` sets the starting state.
1412
+ */
1413
+ options?: {
1414
+ key: string;
1415
+ label: string;
1416
+ initial?: boolean;
1417
+ }[];
1316
1418
  }
1317
1419
  /**
1318
1420
  * @pattern NameListModal
1319
- * @description Minimal create/rename dialog — just the list name. Shared by
1320
- * the Account Lists table and the list detail page so create/rename look
1321
- * identical.
1322
- * @tokens rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, rounded-control, bg-input, focus:border-brand-primaryAction
1421
+ * @description Create/rename dialog — a name field, and optionally a few
1422
+ * checkboxes under it. Shared by the Account Lists table and the list detail
1423
+ * page so create/rename look identical; `fieldLabel`/`placeholder` relabel it
1424
+ * for dialogs that name something other than a list.
1425
+ * @tokens bg-scrim, rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, rounded-control, bg-input, focus:border-brand-primaryAction
1323
1426
  * @behavior Escape closes the dialog via `onCancel`, same as clicking the
1324
1427
  * scrim backdrop. Submit is disabled until the name is non-empty (trimmed).
1428
+ * When `options` are given they render as CheckBox rows below the field, and
1429
+ * their state comes back as `onSubmit`'s second argument -- a handler that
1430
+ * only takes the name stays valid.
1431
+ * @a11y role="dialog" with aria-modal, labelled by its title. The name field
1432
+ * takes focus on open and Escape closes via onCancel. Focus is NOT trapped
1433
+ * and NOT restored to the opener on close -- confirmed in the source -- so
1434
+ * a consumer that needs either must supply it around this component.
1325
1435
  * @usage
1326
1436
  * ```tsx
1327
1437
  * <NameListModal title="Rename list" initialName={list.name} submitLabel="Save" onCancel={close} onSubmit={rename} />
1328
1438
  * ```
1329
1439
  */
1330
- declare function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit }: NameListModalProps): react.ReactPortal;
1440
+ declare function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit, fieldLabel, placeholder, options, }: NameListModalProps): react.ReactPortal;
1331
1441
 
1332
1442
  /**
1333
1443
  * Which stroke a chip trigger carries.
@@ -1361,6 +1471,9 @@ interface ChipContentProps {
1361
1471
  * treatment every dropdown trigger depends on — open/close, Escape, and
1362
1472
  * outside-click dismissal all live in each consumer, not here. A new dropdown
1363
1473
  * built on `chipTriggerClass` has to implement its own dismissal handling.
1474
+ * @a11y `chipTriggerClass` supplies only the shared focus-visible outline.
1475
+ * Roles, aria-expanded and dismissal all belong to the consumer's own
1476
+ * trigger -- this styles a control, it does not make one.
1364
1477
  * @usage
1365
1478
  * ```tsx
1366
1479
  * <button className={chipTriggerClass("box")}>
@@ -1398,6 +1511,9 @@ interface FilterChipBarProps<T extends ChipLike> {
1398
1511
  * @behavior A parked chip (key in `parkedKeys`) renders with no fill and a
1399
1512
  * dashed edge instead of the solid applied style, and its hover tooltip
1400
1513
  * reads "Not in this workspace" instead of the filter's group label.
1514
+ * @a11y Each chip's remove control is a button with its own aria-label naming
1515
+ * what it clears; the chip's icon is aria-hidden. An overflow tooltip uses
1516
+ * role="tooltip", which describes rather than labels.
1401
1517
  * @usage
1402
1518
  * ```tsx
1403
1519
  * <FilterChipBar chips={activeChips} onRemove={removeChip} onClearAll={clearAll} />
@@ -1451,6 +1567,9 @@ interface SortButtonProps<K extends string> {
1451
1567
  * standard three-state cycle — sort, reverse, then unsorted. `disabled` keeps
1452
1568
  * the column's inherited header color rather than dimming it — the column
1453
1569
  * isn't unavailable, there's just no data under it.
1570
+ * @a11y Renders a <button> and sets aria-sort on it. Intended for a table header
1571
+ * cell -- put it inside the <th> rather than replacing it, so the sort
1572
+ * state stays associated with the column for screen readers.
1454
1573
  * @usage
1455
1574
  * ```tsx
1456
1575
  * const [sort, setSort] = useState<SortState<'spend'>>(null)
@@ -1472,6 +1591,9 @@ interface PagerProps {
1472
1591
  * ellipsis gaps. Shared by My Exports and Account Matcher.
1473
1592
  * @tokens rounded-control, text-text-secondary, bg-brand-primaryAction, text-brand-onprimary, hover:bg-subtle, hover:text-text-primary, text-text-tertiary
1474
1593
  * @dependencies lucide-react
1594
+ * @a11y Page controls are buttons with their own aria-labels, and the current
1595
+ * page is marked with aria-current. Don't relabel them with visible text
1596
+ * alone -- the labels are what a screen reader announces.
1475
1597
  * @usage
1476
1598
  * ```tsx
1477
1599
  * <Pager page={page} totalPages={totalPages} onPage={setPage} />
@@ -1540,6 +1662,10 @@ declare function Tag({ children, className }: TagProps): react.JSX.Element;
1540
1662
  * Changing the per-page count reports it and leaves the host to reset to page
1541
1663
  * 1. With one page of results the pager still renders, so the bar's height
1542
1664
  * and the range readout don't come and go as filters narrow.
1665
+ * @a11y A <nav aria-label="Pagination"> wrapping <button> controls, each with
1666
+ * its own aria-label (Previous/Next/Last). The chevron icons are aria-
1667
+ * hidden, so the labels are the only accessible names -- don't override
1668
+ * them with visible text alone.
1543
1669
  * @usage
1544
1670
  * ```tsx
1545
1671
  * <TablePagination
@@ -1564,11 +1690,19 @@ declare function TablePagination({ page, perPage, totalItems, onPageChange, onPe
1564
1690
  }): react.JSX.Element;
1565
1691
  type TablePaginationProps = Parameters<typeof TablePagination>[0];
1566
1692
 
1693
+ /** What the Custom Range From/To selects pick. */
1694
+ type DateGranularity = 'month' | 'quarter' | 'year';
1567
1695
  /** Resolve a label to its actual [start, end] span, ending at `today`. */
1568
1696
  declare function resolveRange(label: string, today?: Date): [Date, Date];
1569
- declare function DateRangePicker({ defaultValue, align, presets, onChange, onRangeChange, showFooter, today, years, }: {
1697
+ declare function DateRangePicker({ defaultValue, granularity, align, presets, onChange, onRangeChange, showFooter, today, years, }: {
1570
1698
  defaultValue?: string;
1571
1699
  align?: 'left' | 'right';
1700
+ /**
1701
+ * What the Custom Range From/To selects pick. `month` shows month + year
1702
+ * selects, `quarter` shows quarter + year, `year` shows year alone -- and
1703
+ * the applied label follows suit. Pair it with matching `presets`.
1704
+ */
1705
+ granularity?: DateGranularity;
1572
1706
  /** Rolling presets shown above Custom Range. Defaults to 3/6/12 months. */
1573
1707
  presets?: string[];
1574
1708
  onChange?: (label: string) => void;
@@ -1602,20 +1736,40 @@ interface MultiSelectGroup {
1602
1736
  * Advertiser filters that share state with the filter tray.
1603
1737
  * @tokens rounded-control, rounded-card, border-border-default, bg-surface, shadow-overlay, text-text-primary, text-text-secondary, text-text-tertiary, text-text-link, border-border-interactive, bg-brand-primaryAction, bg-input, hover:bg-subtle, hover:text-text-primary, placeholder:text-text-tertiary, text-brand-onprimary
1604
1738
  * @dependencies lucide-react
1605
- * @behavior Same draft/commit-on-close pattern as AdvertiserQuickFilter — the
1739
+ * @behavior `variant` picks the trigger's chip stroke: `box` (default, the
1740
+ * boxed two-line chip on the default border) or `inline` (same fill,
1741
+ * darker stroke, for chips sitting directly on the canvas). Left out of
1742
+ * the catalog's variant list deliberately: check-prop-drift can't resolve
1743
+ * the imported ChipVariant alias through this component's inline prop
1744
+ * type, so such a tag would be unvalidated -- and this exact component
1745
+ * has had stale ones stripped before.
1746
+ * Same draft/commit-on-close pattern as AdvertiserQuickFilter — the
1606
1747
  * draft resyncs from `selected` every time the tray opens, and (without
1607
1748
  * showFooter) any close path commits it, while showFooter mode requires the
1608
1749
  * Apply button and discards the draft on every other close. `min` enforces a
1609
1750
  * selection floor by silently ignoring any toggle that would drop below it —
1610
1751
  * there's no error state, the click just does nothing. Group parents are
1611
1752
  * tri-state and toggle all of their children in one action.
1753
+ * @a11y Trigger is a <button> with aria-expanded; the menu is role="dialog" and
1754
+ * Escape closes it. Option rows carry their own checkbox semantics. Focus
1755
+ * is not moved into the menu on open, so keyboard users tab into it in DOM
1756
+ * order.
1612
1757
  * @usage
1613
1758
  * ```tsx
1614
1759
  * <MultiSelectFilter caption="Media" options={mediaOptions} selected={selected} onChange={setSelected} />
1615
1760
  * ```
1616
1761
  */
1617
- declare function MultiSelectFilter({ caption, options, groups, selected, onChange, allLabel, searchable, searchPlaceholder, align, fullIsAll, min, icon, showFooter, clearValue, menuWidthClass, plainParent, fullWidth, }: {
1762
+ declare function MultiSelectFilter({ caption, options, groups, counts, variant, selected, onChange, allLabel, searchable, searchPlaceholder, align, fullIsAll, min, icon, showFooter, clearValue, menuWidthClass, plainParent, fullWidth, }: {
1618
1763
  caption: string;
1764
+ /**
1765
+ * Live option-id -> result count. Supplying it makes the menu faceted:
1766
+ * every label gets a "(n)" suffix and options with nothing behind them
1767
+ * drop out. A selected option is always kept, or there would be no way to
1768
+ * undo it.
1769
+ */
1770
+ counts?: Record<string, number>;
1771
+ /** Chip stroke for the trigger. See ChipVariant. */
1772
+ variant?: ChipVariant;
1619
1773
  options?: {
1620
1774
  id: string;
1621
1775
  label: string;
@@ -1700,6 +1854,10 @@ interface ToggleProps {
1700
1854
  * need (usually label left, switch pushed right).
1701
1855
  * @variant md - Settings panels and modals, where the switch is the row's subject.
1702
1856
  * @variant sm - Dense rows next to 13px body text, where the md track overpowers its own label.
1857
+ * @a11y The <button> carries role="switch" and aria-checked, so it is the
1858
+ * control -- don't nest it in another interactive element. `label`
1859
+ * supplies the accessible name; without it the switch is announced
1860
+ * unlabelled.
1703
1861
  * @usage
1704
1862
  * ```tsx
1705
1863
  * <Toggle checked={enabled} onChange={setEnabled} label="Email news alerts" />
@@ -1735,6 +1893,9 @@ interface FreshnessProps {
1735
1893
  * timestamps stops reading as a wall of identical text. Color carries the
1736
1894
  * urgency signal at a glance.
1737
1895
  * @tokens bg-status-success, bg-status-warning, bg-text-tertiary
1896
+ * @a11y role="img" with an aria-label per level, so the dot has a text
1897
+ * alternative rather than announcing as decoration. The label is the only
1898
+ * thing a screen reader gets -- the colour carries no meaning on its own.
1738
1899
  * @usage
1739
1900
  * ```tsx
1740
1901
  * <Freshness level="fresh" />
@@ -1742,4 +1903,4 @@ interface FreshnessProps {
1742
1903
  */
1743
1904
  declare function Freshness({ level }: FreshnessProps): react.JSX.Element;
1744
1905
 
1745
- export { AISpark, type AISparkProps, AdvertiserNoResults, type AdvertiserNoResultsProps, AdvertiserQuickFilter, type AdvertiserQuickFilterProps, AdvertiserSearchPrompt, type AdvertiserSearchPromptProps, BarChartPlaceholder, type BarChartPlaceholderProps, Button, type ButtonProps, Card, type CardProps, CheckBox, CheckBoxBox, type CheckBoxBoxProps, type CheckBoxProps, ChipContent, type ChipContentProps, type ChipVariant, DEFAULT_SEARCH_MATCH, DataScopeFilter, type DataScopeFilterProps, DateRangeFilter, type DateRangeFilterProps, DateRangePicker, type DateRangePickerProps, FilterChipBar, type FilterChipBarProps, FilterDropdownFooter, type FilterDropdownFooterProps, Freshness, type FreshnessLevel, type FreshnessProps, InfoTip, type InfoTipProps, LineChartPlaceholder, type LineChartPlaceholderProps, MultiSelectFilter, type MultiSelectFilterProps, type MultiSelectGroup, NO_RESULTS_BODY, NO_RESULTS_TITLE, NameListModal, type NameListModalProps, type NoResultsAction, NoResultsEmptyState, type NoResultsEmptyStateProps, PRIMARY_ACTION_CLASS, Pager, type PagerProps, type PickerColumn, type PickerFilter, type PickerRow, PieChartPlaceholder, type PieChartPlaceholderProps, type PubBreak, PublisherBreakdownList, type PublisherBreakdownListProps, QUIET_ACTION_CLASS, SearchBar, type SearchBarProps, type SearchBarVariant, type SearchMatchMode, type SearchMatchValue, SectionRail, type SectionRailProps, SelectAllVisible, type SelectAllVisibleProps, SelectFilter, type SelectFilterProps, SelectedSection, type SelectedSectionProps, SelectionPicker, type SelectionPickerAccountList, type SelectionPickerProps, SortButton, type SortButtonProps, type SortDir, type SortState, StackedColumnPlaceholder, type StackedColumnPlaceholderProps, type SummaryGroup, type SummaryGroupItemValue, TablePagination, type TablePaginationProps, Tag, type TagProps, Toggle, type ToggleProps, Tooltip, type TooltipProps, WorkspaceAvatar, type WorkspaceAvatarProps, WorkspaceSelectedCard, type WorkspaceSelectedCardProps, buttonVariants, chipTriggerClass, cycleSort, noResultsBody, resolveRange, sortProp };
1906
+ export { AISpark, type AISparkProps, AdvertiserNoResults, type AdvertiserNoResultsProps, AdvertiserQuickFilter, type AdvertiserQuickFilterProps, AdvertiserSearchPrompt, type AdvertiserSearchPromptProps, BarChartPlaceholder, type BarChartPlaceholderProps, Button, type ButtonProps, Card, type CardProps, CheckBox, CheckBoxBox, type CheckBoxBoxProps, type CheckBoxProps, ChipContent, type ChipContentProps, type ChipVariant, DEFAULT_SEARCH_MATCH, DataScopeFilter, type DataScopeFilterProps, type DateGranularity, DateRangeFilter, type DateRangeFilterProps, DateRangePicker, type DateRangePickerProps, FilterChipBar, type FilterChipBarProps, FilterDropdownFooter, type FilterDropdownFooterProps, Freshness, type FreshnessLevel, type FreshnessProps, InfoTip, type InfoTipProps, LineChartPlaceholder, type LineChartPlaceholderProps, MultiSelectFilter, type MultiSelectFilterProps, type MultiSelectGroup, NO_RESULTS_BODY, NO_RESULTS_TITLE, NameListModal, type NameListModalProps, type NoResultsAction, NoResultsEmptyState, type NoResultsEmptyStateProps, PRIMARY_ACTION_CLASS, Pager, type PagerProps, type PickerColumn, type PickerFilter, type PickerRow, PieChartPlaceholder, type PieChartPlaceholderProps, type PubBreak, PublisherBreakdownList, type PublisherBreakdownListProps, QUIET_ACTION_CLASS, SearchBar, type SearchBarProps, type SearchBarVariant, type SearchMatchMode, type SearchMatchValue, SectionRail, type SectionRailProps, SelectAllVisible, type SelectAllVisibleProps, SelectFilter, type SelectFilterProps, SelectedSection, type SelectedSectionProps, SelectionPicker, type SelectionPickerAccountList, type SelectionPickerProps, SortButton, type SortButtonProps, type SortDir, type SortState, StackedColumnPlaceholder, type StackedColumnPlaceholderProps, type SummaryGroup, type SummaryGroupItemValue, TablePagination, type TablePaginationProps, Tag, type TagProps, Toggle, type ToggleProps, Tooltip, type TooltipProps, WorkspaceAvatar, type WorkspaceAvatarProps, WorkspaceSelectedCard, type WorkspaceSelectedCardProps, buttonVariants, chipTriggerClass, cycleSort, noResultsBody, resolveRange, sortProp };