@blakesteve/roster 5.6.0 → 5.8.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 (99) hide show
  1. package/README.md +190 -5
  2. package/dist/components/atoms/Avatar/Avatar.cjs +1 -1
  3. package/dist/components/atoms/Avatar/Avatar.d.ts +4 -0
  4. package/dist/components/atoms/Avatar/Avatar.js +1 -1
  5. package/dist/components/atoms/AvatarStrip/AvatarStrip.cjs +1 -1
  6. package/dist/components/atoms/AvatarStrip/AvatarStrip.d.ts +10 -1
  7. package/dist/components/atoms/AvatarStrip/AvatarStrip.js +34 -30
  8. package/dist/components/atoms/Button/button-variants.cjs +1 -1
  9. package/dist/components/atoms/Button/button-variants.js +5 -3
  10. package/dist/components/atoms/Eyebrow/eyebrow-variants.cjs +1 -1
  11. package/dist/components/atoms/Eyebrow/eyebrow-variants.js +8 -4
  12. package/dist/components/atoms/LoadingDots/LoadingDots.cjs +1 -0
  13. package/dist/components/atoms/LoadingDots/LoadingDots.d.ts +20 -0
  14. package/dist/components/atoms/LoadingDots/LoadingDots.js +43 -0
  15. package/dist/components/atoms/MultiSelect/MultiSelect.cjs +1 -1
  16. package/dist/components/atoms/MultiSelect/MultiSelect.d.ts +3 -1
  17. package/dist/components/atoms/MultiSelect/MultiSelect.js +87 -89
  18. package/dist/components/atoms/Progress/Progress.cjs +1 -0
  19. package/dist/components/atoms/Progress/Progress.d.ts +62 -0
  20. package/dist/components/atoms/Progress/Progress.js +107 -0
  21. package/dist/components/atoms/Progress/progress-values.cjs +1 -0
  22. package/dist/components/atoms/Progress/progress-values.d.ts +26 -0
  23. package/dist/components/atoms/Progress/progress-values.js +12 -0
  24. package/dist/components/atoms/Skeleton/Skeleton.cjs +1 -0
  25. package/dist/components/atoms/Skeleton/Skeleton.d.ts +79 -0
  26. package/dist/components/atoms/Skeleton/Skeleton.js +80 -0
  27. package/dist/components/atoms/Stat/Stat.cjs +1 -1
  28. package/dist/components/atoms/Stat/Stat.js +19 -19
  29. package/dist/components/atoms/Stat/stat-variants.cjs +1 -1
  30. package/dist/components/atoms/Stat/stat-variants.d.ts +1 -0
  31. package/dist/components/atoms/Stat/stat-variants.js +10 -7
  32. package/dist/components/molecules/Breadcrumbs/Breadcrumbs.cjs +1 -1
  33. package/dist/components/molecules/Breadcrumbs/Breadcrumbs.d.ts +10 -1
  34. package/dist/components/molecules/Breadcrumbs/Breadcrumbs.js +31 -29
  35. package/dist/components/molecules/CallToAction/CallToAction.cjs +1 -1
  36. package/dist/components/molecules/CallToAction/CallToAction.d.ts +8 -1
  37. package/dist/components/molecules/CallToAction/CallToAction.js +34 -29
  38. package/dist/components/molecules/Carousel/Carousel.cjs +1 -1
  39. package/dist/components/molecules/Carousel/Carousel.d.ts +7 -0
  40. package/dist/components/molecules/Carousel/Carousel.js +155 -155
  41. package/dist/components/molecules/ErrorState/ErrorState.cjs +1 -1
  42. package/dist/components/molecules/ErrorState/ErrorState.d.ts +8 -1
  43. package/dist/components/molecules/ErrorState/ErrorState.js +44 -39
  44. package/dist/components/molecules/FileUpload/FileUpload.cjs +1 -1
  45. package/dist/components/molecules/FileUpload/FileUpload.js +122 -142
  46. package/dist/components/molecules/MediaPreview/MediaPreview.cjs +1 -1
  47. package/dist/components/molecules/MediaPreview/MediaPreview.d.ts +3 -1
  48. package/dist/components/molecules/MediaPreview/MediaPreview.js +13 -12
  49. package/dist/components/molecules/Pagination/Pagination.cjs +1 -1
  50. package/dist/components/molecules/Pagination/Pagination.d.ts +1 -0
  51. package/dist/components/molecules/Pagination/Pagination.js +47 -46
  52. package/dist/components/molecules/ProgressField/ProgressField.cjs +1 -0
  53. package/dist/components/molecules/ProgressField/ProgressField.d.ts +24 -0
  54. package/dist/components/molecules/ProgressField/ProgressField.js +32 -0
  55. package/dist/components/molecules/SkeletonPresets/SkeletonPresets.cjs +1 -0
  56. package/dist/components/molecules/SkeletonPresets/SkeletonPresets.d.ts +55 -0
  57. package/dist/components/molecules/SkeletonPresets/SkeletonPresets.js +45 -0
  58. package/dist/components/molecules/StepProgress/StepProgress.cjs +1 -0
  59. package/dist/components/molecules/StepProgress/StepProgress.d.ts +37 -0
  60. package/dist/components/molecules/StepProgress/StepProgress.js +90 -0
  61. package/dist/components/organisms/Countdown/Countdown.cjs +1 -1
  62. package/dist/components/organisms/Countdown/Countdown.d.ts +13 -0
  63. package/dist/components/organisms/Countdown/Countdown.js +54 -47
  64. package/dist/components/organisms/DataTable/DataTable.cjs +1 -1
  65. package/dist/components/organisms/DataTable/DataTable.d.ts +5 -3
  66. package/dist/components/organisms/DataTable/DataTable.js +27 -26
  67. package/dist/components/organisms/Dialog/Dialog.cjs +1 -1
  68. package/dist/components/organisms/Dialog/Dialog.d.ts +9 -2
  69. package/dist/components/organisms/Dialog/Dialog.js +25 -23
  70. package/dist/components/organisms/Footer/Footer.cjs +1 -1
  71. package/dist/components/organisms/Footer/Footer.d.ts +9 -0
  72. package/dist/components/organisms/Footer/Footer.js +21 -23
  73. package/dist/components/organisms/ModerationQueue/ModerationQueue.cjs +1 -1
  74. package/dist/components/organisms/ModerationQueue/ModerationQueue.d.ts +40 -1
  75. package/dist/components/organisms/ModerationQueue/ModerationQueue.js +262 -237
  76. package/dist/components/organisms/ModerationQueue/QueueEditDialog.cjs +1 -1
  77. package/dist/components/organisms/ModerationQueue/QueueEditDialog.d.ts +1 -1
  78. package/dist/components/organisms/ModerationQueue/QueueEditDialog.js +23 -21
  79. package/dist/components/organisms/ModerationQueue/QueueEditSheet.cjs +1 -1
  80. package/dist/components/organisms/ModerationQueue/QueueEditSheet.d.ts +1 -1
  81. package/dist/components/organisms/ModerationQueue/QueueEditSheet.js +22 -20
  82. package/dist/components/organisms/ModerationQueue/queue-actions.d.ts +29 -10
  83. package/dist/components/organisms/Navbar/Navbar.cjs +1 -1
  84. package/dist/components/organisms/Navbar/Navbar.d.ts +38 -3
  85. package/dist/components/organisms/Navbar/Navbar.js +210 -187
  86. package/dist/components/organisms/Navbar/navbar-variants.cjs +1 -1
  87. package/dist/components/organisms/Navbar/navbar-variants.js +4 -2
  88. package/dist/components/organisms/Sheet/Sheet.cjs +1 -1
  89. package/dist/components/organisms/Sheet/Sheet.d.ts +8 -1
  90. package/dist/components/organisms/Sheet/Sheet.js +65 -63
  91. package/dist/index.d.ts +6 -0
  92. package/dist/lib/labels.cjs +1 -0
  93. package/dist/lib/labels.d.ts +7 -0
  94. package/dist/lib/labels.js +12 -0
  95. package/dist/meta.json +3 -3
  96. package/dist/roster.cjs +1 -1
  97. package/dist/roster.css +1 -1
  98. package/dist/roster.js +174 -157
  99. package/package.json +1 -1
package/README.md CHANGED
@@ -113,6 +113,12 @@ import "@blakesteve/roster/style.css";
113
113
  Skip it and components render against browser defaults: serif type, bulleted
114
114
  lists, and `content-box` sizing.
115
115
 
116
+ One default Roster does undo itself: a `<button>`'s own border. A `link` or
117
+ `soft` Button sets its border to zero (`soft` since 5.8.0). In an app without a
118
+ reset, `link` drew the browser's 2px border, and `soft` kept it, transparent,
119
+ which took 4px of extra room and showed in forced colors. Zero is what an app
120
+ with Tailwind's reset already had, so no layout moves.
121
+
116
122
  ### Dark mode
117
123
 
118
124
  Every component reads a `.dark` class on an ancestor, so dark mode is whatever
@@ -452,8 +458,15 @@ the supported way now.
452
458
  rule stops matching.** Solid Button, Badge, Pill and Checkbox no longer carry
453
459
  `rst:text-white` or `rst:text-gray-950`, so a selector naming either matches
454
460
  nothing. It fails silently, and it fails *partially*: those classes are still on
455
- `Card`, `Navbar`, `Dialog`, `ActionBar`, `Avatar` and `Breadcrumbs`, so a
456
- themed foreground keeps working there while reverting on every solid control.
461
+ `ActionBar`, `Avatar` and `Breadcrumbs`, so a themed foreground keeps working
462
+ there while reverting on every solid control. The `primary` fills of `Card`,
463
+ `Dialog` and, since 5.8.0, `Navbar` read their ink token too: Navbar's bar,
464
+ brand and active link take `--roster-primary-700-ink`, and its other links and
465
+ menu button the same ink at 80%. Each keeps white in dark mode, where its fill
466
+ is a dark step the ink doesn't describe. A primary Navbar looks different even
467
+ with no ink set: its links were `gray-300` and its active link `primary-400`,
468
+ which was 4.04:1 on Roster's own primary, under the 4.5 text needs. Now they
469
+ are white at 80% and white, the active one still semibold.
457
470
  Replace the rule with the token:
458
471
 
459
472
  ```css
@@ -591,6 +604,14 @@ per glyph, and holding it to 3:1 would flatten the effect.
591
604
  `Spinner` holds still under reduced motion: the arc still reads as loading, and
592
605
  its `label` (default "loading") says so.
593
606
 
607
+ The loading system has its own: `--roster-skeleton` and
608
+ `--roster-skeleton-highlight` are the skeleton's fill and the light that
609
+ crosses it, and the empty part of every progress bar (gray-200 and gray-100,
610
+ gray-700 and gray-600 in dark). Three durations, unset by default, change the
611
+ pace: `--roster-skeleton-duration` (1.8s), `--roster-progress-travel-duration`
612
+ (1.4s, the indeterminate pill) and `--roster-dots-duration` (1.2s). Under
613
+ reduced motion all three stop on a resting frame.
614
+
594
615
  ### Scrollbars
595
616
 
596
617
  `custom-scrollbar` gives any scrollable surface a slim themed scrollbar.
@@ -1250,6 +1271,12 @@ app supplies, inline by default or in a Dialog or Sheet (`QueueEditDialog`,
1250
1271
  `QueueEditSheet`, separate exports so a queue that doesn't use them doesn't
1251
1272
  ship them).
1252
1273
 
1274
+ **A reason outranks a confirm.** An action with both asks the reason's
1275
+ question, and its submit button is the confirmation. A `required` reason asks
1276
+ for one of its `options`, so the types refuse `required` without them: a
1277
+ reason that is only a note is `note: "required"`. That makes `QueueReasonStep`
1278
+ a type rather than an interface (5.8.0), so extend it with `&`, not `extends`.
1279
+
1253
1280
  **Drafts are typed.** An edit's draft is whatever its `initial` returns, and
1254
1281
  `validate`, the form and `run` all get that type. Inside JSX, pass `actions` as
1255
1282
  a function and write edits with the `edit` it's handed, as above; outside it,
@@ -1381,6 +1408,97 @@ submit button from sending its form twice. It no longer dims, since
1381
1408
  the spinner says it's busy. `loadingLabel` names the spinner ("loading" by
1382
1409
  default). `disabled` is unchanged and wins over `isLoading`.
1383
1410
 
1411
+ ### The loading system
1412
+
1413
+ Five components for the time between asking and having, chosen by what the
1414
+ wait is:
1415
+
1416
+ | The wait | Use |
1417
+ | --- | --- |
1418
+ | Content is coming, and you know its shape | `Skeleton`, or a preset, inside `SkeletonRegion` |
1419
+ | A task with a fraction (bytes, pages, items) | `ProgressField` (a `Progress` with its label and value) |
1420
+ | A count of discrete things | `ProgressField` or `Progress`, `variant="segmented"` |
1421
+ | Named stages of a flow | `StepProgress` |
1422
+ | A model generating, before its first token | `LoadingDots` |
1423
+ | A short wait with nothing to show | `Spinner` |
1424
+
1425
+ `SegmentBar` isn't one of these: it shows how a whole divides into parts (a
1426
+ vote split, a budget), not how much of a task is done.
1427
+
1428
+ **Skeleton.** A placeholder in the shape of what's loading, so a page keeps
1429
+ its layout and nothing moves when data lands.
1430
+
1431
+ ```tsx
1432
+ import { SkeletonRegion, SkeletonCard } from "@blakesteve/roster";
1433
+
1434
+ <SkeletonRegion loading={!trails} label="Loading trails" skeleton={<SkeletonCard media={140} lines={2} />}>
1435
+ {trails && <TrailCard trail={trails[0]} />}
1436
+ </SkeletonRegion>;
1437
+ ```
1438
+
1439
+ - A `line` is one line box of its text size: `sm` (12/16), `md` (14/20), `lg`
1440
+ (16/24), or `inherit`. It's a no-break space set in that size with a bar
1441
+ drawn over it, so `lines={3}` is exactly the height of three lines of that
1442
+ text. A `block` takes a `height`; a `circle` takes Avatar's sizes.
1443
+ - Presets draw the real component's box: `SkeletonCard` (a Card with optional
1444
+ media, a `text-base` title and `text-sm` body lines 8px under it),
1445
+ `SkeletonTableRow` (Table's own cells), `SkeletonAvatar`, `SkeletonStat`.
1446
+ - `SkeletonRegion` sets `aria-busy` while loading, hides the skeleton from
1447
+ screen readers and says `label` once (a polite status beside the region,
1448
+ empty until a moment after loading starts). For a grid of cards, wrap the
1449
+ grid in one region, or pass `announce={false}` to all but one. Skeletons are
1450
+ always `aria-hidden`. `SkeletonTableRow` is a `tr`, so it can't sit in a
1451
+ region: set `aria-busy` on the table yourself.
1452
+ - `SkeletonRegion` renders two siblings, the hidden status and then the
1453
+ region, so the status counts in a parent's `first:` and `nth-child`
1454
+ selectors. It takes no room.
1455
+ - The fill is `--roster-skeleton` (gray-200, gray-700 in dark), with
1456
+ `--roster-skeleton-highlight` crossing it. Neutral rather than the brand
1457
+ shimmer Countdown uses, and its own pair, so retinting one never recolors the
1458
+ other. Under reduced motion it holds still.
1459
+
1460
+ **Progress and ProgressField.** `ProgressField` is the form to reach for: the
1461
+ label and value on one baseline above the bar, an optional detail line below.
1462
+
1463
+ ```tsx
1464
+ <ProgressField label="Uploading photos" value={sent} max={total} detail={`${mb(sent)} of ${mb(total)}`} />
1465
+ <ProgressField label="Picks" variant="segmented" segments={["done", "done", "na", "current", "remaining"]} />
1466
+ ```
1467
+
1468
+ - Leave `value` out for indeterminate (a pill crossing the track). Set `busy`
1469
+ when a value stands but work goes on: the bar breathes in place.
1470
+ - Four statuses (`default`, `success`, `warning`, `error`), solid fills only:
1471
+ each clears 3:1 against the track and the page in both themes, where a
1472
+ translucent fill would fade into whatever is behind it. Two sizes, 6px and
1473
+ 10px.
1474
+ - Segments take `done`, `current`, `remaining` and `na` (not part of this
1475
+ one: dashed, and not counted). They're capsules unless `rounded={false}`.
1476
+ - The bar is `aria-hidden`. A status region beside it says the value as text,
1477
+ at most every 1.5 seconds and the end at once, because a changed
1478
+ `aria-label` isn't reliably announced and a `progressbar` may beep or speak
1479
+ on every update. `announce={false}` when something else already says it.
1480
+ - On dark glass in the light theme, set `--roster-skeleton` on that surface to
1481
+ `var(--roster-primary-200)`: the empty cells take it and the bar keeps its
1482
+ extent (primary-600 against primary-200 is 6.4:1). Not in the dark theme,
1483
+ where the fill is primary-400 and that pair is about 2:1; there the default
1484
+ gray-700 track keeps done against remaining at 3.8:1, though its edge is
1485
+ faint on the glass.
1486
+ - In forced colors the fill keeps the system highlight color, the track and
1487
+ empty cells an outline, and the current cell its border.
1488
+
1489
+ **StepProgress.** Named stages: `variant="stepper"` shows every step with a
1490
+ numbered marker and connectors that fill behind the current one;
1491
+ `"segmented"` is the compact form, always with "Step 2 of 5". The current
1492
+ step is `aria-current="step"`, finished ones say "done", and the position is
1493
+ said when it changes.
1494
+
1495
+ **LoadingDots.** Only for a model generating before its first token. It takes
1496
+ the surrounding text's size and color, rests at 1, 0.6 and 0.3 opacity (also
1497
+ what reduced motion shows), and is replaced by the text once it starts: never
1498
+ shown beside it.
1499
+
1500
+ Every string in all five is a prop with an English default.
1501
+
1384
1502
  ### Pagination
1385
1503
 
1386
1504
  Moves through pages of a list, built for a long list browsed on a phone.
@@ -1524,6 +1642,65 @@ well as `next/link`, plus `className`, `children`, `aria-current`, `onClick` and
1524
1642
  `Eyebrow` takes the other approach: `as` accepts any element and the props
1525
1643
  follow it, so `<Eyebrow as="a" href="/work">` works, as does `as={NextLink}`.
1526
1644
 
1645
+ ### Every built-in word is replaceable
1646
+
1647
+ Where a component writes words of its own (a close button's name, a menu
1648
+ button's, "Log In", a sentence a screen reader hears), each can be replaced
1649
+ and defaults to English. Most components take a `labels` prop; pass any entry
1650
+ and the rest stay:
1651
+
1652
+ ```tsx
1653
+ <Navbar labels={{ openMainMenu: t("nav.open"), closeMainMenu: t("nav.close") }} … />
1654
+ <Sheet labels={{ close: t("common.close") }} … />
1655
+ <Countdown labels={{ days: (n) => t("units.days", { count: n }) }} … />
1656
+ ```
1657
+
1658
+ Since 5.8.0 that covers `Navbar`, `Sheet`, `Dialog`, `Breadcrumbs`, `Footer`,
1659
+ `CallToAction`, `AvatarStrip`, `ErrorState`, `Countdown`, `Carousel` and
1660
+ `ModerationQueue` (whose `labels.close` names the close button of its edit
1661
+ Dialog or Sheet), alongside `Pagination`, the loading system and DataTable's
1662
+ `paginationLabels`. A few components name their words with single props
1663
+ instead, and 5.8.0 adds the ones that were missing: MultiSelect's
1664
+ `countLabel`, DataTable's `emptyMessage` and MediaPreview's `newTabLabel`, next
1665
+ to the existing `dismissLabel`, `placeholder`, `removeLabel`, `prevLabel` and
1666
+ the like. Words that take a number or a name are functions, so a language
1667
+ whose word changes with the count can say so. An entry passed as `undefined`
1668
+ (a catalog missing a key) keeps its English rather than leaving a control
1669
+ unnamed.
1670
+
1671
+ `src/labels.test.tsx` renders each of these, in the states where its words
1672
+ appear, with every word pseudo-localized, and fails on any English left. A
1673
+ default it can't reach: `Avatar`'s alt is "Avatar" unless you pass one (`""`
1674
+ marks it decorative, since 5.8.0), and a team without a name in
1675
+ `MatchupCard` is "Team" and its id.
1676
+
1677
+ **From a server component, pass only strings.** Every component is a client
1678
+ component, and functions can't cross the React Server Component boundary, so a
1679
+ function label (Footer's `copyright`, Countdown's units) has to be passed from
1680
+ a `"use client"` wrapper, as `linkComponent` does above.
1681
+
1682
+ ### Eyebrow and Stat line height
1683
+
1684
+ An `Eyebrow`'s line is as tall as its letters, and so is a `Stat`'s figure and
1685
+ its label. Through 5.7.0 neither was: `leading-none` sat before the font size
1686
+ in their variant tables, and `cn()`'s tailwind-merge drops a line height that
1687
+ comes before a size. An Eyebrow drew a line 1.5 times its size (15px for the
1688
+ default `xs`, not 10), and a Stat's figure and label drew lines taller than
1689
+ their type.
1690
+
1691
+ **Upgrading to 5.8.0 moves layouts.** An Eyebrow that makes its own line, as
1692
+ a flex or grid item or rendered as a block (`as="p"`, `as="h2"`), is a third
1693
+ shorter: 10px for `xs`, not 15. One inline in running text sits on its
1694
+ parent's line and doesn't change. A Stat in its default markup loses more:
1695
+ its figure's line was the size's own (28px for `sm`'s 20px figure) or the
1696
+ page's 1.5 (`md`, `lg`), and its label sat on the page's line (24px on a 16px,
1697
+ 1.5 body). So a `sm` Stat goes from 55px tall to 33, and an `lg` one at 48px
1698
+ from 99 to 61. In the `standalone` markup only the label moves, 15px to 10.
1699
+ `LabeledDivider` sets its label in an Eyebrow of its own, so every rule is 5px
1700
+ shorter whatever label it's given. An Eyebrow that wraps now sets solid, its
1701
+ lines as close as its size. Spacing an app tuned against the old lines (a
1702
+ margin that cleared them) may want retuning.
1703
+
1527
1704
  ## Quick start
1528
1705
 
1529
1706
  ```tsx
@@ -1573,7 +1750,10 @@ function App() {
1573
1750
  | `AvatarStrip` | Stacked avatar row with overflow chip, dismiss button, trailing slot, and label area |
1574
1751
  | `CollapsibleSection` | Clamps any content (prose, chips, image grids) to a fixed height with a fade and expand/collapse toggle |
1575
1752
  | `Select` | Dropdown selector, on the same size scale as `Button` and `Input` |
1576
- | `SegmentBar` | Proportional horizontal bar divided into colored segments with optional legend |
1753
+ | `SegmentBar` | Proportional horizontal bar divided into colored segments with optional legend (a split, not progress) |
1754
+ | `Skeleton` | Line, block or circle placeholder at the content's exact size; `SkeletonRegion` sets `aria-busy` |
1755
+ | `Progress` | Continuous or segmented progress bar: determinate, indeterminate or busy; per-segment state |
1756
+ | `LoadingDots` | Three dots for a model generating before its first token; replaced by the text |
1577
1757
  | `Stat` | A figure with its label and, optionally, its source; a valid `<dl>` group, or `semantics="standalone"` |
1578
1758
  | `Spinner` | Loading indicator |
1579
1759
  | `Switch` | Toggle switch; its label toggles it, and every size is a 44px target |
@@ -1600,6 +1780,9 @@ function App() {
1600
1780
  | `MediaPreview` | Thumbnail that falls back to "Preview unavailable, open original" when it can't render |
1601
1781
  | `FileUpload` | Picks files and uploads each through the app's `upload`, with per-file progress, retry and rules |
1602
1782
  | `Pagination` | Page numbers with gaps, or a compact page picker on narrow screens; buttons or real links, 44px targets |
1783
+ | `SkeletonCard`, `SkeletonTableRow`, `SkeletonAvatar`, `SkeletonStat` | Skeleton presets in the real component's box |
1784
+ | `ProgressField` | Progress with a label and value on one baseline and a detail line: the form to reach for |
1785
+ | `StepProgress` | Named steps: a stepper with markers and connectors, or a compact segmented "Step x of y" |
1603
1786
  | `Pullquote` | A line lifted out of prose, as `<figure>` + `<blockquote>` + `<figcaption>` |
1604
1787
  | `RadioGroup` | Radio set reporting one `string`; descriptions, error, 44px targets |
1605
1788
  | `Toast` | Transient floating notice; `Toaster` + the imperative `toast` handle |
@@ -1610,11 +1793,13 @@ function App() {
1610
1793
  | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1611
1794
  | `ActionBar` | Sticky bottom action strip |
1612
1795
  | `Countdown` | Live countdown timer |
1613
- | `DataTable` | Full-featured table with sorting and pagination via TanStack Table v9; its pager is `Pagination`'s arrows, worded through `paginationLabels`. Imported from `@blakesteve/roster/data-table` (see [DataTable columns](#datatable-columns)) |
1796
+ | `DataTable` | Table with sorting and paging via TanStack Table v9. Its pager is built on `Pagination` (since 5.6.0, the arrows layout), worded through `paginationLabels`; the page size is fixed at 10, with no prop to change it yet. Imported from `@blakesteve/roster/data-table` (see [DataTable columns](#datatable-columns)) |
1614
1797
  | `Dialog` | Modal dialog; `onAfterClose` runs once it has finished closing |
1615
1798
  | `Footer` | Site footer |
1616
1799
  | `ModerationQueue` | Items waiting for a decision: busy per action, confirm, reason and edit steps, focus after an item leaves, a live region. Never fetches (see [ModerationQueue](#moderationqueue)) |
1617
- | `Navbar` | Responsive navigation bar with mobile slide-out |
1800
+ | `QueueEditDialog` | A ModerationQueue edit step in a Dialog: pass it as an edit's `surface`. A separate export, so a queue that never uses it doesn't ship it |
1801
+ | `QueueEditSheet` | A ModerationQueue edit step in a Sheet, for a long form: pass it as an edit's `surface`. A separate export, like `QueueEditDialog` |
1802
+ | `Navbar` | Responsive navigation bar with mobile slide-out. A wide logo keeps its own proportions through `logoHeight` and `logoWidth`; its built-in words are in `labels` |
1618
1803
  | `Sheet` | Bottom sheet: drag, Escape or backdrop to dismiss; only its content scrolls; returns focus, even from a deep link; the title may be a node |
1619
1804
  | `Table` | Static data table |
1620
1805
 
@@ -1 +1 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),n=require("react"),o=require("../../../lib/utils.cjs"),h=require("./avatar-variants.cjs"),t=require("../../../node_modules/@headlessui/react/dist/components/popover/popover.cjs"),i=n.forwardRef(({className:c,size:l,colorScheme:u,shape:d,initials:g,src:s,alt:v,title:e,...m},f)=>{const[p,b]=n.useState(!1),x=s&&!p,a=r.jsx("div",{ref:f,className:o.cn(h.avatarVariants({size:l,colorScheme:u,shape:d}),c),...m,children:x?r.jsx("img",{src:s,alt:v||"Avatar",className:"rst:h-full rst:w-full rst:object-cover",onError:()=>b(!0)}):r.jsx("span",{className:"rst:leading-none rst:uppercase",children:g?.slice(0,2)})});return e?r.jsxs(t.Popover,{className:"rst:relative rst:inline-flex",children:[r.jsx(t.PopoverButton,{as:"div",className:"rst:cursor-pointer rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background rst:rounded-full",children:a}),r.jsx(t.PopoverPanel,{anchor:"bottom",className:o.cn("rst:z-50 rst:mt-2 rst:rounded-md rst:px-3 rst:py-1.5 rst:text-xs rst:font-medium rst:elevation-anchored rst:backdrop-blur-md rst:ring","rst:bg-gray-900/95 rst:text-white rst:ring-black/5 rst:dark:bg-gray-100/95 rst:dark:text-gray-900 rst:dark:ring-white/20","rst:transition rst:duration-200 rst:ease-in-out rst:data-closed:opacity-0 rst:data-closed:translate-y-1"),children:e})]}):a});i.displayName="Avatar";exports.Avatar=i;
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),n=require("react"),o=require("../../../lib/utils.cjs"),h=require("./avatar-variants.cjs"),t=require("../../../node_modules/@headlessui/react/dist/components/popover/popover.cjs"),i=n.forwardRef(({className:c,size:l,colorScheme:u,shape:d,initials:g,src:s,alt:v,title:e,...m},f)=>{const[p,b]=n.useState(!1),x=s&&!p,a=r.jsx("div",{ref:f,className:o.cn(h.avatarVariants({size:l,colorScheme:u,shape:d}),c),...m,children:x?r.jsx("img",{src:s,alt:v??"Avatar",className:"rst:h-full rst:w-full rst:object-cover",onError:()=>b(!0)}):r.jsx("span",{className:"rst:leading-none rst:uppercase",children:g?.slice(0,2)})});return e?r.jsxs(t.Popover,{className:"rst:relative rst:inline-flex",children:[r.jsx(t.PopoverButton,{as:"div",className:"rst:cursor-pointer rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background rst:rounded-full",children:a}),r.jsx(t.PopoverPanel,{anchor:"bottom",className:o.cn("rst:z-50 rst:mt-2 rst:rounded-md rst:px-3 rst:py-1.5 rst:text-xs rst:font-medium rst:elevation-anchored rst:backdrop-blur-md rst:ring","rst:bg-gray-900/95 rst:text-white rst:ring-black/5 rst:dark:bg-gray-100/95 rst:dark:text-gray-900 rst:dark:ring-white/20","rst:transition rst:duration-200 rst:ease-in-out rst:data-closed:opacity-0 rst:data-closed:translate-y-1"),children:e})]}):a});i.displayName="Avatar";exports.Avatar=i;
@@ -4,6 +4,10 @@ import { avatarVariants } from './avatar-variants';
4
4
  export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof avatarVariants> {
5
5
  initials?: string;
6
6
  src?: string;
7
+ /**
8
+ * The photo's text alternative. Defaults to "Avatar"; pass the person's
9
+ * name, or `""` where the avatar sits beside a name that already says who.
10
+ */
7
11
  alt?: string;
8
12
  title?: string;
9
13
  }
@@ -26,7 +26,7 @@ const w = b.forwardRef(
26
26
  "img",
27
27
  {
28
28
  src: t,
29
- alt: d || "Avatar",
29
+ alt: d ?? "Avatar",
30
30
  className: "rst:h-full rst:w-full rst:object-cover",
31
31
  onError: () => g(!0)
32
32
  }
@@ -1 +1 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),a=require("../../../lib/utils.cjs"),f=require("../Avatar/Avatar.cjs");function g({items:i,maxDisplay:l=5,totalCount:n,excludeKey:c,onDismiss:o,trailingSlot:d,label:v,ringClass:h="rst:ring-white rst:dark:ring-gray-900",className:p}){const s=i.filter(t=>t.key!==c).slice(0,l),e=n!==void 0?Math.max(0,n-s.length):Math.max(0,i.filter(t=>t.key!==c).length-l);return s.length===0&&!d?null:r.jsxs("div",{"data-testid":"avatar-strip",className:a.cn("rst:font-ui rst:flex rst:items-center rst:gap-3",p),children:[o&&r.jsx("button",{type:"button",onClick:o,"aria-label":"Dismiss","data-testid":"avatar-strip-dismiss",className:"rst:shrink-0 rst:text-gray-400/50 rst:dark:text-gray-500/50 rst:hover:text-gray-400 rst:dark:hover:text-gray-500 rst:transition-colors rst:cursor-pointer",children:"✕"}),r.jsxs("div",{"data-testid":"avatar-strip-stack",className:"rst:flex rst:items-center rst:-space-x-2",children:[s.map(t=>{const x=r.jsx(f.Avatar,{initials:t.label[0].toUpperCase(),src:t.src,colorScheme:t.colorScheme??"neutral",size:"xs"}),u=a.cn("rst:relative rst:inline-flex rst:h-6 rst:w-6 rst:rounded-full rst:ring-2 rst:transition-transform rst:hover:z-10 rst:hover:scale-110",h);return t.href?r.jsx("a",{href:t.href,title:t.label,"data-testid":`avatar-strip-item-${t.key}`,className:u,children:x},t.key):r.jsx("span",{title:t.label,"data-testid":`avatar-strip-item-${t.key}`,className:u,children:x},t.key)}),e>0&&r.jsx("div",{title:`${e} more`,"data-testid":"avatar-strip-overflow",className:a.cn("rst:relative rst:flex rst:h-6 rst:w-6 rst:items-center rst:justify-center rst:rounded-full rst:bg-gray-500/10 rst:ring-2",h),children:r.jsxs("span",{className:"rst:text-[9px] rst:font-bold rst:text-gray-500 rst:dark:text-gray-400 rst:select-none",children:["+",e]})}),d]}),v&&r.jsx("div",{"data-testid":"avatar-strip-label",children:v})]})}exports.AvatarStrip=g;
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),i=require("../../../lib/utils.cjs"),y=require("../../../lib/labels.cjs"),b=require("../Avatar/Avatar.cjs"),k={dismiss:"Dismiss",more:s=>`${s} more`};function m({items:s,maxDisplay:l=5,totalCount:n,excludeKey:c,onDismiss:o,trailingSlot:d,label:h,ringClass:v="rst:ring-white rst:dark:ring-gray-900",labels:f,className:g}){const x=y.withLabels(k,f),e=s.filter(t=>t.key!==c).slice(0,l),a=n!==void 0?Math.max(0,n-e.length):Math.max(0,s.filter(t=>t.key!==c).length-l);return e.length===0&&!d?null:r.jsxs("div",{"data-testid":"avatar-strip",className:i.cn("rst:font-ui rst:flex rst:items-center rst:gap-3",g),children:[o&&r.jsx("button",{type:"button",onClick:o,"aria-label":x.dismiss,"data-testid":"avatar-strip-dismiss",className:"rst:shrink-0 rst:text-gray-400/50 rst:dark:text-gray-500/50 rst:hover:text-gray-400 rst:dark:hover:text-gray-500 rst:transition-colors rst:cursor-pointer",children:"✕"}),r.jsxs("div",{"data-testid":"avatar-strip-stack",className:"rst:flex rst:items-center rst:-space-x-2",children:[e.map(t=>{const u=r.jsx(b.Avatar,{initials:t.label[0].toUpperCase(),src:t.src,alt:t.label,colorScheme:t.colorScheme??"neutral",size:"xs"}),p=i.cn("rst:relative rst:inline-flex rst:h-6 rst:w-6 rst:rounded-full rst:ring-2 rst:transition-transform rst:hover:z-10 rst:hover:scale-110",v);return t.href?r.jsx("a",{href:t.href,title:t.label,"data-testid":`avatar-strip-item-${t.key}`,className:p,children:u},t.key):r.jsx("span",{title:t.label,"data-testid":`avatar-strip-item-${t.key}`,className:p,children:u},t.key)}),a>0&&r.jsx("div",{title:x.more(a),"data-testid":"avatar-strip-overflow",className:i.cn("rst:relative rst:flex rst:h-6 rst:w-6 rst:items-center rst:justify-center rst:rounded-full rst:bg-gray-500/10 rst:ring-2",v),children:r.jsxs("span",{className:"rst:text-[9px] rst:font-bold rst:text-gray-500 rst:dark:text-gray-400 rst:select-none",children:["+",a]})}),d]}),h&&r.jsx("div",{"data-testid":"avatar-strip-label",children:h})]})}exports.AvatarStrip=m;
@@ -12,6 +12,13 @@ export interface AvatarStripItem {
12
12
  /** When provided, the avatar is wrapped in an `<a>` tag with this href. */
13
13
  href?: string;
14
14
  }
15
+ /** Every word AvatarStrip says of its own. Pass any of them in `labels` to replace it. */
16
+ export interface AvatarStripLabels {
17
+ /** The dismiss button's name, with `onDismiss`. */
18
+ dismiss: string;
19
+ /** The overflow chip's title: how many more there are. */
20
+ more: (count: number) => string;
21
+ }
15
22
  export interface AvatarStripProps {
16
23
  /** Ordered list of avatar items. */
17
24
  items: AvatarStripItem[];
@@ -35,6 +42,8 @@ export interface AvatarStripProps {
35
42
  trailingSlot?: ReactNode;
36
43
  /** Rendered to the right of the avatar stack. Accepts any React node. */
37
44
  label?: ReactNode;
45
+ /** The component's own words, replaced; any left out stay English. */
46
+ labels?: Partial<AvatarStripLabels>;
38
47
  /**
39
48
  * Tailwind class that sets the ring color around each avatar and the overflow chip.
40
49
  * Should match the background the strip is rendered on to produce the cutout stack effect.
@@ -56,4 +65,4 @@ export interface AvatarStripProps {
56
65
  *
57
66
  * Returns `null` when there are no visible items and no `trailingSlot`.
58
67
  */
59
- export declare function AvatarStrip({ items, maxDisplay, totalCount, excludeKey, onDismiss, trailingSlot, label, ringClass, className, }: AvatarStripProps): import("react/jsx-runtime").JSX.Element | null;
68
+ export declare function AvatarStrip({ items, maxDisplay, totalCount, excludeKey, onDismiss, trailingSlot, label, ringClass, labels, className, }: AvatarStripProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1,54 +1,58 @@
1
1
  "use client";
2
- import { jsxs as a, jsx as r } from "react/jsx-runtime";
3
- import { cn as i } from "../../../lib/utils.js";
4
- import { Avatar as m } from "../Avatar/Avatar.js";
5
- function b({
6
- items: l,
2
+ import { jsxs as i, jsx as r } from "react/jsx-runtime";
3
+ import { cn as l } from "../../../lib/utils.js";
4
+ import { withLabels as y } from "../../../lib/labels.js";
5
+ import { Avatar as k } from "../Avatar/Avatar.js";
6
+ const b = { dismiss: "Dismiss", more: (s) => `${s} more` };
7
+ function L({
8
+ items: s,
7
9
  maxDisplay: n = 5,
8
- totalCount: c,
9
- excludeKey: o,
10
+ totalCount: o,
11
+ excludeKey: c,
10
12
  onDismiss: d,
11
13
  trailingSlot: h,
12
- label: v,
13
- ringClass: p = "rst:ring-white rst:dark:ring-gray-900",
14
- className: g
14
+ label: p,
15
+ ringClass: v = "rst:ring-white rst:dark:ring-gray-900",
16
+ labels: g,
17
+ className: u
15
18
  }) {
16
- const s = l.filter((t) => t.key !== o).slice(0, n), e = c !== void 0 ? Math.max(0, c - s.length) : Math.max(0, l.filter((t) => t.key !== o).length - n);
17
- return s.length === 0 && !h ? null : /* @__PURE__ */ a(
19
+ const f = y(b, g), e = s.filter((t) => t.key !== c).slice(0, n), a = o !== void 0 ? Math.max(0, o - e.length) : Math.max(0, s.filter((t) => t.key !== c).length - n);
20
+ return e.length === 0 && !h ? null : /* @__PURE__ */ i(
18
21
  "div",
19
22
  {
20
23
  "data-testid": "avatar-strip",
21
- className: i("rst:font-ui rst:flex rst:items-center rst:gap-3", g),
24
+ className: l("rst:font-ui rst:flex rst:items-center rst:gap-3", u),
22
25
  children: [
23
26
  d && /* @__PURE__ */ r(
24
27
  "button",
25
28
  {
26
29
  type: "button",
27
30
  onClick: d,
28
- "aria-label": "Dismiss",
31
+ "aria-label": f.dismiss,
29
32
  "data-testid": "avatar-strip-dismiss",
30
33
  className: "rst:shrink-0 rst:text-gray-400/50 rst:dark:text-gray-500/50 rst:hover:text-gray-400 rst:dark:hover:text-gray-500 rst:transition-colors rst:cursor-pointer",
31
34
  children: "✕"
32
35
  }
33
36
  ),
34
- /* @__PURE__ */ a(
37
+ /* @__PURE__ */ i(
35
38
  "div",
36
39
  {
37
40
  "data-testid": "avatar-strip-stack",
38
41
  className: "rst:flex rst:items-center rst:-space-x-2",
39
42
  children: [
40
- s.map((t) => {
41
- const f = /* @__PURE__ */ r(
42
- m,
43
+ e.map((t) => {
44
+ const m = /* @__PURE__ */ r(
45
+ k,
43
46
  {
44
47
  initials: t.label[0].toUpperCase(),
45
48
  src: t.src,
49
+ alt: t.label,
46
50
  colorScheme: t.colorScheme ?? "neutral",
47
51
  size: "xs"
48
52
  }
49
- ), x = i(
53
+ ), x = l(
50
54
  "rst:relative rst:inline-flex rst:h-6 rst:w-6 rst:rounded-full rst:ring-2 rst:transition-transform rst:hover:z-10 rst:hover:scale-110",
51
- p
55
+ v
52
56
  );
53
57
  return t.href ? /* @__PURE__ */ r(
54
58
  "a",
@@ -57,7 +61,7 @@ function b({
57
61
  title: t.label,
58
62
  "data-testid": `avatar-strip-item-${t.key}`,
59
63
  className: x,
60
- children: f
64
+ children: m
61
65
  },
62
66
  t.key
63
67
  ) : /* @__PURE__ */ r(
@@ -66,23 +70,23 @@ function b({
66
70
  title: t.label,
67
71
  "data-testid": `avatar-strip-item-${t.key}`,
68
72
  className: x,
69
- children: f
73
+ children: m
70
74
  },
71
75
  t.key
72
76
  );
73
77
  }),
74
- e > 0 && /* @__PURE__ */ r(
78
+ a > 0 && /* @__PURE__ */ r(
75
79
  "div",
76
80
  {
77
- title: `${e} more`,
81
+ title: f.more(a),
78
82
  "data-testid": "avatar-strip-overflow",
79
- className: i(
83
+ className: l(
80
84
  "rst:relative rst:flex rst:h-6 rst:w-6 rst:items-center rst:justify-center rst:rounded-full rst:bg-gray-500/10 rst:ring-2",
81
- p
85
+ v
82
86
  ),
83
- children: /* @__PURE__ */ a("span", { className: "rst:text-[9px] rst:font-bold rst:text-gray-500 rst:dark:text-gray-400 rst:select-none", children: [
87
+ children: /* @__PURE__ */ i("span", { className: "rst:text-[9px] rst:font-bold rst:text-gray-500 rst:dark:text-gray-400 rst:select-none", children: [
84
88
  "+",
85
- e
89
+ a
86
90
  ] })
87
91
  }
88
92
  ),
@@ -90,11 +94,11 @@ function b({
90
94
  ]
91
95
  }
92
96
  ),
93
- v && /* @__PURE__ */ r("div", { "data-testid": "avatar-strip-label", children: v })
97
+ p && /* @__PURE__ */ r("div", { "data-testid": "avatar-strip-label", children: p })
94
98
  ]
95
99
  }
96
100
  );
97
101
  }
98
102
  export {
99
- b as AvatarStrip
103
+ L as AvatarStrip
100
104
  };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("../../../node_modules/class-variance-authority/dist/index.cjs"),t=r.cva("rst:font-ui rst:inline-flex rst:items-center rst:justify-center rst:cursor-pointer rst:whitespace-nowrap rst:rounded-md rst:text-sm rst:font-medium rst:ring-offset-background rst:transition-colors rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:disabled:pointer-events-none rst:disabled:opacity-50",{variants:{variant:{solid:"rst:border rst:border-transparent rst:elevation-control",soft:"rst:border-transparent rst:shadow-none",outline:"rst:border rst:bg-transparent rst:elevation-control",ghost:"rst:border rst:border-transparent rst:bg-transparent",link:"rst:border-0 rst:bg-transparent rst:underline-offset-4 rst:hover:underline"},colorScheme:{primary:"",orange:"",teal:"",purple:"",amber:"",success:"",error:"",neutral:""},size:{xs:"rst:h-7 rst:rounded-sm rst:px-2 rst:text-xs",sm:"rst:h-9 rst:rounded-md rst:px-3",default:"rst:h-10 rst:px-4 rst:py-2",lg:"rst:h-11 rst:rounded-md rst:px-8",icon:"rst:h-10 rst:w-10"}},compoundVariants:[{variant:"solid",colorScheme:"primary",className:"rst:bg-primary-600 rst:hover:bg-primary-700 rst:dark:bg-primary-600 rst:dark:hover:bg-primary-500 rst:text-primary-600-ink rst:hover:text-primary-700-ink rst:dark:hover:text-primary-500-ink"},{variant:"solid",colorScheme:"orange",className:"rst:bg-orange-600 rst:hover:bg-orange-700 rst:dark:bg-orange-600 rst:dark:hover:bg-orange-700 rst:text-orange-600-ink rst:hover:text-orange-700-ink rst:dark:hover:text-orange-700-ink"},{variant:"solid",colorScheme:"teal",className:"rst:bg-teal-600 rst:hover:bg-teal-500 rst:dark:bg-teal-600 rst:dark:hover:bg-teal-500 rst:text-teal-600-ink rst:hover:text-teal-500-ink rst:dark:hover:text-teal-500-ink"},{variant:"solid",colorScheme:"purple",className:"rst:bg-purple-600 rst:hover:bg-purple-700 rst:dark:bg-purple-600 rst:dark:hover:bg-purple-700 rst:text-purple-600-ink rst:hover:text-purple-700-ink rst:dark:hover:text-purple-700-ink"},{variant:"solid",colorScheme:"amber",className:"rst:bg-amber-400 rst:hover:bg-amber-500 rst:dark:bg-amber-500 rst:dark:hover:bg-amber-400 rst:text-amber-400-ink rst:hover:text-amber-500-ink rst:dark:text-amber-500-ink rst:dark:hover:text-amber-400-ink"},{variant:"solid",colorScheme:"success",className:"rst:bg-success-600 rst:hover:bg-success-700 rst:dark:bg-success-600 rst:dark:hover:bg-success-700 rst:text-success-600-ink rst:hover:text-success-700-ink rst:dark:hover:text-success-700-ink"},{variant:"solid",colorScheme:"error",className:"rst:bg-error-600 rst:hover:bg-error-700 rst:dark:bg-error-600 rst:dark:hover:bg-error-500 rst:text-error-600-ink rst:hover:text-error-700-ink rst:dark:hover:text-error-500-ink"},{variant:"solid",colorScheme:"neutral",className:"rst:bg-gray-600 rst:hover:bg-gray-700 rst:dark:bg-gray-600 rst:dark:hover:bg-gray-500 rst:text-gray-600-ink rst:hover:text-gray-700-ink rst:dark:hover:text-gray-500-ink"},{variant:"soft",colorScheme:"primary",className:"rst:bg-primary-50 rst:text-primary-700 rst:hover:bg-primary-100 rst:dark:bg-primary-900/40 rst:dark:text-primary-300 rst:dark:hover:bg-primary-900/60"},{variant:"soft",colorScheme:"orange",className:"rst:bg-orange-50 rst:text-orange-700 rst:hover:bg-orange-100 rst:dark:bg-orange-900/30 rst:dark:text-orange-300 rst:dark:hover:bg-orange-900/50"},{variant:"soft",colorScheme:"teal",className:"rst:bg-teal-100 rst:text-teal-800 rst:hover:bg-teal-200 rst:dark:bg-teal-900/30 rst:dark:text-teal-300 rst:dark:hover:bg-teal-900/50"},{variant:"soft",colorScheme:"purple",className:"rst:bg-purple-50 rst:text-purple-700 rst:hover:bg-purple-100 rst:dark:bg-purple-900/30 rst:dark:text-purple-300 rst:dark:hover:bg-purple-900/50"},{variant:"soft",colorScheme:"amber",className:"rst:bg-amber-50 rst:text-amber-800 rst:hover:bg-amber-100 rst:dark:bg-amber-900/30 rst:dark:text-amber-300 rst:dark:hover:bg-amber-900/50"},{variant:"soft",colorScheme:"success",className:"rst:bg-success-50 rst:text-success-700 rst:hover:bg-success-100 rst:dark:bg-success-900/30 rst:dark:text-success-300 rst:dark:hover:bg-success-900/50"},{variant:"soft",colorScheme:"error",className:"rst:bg-error-50 rst:text-error-700 rst:hover:bg-error-100 rst:dark:bg-error-900/30 rst:dark:text-error-300 rst:dark:hover:bg-error-900/50"},{variant:"soft",colorScheme:"neutral",className:"rst:bg-gray-100 rst:text-gray-700 rst:hover:bg-gray-200 rst:dark:bg-gray-800/50 rst:dark:text-gray-300 rst:dark:hover:bg-gray-800"},{variant:"outline",colorScheme:"primary",className:"rst:border-primary-600 rst:text-primary-600 rst:hover:bg-primary-50 rst:dark:border-primary-500 rst:dark:text-primary-400 rst:dark:hover:bg-primary-500/10"},{variant:"outline",colorScheme:"orange",className:"rst:border-orange-600 rst:text-orange-600 rst:hover:bg-orange-50 rst:dark:border-orange-500 rst:dark:text-orange-400 rst:dark:hover:bg-orange-500/10"},{variant:"outline",colorScheme:"teal",className:"rst:border-teal-600 rst:text-teal-600 rst:hover:bg-teal-50 rst:dark:border-teal-500 rst:dark:text-teal-400 rst:dark:hover:bg-teal-500/10"},{variant:"outline",colorScheme:"purple",className:"rst:border-purple-600 rst:text-purple-600 rst:hover:bg-purple-50 rst:dark:border-purple-500 rst:dark:text-purple-400 rst:dark:hover:bg-purple-500/10"},{variant:"outline",colorScheme:"amber",className:"rst:border-amber-600 rst:text-amber-600 rst:hover:bg-amber-50 rst:dark:border-amber-500 rst:dark:text-amber-400 rst:dark:hover:bg-amber-500/10"},{variant:"outline",colorScheme:"success",className:"rst:border-success-600 rst:text-success-600 rst:hover:bg-success-50 rst:dark:border-success-500 rst:dark:text-success-400 rst:dark:hover:bg-success-500/10"},{variant:"outline",colorScheme:"error",className:"rst:border-error-600 rst:text-error-600 rst:hover:bg-error-50 rst:dark:border-error-500 rst:dark:text-error-400 rst:dark:hover:bg-error-500/10"},{variant:"outline",colorScheme:"neutral",className:"rst:border-gray-300 rst:text-gray-700 rst:hover:bg-gray-50 rst:dark:border-gray-600 rst:dark:text-gray-300 rst:dark:hover:bg-gray-800/50"},{variant:"ghost",colorScheme:"primary",className:"rst:text-primary-600 rst:hover:bg-primary-500/10 rst:dark:text-primary-400 rst:dark:hover:bg-primary-400/15"},{variant:"ghost",colorScheme:"orange",className:"rst:text-orange-600 rst:hover:bg-orange-500/10 rst:dark:text-orange-400 rst:dark:hover:bg-orange-400/15"},{variant:"ghost",colorScheme:"teal",className:"rst:text-teal-600 rst:hover:bg-teal-500/10 rst:dark:text-teal-400 rst:dark:hover:bg-teal-400/15"},{variant:"ghost",colorScheme:"purple",className:"rst:text-purple-600 rst:hover:bg-purple-500/10 rst:dark:text-purple-400 rst:dark:hover:bg-purple-400/15"},{variant:"ghost",colorScheme:"amber",className:"rst:text-amber-600 rst:hover:bg-amber-500/10 rst:dark:text-amber-400 rst:dark:hover:bg-amber-400/15"},{variant:"ghost",colorScheme:"success",className:"rst:text-success-600 rst:hover:bg-success-500/10 rst:dark:text-success-400 rst:dark:hover:bg-success-400/15"},{variant:"ghost",colorScheme:"error",className:"rst:text-error-600 rst:hover:bg-error-500/10 rst:dark:text-error-400 rst:dark:hover:bg-error-400/15"},{variant:"ghost",colorScheme:"neutral",className:"rst:text-gray-600 rst:hover:bg-gray-500/10 rst:dark:text-gray-400 rst:dark:hover:bg-gray-400/15"},{variant:"link",colorScheme:"primary",className:"rst:text-primary-600 rst:hover:text-primary-700 rst:dark:text-primary-400 rst:dark:hover:text-primary-300"},{variant:"link",colorScheme:"orange",className:"rst:text-orange-600 rst:hover:text-orange-700 rst:dark:text-orange-400 rst:dark:hover:text-orange-300"},{variant:"link",colorScheme:"teal",className:"rst:text-teal-600 rst:hover:text-teal-700 rst:dark:text-teal-400 rst:dark:hover:text-teal-300"},{variant:"link",colorScheme:"purple",className:"rst:text-purple-600 rst:hover:text-purple-700 rst:dark:text-purple-400 rst:dark:hover:text-purple-300"},{variant:"link",colorScheme:"amber",className:"rst:text-amber-600 rst:hover:text-amber-700 rst:dark:text-amber-400 rst:dark:hover:text-amber-300"},{variant:"link",colorScheme:"success",className:"rst:text-success-600 rst:hover:text-success-700 rst:dark:text-success-400 rst:dark:hover:text-success-300"},{variant:"link",colorScheme:"error",className:"rst:text-error-600 rst:hover:text-error-700 rst:dark:text-error-400 rst:dark:hover:text-error-300"},{variant:"link",colorScheme:"neutral",className:"rst:text-gray-600 rst:hover:text-gray-900 rst:dark:text-gray-400 rst:dark:hover:text-gray-100"}],defaultVariants:{colorScheme:"primary",variant:"solid",size:"default"}});exports.buttonVariants=t;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("../../../node_modules/class-variance-authority/dist/index.cjs"),t=r.cva("rst:font-ui rst:inline-flex rst:items-center rst:justify-center rst:cursor-pointer rst:whitespace-nowrap rst:rounded-md rst:text-sm rst:font-medium rst:ring-offset-background rst:transition-colors rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:disabled:pointer-events-none rst:disabled:opacity-50",{variants:{variant:{solid:"rst:border rst:border-transparent rst:elevation-control",soft:"rst:border-0 rst:shadow-none",outline:"rst:border rst:bg-transparent rst:elevation-control",ghost:"rst:border rst:border-transparent rst:bg-transparent",link:"rst:border-0 rst:bg-transparent rst:underline-offset-4 rst:hover:underline"},colorScheme:{primary:"",orange:"",teal:"",purple:"",amber:"",success:"",error:"",neutral:""},size:{xs:"rst:h-7 rst:rounded-sm rst:px-2 rst:text-xs",sm:"rst:h-9 rst:rounded-md rst:px-3",default:"rst:h-10 rst:px-4 rst:py-2",lg:"rst:h-11 rst:rounded-md rst:px-8",icon:"rst:h-10 rst:w-10"}},compoundVariants:[{variant:"solid",colorScheme:"primary",className:"rst:bg-primary-600 rst:hover:bg-primary-700 rst:dark:bg-primary-600 rst:dark:hover:bg-primary-500 rst:text-primary-600-ink rst:hover:text-primary-700-ink rst:dark:hover:text-primary-500-ink"},{variant:"solid",colorScheme:"orange",className:"rst:bg-orange-600 rst:hover:bg-orange-700 rst:dark:bg-orange-600 rst:dark:hover:bg-orange-700 rst:text-orange-600-ink rst:hover:text-orange-700-ink rst:dark:hover:text-orange-700-ink"},{variant:"solid",colorScheme:"teal",className:"rst:bg-teal-600 rst:hover:bg-teal-500 rst:dark:bg-teal-600 rst:dark:hover:bg-teal-500 rst:text-teal-600-ink rst:hover:text-teal-500-ink rst:dark:hover:text-teal-500-ink"},{variant:"solid",colorScheme:"purple",className:"rst:bg-purple-600 rst:hover:bg-purple-700 rst:dark:bg-purple-600 rst:dark:hover:bg-purple-700 rst:text-purple-600-ink rst:hover:text-purple-700-ink rst:dark:hover:text-purple-700-ink"},{variant:"solid",colorScheme:"amber",className:"rst:bg-amber-400 rst:hover:bg-amber-500 rst:dark:bg-amber-500 rst:dark:hover:bg-amber-400 rst:text-amber-400-ink rst:hover:text-amber-500-ink rst:dark:text-amber-500-ink rst:dark:hover:text-amber-400-ink"},{variant:"solid",colorScheme:"success",className:"rst:bg-success-600 rst:hover:bg-success-700 rst:dark:bg-success-600 rst:dark:hover:bg-success-700 rst:text-success-600-ink rst:hover:text-success-700-ink rst:dark:hover:text-success-700-ink"},{variant:"solid",colorScheme:"error",className:"rst:bg-error-600 rst:hover:bg-error-700 rst:dark:bg-error-600 rst:dark:hover:bg-error-500 rst:text-error-600-ink rst:hover:text-error-700-ink rst:dark:hover:text-error-500-ink"},{variant:"solid",colorScheme:"neutral",className:"rst:bg-gray-600 rst:hover:bg-gray-700 rst:dark:bg-gray-600 rst:dark:hover:bg-gray-500 rst:text-gray-600-ink rst:hover:text-gray-700-ink rst:dark:hover:text-gray-500-ink"},{variant:"soft",colorScheme:"primary",className:"rst:bg-primary-50 rst:text-primary-700 rst:hover:bg-primary-100 rst:dark:bg-primary-900/40 rst:dark:text-primary-300 rst:dark:hover:bg-primary-900/60"},{variant:"soft",colorScheme:"orange",className:"rst:bg-orange-50 rst:text-orange-700 rst:hover:bg-orange-100 rst:dark:bg-orange-900/30 rst:dark:text-orange-300 rst:dark:hover:bg-orange-900/50"},{variant:"soft",colorScheme:"teal",className:"rst:bg-teal-100 rst:text-teal-800 rst:hover:bg-teal-200 rst:dark:bg-teal-900/30 rst:dark:text-teal-300 rst:dark:hover:bg-teal-900/50"},{variant:"soft",colorScheme:"purple",className:"rst:bg-purple-50 rst:text-purple-700 rst:hover:bg-purple-100 rst:dark:bg-purple-900/30 rst:dark:text-purple-300 rst:dark:hover:bg-purple-900/50"},{variant:"soft",colorScheme:"amber",className:"rst:bg-amber-50 rst:text-amber-800 rst:hover:bg-amber-100 rst:dark:bg-amber-900/30 rst:dark:text-amber-300 rst:dark:hover:bg-amber-900/50"},{variant:"soft",colorScheme:"success",className:"rst:bg-success-50 rst:text-success-700 rst:hover:bg-success-100 rst:dark:bg-success-900/30 rst:dark:text-success-300 rst:dark:hover:bg-success-900/50"},{variant:"soft",colorScheme:"error",className:"rst:bg-error-50 rst:text-error-700 rst:hover:bg-error-100 rst:dark:bg-error-900/30 rst:dark:text-error-300 rst:dark:hover:bg-error-900/50"},{variant:"soft",colorScheme:"neutral",className:"rst:bg-gray-100 rst:text-gray-700 rst:hover:bg-gray-200 rst:dark:bg-gray-800/50 rst:dark:text-gray-300 rst:dark:hover:bg-gray-800"},{variant:"outline",colorScheme:"primary",className:"rst:border-primary-600 rst:text-primary-600 rst:hover:bg-primary-50 rst:dark:border-primary-500 rst:dark:text-primary-400 rst:dark:hover:bg-primary-500/10"},{variant:"outline",colorScheme:"orange",className:"rst:border-orange-600 rst:text-orange-600 rst:hover:bg-orange-50 rst:dark:border-orange-500 rst:dark:text-orange-400 rst:dark:hover:bg-orange-500/10"},{variant:"outline",colorScheme:"teal",className:"rst:border-teal-600 rst:text-teal-600 rst:hover:bg-teal-50 rst:dark:border-teal-500 rst:dark:text-teal-400 rst:dark:hover:bg-teal-500/10"},{variant:"outline",colorScheme:"purple",className:"rst:border-purple-600 rst:text-purple-600 rst:hover:bg-purple-50 rst:dark:border-purple-500 rst:dark:text-purple-400 rst:dark:hover:bg-purple-500/10"},{variant:"outline",colorScheme:"amber",className:"rst:border-amber-600 rst:text-amber-600 rst:hover:bg-amber-50 rst:dark:border-amber-500 rst:dark:text-amber-400 rst:dark:hover:bg-amber-500/10"},{variant:"outline",colorScheme:"success",className:"rst:border-success-600 rst:text-success-600 rst:hover:bg-success-50 rst:dark:border-success-500 rst:dark:text-success-400 rst:dark:hover:bg-success-500/10"},{variant:"outline",colorScheme:"error",className:"rst:border-error-600 rst:text-error-600 rst:hover:bg-error-50 rst:dark:border-error-500 rst:dark:text-error-400 rst:dark:hover:bg-error-500/10"},{variant:"outline",colorScheme:"neutral",className:"rst:border-gray-300 rst:text-gray-700 rst:hover:bg-gray-50 rst:dark:border-gray-600 rst:dark:text-gray-300 rst:dark:hover:bg-gray-800/50"},{variant:"ghost",colorScheme:"primary",className:"rst:text-primary-600 rst:hover:bg-primary-500/10 rst:dark:text-primary-400 rst:dark:hover:bg-primary-400/15"},{variant:"ghost",colorScheme:"orange",className:"rst:text-orange-600 rst:hover:bg-orange-500/10 rst:dark:text-orange-400 rst:dark:hover:bg-orange-400/15"},{variant:"ghost",colorScheme:"teal",className:"rst:text-teal-600 rst:hover:bg-teal-500/10 rst:dark:text-teal-400 rst:dark:hover:bg-teal-400/15"},{variant:"ghost",colorScheme:"purple",className:"rst:text-purple-600 rst:hover:bg-purple-500/10 rst:dark:text-purple-400 rst:dark:hover:bg-purple-400/15"},{variant:"ghost",colorScheme:"amber",className:"rst:text-amber-600 rst:hover:bg-amber-500/10 rst:dark:text-amber-400 rst:dark:hover:bg-amber-400/15"},{variant:"ghost",colorScheme:"success",className:"rst:text-success-600 rst:hover:bg-success-500/10 rst:dark:text-success-400 rst:dark:hover:bg-success-400/15"},{variant:"ghost",colorScheme:"error",className:"rst:text-error-600 rst:hover:bg-error-500/10 rst:dark:text-error-400 rst:dark:hover:bg-error-400/15"},{variant:"ghost",colorScheme:"neutral",className:"rst:text-gray-600 rst:hover:bg-gray-500/10 rst:dark:text-gray-400 rst:dark:hover:bg-gray-400/15"},{variant:"link",colorScheme:"primary",className:"rst:text-primary-600 rst:hover:text-primary-700 rst:dark:text-primary-400 rst:dark:hover:text-primary-300"},{variant:"link",colorScheme:"orange",className:"rst:text-orange-600 rst:hover:text-orange-700 rst:dark:text-orange-400 rst:dark:hover:text-orange-300"},{variant:"link",colorScheme:"teal",className:"rst:text-teal-600 rst:hover:text-teal-700 rst:dark:text-teal-400 rst:dark:hover:text-teal-300"},{variant:"link",colorScheme:"purple",className:"rst:text-purple-600 rst:hover:text-purple-700 rst:dark:text-purple-400 rst:dark:hover:text-purple-300"},{variant:"link",colorScheme:"amber",className:"rst:text-amber-600 rst:hover:text-amber-700 rst:dark:text-amber-400 rst:dark:hover:text-amber-300"},{variant:"link",colorScheme:"success",className:"rst:text-success-600 rst:hover:text-success-700 rst:dark:text-success-400 rst:dark:hover:text-success-300"},{variant:"link",colorScheme:"error",className:"rst:text-error-600 rst:hover:text-error-700 rst:dark:text-error-400 rst:dark:hover:text-error-300"},{variant:"link",colorScheme:"neutral",className:"rst:text-gray-600 rst:hover:text-gray-900 rst:dark:text-gray-400 rst:dark:hover:text-gray-100"}],defaultVariants:{colorScheme:"primary",variant:"solid",size:"default"}});exports.buttonVariants=t;
@@ -6,11 +6,13 @@ const e = /* @__PURE__ */ r(
6
6
  variants: {
7
7
  variant: {
8
8
  solid: "rst:border rst:border-transparent rst:elevation-control",
9
- soft: "rst:border-transparent rst:shadow-none",
9
+ // `border-0`, here and on `link`: a <button> draws the browser's own
10
+ // border unless told otherwise, and an app without a reset would see
11
+ // it. Zero rather than the 1px the others have, because zero is what
12
+ // every app with a reset already draws: none of them moves.
13
+ soft: "rst:border-0 rst:shadow-none",
10
14
  outline: "rst:border rst:bg-transparent rst:elevation-control",
11
15
  ghost: "rst:border rst:border-transparent rst:bg-transparent",
12
- // `border-0`: a <button> draws the browser's own border unless told
13
- // otherwise, and an app without a reset would see it round a link.
14
16
  link: "rst:border-0 rst:bg-transparent rst:underline-offset-4 rst:hover:underline"
15
17
  },
16
18
  colorScheme: {
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../../../node_modules/class-variance-authority/dist/index.cjs"),r=t.cva("rst:font-mono rst:uppercase rst:leading-none",{variants:{size:{xs:"rst:text-[0.625rem] rst:tracking-[0.16em]",sm:"rst:text-[0.6875rem] rst:tracking-[0.14em]",md:"rst:text-xs rst:tracking-[0.12em]"},tone:{faint:"rst:text-gray-500 rst:dark:text-gray-400",default:"rst:text-gray-700 rst:dark:text-gray-300",strong:"rst:text-gray-900 rst:dark:text-gray-100",primary:"rst:text-primary-600 rst:dark:text-primary-400"},weight:{normal:"rst:font-normal",medium:"rst:font-medium",semibold:"rst:font-semibold"}},defaultVariants:{size:"xs",tone:"faint",weight:"normal"}});exports.eyebrowVariants=r;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../../../node_modules/class-variance-authority/dist/index.cjs"),r=t.cva("rst:font-mono rst:uppercase",{variants:{size:{xs:"rst:text-[0.625rem] rst:leading-none rst:tracking-[0.16em]",sm:"rst:text-[0.6875rem] rst:leading-none rst:tracking-[0.14em]",md:"rst:text-xs rst:leading-none rst:tracking-[0.12em]"},tone:{faint:"rst:text-gray-500 rst:dark:text-gray-400",default:"rst:text-gray-700 rst:dark:text-gray-300",strong:"rst:text-gray-900 rst:dark:text-gray-100",primary:"rst:text-primary-600 rst:dark:text-primary-400"},weight:{normal:"rst:font-normal",medium:"rst:font-medium",semibold:"rst:font-semibold"}},defaultVariants:{size:"xs",tone:"faint",weight:"normal"}});exports.eyebrowVariants=r;
@@ -1,12 +1,16 @@
1
1
  import { cva as t } from "../../../node_modules/class-variance-authority/dist/index.js";
2
2
  const e = /* @__PURE__ */ t(
3
- "rst:font-mono rst:uppercase rst:leading-none",
3
+ "rst:font-mono rst:uppercase",
4
4
  {
5
5
  variants: {
6
+ /* `leading-none` after each size, never before it: tailwind-merge
7
+ drops a line height that comes before a font size, because a size
8
+ can carry its own. Placed first, it was lost, and the line was 1.5
9
+ times the size instead of 1. */
6
10
  size: {
7
- xs: "rst:text-[0.625rem] rst:tracking-[0.16em]",
8
- sm: "rst:text-[0.6875rem] rst:tracking-[0.14em]",
9
- md: "rst:text-xs rst:tracking-[0.12em]"
11
+ xs: "rst:text-[0.625rem] rst:leading-none rst:tracking-[0.16em]",
12
+ sm: "rst:text-[0.6875rem] rst:leading-none rst:tracking-[0.14em]",
13
+ md: "rst:text-xs rst:leading-none rst:tracking-[0.12em]"
10
14
  },
11
15
  tone: {
12
16
  faint: "rst:text-gray-500 rst:dark:text-gray-400",
@@ -0,0 +1 @@
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),a=require("react"),o=require("../../../lib/utils.cjs"),l=[{rest:"rst:opacity-100",delay:"0s"},{rest:"rst:opacity-60",delay:"0.2s"},{rest:"rst:opacity-30",delay:"0.4s"}];function u({label:s="Loading",announce:r=!0,className:i}){const[n,c]=a.useState("");return a.useEffect(()=>{const t=setTimeout(()=>c(s),50);return()=>clearTimeout(t)},[s]),e.jsxs("span",{role:r?"status":void 0,className:o.cn("rst:inline-flex rst:items-center rst:gap-[0.25em] rst:align-middle",i),"data-loading-dots":"",children:[l.map((t,d)=>e.jsx("span",{"aria-hidden":"true",className:o.cn("rst:block rst:h-[0.4em] rst:w-[0.4em] rst:rounded-full rst:bg-current rst:animate-dot","rst:forced-colors:forced-color-adjust-none rst:forced-colors:bg-[CanvasText]",t.rest),style:{animationDelay:t.delay,animationFillMode:"backwards"}},d)),e.jsx("span",{className:"rst:sr-only",children:r?n:s})]})}exports.LoadingDots=u;
@@ -0,0 +1,20 @@
1
+ export interface LoadingDotsProps {
2
+ /** What a screen reader hears: "Writing a reply". */
3
+ label?: string;
4
+ /**
5
+ * Say `label` in a polite status of its own (the default). Off inside a
6
+ * chat log or any live region that already announces what's added to it,
7
+ * where it would be said twice; the label is still there to be read.
8
+ */
9
+ announce?: boolean;
10
+ className?: string;
11
+ }
12
+ /**
13
+ * Three dots for a model that's generating and hasn't sent anything yet.
14
+ *
15
+ * It stands in for text, so it's sized and colored by the text around it (em
16
+ * and `currentColor`), and it goes the moment the first token arrives: render
17
+ * the text instead of it, never beside it.
18
+ */
19
+ declare function LoadingDots({ label, announce, className }: LoadingDotsProps): import("react/jsx-runtime").JSX.Element;
20
+ export { LoadingDots };