@teamblind-chorus/ui 1.0.1 → 1.1.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.
Files changed (105) hide show
  1. package/agents/AGENTS.md +4 -6
  2. package/agents/DESIGN.md +2 -0
  3. package/agents/LOVABLE.md +167 -373
  4. package/agents/anti-patterns.md +2 -2
  5. package/agents/catalog.md +7 -3
  6. package/agents/components/avatar-rail/avatar-rail.md +2 -0
  7. package/agents/components/badge/badge.md +2 -0
  8. package/agents/components/badge/role.md +2 -0
  9. package/agents/components/badge/update.md +2 -0
  10. package/agents/components/banner/banner.md +72 -9
  11. package/agents/components/banner/banner.spec.json +40 -2
  12. package/agents/components/bottom-sheet/bottom-sheet.md +2 -0
  13. package/agents/components/bubble/bubble.md +2 -0
  14. package/agents/components/button/button.family.json +8 -2
  15. package/agents/components/button/button.md +2 -0
  16. package/agents/components/button/check.md +2 -0
  17. package/agents/components/button/fab.md +2 -0
  18. package/agents/components/button/group.spec.json +65 -0
  19. package/agents/components/button/icon.md +2 -0
  20. package/agents/components/button/standard.md +45 -19
  21. package/agents/components/button/text.md +2 -0
  22. package/agents/components/button/toggle.md +2 -0
  23. package/agents/components/button/toolbar.md +2 -0
  24. package/agents/components/carousel/carousel.md +2 -0
  25. package/agents/components/carousel/post.md +5 -3
  26. package/agents/components/carousel/post.spec.json +4 -6
  27. package/agents/components/carousel/profile.md +4 -2
  28. package/agents/components/carousel/profile.spec.json +4 -6
  29. package/agents/components/chip/chip.md +2 -0
  30. package/agents/components/chip/filter.md +2 -0
  31. package/agents/components/chip/tag.md +2 -0
  32. package/agents/components/dialog/dialog.md +2 -0
  33. package/agents/components/directory-list/directory-list.md +2 -0
  34. package/agents/components/divider/divider.md +2 -0
  35. package/agents/components/feed/ad.md +2 -0
  36. package/agents/components/feed/feed.md +2 -0
  37. package/agents/components/feed/post.md +2 -0
  38. package/agents/components/form-field/form-field.md +3 -1
  39. package/agents/components/form-field/input.md +2 -0
  40. package/agents/components/form-field/input.spec.json +2 -1
  41. package/agents/components/form-field/search.md +2 -0
  42. package/agents/components/form-field/search.spec.json +2 -1
  43. package/agents/components/form-field/select.md +2 -0
  44. package/agents/components/form-field/textarea.md +2 -0
  45. package/agents/components/form-field/textarea.spec.json +2 -1
  46. package/agents/components/header/header.md +2 -0
  47. package/agents/components/header/main.md +2 -0
  48. package/agents/components/header/sub.md +2 -0
  49. package/agents/components/list/accordion.md +2 -0
  50. package/agents/components/list/entry.md +2 -0
  51. package/agents/components/list/entry.spec.json +2 -1
  52. package/agents/components/list/list.md +3 -1
  53. package/agents/components/list/radio.md +2 -0
  54. package/agents/components/list/standard.md +2 -0
  55. package/agents/components/list/standard.spec.json +2 -1
  56. package/agents/components/metadata/compact.md +13 -7
  57. package/agents/components/metadata/compact.spec.json +19 -6
  58. package/agents/components/metadata/metadata.family.json +3 -3
  59. package/agents/components/metadata/metadata.md +4 -2
  60. package/agents/components/metadata/standard.md +24 -0
  61. package/agents/components/nav-card/nav-card.md +2 -0
  62. package/agents/components/nav-list/nav-list.md +2 -0
  63. package/agents/components/navigation-bar/main.md +2 -0
  64. package/agents/components/navigation-bar/navigation-bar.md +2 -0
  65. package/agents/components/navigation-bar/search.md +2 -0
  66. package/agents/components/navigation-bar/sub.md +2 -0
  67. package/agents/components/page-shell/page-shell.md +2 -0
  68. package/agents/components/pagination/pagination.family.json +26 -0
  69. package/agents/components/pagination/pagination.md +40 -0
  70. package/agents/components/pagination/pagination.spec.json +54 -0
  71. package/agents/components/profile-header/profile-header.md +2 -0
  72. package/agents/components/progress/progress.md +2 -0
  73. package/agents/components/side-sheet/side-sheet.md +2 -0
  74. package/agents/components/skeleton/skeleton.md +2 -0
  75. package/agents/components/status-tag/status-tag.md +2 -0
  76. package/agents/components/suggestion-list/suggestion-list.md +2 -0
  77. package/agents/components/switch/switch.md +2 -0
  78. package/agents/components/tab-bar/tab-bar.md +2 -0
  79. package/agents/components/tabs/rounded.md +2 -0
  80. package/agents/components/tabs/segmented.md +2 -0
  81. package/agents/components/tabs/tabs.md +2 -0
  82. package/agents/components/tabs/underline.md +2 -0
  83. package/agents/components/thumbnail/thumbnail.md +2 -0
  84. package/agents/components/toast/toast.md +2 -0
  85. package/agents/components/tooltip/tooltip.md +2 -0
  86. package/agents/compose.md +3 -3
  87. package/agents/manifest.json +1 -0
  88. package/agents/patterns/README.md +2 -0
  89. package/agents/patterns/actions.md +2 -0
  90. package/agents/patterns/browsing.md +2 -0
  91. package/agents/patterns/communications.md +2 -0
  92. package/agents/patterns/layout.md +2 -0
  93. package/agents/patterns/modals.md +2 -0
  94. package/agents/patterns/visual.md +2 -0
  95. package/agents/usage.json +15 -3
  96. package/dist/index.cjs +95 -39
  97. package/dist/index.cjs.map +1 -1
  98. package/dist/index.d.cts +28 -1
  99. package/dist/index.d.ts +28 -1
  100. package/dist/index.js +94 -40
  101. package/dist/index.js.map +1 -1
  102. package/dist/styles.css +183 -41
  103. package/package.json +1 -2
  104. package/agents/reconstruct.md +0 -55
  105. package/agents/scoped-adoption.md +0 -111
package/dist/index.d.cts CHANGED
@@ -32,8 +32,14 @@ export type BadgeProps =
32
32
  // ── Banner (banner/banner) ──
33
33
  interface BannerPropsOwn {
34
34
  appearance?: "default" | "accent" | "destructive";
35
+ /** Paints a `sys.borderWidth.hairline` (1) inset stroke around the container, toned to the appearance's color family and kept deliberately faint so it reads as a soft edge of the same tint, not a frame — the subtle gray hairline (`sys.color.outlineVariant`) on `default`'s gray-tinted fill, `primary` at 40% (`color-mix(sys.color.primary, 40%)`) on `accent`'s blue-tinted fill, `error` at 40% on `destructive`. Rendered as an inset box-shadow, never a real border, so toggling it cannot change the banner's footprint (see DESIGN.md → Border & Stroke). Reach for it when the tinted fill alone doesn't separate the banner from its host surface. */
36
+ outlined?: boolean;
37
+ /** Optional heading line above the body. label.md (14 / Semibold 600) in the container's foreground, separated from the body by `sys.layout.stack.2xs` (4). Reach for it when the aside needs a scannable lead-in; omit for single-thought asides where the body carries itself. */
38
+ title?: React.ReactNode;
35
39
  /** A 16 × 16 (`sys.icon.md`) glyph at the container's leading edge. Inherits the banner's foreground (`currentColor`) so the mark reads as part of the body copy. The slot occupies the body.sm line-box height so the glyph centers on the **first line** of the body — multi-line bodies keep the icon anchored to the first-line cap, not the block center. Ignored when `thumbnail` is also passed. */
36
40
  icon?: React.ReactNode;
41
+ /** A 16 × 16 (`sys.icon.md`) glyph at the container's trailing edge, vertically centered against the whole block (`align-self: center`). Paints in `currentColor`. Reach for it when the banner leads somewhere — a forward affordance such as `ForwardCircleFillIcon` signaling the whole aside opens a destination. */
42
+ trailingIcon?: React.ReactNode;
37
43
  /** A leading visual rendered by [Thumbnail](../thumbnail/thumbnail.md) — used when the aside is anchored to a channel, author, or sub-brand image rather than to a glyph. Takes precedence over `icon`. */
38
44
  thumbnail?: React.ReactNode;
39
45
  /** { label, href? , onClick? } — a follow-through link rendered as a block child below the body. */
@@ -152,6 +158,14 @@ export type ButtonProps =
152
158
  | ButtonToggleProps
153
159
  | ButtonToolbarProps;
154
160
 
161
+ // ── ButtonGroup (button/group) ──
162
+ interface ButtonGroupPropsOwn {
163
+ variant?: "inline" | "docked";
164
+ orientation?: "horizontal" | "vertical";
165
+ label?: React.ReactNode;
166
+ }
167
+ export interface ButtonGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, keyof ButtonGroupPropsOwn>, ButtonGroupPropsOwn {}
168
+
155
169
  // ── Fab (button/fab) ──
156
170
  interface FabPropsOwn {
157
171
  variant?: "fab";
@@ -491,9 +505,11 @@ export interface MetadataStandardProps extends Omit<React.HTMLAttributes<HTMLDiv
491
505
 
492
506
  interface MetadataCompactPropsOwn {
493
507
  variant: "compact";
508
+ /** Leading [Thumbnail](../thumbnail/thumbnail.md) at `size={32}` — same prop and rung as the [Standard](standard.md) head. Forwards every Thumbnail prop verbatim (`{ src, alt }`). When omitted, the Thumbnail renders its image-area fallback over `surfaceContainerHigh`. */
509
+ avatar?: Record<string, unknown>;
494
510
  /** Array of independently-linked identity items — canonical fill is `[company name, nickname]`, the nickname canonically last, displayed bare (no @ prefix). Each entry is either a string (renders as a stub-href link) or a `{ label, href, badge }` object — `badge` is an optional SINGLE presentational mark node rendered AFTER the item's link, outside the <a> (canonical fill: Badge variant="role" on the trailing nickname item). Items separate by middot. Same grammar as the standard sub's `meta`; here it is the whole cluster, so it is required. */
495
511
  meta: React.ReactNode;
496
- /** Posting time at the line's trailing edge — plain text (never a link), preceded by a middot, in `label.sm` / `sys.color.outline` so it recedes behind the identity links. Required: the timestamp is what distinguishes a compact attribution from a bare identity row. */
512
+ /** Posting time at the line's trailing edge — plain text (never a link), in `label.sm` / `sys.color.outline` so it recedes behind the identity links. NOT preceded by a middot: the time is separated from the identity cluster by an `inline.md` (8) gap so it reads as a distinct trailing element rather than another identity item (mirrors the Standard head's name↔time treatment). Required: the timestamp is what distinguishes a compact attribution from a bare identity row. */
497
513
  timestamp: string;
498
514
  }
499
515
  export interface MetadataCompactProps extends Omit<React.HTMLAttributes<HTMLDivElement>, keyof MetadataCompactPropsOwn>, MetadataCompactPropsOwn {}
@@ -594,6 +610,15 @@ export type NavigationBarProps =
594
610
  | NavigationBarSubProps
595
611
  | NavigationBarSearchProps;
596
612
 
613
+ // ── Pagination (pagination/pagination) ──
614
+ interface PaginationPropsOwn {
615
+ /** Total number of pages — one dot renders per page. Below 2 the component renders nothing. */
616
+ count?: number;
617
+ /** Zero-based index of the active page. Clamped to `0..count-1`. Owned by the host pager (e.g. updated from an IntersectionObserver on its scroll-snap targets). */
618
+ activeIndex?: number;
619
+ }
620
+ export interface PaginationProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, keyof PaginationPropsOwn>, PaginationPropsOwn {}
621
+
597
622
  // ── ProfileHeader (profile-header/profile-header) ──
598
623
  interface ProfileHeaderPropsOwn {
599
624
  /** Entity name — channel topic, person, or company. Renders as the page-level `<h1>` at `sys.typo.heading.lg` / Semibold / `onSurface`. Single line; truncates with ellipsis at narrow widths. */
@@ -825,6 +850,7 @@ export const Banner: React.ForwardRefExoticComponent<BannerProps & React.RefAttr
825
850
  export const BottomSheet: React.ForwardRefExoticComponent<BottomSheetProps & React.RefAttributes<HTMLDivElement>>;
826
851
  export const Bubble: React.ForwardRefExoticComponent<BubbleProps & React.RefAttributes<HTMLDivElement>>;
827
852
  export const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
853
+ export const ButtonGroup: React.ForwardRefExoticComponent<ButtonGroupProps & React.RefAttributes<HTMLDivElement>>;
828
854
  export const Fab: React.ForwardRefExoticComponent<FabProps & React.RefAttributes<HTMLButtonElement>>;
829
855
  export const SuggestionList: React.ForwardRefExoticComponent<SuggestionListProps & React.RefAttributes<HTMLDivElement>>;
830
856
  export const AvatarRail: React.ForwardRefExoticComponent<AvatarRailProps & React.RefAttributes<HTMLDivElement>>;
@@ -842,6 +868,7 @@ export const Metadata: React.ForwardRefExoticComponent<MetadataProps & React.Ref
842
868
  export const NavCard: React.ForwardRefExoticComponent<NavCardProps & React.RefAttributes<HTMLButtonElement>>;
843
869
  export const NavList: React.ForwardRefExoticComponent<NavListProps & React.RefAttributes<HTMLElement>>;
844
870
  export const NavigationBar: React.ForwardRefExoticComponent<NavigationBarProps & React.RefAttributes<HTMLElement>>;
871
+ export const Pagination: React.ForwardRefExoticComponent<PaginationProps & React.RefAttributes<HTMLSpanElement>>;
845
872
  export const ProfileHeader: React.ForwardRefExoticComponent<ProfileHeaderProps & React.RefAttributes<HTMLElement>>;
846
873
  export const Progress: React.ForwardRefExoticComponent<ProgressProps & React.RefAttributes<HTMLDivElement>>;
847
874
  export const PostCarousel: React.ForwardRefExoticComponent<PostCarouselProps & React.RefAttributes<HTMLDivElement>>;
package/dist/index.d.ts CHANGED
@@ -32,8 +32,14 @@ export type BadgeProps =
32
32
  // ── Banner (banner/banner) ──
33
33
  interface BannerPropsOwn {
34
34
  appearance?: "default" | "accent" | "destructive";
35
+ /** Paints a `sys.borderWidth.hairline` (1) inset stroke around the container, toned to the appearance's color family and kept deliberately faint so it reads as a soft edge of the same tint, not a frame — the subtle gray hairline (`sys.color.outlineVariant`) on `default`'s gray-tinted fill, `primary` at 40% (`color-mix(sys.color.primary, 40%)`) on `accent`'s blue-tinted fill, `error` at 40% on `destructive`. Rendered as an inset box-shadow, never a real border, so toggling it cannot change the banner's footprint (see DESIGN.md → Border & Stroke). Reach for it when the tinted fill alone doesn't separate the banner from its host surface. */
36
+ outlined?: boolean;
37
+ /** Optional heading line above the body. label.md (14 / Semibold 600) in the container's foreground, separated from the body by `sys.layout.stack.2xs` (4). Reach for it when the aside needs a scannable lead-in; omit for single-thought asides where the body carries itself. */
38
+ title?: React.ReactNode;
35
39
  /** A 16 × 16 (`sys.icon.md`) glyph at the container's leading edge. Inherits the banner's foreground (`currentColor`) so the mark reads as part of the body copy. The slot occupies the body.sm line-box height so the glyph centers on the **first line** of the body — multi-line bodies keep the icon anchored to the first-line cap, not the block center. Ignored when `thumbnail` is also passed. */
36
40
  icon?: React.ReactNode;
41
+ /** A 16 × 16 (`sys.icon.md`) glyph at the container's trailing edge, vertically centered against the whole block (`align-self: center`). Paints in `currentColor`. Reach for it when the banner leads somewhere — a forward affordance such as `ForwardCircleFillIcon` signaling the whole aside opens a destination. */
42
+ trailingIcon?: React.ReactNode;
37
43
  /** A leading visual rendered by [Thumbnail](../thumbnail/thumbnail.md) — used when the aside is anchored to a channel, author, or sub-brand image rather than to a glyph. Takes precedence over `icon`. */
38
44
  thumbnail?: React.ReactNode;
39
45
  /** { label, href? , onClick? } — a follow-through link rendered as a block child below the body. */
@@ -152,6 +158,14 @@ export type ButtonProps =
152
158
  | ButtonToggleProps
153
159
  | ButtonToolbarProps;
154
160
 
161
+ // ── ButtonGroup (button/group) ──
162
+ interface ButtonGroupPropsOwn {
163
+ variant?: "inline" | "docked";
164
+ orientation?: "horizontal" | "vertical";
165
+ label?: React.ReactNode;
166
+ }
167
+ export interface ButtonGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, keyof ButtonGroupPropsOwn>, ButtonGroupPropsOwn {}
168
+
155
169
  // ── Fab (button/fab) ──
156
170
  interface FabPropsOwn {
157
171
  variant?: "fab";
@@ -491,9 +505,11 @@ export interface MetadataStandardProps extends Omit<React.HTMLAttributes<HTMLDiv
491
505
 
492
506
  interface MetadataCompactPropsOwn {
493
507
  variant: "compact";
508
+ /** Leading [Thumbnail](../thumbnail/thumbnail.md) at `size={32}` — same prop and rung as the [Standard](standard.md) head. Forwards every Thumbnail prop verbatim (`{ src, alt }`). When omitted, the Thumbnail renders its image-area fallback over `surfaceContainerHigh`. */
509
+ avatar?: Record<string, unknown>;
494
510
  /** Array of independently-linked identity items — canonical fill is `[company name, nickname]`, the nickname canonically last, displayed bare (no @ prefix). Each entry is either a string (renders as a stub-href link) or a `{ label, href, badge }` object — `badge` is an optional SINGLE presentational mark node rendered AFTER the item's link, outside the <a> (canonical fill: Badge variant="role" on the trailing nickname item). Items separate by middot. Same grammar as the standard sub's `meta`; here it is the whole cluster, so it is required. */
495
511
  meta: React.ReactNode;
496
- /** Posting time at the line's trailing edge — plain text (never a link), preceded by a middot, in `label.sm` / `sys.color.outline` so it recedes behind the identity links. Required: the timestamp is what distinguishes a compact attribution from a bare identity row. */
512
+ /** Posting time at the line's trailing edge — plain text (never a link), in `label.sm` / `sys.color.outline` so it recedes behind the identity links. NOT preceded by a middot: the time is separated from the identity cluster by an `inline.md` (8) gap so it reads as a distinct trailing element rather than another identity item (mirrors the Standard head's name↔time treatment). Required: the timestamp is what distinguishes a compact attribution from a bare identity row. */
497
513
  timestamp: string;
498
514
  }
499
515
  export interface MetadataCompactProps extends Omit<React.HTMLAttributes<HTMLDivElement>, keyof MetadataCompactPropsOwn>, MetadataCompactPropsOwn {}
@@ -594,6 +610,15 @@ export type NavigationBarProps =
594
610
  | NavigationBarSubProps
595
611
  | NavigationBarSearchProps;
596
612
 
613
+ // ── Pagination (pagination/pagination) ──
614
+ interface PaginationPropsOwn {
615
+ /** Total number of pages — one dot renders per page. Below 2 the component renders nothing. */
616
+ count?: number;
617
+ /** Zero-based index of the active page. Clamped to `0..count-1`. Owned by the host pager (e.g. updated from an IntersectionObserver on its scroll-snap targets). */
618
+ activeIndex?: number;
619
+ }
620
+ export interface PaginationProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, keyof PaginationPropsOwn>, PaginationPropsOwn {}
621
+
597
622
  // ── ProfileHeader (profile-header/profile-header) ──
598
623
  interface ProfileHeaderPropsOwn {
599
624
  /** Entity name — channel topic, person, or company. Renders as the page-level `<h1>` at `sys.typo.heading.lg` / Semibold / `onSurface`. Single line; truncates with ellipsis at narrow widths. */
@@ -825,6 +850,7 @@ export const Banner: React.ForwardRefExoticComponent<BannerProps & React.RefAttr
825
850
  export const BottomSheet: React.ForwardRefExoticComponent<BottomSheetProps & React.RefAttributes<HTMLDivElement>>;
826
851
  export const Bubble: React.ForwardRefExoticComponent<BubbleProps & React.RefAttributes<HTMLDivElement>>;
827
852
  export const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
853
+ export const ButtonGroup: React.ForwardRefExoticComponent<ButtonGroupProps & React.RefAttributes<HTMLDivElement>>;
828
854
  export const Fab: React.ForwardRefExoticComponent<FabProps & React.RefAttributes<HTMLButtonElement>>;
829
855
  export const SuggestionList: React.ForwardRefExoticComponent<SuggestionListProps & React.RefAttributes<HTMLDivElement>>;
830
856
  export const AvatarRail: React.ForwardRefExoticComponent<AvatarRailProps & React.RefAttributes<HTMLDivElement>>;
@@ -842,6 +868,7 @@ export const Metadata: React.ForwardRefExoticComponent<MetadataProps & React.Ref
842
868
  export const NavCard: React.ForwardRefExoticComponent<NavCardProps & React.RefAttributes<HTMLButtonElement>>;
843
869
  export const NavList: React.ForwardRefExoticComponent<NavListProps & React.RefAttributes<HTMLElement>>;
844
870
  export const NavigationBar: React.ForwardRefExoticComponent<NavigationBarProps & React.RefAttributes<HTMLElement>>;
871
+ export const Pagination: React.ForwardRefExoticComponent<PaginationProps & React.RefAttributes<HTMLSpanElement>>;
845
872
  export const ProfileHeader: React.ForwardRefExoticComponent<ProfileHeaderProps & React.RefAttributes<HTMLElement>>;
846
873
  export const Progress: React.ForwardRefExoticComponent<ProgressProps & React.RefAttributes<HTMLDivElement>>;
847
874
  export const PostCarousel: React.ForwardRefExoticComponent<PostCarouselProps & React.RefAttributes<HTMLDivElement>>;
package/dist/index.js CHANGED
@@ -235,9 +235,12 @@ function useFullBleedGuard(ref, name) {
235
235
  }
236
236
  function Banner({
237
237
  appearance = "default",
238
+ outlined = false,
239
+ title,
238
240
  icon,
239
241
  thumbnail,
240
242
  action,
243
+ trailingIcon,
241
244
  children,
242
245
  className,
243
246
  ...rest
@@ -248,13 +251,19 @@ function Banner({
248
251
  "div",
249
252
  {
250
253
  ref,
251
- className: joinClasses("chorus-banner", `chorus-banner--${appearance}`, className),
254
+ className: joinClasses(
255
+ "chorus-banner",
256
+ `chorus-banner--${appearance}`,
257
+ outlined && "chorus-banner--outlined",
258
+ className
259
+ ),
252
260
  role: "note",
253
261
  ...rest,
254
262
  children: [
255
263
  thumbnail ? /* @__PURE__ */ jsx("span", { className: "chorus-banner__thumbnail", "aria-hidden": "true", children: thumbnail }) : null,
256
264
  !thumbnail && icon ? /* @__PURE__ */ jsx("span", { className: "chorus-banner__icon", "aria-hidden": "true", children: icon }) : null,
257
265
  /* @__PURE__ */ jsxs("div", { className: "chorus-banner__content", children: [
266
+ title ? /* @__PURE__ */ jsx("p", { className: "chorus-banner__title", children: title }) : null,
258
267
  children ? /* @__PURE__ */ jsx("p", { className: "chorus-banner__body", children }) : null,
259
268
  action ? /* @__PURE__ */ jsx(
260
269
  "a",
@@ -265,7 +274,8 @@ function Banner({
265
274
  children: action.label
266
275
  }
267
276
  ) : null
268
- ] })
277
+ ] }),
278
+ trailingIcon ? /* @__PURE__ */ jsx("span", { className: "chorus-banner__trailing-icon", "aria-hidden": "true", children: trailingIcon }) : null
269
279
  ]
270
280
  }
271
281
  );
@@ -1845,7 +1855,7 @@ var FORCEABLE_STATES3 = /* @__PURE__ */ new Set(["hovered", "pressed", "focused"
1845
1855
  var SPECS = {
1846
1856
  filter: filter_spec_default,
1847
1857
  tag: tag_spec_default,
1848
- "toggle": toggle_spec_default
1858
+ toggle: toggle_spec_default
1849
1859
  };
1850
1860
  function pickAppearance(spec, appearance) {
1851
1861
  const appearances = spec.appearances || {};
@@ -1987,11 +1997,11 @@ function ButtonToggle({ active = false, ...rest }) {
1987
1997
  }
1988
1998
  var VARIANTS = {
1989
1999
  fab: ButtonFab,
1990
- "icon": ButtonIcon,
1991
- "text": ButtonText,
1992
- "check": ButtonCheck,
1993
- "toolbar": ButtonToolbar,
1994
- "toggle": ButtonToggle
2000
+ icon: ButtonIcon,
2001
+ text: ButtonText,
2002
+ check: ButtonCheck,
2003
+ toolbar: ButtonToolbar,
2004
+ toggle: ButtonToggle
1995
2005
  };
1996
2006
  var Button = forwardRef(function Button2({ variant, ...rest }, ref) {
1997
2007
  const Impl = variant && VARIANTS[variant] || ButtonStandard;
@@ -2153,6 +2163,35 @@ function Bubble({
2153
2163
  }
2154
2164
  );
2155
2165
  }
2166
+ function ButtonGroup({
2167
+ variant = "inline",
2168
+ orientation = "horizontal",
2169
+ label,
2170
+ children,
2171
+ className,
2172
+ "aria-label": ariaLabel,
2173
+ ...rest
2174
+ }) {
2175
+ const docked = variant === "docked";
2176
+ return /* @__PURE__ */ jsxs(
2177
+ "div",
2178
+ {
2179
+ className: joinClasses(
2180
+ "chorus-button-group",
2181
+ docked && "chorus-button-group--docked",
2182
+ orientation === "vertical" && "chorus-button-group--vertical",
2183
+ className
2184
+ ),
2185
+ role: "group",
2186
+ "aria-label": ariaLabel,
2187
+ ...rest,
2188
+ children: [
2189
+ label != null ? /* @__PURE__ */ jsx("div", { className: "chorus-button-group__label", children: label }) : null,
2190
+ /* @__PURE__ */ jsx("div", { className: "chorus-button-group__row", children })
2191
+ ]
2192
+ }
2193
+ );
2194
+ }
2156
2195
 
2157
2196
  // ../../schema/components/header/main.spec.json
2158
2197
  var main_spec_default = {
@@ -2313,6 +2352,7 @@ function EntryRow({
2313
2352
  "span",
2314
2353
  {
2315
2354
  className: "chorus-entry-row__trailing",
2355
+ "data-nested-action": "",
2316
2356
  onClick: (e) => e.stopPropagation(),
2317
2357
  onKeyDown: (e) => e.stopPropagation(),
2318
2358
  children: trailing
@@ -2434,6 +2474,7 @@ function List({
2434
2474
  "span",
2435
2475
  {
2436
2476
  className: "chorus-list__trailing",
2477
+ "data-nested-action": "",
2437
2478
  onClick: (e) => e.stopPropagation(),
2438
2479
  onKeyDown: (e) => e.stopPropagation(),
2439
2480
  children: item.trailingIcon
@@ -3187,13 +3228,13 @@ function Metadata({
3187
3228
  const hasMeta = Array.isArray(meta) && meta.length > 0;
3188
3229
  const hasSubtitle = !hasMeta && subtitle != null && subtitle !== "";
3189
3230
  if (variant === "compact") {
3190
- return /* @__PURE__ */ jsx("div", { className: joinClasses("chorus-metadata", "chorus-metadata--compact", className), ...rest, children: /* @__PURE__ */ jsxs("div", { className: "chorus-metadata__meta", children: [
3191
- hasMeta ? metaParts(meta) : null,
3192
- timestamp ? /* @__PURE__ */ jsxs(Fragment, { children: [
3193
- /* @__PURE__ */ jsx("span", { className: "chorus-metadata__dot", "aria-hidden": "true", children: "\xB7" }),
3194
- /* @__PURE__ */ jsx("span", { className: "chorus-metadata__timestamp", children: timestamp })
3195
- ] }) : null
3196
- ] }) });
3231
+ return /* @__PURE__ */ jsxs("div", { className: joinClasses("chorus-metadata", "chorus-metadata--compact", className), ...rest, children: [
3232
+ avatar ? /* @__PURE__ */ jsx(Thumbnail, { size: 32, ...avatar }) : null,
3233
+ /* @__PURE__ */ jsxs("div", { className: "chorus-metadata__meta", children: [
3234
+ hasMeta ? metaParts(meta) : null,
3235
+ timestamp ? /* @__PURE__ */ jsx("span", { className: "chorus-metadata__timestamp", children: timestamp }) : null
3236
+ ] })
3237
+ ] });
3197
3238
  }
3198
3239
  return /* @__PURE__ */ jsxs("div", { className: joinClasses("chorus-metadata", className), ...rest, children: [
3199
3240
  /* @__PURE__ */ jsx(Thumbnail, { size: 32, ...avatar ?? { alt: typeof name === "string" ? name : "" } }),
@@ -3484,6 +3525,33 @@ function FeedAd({
3484
3525
  ) : null
3485
3526
  ] });
3486
3527
  }
3528
+ function Pagination({
3529
+ count = 0,
3530
+ activeIndex = 0,
3531
+ className,
3532
+ ...rest
3533
+ }) {
3534
+ if (count < 2) return null;
3535
+ const active = Math.max(0, Math.min(count - 1, activeIndex));
3536
+ return /* @__PURE__ */ jsx(
3537
+ "span",
3538
+ {
3539
+ className: joinClasses("chorus-pagination", className),
3540
+ "aria-hidden": "true",
3541
+ ...rest,
3542
+ children: Array.from({ length: count }, (_, idx) => /* @__PURE__ */ jsx(
3543
+ "span",
3544
+ {
3545
+ className: joinClasses(
3546
+ "chorus-pagination__dot",
3547
+ idx === active && "chorus-pagination__dot--active"
3548
+ )
3549
+ },
3550
+ idx
3551
+ ))
3552
+ }
3553
+ );
3554
+ }
3487
3555
  var MAX_CARDS = 5;
3488
3556
  function PostCarousel({
3489
3557
  items = [],
@@ -3544,16 +3612,7 @@ function PostCarousel({
3544
3612
  ))
3545
3613
  }
3546
3614
  ),
3547
- cards.length > 1 ? /* @__PURE__ */ jsx("div", { className: "chorus-post-carousel__pagination", "aria-hidden": "true", children: cards.map((_, idx) => /* @__PURE__ */ jsx(
3548
- "span",
3549
- {
3550
- className: joinClasses(
3551
- "chorus-post-carousel__dot",
3552
- idx === activeIndex && "chorus-post-carousel__dot--active"
3553
- )
3554
- },
3555
- idx
3556
- )) }) : null
3615
+ /* @__PURE__ */ jsx(Pagination, { count: cards.length, activeIndex })
3557
3616
  ]
3558
3617
  }
3559
3618
  );
@@ -3704,16 +3763,7 @@ function ProfileCarousel({
3704
3763
  ))
3705
3764
  }
3706
3765
  ),
3707
- cards.length > 1 ? /* @__PURE__ */ jsx("div", { className: "chorus-profile-carousel__pagination", "aria-hidden": "true", children: cards.map((_, idx) => /* @__PURE__ */ jsx(
3708
- "span",
3709
- {
3710
- className: joinClasses(
3711
- "chorus-profile-carousel__dot",
3712
- idx === activeIndex && "chorus-profile-carousel__dot--active"
3713
- )
3714
- },
3715
- idx
3716
- )) }) : null
3766
+ /* @__PURE__ */ jsx(Pagination, { count: cards.length, activeIndex })
3717
3767
  ]
3718
3768
  }
3719
3769
  );
@@ -4317,7 +4367,8 @@ var input_spec_default = {
4317
4367
  overlay: {
4318
4368
  color: "text",
4319
4369
  opacity: "sys.state.pressed"
4320
- }
4370
+ },
4371
+ nestedActionScope: "The pressed overlay (and hover stroke) is suppressed while the pointer presses / hovers the trailing clear button \u2014 that '\xD7' is an independent nested action, so the small control owns the state and the large field does not also read as pressed. The visual-state boundary matches the action boundary."
4321
4372
  },
4322
4373
  active: {
4323
4374
  overlay: null,
@@ -4503,7 +4554,8 @@ var textarea_spec_default = {
4503
4554
  hovered: { overlay: null, border: "borderHover" },
4504
4555
  pressed: {
4505
4556
  border: "borderHover",
4506
- overlay: { color: "text", opacity: "sys.state.pressed" }
4557
+ overlay: { color: "text", opacity: "sys.state.pressed" },
4558
+ nestedActionScope: "The pressed overlay (and hover stroke) is suppressed while the pointer presses / hovers the trailing clear button \u2014 that '\xD7' is an independent nested action, so the small control owns the state and the large field does not also read as pressed. The visual-state boundary matches the action boundary."
4507
4559
  },
4508
4560
  active: {
4509
4561
  overlay: null,
@@ -4640,7 +4692,8 @@ var search_spec_default = {
4640
4692
  overlay: {
4641
4693
  color: "text",
4642
4694
  opacity: "sys.state.pressed"
4643
- }
4695
+ },
4696
+ nestedActionScope: "The pressed overlay (and hover stroke) is suppressed while the pointer presses / hovers the trailing clear button \u2014 that '\xD7' is an independent nested action, so the small control owns the state and the large field does not also read as pressed. The visual-state boundary matches the action boundary."
4644
4697
  },
4645
4698
  active: {
4646
4699
  overlay: null,
@@ -5011,6 +5064,7 @@ function FormFieldBox({
5011
5064
  {
5012
5065
  type: "button",
5013
5066
  className: "chorus-field__clear",
5067
+ "data-nested-action": "",
5014
5068
  "aria-label": "Clear",
5015
5069
  onClick: handleClear,
5016
5070
  children: /* @__PURE__ */ jsx(XCircleFillIcon, {})
@@ -5105,7 +5159,7 @@ var FormFieldSelect = Select;
5105
5159
  var VARIANTS3 = {
5106
5160
  input: FormFieldInput,
5107
5161
  textarea: FormFieldTextarea,
5108
- "search": FormFieldSearchBar,
5162
+ search: FormFieldSearchBar,
5109
5163
  select: FormFieldSelect
5110
5164
  };
5111
5165
  function FormField({ variant = "input", ...rest }) {
@@ -5842,6 +5896,6 @@ function Tooltip({
5842
5896
  );
5843
5897
  }
5844
5898
 
5845
- export { Accordion, Banner as Alert, NavigationBar as AppBar, Thumbnail as Avatar, AvatarRail, Badge, Banner, TabBar as BottomNav, BottomSheet, Bubble, Button, Carousel, SuggestionList as ChannelList, AvatarRail as ChannelRail, Chip, Dialog, DirectoryList, Divider, BottomSheet as Drawer, Feed, FeedAd, FeedGroup, FormField, FormFieldGroup, Header, Input, List, Metadata, NavCard, NavCardGroup, NavList, NavigationBar, PageShell, PostCarousel, ProfileCarousel, ProfileHeader, Progress, SearchBar2 as SearchBar, Carousel as Section, Select, BottomSheet as Sheet, SideSheet as SideDrawer, SideSheet, SideSheetGroup, Skeleton, SkeletonGroup, StatusTag, SubHeader, SuggestionList, Switch, Tab, TabBar, Tabs, Textarea, Thumbnail, Toast, Tooltip };
5899
+ export { Accordion, Banner as Alert, NavigationBar as AppBar, Thumbnail as Avatar, AvatarRail, Badge, Banner, TabBar as BottomNav, BottomSheet, Bubble, Button, ButtonGroup, Carousel, SuggestionList as ChannelList, AvatarRail as ChannelRail, Chip, Dialog, DirectoryList, Divider, BottomSheet as Drawer, Feed, FeedAd, FeedGroup, FormField, FormFieldGroup, Header, Input, List, Metadata, NavCard, NavCardGroup, NavList, NavigationBar, PageShell, Pagination, PostCarousel, ProfileCarousel, ProfileHeader, Progress, SearchBar2 as SearchBar, Carousel as Section, Select, BottomSheet as Sheet, SideSheet as SideDrawer, SideSheet, SideSheetGroup, Skeleton, SkeletonGroup, StatusTag, SubHeader, SuggestionList, Switch, Tab, TabBar, Tabs, Textarea, Thumbnail, Toast, Tooltip };
5846
5900
  //# sourceMappingURL=index.js.map
5847
5901
  //# sourceMappingURL=index.js.map