@teamblind-chorus/ui 1.1.0 → 1.2.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 (46) hide show
  1. package/agents/catalog.md +6 -4
  2. package/agents/components/avatar-rail/avatar-rail.spec.json +19 -0
  3. package/agents/components/banner/banner.family.json +3 -1
  4. package/agents/components/banner/banner.md +54 -1
  5. package/agents/components/banner/banner.spec.json +24 -1
  6. package/agents/components/button/check.spec.json +19 -0
  7. package/agents/components/button/fab.spec.json +19 -0
  8. package/agents/components/button/icon.spec.json +19 -0
  9. package/agents/components/button/standard.spec.json +19 -0
  10. package/agents/components/button/text.spec.json +19 -0
  11. package/agents/components/button/toggle.spec.json +19 -0
  12. package/agents/components/chip/filter.spec.json +19 -0
  13. package/agents/components/chip/tag.spec.json +19 -0
  14. package/agents/components/empty-state/empty-state.family.json +28 -0
  15. package/agents/components/empty-state/empty-state.md +69 -0
  16. package/agents/components/empty-state/empty-state.spec.json +87 -0
  17. package/agents/components/form-field/input.spec.json +8 -1
  18. package/agents/components/form-field/search.spec.json +8 -1
  19. package/agents/components/form-field/select.spec.json +9 -1
  20. package/agents/components/form-field/textarea.spec.json +8 -1
  21. package/agents/components/list/accordion.spec.json +9 -0
  22. package/agents/components/list/entry.spec.json +19 -0
  23. package/agents/components/list/radio.spec.json +19 -0
  24. package/agents/components/list/standard.md +46 -0
  25. package/agents/components/list/standard.spec.json +37 -2
  26. package/agents/components/nav-card/nav-card.spec.json +9 -0
  27. package/agents/components/page-shell/page-shell.family.json +1 -1
  28. package/agents/components/page-shell/page-shell.md +33 -0
  29. package/agents/components/page-shell/page-shell.spec.json +85 -0
  30. package/agents/components/spinner/spinner.family.json +27 -0
  31. package/agents/components/spinner/spinner.md +98 -0
  32. package/agents/components/spinner/spinner.spec.json +82 -0
  33. package/agents/components/switch/switch.spec.json +9 -0
  34. package/agents/components/tab-bar/tab-bar.spec.json +16 -0
  35. package/agents/components/tabs/rounded.spec.json +19 -0
  36. package/agents/components/tabs/underline.spec.json +19 -0
  37. package/agents/manifest.json +8 -6
  38. package/agents/usage.json +12 -0
  39. package/dist/index.cjs +340 -60
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +46 -2
  42. package/dist/index.d.ts +46 -2
  43. package/dist/index.js +339 -61
  44. package/dist/index.js.map +1 -1
  45. package/dist/styles.css +182 -0
  46. package/package.json +1 -1
package/dist/styles.css CHANGED
@@ -2615,6 +2615,31 @@ a.chorus-metadata__name:focus-visible {
2615
2615
  margin-left: var(--sys-layout-inline-md);
2616
2616
  }
2617
2617
 
2618
+ /* Embedded-Banner row — a Standard row whose text group stacks over a
2619
+ Banner that spans the row's full content width. The row flips from a
2620
+ single horizontal line to a vertical stack: the normal leading + label
2621
+ + trailing line (`__row-main`) sits on top, the Banner `stack.xs` (8)
2622
+ below it. The stack fills the row's content box so the Banner aligns to
2623
+ the same 16px inline inset as the text group above it. The Banner owns
2624
+ its own tinted fill / radius / padding; the slot only spaces it and
2625
+ marks it a nested-action region (its controls never commit the row). */
2626
+ .chorus-list__stack {
2627
+ display: flex;
2628
+ flex-direction: column;
2629
+ gap: var(--sys-layout-stack-xs);
2630
+ flex: 1 1 auto;
2631
+ min-width: 0;
2632
+ }
2633
+
2634
+ .chorus-list__row-main {
2635
+ display: flex;
2636
+ align-items: center;
2637
+ }
2638
+
2639
+ .chorus-list__banner {
2640
+ display: block;
2641
+ }
2642
+
2618
2643
  /* Entry variant — directory-entry row with selectable leading Thumbnail
2619
2644
  (32 / 40 / 48 / 56 via `data-size="small|medium|large|xlarge"`), an
2620
2645
  identity group (label + optional inline count Badge + optional stacked
@@ -3278,6 +3303,65 @@ a.chorus-metadata__name:focus-visible {
3278
3303
  rule already excludes `[data-divider="false"]`, so no extra CSS
3279
3304
  is needed to hide it here. */
3280
3305
 
3306
+ /* ============================================================
3307
+ EmptyState — centered no-data composition. Painted inside the
3308
+ surface that would otherwise hold the data: an optional monochrome
3309
+ illustration, a required headline, optional body copy, and an
3310
+ optional primary-Button CTA. Ships no surface fill of its own —
3311
+ the host supplies the surface tier and the bounding box; EmptyState
3312
+ only centers its column inside it. Inter-slot rhythm follows the
3313
+ stack tokens (illustration→headline 12, headline→body 4, body→CTA
3314
+ 16). Distinct from Skeleton (an in-flight loading placeholder).
3315
+ ============================================================ */
3316
+ .chorus-empty-state {
3317
+ display: flex;
3318
+ flex-direction: column;
3319
+ align-items: center;
3320
+ text-align: center;
3321
+ }
3322
+
3323
+ /* Optional illustration — a glyph / illustration sized to a 48-box
3324
+ (larger than `sys.icon.lg`, realizing the 'icon.xl or larger' intent
3325
+ since no `sys.icon.xl` rung exists), painted monochrome in
3326
+ `onSurfaceVariant` via `currentColor` so it reads as quiet chrome,
3327
+ not a brand moment. 12 below it to the headline. */
3328
+ .chorus-empty-state__illustration {
3329
+ display: inline-flex;
3330
+ align-items: center;
3331
+ justify-content: center;
3332
+ width: var(--empty-state-illustration-size);
3333
+ height: var(--empty-state-illustration-size);
3334
+ margin-bottom: var(--empty-state-illustration-gap);
3335
+ color: var(--empty-state-illustration-color);
3336
+ }
3337
+
3338
+ .chorus-empty-state__illustration img,
3339
+ .chorus-empty-state__illustration svg {
3340
+ width: var(--empty-state-illustration-size);
3341
+ height: var(--empty-state-illustration-size);
3342
+ display: block;
3343
+ color: currentColor;
3344
+ }
3345
+
3346
+ /* Required headline — heading.sm in `onSurface`. Typography vars are
3347
+ emitted inline by the React file (typoStyles). */
3348
+ .chorus-empty-state__headline {
3349
+ margin: 0;
3350
+ color: var(--empty-state-headline-color);
3351
+ }
3352
+
3353
+ /* Optional body — body.sm in `onSurfaceVariant`, 4 below the headline. */
3354
+ .chorus-empty-state__body {
3355
+ margin: 0;
3356
+ margin-top: var(--empty-state-body-gap);
3357
+ color: var(--empty-state-body-color);
3358
+ }
3359
+
3360
+ /* Optional CTA — a default-size primary Button, 16 below the body. */
3361
+ .chorus-empty-state__action {
3362
+ margin-top: var(--empty-state-action-gap);
3363
+ }
3364
+
3281
3365
  /* ============================================================
3282
3366
  Banner — in-body explanation block (info / neutral)
3283
3367
  ============================================================ */
@@ -3417,6 +3501,21 @@ a.chorus-metadata__name:focus-visible {
3417
3501
  color: var(--sys-color-primary);
3418
3502
  }
3419
3503
 
3504
+ /* neutral-body — keeps the `accent` fill but lays the Default
3505
+ appearance's neutral foreground over it: title + body re-tone to
3506
+ `onSurface` (quiet, high-legibility body copy) while the action
3507
+ steps to `primary`, exactly as on `default`. The accent tint still
3508
+ pulls the eye; the text just stops shouting in the primary family.
3509
+ Only meaningful combined with `--accent` (default is already
3510
+ `onSurface`; destructive must carry the warning tone through copy). */
3511
+ .chorus-banner--accent.chorus-banner--neutral-body {
3512
+ color: var(--sys-color-onSurface);
3513
+ }
3514
+
3515
+ .chorus-banner--accent.chorus-banner--neutral-body .chorus-banner__action {
3516
+ color: var(--sys-color-primary);
3517
+ }
3518
+
3420
3519
  /* Trailing icon slot — a 16 × 16 glyph (`sys.icon.md`) at the trailing
3421
3520
  edge, vertically centered against the whole block (`align-self:
3422
3521
  center` overrides the container's flex-start). Paints in the
@@ -3439,6 +3538,23 @@ a.chorus-metadata__name:focus-visible {
3439
3538
  color: currentColor;
3440
3539
  }
3441
3540
 
3541
+ /* Trailing action slot — hosts an inline Text Button (`<Button
3542
+ variant="text">`) at the trailing edge, vertically centered against
3543
+ the whole block (`align-self: center` overrides the container's
3544
+ flex-start) and footprint-preserving (`flex: 0 0 auto`). The Button
3545
+ owns its own size + appearance per the button/text spec; by default
3546
+ pick the appearance whose color family matches the banner fill
3547
+ (accent → accent, default → default, destructive → destructive
3548
+ flavor) so the commit reads as part of the tinted block. Unlike the
3549
+ trailing icon it is a real interactive control, so it is not
3550
+ aria-hidden. The Text Button's optical-alignment margin lets its
3551
+ visible label sit flush against the container's trailing padding. */
3552
+ .chorus-banner__trailing-action {
3553
+ flex: 0 0 auto;
3554
+ align-self: center;
3555
+ display: inline-flex;
3556
+ }
3557
+
3442
3558
  /* ============================================================
3443
3559
  Divider — section-break band between adjacent regions that
3444
3560
  don't share an enclosing container. Single full-bleed block
@@ -5505,6 +5621,72 @@ a.chorus-metadata__name:focus-visible {
5505
5621
  }
5506
5622
  }
5507
5623
 
5624
+ /* ============================================================
5625
+ Spinner — indeterminate rotating-arc loading indicator
5626
+ ============================================================ */
5627
+ /* A rotating ring for short, progress-unknown waits (< ~1s) on a
5628
+ neutral host surface. The arc paints `sys.color.primary` as the
5629
+ foreground motion over a faint `sys.color.scrimSubtle` track ring
5630
+ (inverse-tone ~8% tint) so the rotation reads on any surface tier.
5631
+ The ring is drawn with a conic gradient masked to an annulus — no
5632
+ `border:` (per the no-layout-strokes rule). Diameter rides the
5633
+ icon.* ladder via the `--spinner-diameter` plumbing var (sys.icon.lg
5634
+ medium / sys.icon.md small). Rotation modulates position, not
5635
+ luminance, and is suppressed under `prefers-reduced-motion: reduce`,
5636
+ leaving the full ring static as a quiet loading mark. */
5637
+ @keyframes chorus-spinner-rotate {
5638
+ to { transform: rotate(360deg); }
5639
+ }
5640
+
5641
+ .chorus-spinner {
5642
+ display: inline-flex;
5643
+ align-items: center;
5644
+ gap: var(--spinner-gap);
5645
+ }
5646
+
5647
+ .chorus-spinner__arc {
5648
+ display: block;
5649
+ flex: none;
5650
+ width: var(--spinner-diameter);
5651
+ height: var(--spinner-diameter);
5652
+ border-radius: var(--sys-radius-full);
5653
+ /* Foreground arc sweeps from primary to transparent over the track. */
5654
+ background:
5655
+ conic-gradient(var(--sys-color-primary), color-mix(in srgb, var(--sys-color-primary) 0%, transparent) 75%, color-mix(in srgb, var(--sys-color-primary) 0%, transparent));
5656
+ /* Annulus mask: punch out the centre so it reads as a ring, 2px thick.
5657
+ The mask fill is alpha-only — the opaque keep-region of the mask is
5658
+ not a design color, so it is not a token binding. */
5659
+ /* chorus-token-exempt */
5660
+ -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
5661
+ /* chorus-token-exempt */
5662
+ mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
5663
+ animation: chorus-spinner-rotate 0.8s linear infinite;
5664
+ }
5665
+
5666
+ /* Faint full track ring under the rotating arc, painted via box-shadow
5667
+ inset so the bare ring stays visible on any surface tier. */
5668
+ .chorus-spinner__arc::before {
5669
+ content: '';
5670
+ position: absolute;
5671
+ inset: 0;
5672
+ border-radius: inherit;
5673
+ box-shadow: inset 0 0 0 2px var(--sys-color-scrimSubtle);
5674
+ }
5675
+
5676
+ .chorus-spinner__arc {
5677
+ position: relative;
5678
+ }
5679
+
5680
+ .chorus-spinner__label {
5681
+ color: var(--sys-color-onSurfaceVariant);
5682
+ }
5683
+
5684
+ @media (prefers-reduced-motion: reduce) {
5685
+ .chorus-spinner__arc {
5686
+ animation: none;
5687
+ }
5688
+ }
5689
+
5508
5690
  /* ============================================================
5509
5691
  Switch — binary active/inactive pill with translating thumb
5510
5692
  ============================================================ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamblind-chorus/ui",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Chorus React components. Ships prebuilt ESM + CJS bundles (`dist/`) and a single `styles.css`; import `@teamblind-chorus/tokens/tokens.css` + `@teamblind-chorus/ui/styles.css` once at the app entry. The contract every component honors lives in schema/components/<family>/<sub>.spec.json; see schema/manifest.json for the inventory.",
5
5
  "license": "MIT",
6
6
  "author": "Teamblind, Inc.",