@mediaradar/design-components 0.18.7 → 0.19.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
@@ -424,6 +424,7 @@ declare function CheckBoxBox({ checked, indeterminate, disabled, className }: Ch
424
424
  * @usage
425
425
  * ```tsx
426
426
  * <DateRangeFilter caption="Date Range" defaultValue="Rolling 6 months" onChange={setRange} />
427
+ * <DateRangeFilter caption="Dates" showDates shortDates placement="right" />
427
428
  * <DateRangeFilter presetSet="creativeIntel" defaultValue="Last 7 days" onChange={setRange} />
428
429
  * <DateRangeFilter presetSet="creativeIntel" value={preset} range={[start, end]} onChange={setPreset} onRangeChange={(s, e) => setRange({ start: s, end: e })} />
429
430
  * ```
@@ -449,6 +450,13 @@ interface DateRangeFilterProps {
449
450
  range?: [Date, Date];
450
451
  /** Which edge of the trigger the popup aligns to. */
451
452
  align?: "left" | "right";
453
+ /**
454
+ * Where the popup opens. 'below' (default) under the chip; 'above' over it,
455
+ * falling back to below when there is no room at the top of the window;
456
+ * 'right' beside it with bottoms aligned -- for a chip low on the page or
457
+ * in a narrow column, where opening below would push the popup off screen.
458
+ */
459
+ placement?: "below" | "above" | "right";
452
460
  /** Fired on Apply with the chip's new display value. */
453
461
  onChange?: (value: string) => void;
454
462
  /** Fired on Apply (and once on mount, uncontrolled only) with the resolved start/end dates -- e.g. to drive dependent table columns. */
@@ -464,7 +472,7 @@ interface DateRangeFilterProps {
464
472
  /** Prefix for data-testid attributes on the trigger, popover, each preset option, and Cancel/Apply. Omit for no test-id wiring. */
465
473
  testIdPrefix?: string;
466
474
  }
467
- declare function DateRangeFilter({ caption, defaultValue, value: controlledValue, range: controlledRange, align, onChange, onRangeChange, showDates, shortDates, icon, presetSet, testIdPrefix, }: DateRangeFilterProps): react.JSX.Element;
475
+ declare function DateRangeFilter({ caption, defaultValue, value: controlledValue, range: controlledRange, align, placement, onChange, onRangeChange, showDates, shortDates, icon, presetSet, testIdPrefix, }: DateRangeFilterProps): react.JSX.Element;
468
476
 
469
477
  /**
470
478
  * @pattern SearchBar
@@ -2118,10 +2126,12 @@ interface ToggleProps {
2118
2126
  * Rendered as a `<button role="switch">` so the on/off state is announced as a
2119
2127
  * switch rather than a checkbox, and so the track and knob can carry the brand
2120
2128
  * fill without fighting a native input's styling hooks.
2121
- * @tokens bg-brand-primaryAction, bg-border-interactive, bg-surface, shadow-raised, outline-border-focus
2129
+ * @tokens bg-brand-primaryAction, bg-surface, shadow-raised, outline-border-focus
2122
2130
  * @behavior The knob is positioned by `translate-x`, not by flex alignment, so
2123
- * the slide animates. Off uses `bg-border-interactive` rather than a grey
2124
- * literal, which keeps the track visible against `bg-surface` in dark mode.
2131
+ * the slide animates. Off is `border-interactive` mixed 70/30 with
2132
+ * `text-secondary` (an inline style), so the track and the knob on it are at
2133
+ * least 3:1 against the surface in both themes (WCAG 1.4.11). The two tokens
2134
+ * are the same colour in light mode, so light is unchanged.
2125
2135
  * Pair it with a label and any InfoTip in the surrounding row: this component
2126
2136
  * draws only the switch, so rows stay free to lay the label out however they
2127
2137
  * need (usually label left, switch pushed right).
@@ -2176,4 +2186,97 @@ interface FreshnessProps {
2176
2186
  */
2177
2187
  declare function Freshness({ level }: FreshnessProps): react.JSX.Element;
2178
2188
 
2179
- export { AISpark, type AISparkProps, AdvertiserNoResults, type AdvertiserNoResultsProps, AdvertiserQuickFilter, type AdvertiserQuickFilterProps, AdvertiserSearchPrompt, type AdvertiserSearchPromptProps, Badge, type BadgeKind, type BadgeProps, type BadgeTone, 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, Delta, type DeltaProps, 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, ariaSortFor, buttonVariants, chipTriggerClass, cycleSort, noResultsBody, resolveRange, sortProp };
2189
+ interface SectionHeadingProps {
2190
+ /** The section's name, in sentence case -- "Saved reports". */
2191
+ title: ReactNode;
2192
+ /** One line under the title saying what the section is or how it works. */
2193
+ description?: ReactNode;
2194
+ /** Controls that act on the whole section -- a search box, a button. Sit right, aligned to the bottom. */
2195
+ actions?: ReactNode;
2196
+ /** Heading level. Defaults to h2, the level under a page's own h1 title. */
2197
+ as?: "h2" | "h3";
2198
+ /** Id for the heading, so the section can be `aria-labelledby` it. */
2199
+ id?: string;
2200
+ className?: string;
2201
+ }
2202
+ /**
2203
+ * @pattern SectionHeading
2204
+ * @description The title of a section within a page -- "Start from a template",
2205
+ * "Saved reports". One size everywhere (16px semibold), so every page's sections
2206
+ * read at the same level under the page title. Optional one-line description
2207
+ * under it, optional actions on the right.
2208
+ * @props
2209
+ * title: ReactNode -- the section's name, sentence case
2210
+ * description?: ReactNode -- one line under the title
2211
+ * actions?: ReactNode -- section-wide controls on the right (search, a button)
2212
+ * as?: 'h2' | 'h3' (default 'h2') -- heading level
2213
+ * id?: string -- for the section's aria-labelledby
2214
+ * @tokens text-base, font-semibold, text-text-primary, text-dense, text-text-secondary
2215
+ * @use for every titled section of a page, below the page title.
2216
+ * @use `description` for the one thing a reader must know before using the
2217
+ * section -- it sits above the content, where a long list cannot push it out
2218
+ * of view.
2219
+ * @avoid for a card's own title, or a field label inside a form. Those are
2220
+ * smaller and belong to the card or the field.
2221
+ * @avoid writing a paragraph into `description`. One line; anything longer is
2222
+ * help text and belongs elsewhere.
2223
+ * @a11y Renders a real heading (h2 by default) so screen-reader users can jump
2224
+ * between sections. Pass `id` and point the section's `aria-labelledby` at it.
2225
+ * @usage
2226
+ * ```tsx
2227
+ * <section aria-labelledby="saved-title">
2228
+ * <SectionHeading
2229
+ * id="saved-title"
2230
+ * title="Saved reports"
2231
+ * description="A saved report is its setup, with no data in it."
2232
+ * actions={<SearchBar placeholder="Search saved reports" value={q} onChange={setQ} />}
2233
+ * />
2234
+ * ...
2235
+ * </section>
2236
+ * ```
2237
+ */
2238
+ declare function SectionHeading({ title, description, actions, as: Tag, id, className }: SectionHeadingProps): react.JSX.Element;
2239
+
2240
+ interface PageHeaderProps {
2241
+ /** The page's name -- "Report Builder". Title Case for a feature name. */
2242
+ title: ReactNode;
2243
+ /** One line under the title saying what the user can do on this page. */
2244
+ description?: ReactNode;
2245
+ /** The page's main actions, right-aligned -- usually one primary Button. */
2246
+ actions?: ReactNode;
2247
+ className?: string;
2248
+ }
2249
+ /**
2250
+ * @pattern PageHeader
2251
+ * @description The top of a page: its title (the page's only h1), an optional
2252
+ * one-line description under it, and the page's main actions on the right.
2253
+ * Title 20px over a 14px description, 2px apart, so the two read as one unit;
2254
+ * the actions centre on the pair. Type steps down evenly from there: page
2255
+ * title 20, SectionHeading 16, body 14.
2256
+ * @props
2257
+ * title: ReactNode -- the page's name
2258
+ * description?: ReactNode -- one line, about 70 characters at most, on what the user can do here
2259
+ * actions?: ReactNode -- primary actions, right-aligned
2260
+ * @tokens text-xl, font-semibold, tracking-tight, text-text-primary, text-sm, text-text-secondary, max-w-2xl
2261
+ * @use at the top of every top-level page.
2262
+ * @use `description` to say what the page is for, in one sentence a first-time
2263
+ * user can act on ("Build your own tables from MediaRadar data...").
2264
+ * @avoid putting the description to the right of the title. It competes with
2265
+ * the actions and wraps unpredictably on narrow screens.
2266
+ * @avoid more than one primary action in `actions`.
2267
+ * @avoid a description on every page by habit. Use one only where a first-time
2268
+ * user would not know what the page is for; a pipe-separated subtitle beside
2269
+ * the title is the pattern this replaces.
2270
+ * @a11y Renders the page's h1. Use `SectionHeading` (h2) for the sections below it.
2271
+ * @usage
2272
+ * ```tsx
2273
+ * <PageHeader
2274
+ * title="Report Builder"
2275
+ * description="Build tables from MediaRadar data and export them whenever you need."
2276
+ * actions={<Button><Plus /> New report</Button>}
2277
+ * />
2278
+ * ```
2279
+ */
2280
+ declare function PageHeader({ title, description, actions, className }: PageHeaderProps): react.JSX.Element;
2281
+
2282
+ export { AISpark, type AISparkProps, AdvertiserNoResults, type AdvertiserNoResultsProps, AdvertiserQuickFilter, type AdvertiserQuickFilterProps, AdvertiserSearchPrompt, type AdvertiserSearchPromptProps, Badge, type BadgeKind, type BadgeProps, type BadgeTone, 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, Delta, type DeltaProps, 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, PageHeader, type PageHeaderProps, 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, SectionHeading, type SectionHeadingProps, 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, ariaSortFor, buttonVariants, chipTriggerClass, cycleSort, noResultsBody, resolveRange, sortProp };
package/dist/index.d.ts CHANGED
@@ -424,6 +424,7 @@ declare function CheckBoxBox({ checked, indeterminate, disabled, className }: Ch
424
424
  * @usage
425
425
  * ```tsx
426
426
  * <DateRangeFilter caption="Date Range" defaultValue="Rolling 6 months" onChange={setRange} />
427
+ * <DateRangeFilter caption="Dates" showDates shortDates placement="right" />
427
428
  * <DateRangeFilter presetSet="creativeIntel" defaultValue="Last 7 days" onChange={setRange} />
428
429
  * <DateRangeFilter presetSet="creativeIntel" value={preset} range={[start, end]} onChange={setPreset} onRangeChange={(s, e) => setRange({ start: s, end: e })} />
429
430
  * ```
@@ -449,6 +450,13 @@ interface DateRangeFilterProps {
449
450
  range?: [Date, Date];
450
451
  /** Which edge of the trigger the popup aligns to. */
451
452
  align?: "left" | "right";
453
+ /**
454
+ * Where the popup opens. 'below' (default) under the chip; 'above' over it,
455
+ * falling back to below when there is no room at the top of the window;
456
+ * 'right' beside it with bottoms aligned -- for a chip low on the page or
457
+ * in a narrow column, where opening below would push the popup off screen.
458
+ */
459
+ placement?: "below" | "above" | "right";
452
460
  /** Fired on Apply with the chip's new display value. */
453
461
  onChange?: (value: string) => void;
454
462
  /** Fired on Apply (and once on mount, uncontrolled only) with the resolved start/end dates -- e.g. to drive dependent table columns. */
@@ -464,7 +472,7 @@ interface DateRangeFilterProps {
464
472
  /** Prefix for data-testid attributes on the trigger, popover, each preset option, and Cancel/Apply. Omit for no test-id wiring. */
465
473
  testIdPrefix?: string;
466
474
  }
467
- declare function DateRangeFilter({ caption, defaultValue, value: controlledValue, range: controlledRange, align, onChange, onRangeChange, showDates, shortDates, icon, presetSet, testIdPrefix, }: DateRangeFilterProps): react.JSX.Element;
475
+ declare function DateRangeFilter({ caption, defaultValue, value: controlledValue, range: controlledRange, align, placement, onChange, onRangeChange, showDates, shortDates, icon, presetSet, testIdPrefix, }: DateRangeFilterProps): react.JSX.Element;
468
476
 
469
477
  /**
470
478
  * @pattern SearchBar
@@ -2118,10 +2126,12 @@ interface ToggleProps {
2118
2126
  * Rendered as a `<button role="switch">` so the on/off state is announced as a
2119
2127
  * switch rather than a checkbox, and so the track and knob can carry the brand
2120
2128
  * fill without fighting a native input's styling hooks.
2121
- * @tokens bg-brand-primaryAction, bg-border-interactive, bg-surface, shadow-raised, outline-border-focus
2129
+ * @tokens bg-brand-primaryAction, bg-surface, shadow-raised, outline-border-focus
2122
2130
  * @behavior The knob is positioned by `translate-x`, not by flex alignment, so
2123
- * the slide animates. Off uses `bg-border-interactive` rather than a grey
2124
- * literal, which keeps the track visible against `bg-surface` in dark mode.
2131
+ * the slide animates. Off is `border-interactive` mixed 70/30 with
2132
+ * `text-secondary` (an inline style), so the track and the knob on it are at
2133
+ * least 3:1 against the surface in both themes (WCAG 1.4.11). The two tokens
2134
+ * are the same colour in light mode, so light is unchanged.
2125
2135
  * Pair it with a label and any InfoTip in the surrounding row: this component
2126
2136
  * draws only the switch, so rows stay free to lay the label out however they
2127
2137
  * need (usually label left, switch pushed right).
@@ -2176,4 +2186,97 @@ interface FreshnessProps {
2176
2186
  */
2177
2187
  declare function Freshness({ level }: FreshnessProps): react.JSX.Element;
2178
2188
 
2179
- export { AISpark, type AISparkProps, AdvertiserNoResults, type AdvertiserNoResultsProps, AdvertiserQuickFilter, type AdvertiserQuickFilterProps, AdvertiserSearchPrompt, type AdvertiserSearchPromptProps, Badge, type BadgeKind, type BadgeProps, type BadgeTone, 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, Delta, type DeltaProps, 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, ariaSortFor, buttonVariants, chipTriggerClass, cycleSort, noResultsBody, resolveRange, sortProp };
2189
+ interface SectionHeadingProps {
2190
+ /** The section's name, in sentence case -- "Saved reports". */
2191
+ title: ReactNode;
2192
+ /** One line under the title saying what the section is or how it works. */
2193
+ description?: ReactNode;
2194
+ /** Controls that act on the whole section -- a search box, a button. Sit right, aligned to the bottom. */
2195
+ actions?: ReactNode;
2196
+ /** Heading level. Defaults to h2, the level under a page's own h1 title. */
2197
+ as?: "h2" | "h3";
2198
+ /** Id for the heading, so the section can be `aria-labelledby` it. */
2199
+ id?: string;
2200
+ className?: string;
2201
+ }
2202
+ /**
2203
+ * @pattern SectionHeading
2204
+ * @description The title of a section within a page -- "Start from a template",
2205
+ * "Saved reports". One size everywhere (16px semibold), so every page's sections
2206
+ * read at the same level under the page title. Optional one-line description
2207
+ * under it, optional actions on the right.
2208
+ * @props
2209
+ * title: ReactNode -- the section's name, sentence case
2210
+ * description?: ReactNode -- one line under the title
2211
+ * actions?: ReactNode -- section-wide controls on the right (search, a button)
2212
+ * as?: 'h2' | 'h3' (default 'h2') -- heading level
2213
+ * id?: string -- for the section's aria-labelledby
2214
+ * @tokens text-base, font-semibold, text-text-primary, text-dense, text-text-secondary
2215
+ * @use for every titled section of a page, below the page title.
2216
+ * @use `description` for the one thing a reader must know before using the
2217
+ * section -- it sits above the content, where a long list cannot push it out
2218
+ * of view.
2219
+ * @avoid for a card's own title, or a field label inside a form. Those are
2220
+ * smaller and belong to the card or the field.
2221
+ * @avoid writing a paragraph into `description`. One line; anything longer is
2222
+ * help text and belongs elsewhere.
2223
+ * @a11y Renders a real heading (h2 by default) so screen-reader users can jump
2224
+ * between sections. Pass `id` and point the section's `aria-labelledby` at it.
2225
+ * @usage
2226
+ * ```tsx
2227
+ * <section aria-labelledby="saved-title">
2228
+ * <SectionHeading
2229
+ * id="saved-title"
2230
+ * title="Saved reports"
2231
+ * description="A saved report is its setup, with no data in it."
2232
+ * actions={<SearchBar placeholder="Search saved reports" value={q} onChange={setQ} />}
2233
+ * />
2234
+ * ...
2235
+ * </section>
2236
+ * ```
2237
+ */
2238
+ declare function SectionHeading({ title, description, actions, as: Tag, id, className }: SectionHeadingProps): react.JSX.Element;
2239
+
2240
+ interface PageHeaderProps {
2241
+ /** The page's name -- "Report Builder". Title Case for a feature name. */
2242
+ title: ReactNode;
2243
+ /** One line under the title saying what the user can do on this page. */
2244
+ description?: ReactNode;
2245
+ /** The page's main actions, right-aligned -- usually one primary Button. */
2246
+ actions?: ReactNode;
2247
+ className?: string;
2248
+ }
2249
+ /**
2250
+ * @pattern PageHeader
2251
+ * @description The top of a page: its title (the page's only h1), an optional
2252
+ * one-line description under it, and the page's main actions on the right.
2253
+ * Title 20px over a 14px description, 2px apart, so the two read as one unit;
2254
+ * the actions centre on the pair. Type steps down evenly from there: page
2255
+ * title 20, SectionHeading 16, body 14.
2256
+ * @props
2257
+ * title: ReactNode -- the page's name
2258
+ * description?: ReactNode -- one line, about 70 characters at most, on what the user can do here
2259
+ * actions?: ReactNode -- primary actions, right-aligned
2260
+ * @tokens text-xl, font-semibold, tracking-tight, text-text-primary, text-sm, text-text-secondary, max-w-2xl
2261
+ * @use at the top of every top-level page.
2262
+ * @use `description` to say what the page is for, in one sentence a first-time
2263
+ * user can act on ("Build your own tables from MediaRadar data...").
2264
+ * @avoid putting the description to the right of the title. It competes with
2265
+ * the actions and wraps unpredictably on narrow screens.
2266
+ * @avoid more than one primary action in `actions`.
2267
+ * @avoid a description on every page by habit. Use one only where a first-time
2268
+ * user would not know what the page is for; a pipe-separated subtitle beside
2269
+ * the title is the pattern this replaces.
2270
+ * @a11y Renders the page's h1. Use `SectionHeading` (h2) for the sections below it.
2271
+ * @usage
2272
+ * ```tsx
2273
+ * <PageHeader
2274
+ * title="Report Builder"
2275
+ * description="Build tables from MediaRadar data and export them whenever you need."
2276
+ * actions={<Button><Plus /> New report</Button>}
2277
+ * />
2278
+ * ```
2279
+ */
2280
+ declare function PageHeader({ title, description, actions, className }: PageHeaderProps): react.JSX.Element;
2281
+
2282
+ export { AISpark, type AISparkProps, AdvertiserNoResults, type AdvertiserNoResultsProps, AdvertiserQuickFilter, type AdvertiserQuickFilterProps, AdvertiserSearchPrompt, type AdvertiserSearchPromptProps, Badge, type BadgeKind, type BadgeProps, type BadgeTone, 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, Delta, type DeltaProps, 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, PageHeader, type PageHeaderProps, 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, SectionHeading, type SectionHeadingProps, 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, ariaSortFor, buttonVariants, chipTriggerClass, cycleSort, noResultsBody, resolveRange, sortProp };
package/dist/index.js CHANGED
@@ -583,7 +583,7 @@ function CheckBoxBox({ checked, indeterminate, disabled, className }) {
583
583
  }
584
584
 
585
585
  // src/DateRangeFilter.tsx
586
- import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState3 } from "react";
586
+ import { useEffect as useEffect3, useLayoutEffect, useMemo as useMemo2, useRef as useRef3, useState as useState3 } from "react";
587
587
  import { ChevronDown as ChevronDown2, ChevronLeft, ChevronRight } from "lucide-react";
588
588
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
589
589
  var DEFAULT_SHORTCUTS = [
@@ -707,6 +707,7 @@ function DateRangeFilter({
707
707
  value: controlledValue,
708
708
  range: controlledRange,
709
709
  align = "left",
710
+ placement = "below",
710
711
  onChange,
711
712
  onRangeChange,
712
713
  showDates = false,
@@ -791,6 +792,13 @@ function DateRangeFilter({
791
792
  onRangeChange?.(s, e);
792
793
  setOpen(false);
793
794
  };
795
+ const popRef = useRef3(null);
796
+ const [flipBelow, setFlipBelow] = useState3(false);
797
+ useLayoutEffect(() => {
798
+ if (!open || placement !== "above" || !ref.current || !popRef.current) return;
799
+ setFlipBelow(ref.current.getBoundingClientRect().top < popRef.current.offsetHeight + 16);
800
+ }, [open, placement]);
801
+ const above = placement === "above" && !flipBelow;
794
802
  return /* @__PURE__ */ jsxs6("div", { className: "relative", ref, children: [
795
803
  /* @__PURE__ */ jsxs6(
796
804
  "button",
@@ -814,7 +822,8 @@ function DateRangeFilter({
814
822
  "div",
815
823
  {
816
824
  "data-testid": testIdPrefix && `${testIdPrefix}-popover`,
817
- className: `absolute top-[calc(100%+8px)] z-30 flex overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay ${align === "right" ? "right-0" : "left-0"}`,
825
+ ref: popRef,
826
+ className: `absolute z-30 flex overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay ${placement === "right" ? "bottom-0 left-full ml-2" : `${above ? "bottom-full mb-2" : "top-[calc(100%+8px)]"} ${align === "right" ? "right-0" : "left-0"}`}`,
818
827
  role: "dialog",
819
828
  "aria-label": "Select date range",
820
829
  children: [
@@ -1375,7 +1384,7 @@ function Option({
1375
1384
  }
1376
1385
 
1377
1386
  // src/SelectFilter.tsx
1378
- import { useCallback as useCallback2, useEffect as useEffect6, useLayoutEffect, useRef as useRef7, useState as useState6 } from "react";
1387
+ import { useCallback as useCallback2, useEffect as useEffect6, useLayoutEffect as useLayoutEffect2, useRef as useRef7, useState as useState6 } from "react";
1379
1388
  import { createPortal as createPortal2 } from "react-dom";
1380
1389
  import { Check as Check5, ChevronDown as ChevronDown5 } from "lucide-react";
1381
1390
  import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
@@ -1405,7 +1414,7 @@ function SelectFilter({
1405
1414
  const r = ref.current.getBoundingClientRect();
1406
1415
  setPos({ top: r.bottom + 8, left: align === "right" ? r.right - r.width : r.left, width: r.width });
1407
1416
  }, [align]);
1408
- useLayoutEffect(() => {
1417
+ useLayoutEffect2(() => {
1409
1418
  if (!open) return;
1410
1419
  reposition();
1411
1420
  }, [open, reposition]);
@@ -1878,7 +1887,7 @@ function StackedColumnPlaceholder({
1878
1887
  }
1879
1888
 
1880
1889
  // src/Tooltip.tsx
1881
- import { useEffect as useEffect8, useId as useId3, useLayoutEffect as useLayoutEffect2, useRef as useRef9, useState as useState8 } from "react";
1890
+ import { useEffect as useEffect8, useId as useId3, useLayoutEffect as useLayoutEffect3, useRef as useRef9, useState as useState8 } from "react";
1882
1891
  import { createPortal as createPortal3 } from "react-dom";
1883
1892
  import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
1884
1893
  function cx6(...parts) {
@@ -2044,7 +2053,7 @@ function Tooltip({
2044
2053
  window.addEventListener("keydown", onKey);
2045
2054
  return () => window.removeEventListener("keydown", onKey);
2046
2055
  }, [anchor]);
2047
- useLayoutEffect2(() => {
2056
+ useLayoutEffect3(() => {
2048
2057
  if (!anchor) return;
2049
2058
  const el = boxRef.current;
2050
2059
  if (!el) return;
@@ -2185,7 +2194,7 @@ function SelectedSection({ count, open, onToggle, children, testIdPrefix }) {
2185
2194
  }
2186
2195
 
2187
2196
  // src/SelectionPicker.tsx
2188
- import { useCallback as useCallback3, useEffect as useEffect9, useLayoutEffect as useLayoutEffect3, useMemo as useMemo3, useRef as useRef10, useState as useState9 } from "react";
2197
+ import { useCallback as useCallback3, useEffect as useEffect9, useLayoutEffect as useLayoutEffect4, useMemo as useMemo3, useRef as useRef10, useState as useState9 } from "react";
2189
2198
  import { createPortal as createPortal4 } from "react-dom";
2190
2199
  import { Search as Search4, Plus, Info as Info2, ChevronRight as ChevronRight3, ChevronDown as ChevronDown8, Check as Check6, List, Loader2 } from "lucide-react";
2191
2200
  import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
@@ -2590,7 +2599,7 @@ function FilterDropdown({
2590
2599
  const [pos, setPos] = useState9(null);
2591
2600
  const searchable = filter.options.length > 8;
2592
2601
  const shownOptions = searchable && q.trim() ? filter.options.filter((o) => o.toLowerCase().includes(q.trim().toLowerCase())) : filter.options;
2593
- useLayoutEffect3(() => {
2602
+ useLayoutEffect4(() => {
2594
2603
  if (!open || !btnRef.current) return;
2595
2604
  const r = btnRef.current.getBoundingClientRect();
2596
2605
  setPos({ top: r.bottom + 6, left: r.left });
@@ -3833,6 +3842,7 @@ var SIZES2 = {
3833
3842
  sm: { track: "h-5 w-9", knob: "h-4 w-4", on: "translate-x-[18px]" },
3834
3843
  md: { track: "h-6 w-11", knob: "h-5 w-5", on: "translate-x-[22px]" }
3835
3844
  };
3845
+ var OFF_TRACK = "color-mix(in srgb, var(--mr-color-border-interactive) 70%, var(--mr-color-text-secondary))";
3836
3846
  function Toggle({ checked, onChange, label, size = "md", disabled, className, testIdPrefix }) {
3837
3847
  const s = SIZES2[size];
3838
3848
  return /* @__PURE__ */ jsx38(
@@ -3845,10 +3855,11 @@ function Toggle({ checked, onChange, label, size = "md", disabled, className, te
3845
3855
  disabled,
3846
3856
  "data-testid": testIdPrefix && `${testIdPrefix}-toggle`,
3847
3857
  onClick: () => onChange(!checked),
3858
+ style: checked ? void 0 : { backgroundColor: OFF_TRACK },
3848
3859
  className: cn(
3849
3860
  "relative inline-flex shrink-0 items-center rounded-full transition-colors focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus",
3850
3861
  s.track,
3851
- checked ? "bg-brand-primaryAction" : "bg-border-interactive",
3862
+ checked && "bg-brand-primaryAction",
3852
3863
  disabled && "cursor-not-allowed opacity-50",
3853
3864
  className
3854
3865
  ),
@@ -3903,6 +3914,30 @@ function Freshness({ level }) {
3903
3914
  }
3904
3915
  );
3905
3916
  }
3917
+
3918
+ // src/SectionHeading.tsx
3919
+ import { jsx as jsx41, jsxs as jsxs35 } from "react/jsx-runtime";
3920
+ function SectionHeading({ title, description, actions, as: Tag2 = "h2", id, className }) {
3921
+ return /* @__PURE__ */ jsxs35("div", { className: cn("flex flex-wrap items-end justify-between gap-x-4 gap-y-2", className), children: [
3922
+ /* @__PURE__ */ jsxs35("div", { className: "min-w-0", children: [
3923
+ /* @__PURE__ */ jsx41(Tag2, { id, className: "text-base font-semibold text-text-primary", children: title }),
3924
+ description && /* @__PURE__ */ jsx41("p", { className: "mt-0.5 text-dense text-text-secondary", children: description })
3925
+ ] }),
3926
+ actions && /* @__PURE__ */ jsx41("div", { className: "flex shrink-0 items-center gap-2", children: actions })
3927
+ ] });
3928
+ }
3929
+
3930
+ // src/PageHeader.tsx
3931
+ import { jsx as jsx42, jsxs as jsxs36 } from "react/jsx-runtime";
3932
+ function PageHeader({ title, description, actions, className }) {
3933
+ return /* @__PURE__ */ jsxs36("header", { className: cn("flex flex-wrap items-center justify-between gap-x-6 gap-y-3", className), children: [
3934
+ /* @__PURE__ */ jsxs36("div", { className: "min-w-0", children: [
3935
+ /* @__PURE__ */ jsx42("h1", { className: "text-xl font-semibold tracking-tight text-text-primary", children: title }),
3936
+ description && /* @__PURE__ */ jsx42("p", { className: "mt-0.5 max-w-2xl text-sm text-text-secondary", children: description })
3937
+ ] }),
3938
+ actions && /* @__PURE__ */ jsx42("div", { className: "flex shrink-0 items-center gap-2", children: actions })
3939
+ ] });
3940
+ }
3906
3941
  export {
3907
3942
  AISpark,
3908
3943
  AdvertiserNoResults,
@@ -3931,11 +3966,13 @@ export {
3931
3966
  NameListModal,
3932
3967
  NoResultsEmptyState,
3933
3968
  PRIMARY_ACTION_CLASS,
3969
+ PageHeader,
3934
3970
  Pager,
3935
3971
  PieChartPlaceholder,
3936
3972
  PublisherBreakdownList,
3937
3973
  QUIET_ACTION_CLASS,
3938
3974
  SearchBar,
3975
+ SectionHeading,
3939
3976
  SectionRail,
3940
3977
  SelectAllVisible,
3941
3978
  SelectFilter,