@thewhatmatters/wmds 0.4.6 → 0.4.8

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 (185) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/CONSUMING.md +4 -0
  3. package/README.md +2 -2
  4. package/dist/components/molecules/LinkTile/LinkTile.d.ts +45 -0
  5. package/dist/components/molecules/LinkTile/LinkTile.d.ts.map +1 -0
  6. package/dist/components/molecules/LinkTile/LinkTile.js +115 -0
  7. package/dist/components/molecules/LinkTile/linkTileStyles.d.ts +31 -0
  8. package/dist/components/molecules/LinkTile/linkTileStyles.d.ts.map +1 -0
  9. package/dist/components/molecules/LinkTile/linkTileStyles.js +8 -0
  10. package/dist/components/molecules/TileGrid/TileGrid.d.ts +42 -0
  11. package/dist/components/molecules/TileGrid/TileGrid.d.ts.map +1 -0
  12. package/dist/components/molecules/TileGrid/TileGrid.js +94 -0
  13. package/dist/components/molecules/TileGrid/tileGridMath.d.ts +8 -0
  14. package/dist/components/molecules/TileGrid/tileGridMath.d.ts.map +1 -0
  15. package/dist/components/molecules/TileGrid/tileGridMath.js +20 -0
  16. package/dist/components/molecules/TileGrid/tileGridStyles.d.ts +33 -0
  17. package/dist/components/molecules/TileGrid/tileGridStyles.d.ts.map +1 -0
  18. package/dist/components/molecules/TileGrid/tileGridStyles.js +16 -0
  19. package/dist/components/organisms/Carousel/Carousel.d.ts +58 -0
  20. package/dist/components/organisms/Carousel/Carousel.d.ts.map +1 -0
  21. package/dist/components/organisms/Carousel/Carousel.js +310 -0
  22. package/dist/components/organisms/Carousel/carouselMath.d.ts +39 -0
  23. package/dist/components/organisms/Carousel/carouselMath.d.ts.map +1 -0
  24. package/dist/components/organisms/Carousel/carouselMath.js +47 -0
  25. package/dist/components/organisms/Carousel/carouselStyles.d.ts +49 -0
  26. package/dist/components/organisms/Carousel/carouselStyles.d.ts.map +1 -0
  27. package/dist/components/organisms/Carousel/carouselStyles.js +25 -0
  28. package/dist/components/organisms/Dialog/Dialog.d.ts +12 -2
  29. package/dist/components/organisms/Dialog/Dialog.d.ts.map +1 -1
  30. package/dist/components/organisms/Dialog/Dialog.js +46 -44
  31. package/dist/components/organisms/Dialog/OverlayPanelHeader.d.ts +3 -1
  32. package/dist/components/organisms/Dialog/OverlayPanelHeader.d.ts.map +1 -1
  33. package/dist/components/organisms/Dialog/OverlayPanelHeader.js +20 -17
  34. package/dist/components/organisms/Dialog/dialogStyles.d.ts +5 -1
  35. package/dist/components/organisms/Dialog/dialogStyles.d.ts.map +1 -1
  36. package/dist/components/organisms/Dialog/dialogStyles.js +13 -11
  37. package/dist/components/organisms/FilterPanel/FilterPanel.d.ts +54 -0
  38. package/dist/components/organisms/FilterPanel/FilterPanel.d.ts.map +1 -0
  39. package/dist/components/organisms/FilterPanel/FilterPanel.js +137 -0
  40. package/dist/components/organisms/FilterPanel/filterSelection.d.ts +44 -0
  41. package/dist/components/organisms/FilterPanel/filterSelection.d.ts.map +1 -0
  42. package/dist/components/organisms/FilterPanel/filterSelection.js +35 -0
  43. package/dist/index.d.ts +4 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +73 -65
  46. package/dist/lib/compositionAudit.d.ts.map +1 -1
  47. package/dist/styles.css +1 -1
  48. package/docs/components.md +8 -4
  49. package/docs/exports.json +56 -3
  50. package/docs/patterns/components-accordion--flush.tsx +1 -1
  51. package/docs/patterns/components-avatar--dropdown-row.tsx +1 -1
  52. package/docs/patterns/components-badge--outline-tags.tsx +1 -1
  53. package/docs/patterns/components-badge--with-avatar.tsx +1 -1
  54. package/docs/patterns/components-breadcrumb--editorial.tsx +1 -1
  55. package/docs/patterns/components-breadcrumb--long-path.tsx +1 -1
  56. package/docs/patterns/components-breadcrumb--path.tsx +1 -1
  57. package/docs/patterns/components-breadcrumb--router-links.tsx +1 -1
  58. package/docs/patterns/components-button-button--copy-button.tsx +1 -1
  59. package/docs/patterns/components-button-button--destructive-action.tsx +1 -1
  60. package/docs/patterns/components-button-button--external-link.tsx +1 -1
  61. package/docs/patterns/components-button-button--ghost-action.tsx +1 -1
  62. package/docs/patterns/components-button-button--inverse-action.tsx +1 -1
  63. package/docs/patterns/components-button-button--link-render.tsx +1 -1
  64. package/docs/patterns/components-button-button--multi-state-badge.tsx +1 -1
  65. package/docs/patterns/components-button-button--outline-mono.tsx +1 -1
  66. package/docs/patterns/components-button-button--primary-action.tsx +1 -1
  67. package/docs/patterns/components-button-button--row-hug.tsx +1 -1
  68. package/docs/patterns/components-button-button--row-layout.tsx +1 -1
  69. package/docs/patterns/components-button-button--secondary-action.tsx +1 -1
  70. package/docs/patterns/components-button-button--suggestion-pills.tsx +1 -1
  71. package/docs/patterns/components-button-button--with-count.tsx +1 -1
  72. package/docs/patterns/components-button-button--with-icon.tsx +1 -1
  73. package/docs/patterns/components-button-floatingactionbutton--vertical-actions.tsx +1 -1
  74. package/docs/patterns/components-calembed--pattern-skip-in-footer.tsx +1 -1
  75. package/docs/patterns/components-card-card--body-slot-occupancy-history.tsx +1 -1
  76. package/docs/patterns/components-card-card--headerless-media.tsx +1 -1
  77. package/docs/patterns/components-card-card--outlined-layout.tsx +1 -1
  78. package/docs/patterns/components-card-card--pinned-height.tsx +1 -1
  79. package/docs/patterns/components-card-selectablecard--selectable-cards-pattern.tsx +1 -1
  80. package/docs/patterns/components-carousel--image-carousel.tsx +30 -0
  81. package/docs/patterns/components-chart--audience-activity-heatmap.tsx +1 -1
  82. package/docs/patterns/components-chart--cartesian-no-data-gaps.tsx +1 -1
  83. package/docs/patterns/components-chart--occupancy-history-in-card.tsx +1 -1
  84. package/docs/patterns/components-chart--occupancy-in-card.tsx +1 -1
  85. package/docs/patterns/components-chart--post-reach-distribution.tsx +1 -1
  86. package/docs/patterns/components-chart--ranked-audience-breakdown.tsx +1 -1
  87. package/docs/patterns/components-chart--unit-grid-composition.tsx +1 -1
  88. package/docs/patterns/components-chatdock--pattern-chat-dock.tsx +1 -1
  89. package/docs/patterns/components-chatdock--pattern-start-project-gate.tsx +1 -1
  90. package/docs/patterns/components-chatqa--pattern-qa-with-reply.tsx +1 -1
  91. package/docs/patterns/components-checkbox-checkbox--default.tsx +1 -1
  92. package/docs/patterns/components-checkbox-checkbox--with-count.tsx +1 -1
  93. package/docs/patterns/components-checkbox-checkbox--with-description.tsx +1 -1
  94. package/docs/patterns/components-checkbox-checkboxgroup--default.tsx +1 -1
  95. package/docs/patterns/components-checkbox-checkboxgroup--option-counts.tsx +1 -1
  96. package/docs/patterns/components-descriptionlist--details.tsx +1 -1
  97. package/docs/patterns/components-descriptionlist--post-metadata.tsx +1 -1
  98. package/docs/patterns/components-dialog--alert-dialog-destructive.tsx +1 -1
  99. package/docs/patterns/components-dialog--default-dialog.tsx +1 -1
  100. package/docs/patterns/components-dialog--form-dialog.tsx +1 -1
  101. package/docs/patterns/components-displaycontrols--page-utilities.tsx +1 -1
  102. package/docs/patterns/components-field--horizontal-input.tsx +1 -1
  103. package/docs/patterns/components-field--horizontal-text-area.tsx +1 -1
  104. package/docs/patterns/components-field--multi-control.tsx +1 -1
  105. package/docs/patterns/components-filterpanel--panel.tsx +55 -0
  106. package/docs/patterns/components-footerreveal--marketing-hero-pattern.tsx +1 -1
  107. package/docs/patterns/components-footerreveal--marketing-hero-ruled-pattern.tsx +1 -1
  108. package/docs/patterns/components-footerreveal--marketing-hero-with-gallery-intro.tsx +1 -1
  109. package/docs/patterns/components-footerreveal--marketing-page-pattern.tsx +1 -1
  110. package/docs/patterns/components-footerreveal--ruled-grid-footer-pattern.tsx +1 -1
  111. package/docs/patterns/components-footerreveal--sequenced-marketing-hero.tsx +1 -1
  112. package/docs/patterns/components-herointro--two-line-intro.tsx +1 -1
  113. package/docs/patterns/components-herotilestack--marketing-hero-pattern.tsx +1 -1
  114. package/docs/patterns/components-herotilestack--marketing-hero-text-sequence.tsx +1 -1
  115. package/docs/patterns/components-herotilestack--marketing-hero-with-gallery-intro.tsx +1 -1
  116. package/docs/patterns/components-indexlist--post-index.tsx +1 -1
  117. package/docs/patterns/components-intakeconfirmation--booked-pattern.tsx +1 -1
  118. package/docs/patterns/components-intakeconfirmation--emailed-pattern.tsx +1 -1
  119. package/docs/patterns/components-intakeform--about-you-pattern.tsx +1 -1
  120. package/docs/patterns/components-intakeform--short-form-pattern.tsx +1 -1
  121. package/docs/patterns/components-intakemodal--intake-modal-pattern.tsx +1 -1
  122. package/docs/patterns/components-kbd--command-row.tsx +1 -1
  123. package/docs/patterns/components-kbd--numbered-choices.tsx +1 -1
  124. package/docs/patterns/components-kbd--shortcut.tsx +1 -1
  125. package/docs/patterns/components-linktile--resource-tile.tsx +33 -0
  126. package/docs/patterns/components-linktile--router-link.tsx +25 -0
  127. package/docs/patterns/components-moremenu--action-menu.tsx +1 -1
  128. package/docs/patterns/components-moremenu--in-card-header.tsx +1 -1
  129. package/docs/patterns/components-navlist--side-nav-settings.tsx +1 -1
  130. package/docs/patterns/components-pageheader--app-header-pattern.tsx +1 -1
  131. package/docs/patterns/components-pageheader--page-section-header.tsx +1 -1
  132. package/docs/patterns/components-pageheader--toolbar-header.tsx +1 -1
  133. package/docs/patterns/components-panel--end-detail-rail.tsx +1 -1
  134. package/docs/patterns/components-pillgroup--pill-group-pattern.tsx +1 -1
  135. package/docs/patterns/components-promptbar--pattern-prompt-bar.tsx +1 -1
  136. package/docs/patterns/components-prose--article-body.tsx +1 -1
  137. package/docs/patterns/components-radio-radiogroup--default.tsx +1 -1
  138. package/docs/patterns/components-scrollhorizontal--project-gallery-pattern.tsx +1 -1
  139. package/docs/patterns/components-scrollhorizontal--with-intro.tsx +1 -1
  140. package/docs/patterns/components-sectioncaption--column-caption.tsx +1 -1
  141. package/docs/patterns/components-sectioncaption--with-action.tsx +1 -1
  142. package/docs/patterns/components-sheet--bottom-sheet.tsx +1 -1
  143. package/docs/patterns/components-sheet--end-sheet.tsx +1 -1
  144. package/docs/patterns/components-sitenav--brand-and-cta.tsx +1 -1
  145. package/docs/patterns/components-sitenav--centered-links.tsx +1 -1
  146. package/docs/patterns/components-sitenav--compact.tsx +1 -1
  147. package/docs/patterns/components-sitenav--marketing-header.tsx +1 -1
  148. package/docs/patterns/components-sitenav--mega-menu.tsx +1 -1
  149. package/docs/patterns/components-stat--insights-row.tsx +1 -1
  150. package/docs/patterns/components-stepprogress--step-progress-pattern.tsx +1 -1
  151. package/docs/patterns/components-switch--default.tsx +1 -1
  152. package/docs/patterns/components-switch--settings-row.tsx +1 -1
  153. package/docs/patterns/components-tab--settings-pages.tsx +1 -1
  154. package/docs/patterns/components-taskrows--action-details.tsx +1 -1
  155. package/docs/patterns/components-taskrows--capsules.tsx +1 -1
  156. package/docs/patterns/components-taskrows--card-with-status-rows.tsx +1 -1
  157. package/docs/patterns/components-taskrows--controlled-expand.tsx +1 -1
  158. package/docs/patterns/components-taskrows--custom-slots.tsx +1 -1
  159. package/docs/patterns/components-taskrows--status-list.tsx +1 -1
  160. package/docs/patterns/components-taskrows--tag-chips.tsx +1 -1
  161. package/docs/patterns/components-textlink--external-destination.tsx +1 -1
  162. package/docs/patterns/components-textlink--inline-prose.tsx +1 -1
  163. package/docs/patterns/components-textlink--quiet-title.tsx +1 -1
  164. package/docs/patterns/components-textlink--supporting-copy.tsx +1 -1
  165. package/docs/patterns/components-textsequence--default.tsx +1 -1
  166. package/docs/patterns/components-textsequence--reduced-motion.tsx +1 -1
  167. package/docs/patterns/components-textsequence--shapes.tsx +1 -1
  168. package/docs/patterns/components-tilegrid--masonry.tsx +44 -0
  169. package/docs/patterns/components-toast--stacked-notifications.tsx +1 -1
  170. package/docs/patterns/components-tooltip--controlled.tsx +1 -1
  171. package/docs/patterns/components-tooltip--disabled-control.tsx +1 -1
  172. package/docs/patterns/components-tooltip--icon-action.tsx +1 -1
  173. package/docs/patterns/components-tooltip--keyboard-shortcut.tsx +1 -1
  174. package/docs/patterns/components-tooltip--placement.tsx +1 -1
  175. package/docs/patterns/foundations-scroll-fade--horizontal-rail.tsx +1 -1
  176. package/docs/patterns/foundations-scroll-fade--overflowing-list.tsx +1 -1
  177. package/docs/patterns/guides-chart-explorations--comparison-gallery.tsx +1 -1
  178. package/docs/patterns/guides-filter-panel--filtered-grid.tsx +182 -0
  179. package/docs/patterns/guides-filter-panel--filtered-index.tsx +64 -153
  180. package/docs/patterns/guides-overlay-flows--notification-preferences.tsx +1 -1
  181. package/docs/patterns/guides-post-page--post-page.tsx +98 -54
  182. package/docs/patterns/guides-profile-typography--editorial-profile.tsx +1 -1
  183. package/docs/patterns/guides-resource-detail--detail.tsx +261 -0
  184. package/docs/patterns/index.json +57 -1
  185. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  # @thewhatmatters/wmds — component contracts
2
2
 
3
- Version 0.4.6. Generated from the WMDS repository's AGENTS.md (Storybook-first) by `scripts/generate-package-docs.mjs` — do not edit here.
3
+ Version 0.4.8. Generated from the WMDS repository's AGENTS.md (Storybook-first) by `scripts/generate-package-docs.mjs` — do not edit here.
4
4
 
5
5
  Storybook paths such as **Components/Button/Button → Pattern — …** name a story; its Show code is in `patterns/` (see `patterns/index.json`). Longer contracts for FooterReveal, HeroTileStack, TextSequence, ScrollHorizontal, RiveHand, and PromptBar are in `component-contracts.md`. ADR numbers refer to decision records in the WMDS repository.
6
6
 
@@ -27,6 +27,7 @@ Storybook paths such as **Components/Button/Button → Pattern — …** name a
27
27
  - **HeroTileStack:** marketing hero image fan — `tiles`; a fine pointer pushes cards away from the pointer, a coarse pointer scatters once on tap, reduced motion keeps the resting fan. **HeroIntro** is the page `h1` on `type-display-2` and sits on `grid-page`. Paste **Components/HeroTileStack → Pattern — marketing hero**. See **ADR-0032**, **ADR-0034**, **ADR-0035**. Full contract: **docs/component-contracts.md → HeroTileStack**.
28
28
  - **TextSequence:** masked word reveal — children mix text and **`TextSequence.Shape`**; `trigger` (`mount` \| `inView`), `emphasis`, `idle`, `lines`, `stagger`, `delay`. Parent owns the type step; `className` is layout only. The only component that imports GSAP (**ADR-0037**) — the rest of WMDS stays on `motion/react`. Reduced motion and the server render the rest state. Copy **Components/TextSequence**. Full contract: **docs/component-contracts.md → TextSequence**.
29
29
  - **ScrollHorizontal:** marketing gallery directly under the hero — `items`, optional `heading`, `intro` (**`ScrollHorizontal.Intro`**), `expandLast`, `expanded`; `className` on the root only. A sticky window translates the row from the first card to the last; `expandLast` then grows the last tile to full bleed. Reduced motion is a native horizontal scroller. Paste **Components/ScrollHorizontal → Pattern — project gallery**. See **ADR-0036**. Full contract: **docs/component-contracts.md → ScrollHorizontal**.
30
+ - **Carousel:** a row of items to drag, scroll, or step through, with a progress scrubber under it — **Carousel.Item** children (any content; direct children, one per item) and a required `aria-label` or `aria-labelledby` (do not give a wrapping `section` the same name). The row is a native scroller: touch, trackpad, and shift-wheel move it; a mouse drags it, with a glide and a soft stop at each end; it does not loop. `itemWidth` is a percentage of the row — one number or `{ base, sm, md, lg }` (default `{ base: 80, sm: 55, lg: 40 }`; keep it under 100 so the next item shows); the gap is the grid gutter. `snap` (default on) rests on an item's leading edge. `bleed` runs the row to the page edges while items still start on the grid. `fade` (default on) fades clipped items the way `scroll-fade-x` does. `progress` is `center` (default) / `start` (a shorter track, full width on phones) / `full` / `none`: the filled part's place is the row's progress and its width the share of the row in view; drag it, or press the track; 44px hit area; it hides itself, keeping its space, while every item fits. Keyboard: the row is the tab stop — Left and Right move one item, Home and End go to the ends (arrows swap in RTL); Tab reaches links inside items and scrolls them into view. The scrubber is `aria-hidden` and not a tab stop. Each item is a group named by its place ("2 of 4"; `labels.item`). A drag never clicks a link inside an item. Reduced motion: no glide; moves are immediate. Server render: the row at its start, the scrubber at zero. No previous / next buttons. `className` is layout only. Not a gallery driven by page scroll (**ScrollHorizontal**). Paste **Components/Carousel → Pattern — image carousel**. See **ADR-0043**.
30
31
  - **RiveHand:** decorative hand on the marketing headline (`@rive-app/react-canvas`) — `hand` (`point` \| `rock`), `size`, `inline`, `active`, `idle`, `entrance`; `aria-hidden` by default. Apps serve two files beside each other: `/rive/interactive-icon-set.riv` and `/rive/rive.wasm` (`riveHandWasmSrc`, copied from `node_modules/@rive-app/canvas/rive.wasm`). Reduced motion draws one static frame. Paste **Components/HeroTileStack → Pattern — marketing hero**. See **ADR-0034**. Full contract: **docs/component-contracts.md → RiveHand**.
31
32
  - **SiteNav:** marketing site header — `start` | `middle` | `end` slots; **page chrome** (`placement="fixed"`, optional `scrollContainer`) vs **specimen** (`placement="inline"`); expanded is **in flow** (scrolls away); after scroll past `collapseAt` (default **50% of scrollport**) a **narrower hug pill pins 1rem from the top** (`compactLayout="grid"` optional); mega panel stays **grid-wide** above a light dim; mega body: **SiteNav.Featured** / **ReadRow** / **MenuMedia** / **MenuLinkGrid** (paste **Pattern — mega menu**); below `md` mega sections stack; **SiteNav.Links** / **Link** / **Menu** / **MenuSection** / **MenuLink** (Base UI NavigationMenu) with Tab-style **More** overflow when the middle track is tight; `mobile` → **Sheet** `side="end"`. Compose **Button** `render={<a/>}` for anchors. Brand: circular **IconButton** via `icon` + `aria-label` (or wordmark **Button**). Not app chrome. See **ADR-0028**.
32
33
  - **Breadcrumb:** the path to the current page — `items` (`{ label, href }` from the root; the last, without `href`, is the current page, `aria-current="page"`). Above `maxItems` (default 4, min 3) the first item and the last `maxItems - 2` stay and the middle folds into a "…" **IconButton** that opens a **Dropdown.Menu** of links — a disclosure (focus to the first link, arrows move, Tab leaves, Escape returns focus), not an ARIA menu; the same on phones. Long labels truncate (full label in the name and `title`). `separator` `chevron` (default) / `slash`; `variant` `sans` (body) / `mono` (eyebrow caps — editorial pages, beside **SectionCaption**). `renderLink={(item) => <Link href={item.href} />}` routes every crumb and menu link. `className` is layout only. Not main navigation (**SiteNav**) or tabs (**Tab**). Paste **Components/Breadcrumb → Pattern — path**, **Pattern — long path**, **Pattern — router links**, or **Pattern — editorial**. See **ADR-0042**.
@@ -38,8 +39,11 @@ Storybook paths such as **Components/Button/Button → Pattern — …** name a
38
39
  - **Accordion:** generic expand/collapse — **leading**, **label**, **trailing**, built-in chevron, `motion-collapse` panel. Variants: `list`, `capsule`, `plain`; **`flush`** (plain only) drops the inset so labels line up with surrounding text — filter side panels. A closed panel turns `visibility: hidden` once it folds, so Tab skips its controls. **TaskRows** is the task-status pattern on top.
39
40
  - **DescriptionList:** a list of facts — `dl` > **DescriptionList.Item** (`div` > `dt` `name` + `dd` value). `layout` `inline` (value beside the name, 2 : 3 tracks, default) or `stacked` (value under it — tags, actions), per list or per item. `rule` `solid` (default) / `dotted` (quieter — beside caption rules) / `none`. `variant` `sans` (caption name, body value) or `mono` (eyebrow name, mono caps value, tabular figures — post metadata). Values take text, `<time>`, **Badge** tags, or **Button** actions; several wrap in a row. Not form fields (**Field**), metrics (**Stat**), or status rows (**TaskRows**). Paste **Components/DescriptionList → Pattern — post metadata** or **Pattern — details**. See **ADR-0041**.
40
41
  - **SectionCaption:** the small uppercase mono caption over a page column ("/ Metadata", "/ Article", "/ Filters") — `type-eyebrow` on a `border-border-emphasized` rule; the "/" `marker` is `aria-hidden`. `as` `h2` (default — pair `id` with the region's `aria-labelledby`) or `p` (labels a column that has its own heading); `end` holds a **Button** `size="xs"` (Clear all) without growing the row; `rule` / `marker` can be turned off. Write `children` in sentence case. Copy **Components/SectionCaption → Pattern — column caption**. See **ADR-0041**.
41
- - **Prose:** long-form content set from plain HTML elements (rendered markdown) — headings, paragraphs, lists, quotes, inline code, code blocks, rules, images, figures, and tables, with the spacing between them. `size` `lg` (default — `type-reading`, headings a step up) or `md` (`type-body`, denser notes); `measure` `reading` (40rem, default) or `none`; `as` `div` / `article` / `section`. Wide tables scroll in their own box. Map markdown `#` to `h2` under a page `h1`, and links to **TextLink** (`external` for other sites). Never add classes to the elements inside. Paste **Components/Prose → Pattern — article body**; the full page is **Guides/Post page → Pattern — post page** (`metadataSide` `start` / `end` and `metadataColumns` 4 / 3 place the panel — never edit its classes). See **ADR-0041**.
42
+ - **Prose:** long-form content set from plain HTML elements (rendered markdown) — headings, paragraphs, lists, quotes, inline code, code blocks, rules, images, figures, and tables, with the spacing between them. `size` `lg` (default — `type-reading`, headings a step up) or `md` (`type-body`, denser notes); `measure` `reading` (40rem, default) or `none`; `as` `div` / `article` / `section`. Wide tables scroll in their own box. Map markdown `#` to `h2` under a page `h1`, and links to **TextLink** (`external` for other sites). Never add classes to the elements inside. Paste **Components/Prose → Pattern — article body**; the full page is **Guides/Post page → Pattern — post page** (`metadataSide` `start` / `end` and `metadataColumns` 4 / 3 place the panel from `lg`; `metadataStack` `after` (default) / `before` places it below `lg`, where it stacks, and in the markup — `after` adds a date and reading-time line under the title below `lg`; pair `end` with `after` or `start` with `before` so tab order matches the layout at every width — never edit its classes). See **ADR-0041**.
42
43
  - **IndexList:** editorial index for list pages (blog, case studies) — **IndexList.Item** rows with `meta` (a `<time>`), a linked `title` (`href`; a quiet **TextLink** in an `h2` by default — `titleAs`), and an optional `preview` an **IconButton** disclosure expands under the title. Optional `captions={{ meta, title }}` in sentence case (`type-eyebrow`, the "/" marker and the **SectionCaption** rule, `aria-hidden`) share the rows' tracks. Two tracks (7.5rem meta, title) once the list is 32rem wide (container query); one column below, captions hidden. `size` `lg` (type-display-3, default) / `md` / `sm`. `empty` replaces the rows when there are none. `className` is layout only. Not tabular data — **Table** is planned. Paste **Components/IndexList → Pattern — post index**; with filters, **Guides/Filter panel → Pattern — filtered index** (a post's `facets` take one option or several per group; `defaultSelection` opens the page filtered, `selection` + `onSelectionChange` hold it in the URL). See **ADR-0040**.
44
+ - **LinkTile:** a resource tile that is one link — `title`, `href` (or `render={<Link href />}` for a router link), `media` (an `<img>` or `next/image` with its `width` and `height`; one image, not a video), `meta` (one line, for example the domain), optional `tag` (a **Badge**, over the image's top-start corner) and `source` (**Avatar** `size="xsm"` or a 20px favicon, before the title). The whole tile is the anchor: one hit area, one focus ring; never put a link or a button inside it. `external` opens a new tab with a safe `rel`, the trailing mark **TextLink** uses, and spoken "(opens in a new tab)" — never hand-write `target`. Screen readers hear the title, the meta, the tag, then the new-tab hint; the image's `alt` is not in the link's name. The image keeps its own ratio by default, so tiles vary in height and hold their space before the image loads; `ratio` (width / height, `4 / 3`) fixes the frame and crops the image. A hairline inside the frame keeps an edge on a light image in light mode and a dark image in dark mode; hover and focus darken it and underline the title. `loading` is a **Skeleton** placeholder, not a link. `className` is layout only. Not a **Card** (a surface with slots that can hold several controls). Paste **Components/LinkTile → Pattern — resource tile** or **Pattern — router link**. See **ADR-0044**.
45
+ - **TileGrid:** a grid of tiles on the grid gutter — **TileGrid.Item** children, each with a stable `key`, and `aria-label` or `aria-labelledby`. `layout` `masonry` (default — tiles keep their heights and pack; each next item goes to the shortest column) or `uniform` (rows of equal height; give the tiles a `ratio`). `columns` — one number or `{ base, sm, md, lg, xl }` (default `{ base: 1, sm: 2, lg: 3 }`). Reading order and tab order are the order of the items in both layouts — across the top row, then down the page; never use CSS columns or `order`. `empty` replaces the tiles when there are none; `busy` marks a grid of placeholders. Masonry packs after it measures: the server and the first paint show aligned rows, then the tiles close up (one column needs no packing); the space under a tile is the 2rem row gap, within 3px. On a server-rendered page that is one instant move at hydration — nothing slides or fades — on grids of two or more columns; `uniform` is CSS alone and does not move at all, so use it where that move is not acceptable. When the items change, the ones that stay move and the others fade; reduced motion changes at once. `className` is layout only. Not dated rows (**IndexList**) or a row to drag (**Carousel**). Paste **Components/TileGrid → Pattern — tile grid**; with filters, **Guides/Filter panel → Pattern — filtered grid**. See **ADR-0044**.
46
+ - **FilterPanel:** checkbox filters for an index page — **FilterPanel** (no element; holds `groups`, `selection` + `onSelectionChange`, `resultsLabel` such as "3 posts", optional `labels`) around the page, with **FilterPanel.Rail** (`aside`: **SectionCaption** "Filters" with Clear all, flush **Accordion** groups of **CheckboxGroup** with counts), **FilterPanel.Trigger** (**Button** `secondary` with the number of options on), and **FilterPanel.Sheet** (the same groups in a bottom **Sheet**; Clear all · Show N). Show the rail and the trigger at opposite breakpoints with `className` (`hidden md:col-span-3 md:block` / `md:hidden`). Helpers: `useFilterSelection({ defaultSelection, selection, onSelectionChange })`, `matchesFilterSelection(facets, selection)` (alternatives within a group, combined across groups), `countFilterOptions(groups, items, label)`, `filterSelectionCount(selection)`. Never write a count into an option label. Not a single choice (**Select**, **SegmentedControl**). Paste **Components/FilterPanel → Pattern — filter panel**; the full pages are **Guides/Filter panel → Pattern — filtered index** and **Pattern — filtered grid** (the grid also takes `renderLink` — the router's link for a tile — and `renderImage` — the app's image component; both take `overlay` for page-level layers such as **GridOverlay**, as does **Guides/Post page → Pattern — post page** — never add elements to a pasted pattern's markup). See **ADR-0044**.
43
47
  - **Card:** `Card.Header`, `Card.Body`, `Card.Footer`. Layout cards (`padding="none"`): header/footer on the shell; **`Card.Header`** is two horizontal slots (`start` | `end`) at **16px** (`px-4`). **`end` is always trailing** (`ml-auto`) — overflow / **MoreMenu** stays on the right even when `start` is omitted. **`Card.Body` is a square composition slot** with a **2px** horizontal gutter — no inner pad, no radius, **no default fill**. The **occupant** dictates how the body region looks; use **`cardLayoutBodyOccupantInsetXClasses`** (`px-3.5` / 14px) + **`cardLayoutBodyOccupantPadYClasses`** (`py-[16px]` / literal 16px vertical) when body content should align with header/footer (2px + 14px = 16px horizontal). Shape config lives in **`src/theme/shape.css`**: shell **`--radius-card-shell: 16px`**, body occupant **`--radius-card-body: 14px`**. Radius-only media → **`cardLayoutBodyOccupantRadiusClasses`**; inset gray/chart wells → **`cardLayoutBodyOccupantWellClasses`** or **`cardLayoutBodyOccupantDotGridWellClasses`**. A headerless layout **Card.Body** densifies the shell top to 2px (`pt-[2px]`) — same density as footerless / `bodyTerminal` bottom; **`headerless`** is only an override for wrapped slot composition. A direct terminal **`Card.Body`** automatically fills stretched cards and gets the 2px bottom shell inset; **`bodyTerminal`** is only an override for wrapped slot composition. Pin a layout height on the root (`className`) with Header + Body + Footer — Header/Footer stay put; **Card.Body** scrolls (2px gutter unchanged; no new variant). See **Components/Card/Card → Pattern — pinned height**. `variant="surface"` is elevated; **`variant="outlined"`** uses **`shadow-soft-card`** with no stroke (same elevation as layout `surface`). Radius stays **`--radius-card-shell`**. Default **`shape="rounded"`**. **`shape="flush"`** only when a parent owns outer chrome. Simple cards: `padding="md"`.
44
48
  - **Input:** pill-only. Optional leading `icon`; trailing `endBadge` or status / `loading`. Hero search with inset button → **Search** molecule. See **ADR-0006**.
45
49
  - **PromptBar:** wide prompt pill — inline **TextArea** (one line when empty, grows through 3 lines, then scrolls) and an inset **IconButton** `sm` send control. Enter sends; Shift+Enter inserts a newline; send stays disabled until the draft has text. Optional `start` (brand mark — **Avatar** `size="md"`) and `end` (extra inset **IconButton** `sm`) slots. No new Button role. Copy **Components/PromptBar → Pattern — prompt bar**. The site assistant on the marketing pages is **ChatDock**, not a hand-pinned PromptBar. Do not restyle **SiteNav**. Full contract: **docs/component-contracts.md → PromptBar**.
@@ -50,13 +54,13 @@ Storybook paths such as **Components/Button/Button → Pattern — …** name a
50
54
  - **Radio:** single option circle — same label row rhythm as **Checkbox**; compose in **RadioGroup**. See **ADR-0006**.
51
55
  - **RadioGroup:** mutually exclusive options — `value` / `onValueChange`, vertical or horizontal layout, group validation band.
52
56
  - **Switch:** instant on/off — pill track + sliding thumb; `layout="settings"` for label-left rows. See **ADR-0006**.
53
- - **CheckboxGroup:** multi-select options — `values` / `onValuesChange`, vertical or horizontal layout, group validation band. **CheckboxGroup.Item** takes `count` / `countLabel` like **Checkbox**. A filter side panel — **Accordion** `flush` groups, counts, Clear all, a **Sheet** on phones — is **Guides/Filter panel → Pattern — filtered index**.
57
+ - **CheckboxGroup:** multi-select options — `values` / `onValuesChange`, vertical or horizontal layout, group validation band. **CheckboxGroup.Item** takes `count` / `countLabel` like **Checkbox**. A filter side panel — **Accordion** `flush` groups, counts, Clear all, a **Sheet** on phones — is **FilterPanel**.
54
58
  - **Select:** pill trigger matched to **Input** shell + floating listbox (**Dropdown.Menu** / **Dropdown.Item**). **`size="sm"`** in Card headers beside **Chip sm**. Options support **`start`** / **`end`** slots for icons and shortcuts. See **Components/Select**, **Components/Dropdown**.
55
59
  - **Dropdown:** shared menu panel (`p-0.5` inset) + three-slot rows (`start` | label | `end`) — composed by **Select**; action menus via **MoreMenu**. **Dropdown.Item** `render={<a href />}` makes a row a link (a menu of links — **Breadcrumb**'s collapsed path).
56
60
  - **MoreMenu:** kebab **IconButton** + floating **Dropdown** action menu — **Card.Header** `end` (right) only; never left-align overflow. Menu right-aligns to trigger; expanded trigger retains the ghost hover surface; **`items`** + **`onAction`**. Sizes **`xs` | `sm` | `md` | `lg`** (**IconButton** scale). Not for single-select — **Select** / **SegmentedControl**.
57
61
  - **Toast:** temporary notification organism — mount one **`Toaster`** at the app root (it renders nothing on the server and mounts its list after hydration, so a layout can hold it) and call **`toast.add()`** / `update()` / `dismiss()`. Six `position` values (top/bottom × left/center/right), default five-item layered deck (newest interactive in front, older surfaces offset behind), semantic tones, optional action (**Button**) and dismiss (**IconButton**). Errors announce as `alert`; other tones as `status`. `duration: null` persists. Blocking decisions use **AlertDialog**. See **ADR-0025**.
58
62
  - **Confetti:** celebratory burst — mount one **`ConfettiProvider`**. After an async success, render the confirmation surface and call **`useConfettiOnMount(options?)`** there (once per mount; a ref skips StrictMode and re-renders). **`useConfetti().fire(options?)`** is the same burst when the moment is not a mount. `origin` is an element, a ref (center of the box), or a viewport `{ x, y }` point; default is the viewport center. Confirmation pages pass the top-center of the viewport and a wide `spread`. Overlapping bursts are kept. Removed `duration + 0.5s` after start. Reduced motion: `fire()` does nothing. Colors default to chart categorical 1–7 (`confettiDefaultColors`). There is no trigger component. **IntakeConfirmation** is the reference composition. See **ADR-0031**.
59
- - **Dialog:** modal overlay — portal scrim, focus trap, scroll lock, **medium** enter/exit; composes **Card** shell + **IconButton** close. **`Dialog.Content`** — `title`, `description`, `footer`, `size` (`sm` | `md` | `lg`); header/footer pinned, body scrolls; **no section hairlines** — brief/direct copy + `gap-4` section rhythm. **`AlertDialog`** — blocking confirm with cancel + confirm **Button** roles; `confirmRole="destructive"` for irreversible actions; scrim dismiss off by default.
63
+ - **Dialog:** modal overlay — portal scrim, focus trap, scroll lock, **medium** enter/exit; composes **Card** shell + **IconButton** close. **`Dialog.Content`** — `title`, `description`, `footer`, `size` (`sm` | `md` | `lg` | **`full`** — the window less a margin, up to 90rem × 60rem, and the whole screen on phones: media viewers and detail views), `headerEnd` (**IconButton** `size="sm"` actions before the close — previous / next), `aria-labelledby` (names the dialog from a heading in the body when there is no `title`); header/footer pinned, body scrolls; **no section hairlines** — brief/direct copy + `gap-4` section rhythm. **`AlertDialog`** — blocking confirm with cancel + confirm **Button** roles; `confirmRole="destructive"` for irreversible actions; scrim dismiss off by default.
60
64
  - **IntakeModal:** full-screen Start a project shell — typographic **WM** + **WhatMatters** wordmark (no separate logo asset), **IconButton** close (Lucide **X**, name **Close**), **StepProgress** (navy segments, pill label **Step N of 4**), pinned **Back** / **Continue** footer. Focus trap, Escape, scroll lock, `aria-modal`. **SelectableCard** is the multi-select grid (2 columns mobile, 3 from `lg`) with a `toggle` slot for hugged **SegmentedControl** and a **Badge** `iconOnly` check. **PillGroup** is the wrapping radio pills; **Not sure yet** uses existing **Badge** neutral `emphasis="muted"` — no new Badge emphasis. **IntakeForm** is **Field** + **Input** / **TextArea** (optional Link URL); required fields show `status` + `message` on blur; company and link stay optional, and `company={false}` / `link={false}` leave them out (the short form — name, email, details — which **Pattern — start a project gate** uses; their values stay empty in `IntakeAboutValues`); the details counter is the field description. **CalEmbed** is the calendar frame plus **TextLink** skip; with no embed mounted it shows a visitor-facing empty state (`emptyTitle`, `emptyDescription`), never developer notes. **CalEmbed.Skip** is that same skip; in a **Card** gate put it in **Card.Footer** and pass `skip={false}` so the in-body link is omitted. **IntakeConfirmation** (`booked` | `emailed`) calls **`useConfettiOnMount`** with `intakeConfettiColors` (includes `--color-brand`); optional `bookingTime` / `videoHref` / `googleCalendarHref` / `icsHref` reuse **TextLink** and **Button**. Copy **Components/IntakeModal → Pattern — intake modal** and compose the steps in the app. See **ADR-0038**.
61
65
  - **Sheet:** dismissible edge overlay — `side="bottom" | "end" | "start"` only (**no `top`** — not a product pattern); same scrim/focus/scroll lock as **Dialog**; bottom drawer or side detail rail; header/footer pinned, body scrolls; **hairline borders** on scroll regions. Mobile **16px inset on trailing edge only** (e.g. `end` → left gap for scrim; entry/top/bottom flush); tablet+ side sheets fully edge-flush. **`Sheet.Content`** — Card header rhythm, scrollable body, optional footer.
62
66
  - **Panel:** persistent edge flyover — `side="end" | "start"` only; **non-blocking visual scrim** (clicks pass through), **no scroll lock**, **no focus trap**; `aria-modal="false"`; page stays interactive. Same width tokens and hairline scroll chrome as **Sheet** side panels. Use for peek/detail rails; use **Sheet** when the canvas should block.
package/docs/exports.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@thewhatmatters/wmds",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "import": "import { Button } from \"@thewhatmatters/wmds\";",
5
5
  "styles": [
6
6
  "@thewhatmatters/wmds/styles.css",
@@ -139,6 +139,19 @@
139
139
  "components-card-card--pinned-height"
140
140
  ]
141
141
  },
142
+ {
143
+ "name": "Carousel",
144
+ "tier": "organism",
145
+ "category": "Container",
146
+ "summary": "A row of items to drag, scroll, or step through, with a progress scrubber under it.",
147
+ "storybook": {
148
+ "title": "Components/Carousel",
149
+ "docs": "?path=/docs/components-carousel--docs"
150
+ },
151
+ "patterns": [
152
+ "components-carousel--image-carousel"
153
+ ]
154
+ },
142
155
  {
143
156
  "name": "Chart",
144
157
  "tier": "organism",
@@ -304,6 +317,19 @@
304
317
  "components-field--multi-control"
305
318
  ]
306
319
  },
320
+ {
321
+ "name": "FilterPanel",
322
+ "tier": "organism",
323
+ "category": "Form controls",
324
+ "summary": "Checkbox filters for an index page: a side rail from tablet up and the same groups in a bottom Sheet on phones.",
325
+ "storybook": {
326
+ "title": "Components/FilterPanel",
327
+ "docs": "?path=/docs/components-filterpanel--docs"
328
+ },
329
+ "patterns": [
330
+ "components-filterpanel--panel"
331
+ ]
332
+ },
307
333
  {
308
334
  "name": "FloatingActionButton",
309
335
  "tier": "molecule",
@@ -454,6 +480,20 @@
454
480
  "components-kbd--shortcut"
455
481
  ]
456
482
  },
483
+ {
484
+ "name": "LinkTile",
485
+ "tier": "molecule",
486
+ "category": "Navigation",
487
+ "summary": "A resource tile that is one link: a preview image with a name, where it lives, and an optional tag.",
488
+ "storybook": {
489
+ "title": "Components/LinkTile",
490
+ "docs": "?path=/docs/components-linktile--docs"
491
+ },
492
+ "patterns": [
493
+ "components-linktile--resource-tile",
494
+ "components-linktile--router-link"
495
+ ]
496
+ },
457
497
  {
458
498
  "name": "MoreMenu",
459
499
  "tier": "organism",
@@ -828,6 +868,19 @@
828
868
  "components-textsequence--shapes"
829
869
  ]
830
870
  },
871
+ {
872
+ "name": "TileGrid",
873
+ "tier": "molecule",
874
+ "category": "Layout",
875
+ "summary": "A grid of tiles that pack as masonry or sit in equal rows, in reading order either way.",
876
+ "storybook": {
877
+ "title": "Components/TileGrid",
878
+ "docs": "?path=/docs/components-tilegrid--docs"
879
+ },
880
+ "patterns": [
881
+ "components-tilegrid--masonry"
882
+ ]
883
+ },
831
884
  {
832
885
  "name": "Toast",
833
886
  "tier": "organism",
@@ -860,7 +913,6 @@
860
913
  }
861
914
  ],
862
915
  "planned": [
863
- "Carousel",
864
916
  "Pagination",
865
917
  "Table"
866
918
  ],
@@ -880,6 +932,7 @@
880
932
  "Guides/Filter panel",
881
933
  "Guides/Overlay flows",
882
934
  "Guides/Post page",
883
- "Guides/Profile typography"
935
+ "Guides/Profile typography",
936
+ "Guides/Resource detail"
884
937
  ]
885
938
  }
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — flush
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — flush
2
2
  // Storybook: Components/Accordion → Pattern — flush (?path=/story/components-accordion--flush)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — dropdown row
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — dropdown row
2
2
  // Storybook: Components/Avatar → Pattern — dropdown row (?path=/story/components-avatar--dropdown-row)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — outline tags
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — outline tags
2
2
  // Storybook: Components/Badge → Pattern — outline tags (?path=/story/components-badge--outline-tags)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — with avatar
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — with avatar
2
2
  // Storybook: Components/Badge → Pattern — with avatar (?path=/story/components-badge--with-avatar)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — editorial
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — editorial
2
2
  // Storybook: Components/Breadcrumb → Pattern — editorial (?path=/story/components-breadcrumb--editorial)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — long path
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — long path
2
2
  // Storybook: Components/Breadcrumb → Pattern — long path (?path=/story/components-breadcrumb--long-path)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — path
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — path
2
2
  // Storybook: Components/Breadcrumb → Pattern — path (?path=/story/components-breadcrumb--path)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — router links
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — router links
2
2
  // Storybook: Components/Breadcrumb → Pattern — router links (?path=/story/components-breadcrumb--router-links)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — copy button
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — copy button
2
2
  // Storybook: Components/Button/Button → Pattern — copy button (?path=/story/components-button-button--copy-button)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — destructive action
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — destructive action
2
2
  // Storybook: Components/Button/Button → Pattern — destructive action (?path=/story/components-button-button--destructive-action)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — external link
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — external link
2
2
  // Storybook: Components/Button/Button → Pattern — external link (?path=/story/components-button-button--external-link)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — ghost action
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — ghost action
2
2
  // Storybook: Components/Button/Button → Pattern — ghost action (?path=/story/components-button-button--ghost-action)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — inverse action
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — inverse action
2
2
  // Storybook: Components/Button/Button → Pattern — inverse action (?path=/story/components-button-button--inverse-action)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — link
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — link
2
2
  // Storybook: Components/Button/Button → Pattern — link (?path=/story/components-button-button--link-render)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — submit / async
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — submit / async
2
2
  // Storybook: Components/Button/Button → Pattern — submit / async (?path=/story/components-button-button--multi-state-badge)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — outline mono
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — outline mono
2
2
  // Storybook: Components/Button/Button → Pattern — outline mono (?path=/story/components-button-button--outline-mono)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — primary action
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — primary action
2
2
  // Storybook: Components/Button/Button → Pattern — primary action (?path=/story/components-button-button--primary-action)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — row (hug)
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — row (hug)
2
2
  // Storybook: Components/Button/Button → Pattern — row (hug) (?path=/story/components-button-button--row-hug)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — row
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — row
2
2
  // Storybook: Components/Button/Button → Pattern — row (?path=/story/components-button-button--row-layout)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — secondary action
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — secondary action
2
2
  // Storybook: Components/Button/Button → Pattern — secondary action (?path=/story/components-button-button--secondary-action)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — suggestion pills
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — suggestion pills
2
2
  // Storybook: Components/Button/Button → Pattern — suggestion pills (?path=/story/components-button-button--suggestion-pills)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — with count
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — with count
2
2
  // Storybook: Components/Button/Button → Pattern — with count (?path=/story/components-button-button--with-count)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — with icon
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — with icon
2
2
  // Storybook: Components/Button/Button → Pattern — with icon (?path=/story/components-button-button--with-icon)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — vertical actions
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — vertical actions
2
2
  // Storybook: Components/Button/FloatingActionButton → Pattern — vertical actions (?path=/story/components-button-floatingactionbutton--vertical-actions)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — skip in footer
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — skip in footer
2
2
  // Storybook: Components/CalEmbed → Pattern — skip in footer (?path=/story/components-calembed--pattern-skip-in-footer)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Example — body slot (occupancy history)
1
+ // @thewhatmatters/wmds@0.4.8 · Example — body slot (occupancy history)
2
2
  // Storybook: Components/Card/Card → Example — body slot (occupancy history) (?path=/story/components-card-card--body-slot-occupancy-history)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — headerless media
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — headerless media
2
2
  // Storybook: Components/Card/Card → Pattern — headerless media (?path=/story/components-card-card--headerless-media)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — outlined layout
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — outlined layout
2
2
  // Storybook: Components/Card/Card → Pattern — outlined layout (?path=/story/components-card-card--outlined-layout)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — pinned height
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — pinned height
2
2
  // Storybook: Components/Card/Card → Pattern — pinned height (?path=/story/components-card-card--pinned-height)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — selectable cards
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — selectable cards
2
2
  // Storybook: Components/Card/SelectableCard → Pattern — selectable cards (?path=/story/components-card-selectablecard--selectable-cards-pattern)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -0,0 +1,30 @@
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — image carousel
2
+ // Storybook: Components/Carousel → Pattern — image carousel (?path=/story/components-carousel--image-carousel)
3
+ // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
+
5
+ import { Card, Carousel, cardLayoutBodyOccupantRadiusClasses } from "@thewhatmatters/wmds";
6
+
7
+ export interface CarouselImage {
8
+ src: string;
9
+ alt: string;
10
+ }
11
+
12
+ export function ImageCarousel({ label, images }: { label: string; images: CarouselImage[] }) {
13
+ return (
14
+ <Carousel aria-label={label}>
15
+ {images.map((image) => (
16
+ <Carousel.Item key={image.src}>
17
+ <Card variant="outlined" shape="rounded">
18
+ <Card.Body>
19
+ <img
20
+ className={`aspect-[4/3] w-full object-cover ${cardLayoutBodyOccupantRadiusClasses}`}
21
+ src={image.src}
22
+ alt={image.alt}
23
+ />
24
+ </Card.Body>
25
+ </Card>
26
+ </Carousel.Item>
27
+ ))}
28
+ </Carousel>
29
+ );
30
+ }
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — matrix heatmap
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — matrix heatmap
2
2
  // Storybook: Components/Chart → Pattern — matrix heatmap (?path=/story/components-chart--audience-activity-heatmap)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — Cartesian no-data gaps
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — Cartesian no-data gaps
2
2
  // Storybook: Components/Chart → Pattern — Cartesian no-data gaps (?path=/story/components-chart--cartesian-no-data-gaps)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — occupancy history in Card
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — occupancy history in Card
2
2
  // Storybook: Components/Chart → Pattern — occupancy history in Card (?path=/story/components-chart--occupancy-history-in-card)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — occupancy KPI in Card
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — occupancy KPI in Card
2
2
  // Storybook: Components/Chart → Pattern — occupancy KPI in Card (?path=/story/components-chart--occupancy-in-card)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — distribution strip
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — distribution strip
2
2
  // Storybook: Components/Chart → Pattern — distribution strip (?path=/story/components-chart--post-reach-distribution)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — ranked audience breakdown
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — ranked audience breakdown
2
2
  // Storybook: Components/Chart → Pattern — ranked audience breakdown (?path=/story/components-chart--ranked-audience-breakdown)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — 100-unit composition
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — 100-unit composition
2
2
  // Storybook: Components/Chart → Pattern — 100-unit composition (?path=/story/components-chart--unit-grid-composition)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — chat dock
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — chat dock
2
2
  // Storybook: Components/ChatDock → Pattern — chat dock (?path=/story/components-chatdock--pattern-chat-dock)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — start a project gate
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — start a project gate
2
2
  // Storybook: Components/ChatDock → Pattern — start a project gate (?path=/story/components-chatdock--pattern-start-project-gate)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — Q&A with reply
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — Q&A with reply
2
2
  // Storybook: Components/ChatQa → Pattern — Q&A with reply (?path=/story/components-chatqa--pattern-qa-with-reply)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — default
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — default
2
2
  // Storybook: Components/Checkbox/Checkbox → Pattern — default (?path=/story/components-checkbox-checkbox--default)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — with count
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — with count
2
2
  // Storybook: Components/Checkbox/Checkbox → Pattern — with count (?path=/story/components-checkbox-checkbox--with-count)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — with description
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — with description
2
2
  // Storybook: Components/Checkbox/Checkbox → Pattern — with description (?path=/story/components-checkbox-checkbox--with-description)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — default
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — default
2
2
  // Storybook: Components/Checkbox/CheckboxGroup → Pattern — default (?path=/story/components-checkbox-checkboxgroup--default)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — option counts
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — option counts
2
2
  // Storybook: Components/Checkbox/CheckboxGroup → Pattern — option counts (?path=/story/components-checkbox-checkboxgroup--option-counts)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — details
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — details
2
2
  // Storybook: Components/DescriptionList → Pattern — details (?path=/story/components-descriptionlist--details)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — post metadata
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — post metadata
2
2
  // Storybook: Components/DescriptionList → Pattern — post metadata (?path=/story/components-descriptionlist--post-metadata)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — alert dialog (destructive)
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — alert dialog (destructive)
2
2
  // Storybook: Components/Dialog → Pattern — alert dialog (destructive) (?path=/story/components-dialog--alert-dialog-destructive)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — dialog
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — dialog
2
2
  // Storybook: Components/Dialog → Pattern — dialog (?path=/story/components-dialog--default-dialog)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — form dialog
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — form dialog
2
2
  // Storybook: Components/Dialog → Pattern — form dialog (?path=/story/components-dialog--form-dialog)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4
 
@@ -1,4 +1,4 @@
1
- // @thewhatmatters/wmds@0.4.6 · Pattern — page display controls
1
+ // @thewhatmatters/wmds@0.4.8 · Pattern — page display controls
2
2
  // Storybook: Components/DisplayControls → Pattern — page display controls (?path=/story/components-displaycontrols--page-utilities)
3
3
  // Show code — copy verbatim and keep this header; upgrades find pasted patterns by it.
4
4