@thewhatmatters/wmds 0.4.7 → 0.4.9

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 (186) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/CONSUMING.md +4 -1
  3. package/bin/wmds-check.mjs +8 -4
  4. package/dist/components/atoms/TextLink/TextLink.d.ts +9 -3
  5. package/dist/components/atoms/TextLink/TextLink.d.ts.map +1 -1
  6. package/dist/components/atoms/TextLink/TextLink.js +22 -17
  7. package/dist/components/molecules/IndexList/IndexList.d.ts +6 -3
  8. package/dist/components/molecules/IndexList/IndexList.d.ts.map +1 -1
  9. package/dist/components/molecules/IndexList/IndexList.js +22 -21
  10. package/dist/components/molecules/LinkTile/LinkTile.d.ts +45 -0
  11. package/dist/components/molecules/LinkTile/LinkTile.d.ts.map +1 -0
  12. package/dist/components/molecules/LinkTile/LinkTile.js +121 -0
  13. package/dist/components/molecules/LinkTile/linkTileStyles.d.ts +37 -0
  14. package/dist/components/molecules/LinkTile/linkTileStyles.d.ts.map +1 -0
  15. package/dist/components/molecules/LinkTile/linkTileStyles.js +8 -0
  16. package/dist/components/molecules/TileGrid/TileGrid.d.ts +42 -0
  17. package/dist/components/molecules/TileGrid/TileGrid.d.ts.map +1 -0
  18. package/dist/components/molecules/TileGrid/TileGrid.js +94 -0
  19. package/dist/components/molecules/TileGrid/tileGridMath.d.ts +8 -0
  20. package/dist/components/molecules/TileGrid/tileGridMath.d.ts.map +1 -0
  21. package/dist/components/molecules/TileGrid/tileGridMath.js +20 -0
  22. package/dist/components/molecules/TileGrid/tileGridStyles.d.ts +33 -0
  23. package/dist/components/molecules/TileGrid/tileGridStyles.d.ts.map +1 -0
  24. package/dist/components/molecules/TileGrid/tileGridStyles.js +16 -0
  25. package/dist/components/organisms/Dialog/Dialog.d.ts +12 -2
  26. package/dist/components/organisms/Dialog/Dialog.d.ts.map +1 -1
  27. package/dist/components/organisms/Dialog/Dialog.js +46 -44
  28. package/dist/components/organisms/Dialog/OverlayPanelHeader.d.ts +3 -1
  29. package/dist/components/organisms/Dialog/OverlayPanelHeader.d.ts.map +1 -1
  30. package/dist/components/organisms/Dialog/OverlayPanelHeader.js +20 -17
  31. package/dist/components/organisms/Dialog/dialogStyles.d.ts +5 -1
  32. package/dist/components/organisms/Dialog/dialogStyles.d.ts.map +1 -1
  33. package/dist/components/organisms/Dialog/dialogStyles.js +13 -11
  34. package/dist/components/organisms/FilterPanel/FilterPanel.d.ts +54 -0
  35. package/dist/components/organisms/FilterPanel/FilterPanel.d.ts.map +1 -0
  36. package/dist/components/organisms/FilterPanel/FilterPanel.js +137 -0
  37. package/dist/components/organisms/FilterPanel/filterSelection.d.ts +44 -0
  38. package/dist/components/organisms/FilterPanel/filterSelection.d.ts.map +1 -0
  39. package/dist/components/organisms/FilterPanel/filterSelection.js +35 -0
  40. package/dist/index.d.ts +3 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +73 -67
  43. package/dist/lib/compositionAudit.d.ts.map +1 -1
  44. package/dist/lib/typography.d.ts +2 -2
  45. package/dist/lib/typography.d.ts.map +1 -1
  46. package/dist/lib/typography.js +11 -0
  47. package/dist/styles.css +1 -1
  48. package/dist/typography.css +16 -0
  49. package/docs/components.md +10 -7
  50. package/docs/exports.json +43 -2
  51. package/docs/patterns/components-accordion--flush.tsx +1 -1
  52. package/docs/patterns/components-avatar--dropdown-row.tsx +1 -1
  53. package/docs/patterns/components-badge--outline-tags.tsx +1 -1
  54. package/docs/patterns/components-badge--with-avatar.tsx +1 -1
  55. package/docs/patterns/components-breadcrumb--editorial.tsx +1 -1
  56. package/docs/patterns/components-breadcrumb--long-path.tsx +1 -1
  57. package/docs/patterns/components-breadcrumb--path.tsx +1 -1
  58. package/docs/patterns/components-breadcrumb--router-links.tsx +1 -1
  59. package/docs/patterns/components-button-button--copy-button.tsx +1 -1
  60. package/docs/patterns/components-button-button--destructive-action.tsx +1 -1
  61. package/docs/patterns/components-button-button--external-link.tsx +1 -1
  62. package/docs/patterns/components-button-button--ghost-action.tsx +1 -1
  63. package/docs/patterns/components-button-button--inverse-action.tsx +1 -1
  64. package/docs/patterns/components-button-button--link-render.tsx +1 -1
  65. package/docs/patterns/components-button-button--multi-state-badge.tsx +1 -1
  66. package/docs/patterns/components-button-button--outline-mono.tsx +1 -1
  67. package/docs/patterns/components-button-button--primary-action.tsx +1 -1
  68. package/docs/patterns/components-button-button--row-hug.tsx +1 -1
  69. package/docs/patterns/components-button-button--row-layout.tsx +1 -1
  70. package/docs/patterns/components-button-button--secondary-action.tsx +1 -1
  71. package/docs/patterns/components-button-button--suggestion-pills.tsx +1 -1
  72. package/docs/patterns/components-button-button--with-count.tsx +1 -1
  73. package/docs/patterns/components-button-button--with-icon.tsx +1 -1
  74. package/docs/patterns/components-button-floatingactionbutton--vertical-actions.tsx +1 -1
  75. package/docs/patterns/components-calembed--pattern-skip-in-footer.tsx +1 -1
  76. package/docs/patterns/components-card-card--body-slot-occupancy-history.tsx +1 -1
  77. package/docs/patterns/components-card-card--headerless-media.tsx +1 -1
  78. package/docs/patterns/components-card-card--outlined-layout.tsx +1 -1
  79. package/docs/patterns/components-card-card--pinned-height.tsx +1 -1
  80. package/docs/patterns/components-card-selectablecard--selectable-cards-pattern.tsx +1 -1
  81. package/docs/patterns/components-carousel--image-carousel.tsx +1 -1
  82. package/docs/patterns/components-chart--audience-activity-heatmap.tsx +1 -1
  83. package/docs/patterns/components-chart--cartesian-no-data-gaps.tsx +1 -1
  84. package/docs/patterns/components-chart--occupancy-history-in-card.tsx +1 -1
  85. package/docs/patterns/components-chart--occupancy-in-card.tsx +1 -1
  86. package/docs/patterns/components-chart--post-reach-distribution.tsx +1 -1
  87. package/docs/patterns/components-chart--ranked-audience-breakdown.tsx +1 -1
  88. package/docs/patterns/components-chart--unit-grid-composition.tsx +1 -1
  89. package/docs/patterns/components-chatdock--pattern-chat-dock.tsx +1 -1
  90. package/docs/patterns/components-chatdock--pattern-start-project-gate.tsx +1 -1
  91. package/docs/patterns/components-chatqa--pattern-qa-with-reply.tsx +1 -1
  92. package/docs/patterns/components-checkbox-checkbox--default.tsx +1 -1
  93. package/docs/patterns/components-checkbox-checkbox--with-count.tsx +1 -1
  94. package/docs/patterns/components-checkbox-checkbox--with-description.tsx +1 -1
  95. package/docs/patterns/components-checkbox-checkboxgroup--default.tsx +1 -1
  96. package/docs/patterns/components-checkbox-checkboxgroup--option-counts.tsx +1 -1
  97. package/docs/patterns/components-descriptionlist--details.tsx +1 -1
  98. package/docs/patterns/components-descriptionlist--post-metadata.tsx +1 -1
  99. package/docs/patterns/components-dialog--alert-dialog-destructive.tsx +1 -1
  100. package/docs/patterns/components-dialog--default-dialog.tsx +1 -1
  101. package/docs/patterns/components-dialog--form-dialog.tsx +1 -1
  102. package/docs/patterns/components-displaycontrols--page-utilities.tsx +1 -1
  103. package/docs/patterns/components-field--horizontal-input.tsx +1 -1
  104. package/docs/patterns/components-field--horizontal-text-area.tsx +1 -1
  105. package/docs/patterns/components-field--multi-control.tsx +1 -1
  106. package/docs/patterns/components-filterpanel--panel.tsx +55 -0
  107. package/docs/patterns/components-footerreveal--marketing-hero-pattern.tsx +1 -1
  108. package/docs/patterns/components-footerreveal--marketing-hero-ruled-pattern.tsx +1 -1
  109. package/docs/patterns/components-footerreveal--marketing-hero-with-gallery-intro.tsx +1 -1
  110. package/docs/patterns/components-footerreveal--marketing-page-pattern.tsx +1 -1
  111. package/docs/patterns/components-footerreveal--ruled-grid-footer-pattern.tsx +1 -1
  112. package/docs/patterns/components-footerreveal--sequenced-marketing-hero.tsx +1 -1
  113. package/docs/patterns/components-herointro--two-line-intro.tsx +1 -1
  114. package/docs/patterns/components-herotilestack--marketing-hero-pattern.tsx +1 -1
  115. package/docs/patterns/components-herotilestack--marketing-hero-text-sequence.tsx +1 -1
  116. package/docs/patterns/components-herotilestack--marketing-hero-with-gallery-intro.tsx +1 -1
  117. package/docs/patterns/components-indexlist--post-index.tsx +1 -1
  118. package/docs/patterns/components-intakeconfirmation--booked-pattern.tsx +1 -1
  119. package/docs/patterns/components-intakeconfirmation--emailed-pattern.tsx +1 -1
  120. package/docs/patterns/components-intakeform--about-you-pattern.tsx +1 -1
  121. package/docs/patterns/components-intakeform--short-form-pattern.tsx +1 -1
  122. package/docs/patterns/components-intakemodal--intake-modal-pattern.tsx +1 -1
  123. package/docs/patterns/components-kbd--command-row.tsx +1 -1
  124. package/docs/patterns/components-kbd--numbered-choices.tsx +1 -1
  125. package/docs/patterns/components-kbd--shortcut.tsx +1 -1
  126. package/docs/patterns/components-linktile--resource-tile.tsx +33 -0
  127. package/docs/patterns/components-linktile--router-link.tsx +25 -0
  128. package/docs/patterns/components-moremenu--action-menu.tsx +1 -1
  129. package/docs/patterns/components-moremenu--in-card-header.tsx +1 -1
  130. package/docs/patterns/components-navlist--side-nav-settings.tsx +1 -1
  131. package/docs/patterns/components-pageheader--app-header-pattern.tsx +1 -1
  132. package/docs/patterns/components-pageheader--page-section-header.tsx +1 -1
  133. package/docs/patterns/components-pageheader--toolbar-header.tsx +1 -1
  134. package/docs/patterns/components-panel--end-detail-rail.tsx +1 -1
  135. package/docs/patterns/components-pillgroup--pill-group-pattern.tsx +1 -1
  136. package/docs/patterns/components-promptbar--pattern-prompt-bar.tsx +1 -1
  137. package/docs/patterns/components-prose--article-body.tsx +1 -1
  138. package/docs/patterns/components-radio-radiogroup--default.tsx +1 -1
  139. package/docs/patterns/components-scrollhorizontal--project-gallery-pattern.tsx +1 -1
  140. package/docs/patterns/components-scrollhorizontal--with-intro.tsx +1 -1
  141. package/docs/patterns/components-sectioncaption--column-caption.tsx +1 -1
  142. package/docs/patterns/components-sectioncaption--with-action.tsx +1 -1
  143. package/docs/patterns/components-sheet--bottom-sheet.tsx +1 -1
  144. package/docs/patterns/components-sheet--end-sheet.tsx +1 -1
  145. package/docs/patterns/components-sitenav--brand-and-cta.tsx +1 -1
  146. package/docs/patterns/components-sitenav--centered-links.tsx +1 -1
  147. package/docs/patterns/components-sitenav--compact.tsx +1 -1
  148. package/docs/patterns/components-sitenav--marketing-header.tsx +1 -1
  149. package/docs/patterns/components-sitenav--mega-menu.tsx +1 -1
  150. package/docs/patterns/components-stat--insights-row.tsx +1 -1
  151. package/docs/patterns/components-stepprogress--step-progress-pattern.tsx +1 -1
  152. package/docs/patterns/components-switch--default.tsx +1 -1
  153. package/docs/patterns/components-switch--settings-row.tsx +1 -1
  154. package/docs/patterns/components-tab--settings-pages.tsx +1 -1
  155. package/docs/patterns/components-taskrows--action-details.tsx +1 -1
  156. package/docs/patterns/components-taskrows--capsules.tsx +1 -1
  157. package/docs/patterns/components-taskrows--card-with-status-rows.tsx +1 -1
  158. package/docs/patterns/components-taskrows--controlled-expand.tsx +1 -1
  159. package/docs/patterns/components-taskrows--custom-slots.tsx +1 -1
  160. package/docs/patterns/components-taskrows--status-list.tsx +1 -1
  161. package/docs/patterns/components-taskrows--tag-chips.tsx +1 -1
  162. package/docs/patterns/components-textlink--external-destination.tsx +1 -1
  163. package/docs/patterns/components-textlink--inline-prose.tsx +1 -1
  164. package/docs/patterns/components-textlink--quiet-title.tsx +1 -1
  165. package/docs/patterns/components-textlink--supporting-copy.tsx +1 -1
  166. package/docs/patterns/components-textsequence--default.tsx +1 -1
  167. package/docs/patterns/components-textsequence--reduced-motion.tsx +1 -1
  168. package/docs/patterns/components-textsequence--shapes.tsx +1 -1
  169. package/docs/patterns/components-tilegrid--masonry.tsx +44 -0
  170. package/docs/patterns/components-toast--stacked-notifications.tsx +1 -1
  171. package/docs/patterns/components-tooltip--controlled.tsx +1 -1
  172. package/docs/patterns/components-tooltip--disabled-control.tsx +1 -1
  173. package/docs/patterns/components-tooltip--icon-action.tsx +1 -1
  174. package/docs/patterns/components-tooltip--keyboard-shortcut.tsx +1 -1
  175. package/docs/patterns/components-tooltip--placement.tsx +1 -1
  176. package/docs/patterns/foundations-scroll-fade--horizontal-rail.tsx +1 -1
  177. package/docs/patterns/foundations-scroll-fade--overflowing-list.tsx +1 -1
  178. package/docs/patterns/guides-chart-explorations--comparison-gallery.tsx +1 -1
  179. package/docs/patterns/guides-filter-panel--filtered-grid.tsx +182 -0
  180. package/docs/patterns/guides-filter-panel--filtered-index.tsx +68 -153
  181. package/docs/patterns/guides-overlay-flows--notification-preferences.tsx +1 -1
  182. package/docs/patterns/guides-post-page--post-page.tsx +117 -56
  183. package/docs/patterns/guides-profile-typography--editorial-profile.tsx +1 -1
  184. package/docs/patterns/guides-resource-detail--detail.tsx +270 -0
  185. package/docs/patterns/index.json +49 -1
  186. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,67 @@ Every release of `@thewhatmatters/wmds` is listed here, newest first.
7
7
  - **Pasted patterns:** when a release changes a **Pattern — …** story's Show code, it is named under Consumer actions so apps re-copy it.
8
8
  - **How to add an entry** (contributors): add your change to the top entry. If that version is already on npm (`npm view @thewhatmatters/wmds versions`), start a new entry above it and bump `version` in `package.json` to match. `npm run check:changelog` enforces the format.
9
9
 
10
+ ## 0.4.9
11
+
12
+ **Fixes from the site's 0.4.8 upgrade: router links in every page pattern, a tighter tile caption, and a checker that no longer skips files.**
13
+
14
+ - **`renderLink` on the page patterns** — one prop name everywhere, for links the app's router should handle. Without it they were plain anchors that reload the page, and swapping one in the pasted markup reads as drift.
15
+ - **Guides/Filter panel → Pattern — filtered index**: `renderLink={(post) => <Link href={post.href} />}` (new) — post titles.
16
+ - **Guides/Post page → Pattern — post page**: `renderLink={(link) => <Link href={link.href} />}` (new) — the **Breadcrumb** and the category tags. View as Markdown and the share links stay plain anchors.
17
+ - **Guides/Resource detail → Pattern — resource detail**: `renderLink={(item) => <Link href={item.href} />}` (new) on `ResourceDetailPage` — the **Breadcrumb**.
18
+ - **Pattern — filtered grid** already had it, for tiles.
19
+ - **IndexList.Item** `render` (new) — `render={<Link href="/blog/post" />}` in place of `href`, the same shape as **LinkTile** and **Badge**. `href` is now optional.
20
+ - **TextLink** `render` (new) — the same, for any text link. `href` is now optional; pass one or the other.
21
+ - **`type-caption`** (new type step; `typographyClass("caption-tight")`) — `type-supporting`'s size and weight on a 16px line. For a single line directly under a label; not for wrapped text, which stays on `type-supporting`. In this release it is used on **LinkTile**'s meta line only. **Foundations → Typography** lists it.
22
+ - **LinkTile** — the title and the meta line sit as a pair: no gap between them, and the meta line is on `type-caption`. The space between the title's text and the meta's goes from about 9px to about 5px. The 12px between the image and the title and the two-line clamp are unchanged. A tile with a meta line is 6px shorter. The `loading` placeholder's bars sit in the same 20px and 16px lines, so a placeholder is exactly as tall as a loaded tile with a one-line title.
23
+ - **`wmds-check`** — finds a pasted pattern's header when a `"use client"` or `"use server"` directive (or blank lines) comes before it. It read line 1 only, so such a file was skipped silently and never checked for drift. Findings name the header's line.
24
+ - **0.4.8 Consumer actions corrected** — they said to put `"use client"` above the pattern header. The header goes first and the directive below it, as the `use-wmds` skill says. Both orders now work with `wmds-check`.
25
+ - **TileGrid docs** — the space under a masonry tile is the 2rem row gap plus less than 4px (32px to just under 36px), not "within 3px". A tile's height rounds up to the next 4px row track. The behavior has not changed.
26
+
27
+ ### Consumer actions
28
+
29
+ Re-copy three patterns, then pass the app's link through `renderLink`. Do the wiring in a client component (a function cannot cross from a server component), and remove any `<Link>` added to pasted markup.
30
+
31
+ 1. **Re-copy Guides/Filter panel → Pattern — filtered index** (`node_modules/@thewhatmatters/wmds/docs/patterns/guides-filter-panel--filtered-index.tsx`) over `components/blog-index.tsx`, re-apply your content, data, and handlers, and pass `renderLink={(post) => <Link href={post.href} />}` to `<FilteredIndex>`.
32
+ 2. **Re-copy Guides/Post page → Pattern — post page** (`…/docs/patterns/guides-post-page--post-page.tsx`) over `components/post-page.tsx`, re-apply your content, and pass `renderLink={(link) => <Link href={link.href} />}` to `<PostPage>`.
33
+ 3. **Re-copy Guides/Resource detail → Pattern — resource detail** (`…/docs/patterns/guides-resource-detail--detail.tsx`) over `components/resource-detail.tsx`, re-apply your content, and pass `renderLink={(item) => <Link href={item.href} />}` to `<ResourceDetailPage>`.
34
+ 4. **Pattern headers:** the header stays on the first lines with `"use client"` below it. A file with the directive first is now checked too, so `npx wmds-check` may report drift it skipped before. Fix the drift, or re-copy.
35
+ 5. **LinkTile:** nothing to do. Tiles with a meta line are 6px shorter. Update a screenshot baseline or a test that measures a tile's height. **Pattern — filtered grid** did not change; no re-copy.
36
+ 6. **`type-caption`:** do not move other text to it. It is for one line under a label.
37
+ 7. Other apps: none. `render` on **TextLink** and **IndexList.Item** is optional.
38
+
39
+ ## 0.4.8
40
+
41
+ **A filtered grid and a resource detail for a resources page.** Three new components and two page patterns: a tile that is one link, a grid that packs tiles in reading order, the filter panel as a component, and a resource's detail as a dialog over the grid or as its own page. The WhatMatters Resources page is the first use. See **ADR-0044**.
42
+
43
+ - **LinkTile** (new) — a resource tile that is one link: `media` (an image with its `width` and `height`), `title`, a `meta` line such as the domain, an optional `tag` (a **Badge** over the image) and `source` mark (**Avatar** `xsm` or a favicon, before the title). One hit area and one focus ring; nothing interactive goes inside. `external` opens a new tab the way **Button** and **TextLink** do; `render={<Link href />}` makes it a router link. The image keeps its own ratio by default; `ratio` fixes it. `loading` is a **Skeleton** placeholder. A hairline inside the frame keeps an edge on light images in light mode and dark images in dark mode. Screen readers hear the title, the meta, the tag, then "opens in a new tab".
44
+ - **TileGrid** (new) with **TileGrid.Item** — `layout` `masonry` (default) or `uniform`; `columns` as one number or `{ base, sm, md, lg, xl }` (default 1, 2 from `sm`, 3 from `lg`); `empty`; `busy`. Reading order and tab order are the order of the items in both layouts: masonry puts each next item in the shortest column, so the order runs across and then down. When the items change, the tiles that stay move to their places and the others fade; reduced motion changes at once.
45
+ - **FilterPanel** (new) with **FilterPanel.Rail**, **.Trigger**, and **.Sheet** — the filter rail, its phone button, and its bottom Sheet as one component, so a page no longer pastes them. With it: `useFilterSelection`, `matchesFilterSelection`, `countFilterOptions`, `filterSelectionCount`, and the types `FilterSelection`, `FilterFacets`, `FilterPanelGroup`, `FilterPanelOption`.
46
+ - New **Guides/Filter panel → Pattern — filtered grid** — the filtered index page with **SectionCaption** over a **TileGrid** of **LinkTile** in the main column. A tile goes to the resource's route in the app (`item.href`), not out of the site; `item.external` is there for an app that links straight out. Props: `title`, `caption`, `items`, `groups`, `layout`, `columns`, `loading`, `defaultSelection`, `selection` + `onSelectionChange`, `renderLink` (the router's link for a tile), `renderImage` (the app's image component), `overlay`.
47
+ - New **Guides/Resource detail → Pattern — resource detail** — one module with both forms. `ResourceDetailDialog` opens over the grid (dimmed, not scrolling): the media as large as the window allows beside an info column — category eyebrow, title, the curator's note, the date added, and a **DescriptionList** (Category, Tags, Source, and the app's `rows`) — with the position, previous and next, and a close in the header, and a primary **Button** `external` to visit the resource pinned in the footer. Left and Right move between resources, Escape closes, and focus returns to the tile. On phones it is the whole screen, media first. `ResourceDetailPage` is the same content on the page grid under a **Breadcrumb**. Media is one image or one `video` with controls. The item is `{ id, title, image, video?: { src, poster, captions? }, category, tags?, meta?, note, added, addedLabel, visitHref, rows? }`.
48
+ - **Dialog.Content** `size="full"` (new) — the window less a margin, up to 90rem × 60rem, and the whole screen on phones. `headerEnd` (new) — actions before the close. `aria-labelledby` (new) — names the dialog from a heading in its body when there is no `title`.
49
+ - **Guides/Filter panel → Pattern — filtered index** now uses **FilterPanel** and the helpers. It looks and behaves the same and is about 90 lines shorter. `FilterGroupDef` is now `FilterPanelGroup` from the package; `FilterSelection` is imported from the package too.
50
+ - **Guides/Post page → Pattern — post page**: `metadataStack` (new, `"before"` | `"after"`, **default `"after"`**) — where the metadata panel sits below `lg`, where the page is one column. The article now comes first, with the date and the reading time in a mono line under the title (hidden from `lg`, where the panel is beside the article). It is also the panel's place in the markup: with `metadataSide="end"` the `aside` follows the article at every width and no order utility is used. From `lg` nothing changes. `metadataStack="before"` is the old stacking. See the amendment to **ADR-0041**.
51
+ - **`overlay`** (new prop) on **Pattern — filtered index**, **Pattern — filtered grid**, and **Guides/Post page → Pattern — post page** — page-level children such as **GridOverlay**, rendered first inside the page grid. Passing a prop leaves the pasted markup unchanged, so `wmds-check` no longer reports drift for an overlay.
52
+ - **Decisions taken** (the requests left them open): **LinkTile** is its own component, not a **Card** option. The detail over the grid is a **Dialog**, not a **Sheet** or a **Panel**. The detail item adds `category`, `tags`, `addedLabel`, and `video.captions` to the shape asked for. No view counts and no save control. No sort, no search field in the rail, no paging or Load more, and no save button in this version — the grid shows every item in the order it is given. A video in the tile is out of scope; `media` is one image.
53
+ - **Known limit:** a masonry grid packs after it measures its tiles. A server-rendered page shows aligned rows first and the tiles close up once at hydration, on grids of two or more columns (phones, at one column, do not move). That move is instant — no tile slides or fades; the reflow animation is for a change in the items only. Nothing moves as images load. The space under a tile is the row gap within 3px. **`layout="uniform"` has no such move**: it is CSS alone, so the server's markup is the final layout.
54
+
55
+ ### Consumer actions
56
+
57
+ 1. **WhatMatters site, Resources page: use the new grid.** Copy **Guides/Filter panel → Pattern — filtered grid** (`node_modules/@thewhatmatters/wmds/docs/patterns/guides-filter-panel--filtered-grid.tsx`) into `components/resource-grid.tsx`, keep its header comment as the first lines, and add `"use client"` below it. Each item is `{ id, title, href, image: { src, alt, width, height }, meta?, tag?, facets }` with `href: "/resources/<slug>"`; give every image its real `width` and `height`. Delete the hand-built list in `app/resources/page.tsx` and its classes.
58
+ 2. **Wire the grid in one small client file** (functions cannot cross from a server component): `components/resources.tsx` with `"use client"` renders `<FilteredGrid title="Resources" caption="Library" items={items} groups={groups} renderLink={(item) => <Link href={item.href} scroll={false} />} renderImage={(image) => <Image {...image} sizes="(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw" />} overlay={<SiteGridOverlay />} />`. `app/resources/page.tsx` loads the items and renders it. Change `sizes` if you change `columns`; allow the image hosts in `next.config.ts`. Do not edit the pasted file for any of this.
59
+ 3. **Add the detail.** Copy **Guides/Resource detail → Pattern — resource detail** (`…/docs/patterns/guides-resource-detail--detail.tsx`) into `components/resource-detail.tsx`, keep its header comment as the first lines, and add `"use client"` below it. Each resource needs `{ id, title, image, video?: { src, poster, captions? }, category, tags?, meta?, note, added, addedLabel, visitHref, rows? }`.
60
+ 4. **Pick the form by route.**
61
+ - The page: `app/resources/[slug]/page.tsx` renders `<ResourceDetailPage item={…} breadcrumb={[{ label: "Home", href: "/" }, { label: "Resources", href: "/resources" }, { label: item.title }]} overlay={<SiteGridOverlay />} />`. Delete `app/resources/[category]`: the categories become a filter group on the grid. No redirects.
62
+ - The dialog: a parallel slot with an intercepting route (`app/resources/@detail/(.)[slug]/page.tsx`, a `default.tsx` that returns `null`, and `{detail}` in `app/resources/layout.tsx`) renders a client component with `<ResourceDetailDialog item={…} open onClose={() => router.back()} onPrevious={previous ? () => router.replace("/resources/" + previous.slug, { scroll: false }) : undefined} onNext={…} position={"3 of 9"} />`. Leave `onPrevious` out on the first resource and `onNext` out on the last.
63
+ - Opening `/resources/<slug>` directly, or from a shared link, shows the page; a tile click shows the dialog over the grid.
64
+ 5. **WhatMatters site, blog index: re-copy Guides/Filter panel → Pattern — filtered index** (`…/docs/patterns/guides-filter-panel--filtered-index.tsx`) over `components/blog-index.tsx` and re-apply only your content, data, and handlers. Then remove `<SiteGridOverlay />` from the markup and pass it as `overlay={<SiteGridOverlay />}` where the page renders `<FilteredIndex>`. If the page imports `FilterGroupDef` from that file, import `FilterPanelGroup` from `@thewhatmatters/wmds` instead (same shape).
65
+ 6. **WhatMatters site, post page: re-copy Guides/Post page → Pattern — post page** (`…/docs/patterns/guides-post-page--post-page.tsx`) over `components/post-page.tsx`, re-apply your content, and move `<SiteGridOverlay />` to `overlay={<SiteGridOverlay />}`. Keep `metadataSide="end"` and `metadataColumns={3}`: with them the panel now stacks after the article below `lg`, the date and reading time sit under the title there, and the `aside` follows the article in the markup. No other prop and no class edit is needed; `metadataStack="after"` is the default. Update any test that expects the panel before the article in the DOM or above it on a phone.
66
+ 7. **Check:** `npx wmds-check` reports no `pattern-drift` for the four pasted files. Any `data-*` attributes the site adds to pasted elements are not drift and can stay.
67
+ 8. **If the one move at hydration is not acceptable** on the Resources page, pass `layout="uniform"` to `<FilteredGrid>`: every image is cropped to 4:3 and nothing moves.
68
+ 9. **Tests:** on a server-rendered grid of two or more columns, wait for `ul[data-packed]` before asserting tile positions or taking a screenshot. The detail dialog fades in over about 0.4s; wait for it before an accessibility or visual check.
69
+ 10. Other apps: an app that pasted **Pattern — post page** and re-copies it gets the panel after the article below `lg`; pass `metadataStack="before"` to keep it above. Everything else here is new; `Dialog` `size`, `headerEnd`, and `aria-labelledby` are optional.
70
+
10
71
  ## 0.4.7
11
72
 
12
73
  **Carousel: a row of items with a progress scrubber.** New component, built on the open `motion` package. The WhatMatters About page is the first use. See **ADR-0043**.
package/CONSUMING.md CHANGED
@@ -273,7 +273,10 @@ import {
273
273
  | `DescriptionList` | `layout` (`inline` \| `stacked`), `rule` (`solid` \| `dotted` \| `none`), `variant` (`sans` \| `mono`), `DescriptionList.Item` `name` / `layout` | Components/DescriptionList — **Pattern — post metadata**, **Pattern — details** |
274
274
  | `SectionCaption` | `children`, `as`, `id`, `end`, `marker`, `rule` | Components/SectionCaption — **Pattern — column caption**, **Pattern — caption with an action** |
275
275
  | `Prose` | `size` (`lg` \| `md`), `measure` (`reading` \| `none`), `as` | Components/Prose — **Pattern — article body**. Full page: **Guides/Post page → Pattern — post page** |
276
- | `IndexList` | `captions`, `size`, `titleAs`, `empty`, `IndexList.Item` `meta` / `title` / `href` / `preview` | Components/IndexList — **Pattern — post index**. With filters: **Guides/Filter panel → Pattern — filtered index** |
276
+ | `IndexList` | `captions`, `size`, `titleAs`, `empty`, `IndexList.Item` `meta` / `title` / `href` or `render` / `preview` | Components/IndexList — **Pattern — post index**. With filters: **Guides/Filter panel → Pattern — filtered index** |
277
+ | `LinkTile` | `title`, `href` / `render`, `external`, `media`, `ratio`, `meta`, `tag`, `source`, `loading` | Components/LinkTile — **Pattern — resource tile**, **Pattern — router link** |
278
+ | `TileGrid` | `layout` (`masonry` / `uniform`), `columns`, `empty`, `busy`, `TileGrid.Item` | Components/TileGrid — **Pattern — tile grid**. With filters: **Guides/Filter panel → Pattern — filtered grid** |
279
+ | `FilterPanel` | `groups`, `selection`, `onSelectionChange`, `resultsLabel`, `labels`; `FilterPanel.Rail` / `.Trigger` / `.Sheet`; `useFilterSelection`, `matchesFilterSelection`, `countFilterOptions` | Components/FilterPanel — **Pattern — filter panel** |
277
280
  | `TaskRows` | `variant`, `status`, `meta`, `detailsLayout`, `TaskRows.Detail` | Components/TaskRows — **Pattern — status rows**, **capsules**, **action details** (`Detail variant="button"`), **tag chips** (`Chip readOnly size="sm"`), detail lines (`Detail` + `onPress` → `Button layout="row"`) |
278
281
  | `Badge` | `variant`, `size`, `emphasis` (`solid` \| `muted` \| `outline`), `mono`, `render` (tag links), `count`, `icon`, `avatar`, `iconOnly` | Components/Badge — copy a **Pattern** story. `avatar={{ src, alt }}` is a leading round **Avatar** sized to the badge (`badgeAvatarSize`: sm → 20px, md → 24px) and is mutually exclusive with `icon`. Pass `alt=""` when the label already speaks the word. |
279
282
  | `Status` | `variant`, `tone`, `label`, `besideLabel`, `pulsing`, `active`, `step` | Components/Status — `variant="ring"` or `variant="dot"` |
@@ -230,22 +230,26 @@ for (const file of files) {
230
230
  });
231
231
 
232
232
  // Pasted patterns.
233
- const header = lines[0]?.match(/^\/\/ @thewhatmatters\/wmds@([\w.-]+) · (.+)$/);
233
+ // The header is the file's first comment line. A "use client" / "use server" directive or blank
234
+ // lines may come before it.
235
+ const headerIndex = lines.findIndex((line) => line.trim() !== "" && !/^\s*["']use (client|server)["'];?\s*$/.test(line));
236
+ const headerLine = headerIndex === -1 ? 0 : headerIndex;
237
+ const header = lines[headerLine]?.match(/^\/\/ @thewhatmatters\/wmds@([\w.-]+) · (.+)$/);
234
238
  const id = source.match(/\?path=\/story\/([\w-]+)/)?.[1];
235
239
  if (header && id && packageRoot) {
236
240
  const shipped = path.join(packageRoot, "docs", "patterns", `${id}.tsx`);
237
241
  if (!existsSync(shipped)) {
238
- report(file, 1, "pattern-removed", "error", `pattern ${id} no longer ships in ${packageVersion} — see CHANGELOG.md`);
242
+ report(file, headerLine + 1, "pattern-removed", "error", `pattern ${id} no longer ships in ${packageVersion} — see CHANGELOG.md`);
239
243
  } else {
240
244
  if (header[1] !== packageVersion) {
241
- report(file, 1, "pattern-stale", "warn", `pasted from ${header[1]}, installed ${packageVersion} — re-copy if CHANGELOG names it`);
245
+ report(file, headerLine + 1, "pattern-stale", "warn", `pasted from ${header[1]}, installed ${packageVersion} — re-copy if CHANGELOG names it`);
242
246
  }
243
247
  const shippedStructure = patternStructure(readFileSync(shipped, "utf8"));
244
248
  const pastedStructure = patternStructure(source);
245
249
  if (shippedStructure.join("\n") !== pastedStructure.join("\n")) {
246
250
  report(
247
251
  file,
248
- 1,
252
+ headerLine + 1,
249
253
  "pattern-drift",
250
254
  "warn",
251
255
  `markup or classes differ from docs/patterns/${id}.tsx (${firstDifference(shippedStructure, pastedStructure)}) — allowed edits are content, data, handlers, exports`,
@@ -1,10 +1,16 @@
1
- import type { AnchorHTMLAttributes, ReactNode } from "react";
1
+ import type { AnchorHTMLAttributes, ReactElement, ReactNode } from "react";
2
2
  import { type TextLinkVariant } from "./textLinkStyles";
3
3
  export { textLinkVariants, type TextLinkVariant } from "./textLinkStyles";
4
4
  /** Layout-only — margin or placement; not for changing the link treatment. */
5
5
  export type TextLinkLayoutClassName = string;
6
6
  export interface TextLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "children" | "className" | "href" | "target"> {
7
- href: string;
7
+ /** Where the link goes. Leave it out when `render` carries the destination. */
8
+ href?: string;
9
+ /**
10
+ * Compose the link onto another element (Base UI `render`) — `render={<Link href="/blog/post" />}`
11
+ * for a router link. The treatment, the focus ring, and `external` stay the same.
12
+ */
13
+ render?: ReactElement;
8
14
  children: ReactNode;
9
15
  /**
10
16
  * `prose` (default) — medium weight with a solid underline, for links inside body copy.
@@ -18,5 +24,5 @@ export interface TextLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorEleme
18
24
  className?: TextLinkLayoutClassName;
19
25
  }
20
26
  /** Inline text navigation — the solid-underline prose link, or a quiet link for titles. */
21
- export declare function TextLink({ href, children, variant, external, className, rel, ...anchorProps }: TextLinkProps): import("react").JSX.Element;
27
+ export declare function TextLink({ href, render, children, variant, external, className, rel, ...anchorProps }: TextLinkProps): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
22
28
  //# sourceMappingURL=TextLink.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextLink.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/TextLink/TextLink.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG7D,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE1E,8EAA8E;AAC9E,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,aACf,SAAQ,IAAI,CACV,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,UAAU,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,CAC7C;IACD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,2FAA2F;AAC3F,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,QAAQ,EACR,OAAiB,EACjB,QAAgB,EAChB,SAAS,EACT,GAAG,EACH,GAAG,WAAW,EACf,EAAE,aAAa,+BAwBf"}
1
+ {"version":3,"file":"TextLink.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/TextLink/TextLink.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG3E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE1E,8EAA8E;AAC9E,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,aACf,SAAQ,IAAI,CACV,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,UAAU,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,CAC7C;IACD,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,2FAA2F;AAC3F,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,OAAiB,EACjB,QAAgB,EAChB,SAAS,EACT,GAAG,EACH,GAAG,WAAW,EACf,EAAE,aAAa,8EA6Bf"}
@@ -3,24 +3,29 @@ import { cn as e } from "../../../lib/cn.js";
3
3
  import { textLinkExternalIconClasses as t, textLinkVariantClasses as n, textLinkVariants as r } from "./textLinkStyles.js";
4
4
  import { SquareArrowOutUpRight as i } from "lucide-react";
5
5
  import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
6
+ import { useRender as c } from "@base-ui/react/use-render";
6
7
  //#region src/components/atoms/TextLink/TextLink.tsx
7
- function c({ href: r, children: c, variant: l = "prose", external: u = !1, className: d, rel: f, ...p }) {
8
- let m = u && f == null ? "noopener noreferrer" : f;
9
- return /* @__PURE__ */ s("a", {
10
- ...p,
11
- href: r,
12
- target: u ? "_blank" : void 0,
13
- rel: m,
14
- className: e(n[l], d),
15
- children: [c, u ? /* @__PURE__ */ s(a, { children: [/* @__PURE__ */ o(i, {
16
- className: t,
17
- strokeWidth: 2,
18
- "aria-hidden": !0
19
- }), /* @__PURE__ */ o("span", {
20
- className: "sr-only",
21
- children: " (opens in a new tab)"
22
- })] }) : null]
8
+ function l({ href: r, render: l, children: u, variant: d = "prose", external: f = !1, className: p, rel: m, ...h }) {
9
+ let g = f && m == null ? "noopener noreferrer" : m;
10
+ return r == null && l == null && console.warn("[WMDS TextLink] Pass `href`, or `render` with a link that carries it."), c({
11
+ render: l,
12
+ defaultTagName: "a",
13
+ props: {
14
+ ...h,
15
+ ...r == null ? null : { href: r },
16
+ ...f ? { target: "_blank" } : null,
17
+ ...g == null ? null : { rel: g },
18
+ className: e(n[d], p),
19
+ children: /* @__PURE__ */ s(a, { children: [u, f ? /* @__PURE__ */ s(a, { children: [/* @__PURE__ */ o(i, {
20
+ className: t,
21
+ strokeWidth: 2,
22
+ "aria-hidden": !0
23
+ }), /* @__PURE__ */ o("span", {
24
+ className: "sr-only",
25
+ children: " (opens in a new tab)"
26
+ })] }) : null] })
27
+ }
23
28
  });
24
29
  }
25
30
  //#endregion
26
- export { c as TextLink, r as textLinkVariants };
31
+ export { l as TextLink, r as textLinkVariants };
@@ -1,4 +1,4 @@
1
- import { type ReactNode } from "react";
1
+ import { type ReactElement, type ReactNode } from "react";
2
2
  import { type IndexListSize, type IndexListTitleElement } from "./indexListStyles";
3
3
  export { indexListSizes, indexListTitleElements, type IndexListSize, type IndexListTitleElement, } from "./indexListStyles";
4
4
  /** Layout-only — width, margin, or grid placement. */
@@ -32,7 +32,10 @@ export interface IndexListProps {
32
32
  export interface IndexListItemProps {
33
33
  /** The row's title — a link to `href`. */
34
34
  title: string;
35
- href: string;
35
+ /** Where the title goes. Leave it out when `render` carries the destination. */
36
+ href?: string;
37
+ /** The router's link for the title, in place of a plain anchor — `render={<Link href="/blog/post" />}`. */
38
+ render?: ReactElement;
36
39
  /** The meta column, for example a `<time>`. Above the title where the list is one column. */
37
40
  meta?: ReactNode;
38
41
  /** A short preview. When set, a control at the row's end expands it under the title. */
@@ -51,7 +54,7 @@ export interface IndexListItemProps {
51
54
  * optional preview that expands under the title. Optional column captions share the rows' tracks.
52
55
  */
53
56
  declare function IndexListRoot({ captions, size, titleAs, empty, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, className, }: IndexListProps): import("react").JSX.Element;
54
- declare function IndexListItem({ title, href, meta, preview, defaultOpen, open: openProp, onOpenChange, previewLabel, className, }: IndexListItemProps): import("react").JSX.Element;
57
+ declare function IndexListItem({ title, href, render, meta, preview, defaultOpen, open: openProp, onOpenChange, previewLabel, className, }: IndexListItemProps): import("react").JSX.Element;
55
58
  export declare const IndexList: typeof IndexListRoot & {
56
59
  Item: typeof IndexListItem;
57
60
  };
@@ -1 +1 @@
1
- {"version":3,"file":"IndexList.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/IndexList/IndexList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,OAAO,EAiBL,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC3B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,qBAAqB,GAC3B,MAAM,mBAAmB,CAAC;AAE3B,sDAAsD;AACtD,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,iGAAiG;IACjG,IAAI,EAAE,SAAS,CAAC;IAChB,2CAA2C;IAC3C,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,4FAA4F;IAC5F,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,mGAAmG;IACnG,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,6FAA6F;IAC7F,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,wFAAwF;IACxF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,kCAAkC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gCAAgC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC;AASD;;;GAGG;AACH,iBAAS,aAAa,CAAC,EACrB,QAAQ,EACR,IAAW,EACX,OAAc,EACd,KAAK,EACL,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,GACV,EAAE,cAAc,+BA8BhB;AAED,iBAAS,aAAa,CAAC,EACrB,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,WAAmB,EACnB,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,YAAY,EACZ,SAAS,GACV,EAAE,kBAAkB,+BA6CpB;AAED,eAAO,MAAM,SAAS;;CAEpB,CAAC"}
1
+ {"version":3,"file":"IndexList.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/IndexList/IndexList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,OAAO,EAiBL,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC3B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,qBAAqB,GAC3B,MAAM,mBAAmB,CAAC;AAE3B,sDAAsD;AACtD,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,iGAAiG;IACjG,IAAI,EAAE,SAAS,CAAC;IAChB,2CAA2C;IAC3C,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,4FAA4F;IAC5F,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,mGAAmG;IACnG,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2GAA2G;IAC3G,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,6FAA6F;IAC7F,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,wFAAwF;IACxF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,kCAAkC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gCAAgC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC;AASD;;;GAGG;AACH,iBAAS,aAAa,CAAC,EACrB,QAAQ,EACR,IAAW,EACX,OAAc,EACd,KAAK,EACL,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,GACV,EAAE,cAAc,+BA8BhB;AAED,iBAAS,aAAa,CAAC,EACrB,KAAK,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,OAAO,EACP,WAAmB,EACnB,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,YAAY,EACZ,SAAS,GACV,EAAE,kBAAkB,+BA6CpB;AAED,eAAO,MAAM,SAAS;;CAEpB,CAAC"}
@@ -43,48 +43,49 @@ function k({ captions: t, size: n = "lg", titleAs: i = "h2", empty: o, "aria-lab
43
43
  })
44
44
  });
45
45
  }
46
- function A({ title: r, href: a, meta: s, preview: f, defaultOpen: p = !1, open: g, onOpenChange: y, previewLabel: b, className: C }) {
47
- let { size: k, titleAs: A } = x(O), j = S(), [M, N] = w(p), P = g !== void 0, F = P ? g : M, I = f != null;
48
- function L() {
49
- let e = !F;
50
- P || N(e), y?.(e);
46
+ function A({ title: r, href: a, render: s, meta: f, preview: p, defaultOpen: g = !1, open: y, onOpenChange: b, previewLabel: C, className: k }) {
47
+ let { size: A, titleAs: j } = x(O), M = S(), [N, P] = w(g), F = y !== void 0, I = F ? y : N, L = p != null;
48
+ function R() {
49
+ let e = !I;
50
+ F || P(e), b?.(e);
51
51
  }
52
52
  return /* @__PURE__ */ D("li", {
53
- className: e(o, C),
53
+ className: e(o, k),
54
54
  children: [
55
- s == null ? null : /* @__PURE__ */ E("div", {
55
+ f == null ? null : /* @__PURE__ */ E("div", {
56
56
  className: c,
57
- children: s
57
+ children: f
58
58
  }),
59
59
  /* @__PURE__ */ D("div", {
60
60
  className: m,
61
- children: [/* @__PURE__ */ E(A, {
62
- className: e(h, _[k]),
61
+ children: [/* @__PURE__ */ E(j, {
62
+ className: e(h, _[A]),
63
63
  children: /* @__PURE__ */ E(n, {
64
64
  variant: "quiet",
65
65
  href: a,
66
+ render: s,
66
67
  children: r
67
68
  })
68
- }), I ? /* @__PURE__ */ E(t, {
69
+ }), L ? /* @__PURE__ */ E(t, {
69
70
  size: "md",
70
- className: v[k],
71
- icon: /* @__PURE__ */ E(T, { className: e(i, F && "rotate-180") }),
72
- "aria-label": b ?? `Preview: ${r}`,
71
+ className: v[A],
72
+ icon: /* @__PURE__ */ E(T, { className: e(i, I && "rotate-180") }),
73
+ "aria-label": C ?? `Preview: ${r}`,
73
74
  title: "",
74
- "aria-expanded": F,
75
- "aria-controls": j,
76
- onClick: L
75
+ "aria-expanded": I,
76
+ "aria-controls": M,
77
+ onClick: R
77
78
  }) : null]
78
79
  }),
79
- I ? /* @__PURE__ */ E("div", {
80
+ L ? /* @__PURE__ */ E("div", {
80
81
  className: e("motion-collapse", l),
81
- "data-visible": F ? "true" : "false",
82
+ "data-visible": I ? "true" : "false",
82
83
  children: /* @__PURE__ */ E("div", {
83
- id: j,
84
+ id: M,
84
85
  className: d,
85
86
  children: /* @__PURE__ */ E("div", {
86
87
  className: u,
87
- children: f
88
+ children: p
88
89
  })
89
90
  })
90
91
  }) : null
@@ -0,0 +1,45 @@
1
+ import { type ReactElement, type ReactNode } from "react";
2
+ export { linkTileLoadingRatio } from "./linkTileStyles";
3
+ /** Layout-only — width, margin, or grid placement. */
4
+ export type LinkTileLayoutClassName = string;
5
+ export interface LinkTileProps {
6
+ /** The resource's name. Two lines at most. Not needed while `loading`. */
7
+ title?: string;
8
+ /** Where the tile goes. Leave it out when `render` carries the destination. */
9
+ href?: string;
10
+ /**
11
+ * Compose the tile onto another element (Base UI `render`) — `render={<Link href="/work" />}` for
12
+ * a router link. The tile is that one link; never put a link or a button inside it.
13
+ */
14
+ render?: ReactElement;
15
+ /**
16
+ * Another site: opens in a new tab (`target="_blank"`, a safe `rel`), tells screen readers so,
17
+ * and shows the mark **TextLink** `external` uses after the title.
18
+ */
19
+ external?: boolean;
20
+ /**
21
+ * The preview — an `<img>` (or `next/image`) with its `width` and `height`, so the tile holds its
22
+ * space before the image loads. One image; not a video.
23
+ */
24
+ media?: ReactNode;
25
+ /**
26
+ * Fixes the frame's shape as width / height (`4 / 3`, `1`, `16 / 9`) and crops the image to it —
27
+ * for a grid of equal tiles. Left out, the image keeps its own ratio and tiles vary in height.
28
+ */
29
+ ratio?: number;
30
+ /** One line under the title — for example the domain, "linear.app". */
31
+ meta?: ReactNode;
32
+ /** A **Badge** over the image's top-start corner (at the caption's end when there is no image). Not a link. */
33
+ tag?: ReactNode;
34
+ /** A mark before the title — **Avatar** `size="xsm"`, or a 20px favicon `<img alt="">`. */
35
+ source?: ReactNode;
36
+ /** A placeholder in the tile's shape, built on **Skeleton** — not a link, and hidden from screen readers. */
37
+ loading?: boolean;
38
+ className?: LinkTileLayoutClassName;
39
+ }
40
+ /**
41
+ * A resource tile that is one link — a preview image with the resource's name and where it lives
42
+ * under it. Screen readers hear the title, the meta line, the tag, then "opens in a new tab".
43
+ */
44
+ export declare function LinkTile({ title, href, render, external, media, ratio, meta, tag, source, loading, className, }: LinkTileProps): import("react").JSX.Element;
45
+ //# sourceMappingURL=LinkTile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LinkTile.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/LinkTile/LinkTile.tsx"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAuBrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,sDAAsD;AACtD,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,+GAA+G;IAC/G,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,6GAA6G;IAC7G,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAuBD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,MAAM,EACN,QAAgB,EAChB,KAAK,EACL,KAAK,EACL,IAAI,EACJ,GAAG,EACH,MAAM,EACN,OAAe,EACf,SAAS,GACV,EAAE,aAAa,+BA0Ff"}
@@ -0,0 +1,121 @@
1
+ "use client";
2
+ import { cn as e } from "../../../lib/cn.js";
3
+ import { Skeleton as t } from "../../atoms/Skeleton/Skeleton.js";
4
+ import { linkTileCaptionClasses as n, linkTileExternalIconClasses as r, linkTileFrameClasses as i, linkTileFrameFixedClasses as a, linkTileFrameNaturalClasses as o, linkTileLoadingLineClasses as s, linkTileLoadingMetaLineClasses as c, linkTileLoadingRatio as l, linkTileLoadingRootClasses as u, linkTileMetaClasses as d, linkTileRootClasses as f, linkTileSourceClasses as p, linkTileTagInlineClasses as m, linkTileTagOverClasses as h, linkTileTextClasses as g, linkTileTitleClasses as _ } from "./linkTileStyles.js";
5
+ import { useId as v } from "react";
6
+ import { SquareArrowOutUpRight as y } from "lucide-react";
7
+ import { jsx as b, jsxs as x } from "react/jsx-runtime";
8
+ import { useRender as S } from "@base-ui/react/use-render";
9
+ //#region src/components/molecules/LinkTile/LinkTile.tsx
10
+ function C({ render: e, ...t }) {
11
+ return S({
12
+ render: e,
13
+ defaultTagName: "a",
14
+ props: t
15
+ });
16
+ }
17
+ function w(e) {
18
+ return e == null ? void 0 : { aspectRatio: String(e) };
19
+ }
20
+ function T({ title: l, href: S, render: T, external: E = !1, media: D, ratio: O, meta: k, tag: A, source: j, loading: M = !1, className: N }) {
21
+ let P = v(), F = `${P}-title`, I = `${P}-meta`, L = `${P}-tag`, R = `${P}-hint`;
22
+ if (M) return /* @__PURE__ */ x("div", {
23
+ className: e(u, N),
24
+ "data-link-tile": "",
25
+ "data-loading": "",
26
+ "aria-hidden": "true",
27
+ children: [/* @__PURE__ */ b("span", {
28
+ className: i,
29
+ style: w(O ?? 1.3333333333333333),
30
+ children: /* @__PURE__ */ b(t, { radius: "none" })
31
+ }), /* @__PURE__ */ x("span", {
32
+ className: g,
33
+ children: [/* @__PURE__ */ b("span", {
34
+ className: s,
35
+ children: /* @__PURE__ */ b(t, {
36
+ width: "70%",
37
+ height: 12,
38
+ radius: "inner",
39
+ index: 1
40
+ })
41
+ }), /* @__PURE__ */ b("span", {
42
+ className: c,
43
+ children: /* @__PURE__ */ b(t, {
44
+ width: "40%",
45
+ height: 10,
46
+ radius: "inner",
47
+ index: 2
48
+ })
49
+ })]
50
+ })]
51
+ });
52
+ S == null && T == null && console.warn("[WMDS LinkTile] Pass `href`, or `render` with a link that carries it.");
53
+ let z = D != null, B = [
54
+ F,
55
+ k != null && I,
56
+ A != null && L,
57
+ E && R
58
+ ].filter(Boolean).join(" ");
59
+ return /* @__PURE__ */ x(C, {
60
+ render: T,
61
+ ...S == null ? null : { href: S },
62
+ ...E ? {
63
+ target: "_blank",
64
+ rel: "noopener noreferrer"
65
+ } : null,
66
+ className: e(f, N),
67
+ "aria-labelledby": B,
68
+ "data-link-tile": "",
69
+ "data-external": E ? "" : void 0,
70
+ children: [z ? /* @__PURE__ */ x("span", {
71
+ className: e(i, O == null ? o : a),
72
+ style: w(O),
73
+ "data-link-tile-frame": "",
74
+ children: [D, A == null ? null : /* @__PURE__ */ b("span", {
75
+ id: L,
76
+ className: h,
77
+ children: A
78
+ })]
79
+ }) : null, /* @__PURE__ */ x("span", {
80
+ className: n,
81
+ children: [
82
+ j == null ? null : /* @__PURE__ */ b("span", {
83
+ className: p,
84
+ "aria-hidden": "true",
85
+ children: j
86
+ }),
87
+ /* @__PURE__ */ x("span", {
88
+ className: g,
89
+ children: [
90
+ /* @__PURE__ */ x("span", {
91
+ id: F,
92
+ className: _,
93
+ children: [l, E ? /* @__PURE__ */ b(y, {
94
+ className: r,
95
+ strokeWidth: 2,
96
+ "aria-hidden": !0
97
+ }) : null]
98
+ }),
99
+ k == null ? null : /* @__PURE__ */ b("span", {
100
+ id: I,
101
+ className: d,
102
+ children: k
103
+ }),
104
+ E ? /* @__PURE__ */ b("span", {
105
+ id: R,
106
+ className: "sr-only",
107
+ children: "(opens in a new tab)"
108
+ }) : null
109
+ ]
110
+ }),
111
+ A != null && !z ? /* @__PURE__ */ b("span", {
112
+ id: L,
113
+ className: m,
114
+ children: A
115
+ }) : null
116
+ ]
117
+ })]
118
+ });
119
+ }
120
+ //#endregion
121
+ export { T as LinkTile, l as linkTileLoadingRatio };
@@ -0,0 +1,37 @@
1
+ /** The frame's ratio (width / height) while `loading`, and for a tile with `ratio` left out there. */
2
+ export declare const linkTileLoadingRatio: number;
3
+ /**
4
+ * The whole tile is the link: one hit area and one focus ring, at the media frame's radius and
5
+ * 4px off the tile so it clears the image's edge.
6
+ */
7
+ export declare const linkTileRootClasses: string;
8
+ export declare const linkTileLoadingRootClasses = "flex w-full min-w-0 flex-col gap-3";
9
+ /**
10
+ * The media frame. The hairline is drawn over the image, inside its edge, so a light image on the
11
+ * light page and a dark image on the dark page both keep an edge; it darkens on hover and focus.
12
+ */
13
+ export declare const linkTileFrameClasses: string;
14
+ /** The image keeps its own ratio: the `width` and `height` on it reserve the space before it loads. */
15
+ export declare const linkTileFrameNaturalClasses = "[&>img]:block [&>img]:h-auto [&>img]:w-full";
16
+ /** A fixed `ratio`: the frame sets the shape and the image fills it, cropped from the center. */
17
+ export declare const linkTileFrameFixedClasses = "[&>img]:absolute [&>img]:inset-0 [&>img]:block [&>img]:size-full [&>img]:object-cover";
18
+ /** The tag over the image's top-start corner. */
19
+ export declare const linkTileTagOverClasses = "absolute start-2 top-2 z-[1] flex max-w-[calc(100%-1rem)]";
20
+ /** Under the image: the source mark, then the title over the meta line. */
21
+ export declare const linkTileCaptionClasses = "flex min-w-0 items-start gap-2";
22
+ /** Holds the source mark on the title's first line. */
23
+ export declare const linkTileSourceClasses = "flex h-5 shrink-0 items-center";
24
+ /** The title's lines, then the meta line on its 16px line, with no gap between them: the leading is the space. */
25
+ export declare const linkTileTextClasses = "flex min-w-0 flex-1 flex-col";
26
+ /** The loading placeholder's title line — the title's 20px line box, with the bar centered in it. */
27
+ export declare const linkTileLoadingLineClasses = "flex h-5 items-center";
28
+ /** The loading placeholder's meta line — the meta's 16px line box. */
29
+ export declare const linkTileLoadingMetaLineClasses = "flex h-4 items-center";
30
+ /** Two lines at most. Hover and keyboard focus underline it, as a quiet **TextLink** does. */
31
+ export declare const linkTileTitleClasses: string;
32
+ export declare const linkTileExternalIconClasses = "ml-1 inline-block size-[0.85em] align-[-0.05em] stroke-current text-muted";
33
+ /** One line, on the 16px caption line so it sits close under the title. */
34
+ export declare const linkTileMetaClasses: string;
35
+ /** A tag on a tile with no image sits at the caption's end. */
36
+ export declare const linkTileTagInlineClasses = "flex shrink-0 items-center";
37
+ //# sourceMappingURL=linkTileStyles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linkTileStyles.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/LinkTile/linkTileStyles.ts"],"names":[],"mappings":"AAIA,sGAAsG;AACtG,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAI/B,CAAC;AAEF,eAAO,MAAM,0BAA0B,uCAAuC,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAMhC,CAAC;AAEF,uGAAuG;AACvG,eAAO,MAAM,2BAA2B,gDAAgD,CAAC;AAEzF,iGAAiG;AACjG,eAAO,MAAM,yBAAyB,0FACmD,CAAC;AAE1F,iDAAiD;AACjD,eAAO,MAAM,sBAAsB,8DAA8D,CAAC;AAElG,2EAA2E;AAC3E,eAAO,MAAM,sBAAsB,mCAAmC,CAAC;AAEvE,uDAAuD;AACvD,eAAO,MAAM,qBAAqB,mCAAmC,CAAC;AAEtE,kHAAkH;AAClH,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAElE,qGAAqG;AACrG,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAElE,sEAAsE;AACtE,eAAO,MAAM,8BAA8B,0BAA0B,CAAC;AAEtE,8FAA8F;AAC9F,eAAO,MAAM,oBAAoB,QAMhC,CAAC;AAEF,eAAO,MAAM,2BAA2B,8EAA8E,CAAC;AAEvH,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,QAAmD,CAAC;AAEpF,+DAA+D;AAC/D,eAAO,MAAM,wBAAwB,+BAA+B,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { cn as e } from "../../../lib/cn.js";
3
+ import { typographyClass as t } from "../../../lib/typography.js";
4
+ import { focusRingTransitionClasses as n, motionTransition as r } from "../../../lib/motion.js";
5
+ //#region src/components/molecules/LinkTile/linkTileStyles.ts
6
+ var i = 4 / 3, a = e("group/link-tile relative flex w-full min-w-0 flex-col gap-3 rounded-[var(--radius-card-body)] text-left no-underline", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-4 focus-visible:ring-offset-body", n), o = "flex w-full min-w-0 flex-col gap-3", s = e("relative block w-full overflow-hidden rounded-[var(--radius-card-body)] bg-muted-surface", "after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-border after:content-['']", "after:transition-[border-color,background-color] after:duration-fast after:ease-standard", "group-hover/link-tile:after:border-border-emphasized group-hover/link-tile:after:bg-overlay-hover", "group-focus-visible/link-tile:after:border-border-emphasized"), c = "[&>img]:block [&>img]:h-auto [&>img]:w-full", l = "[&>img]:absolute [&>img]:inset-0 [&>img]:block [&>img]:size-full [&>img]:object-cover", u = "absolute start-2 top-2 z-[1] flex max-w-[calc(100%-1rem)]", d = "flex min-w-0 items-start gap-2", f = "flex h-5 shrink-0 items-center", p = "flex min-w-0 flex-1 flex-col", m = "flex h-5 items-center", h = "flex h-4 items-center", g = e(t("ui-label"), "line-clamp-2 text-pretty underline decoration-transparent decoration-solid underline-offset-[0.2em]", "transition-[text-decoration-color]", r("fast"), "group-hover/link-tile:decoration-current group-focus-visible/link-tile:decoration-current"), _ = "ml-1 inline-block size-[0.85em] align-[-0.05em] stroke-current text-muted", v = e(t("caption-tight"), "truncate"), y = "flex shrink-0 items-center";
7
+ //#endregion
8
+ export { d as linkTileCaptionClasses, _ as linkTileExternalIconClasses, s as linkTileFrameClasses, l as linkTileFrameFixedClasses, c as linkTileFrameNaturalClasses, m as linkTileLoadingLineClasses, h as linkTileLoadingMetaLineClasses, i as linkTileLoadingRatio, o as linkTileLoadingRootClasses, v as linkTileMetaClasses, a as linkTileRootClasses, f as linkTileSourceClasses, y as linkTileTagInlineClasses, u as linkTileTagOverClasses, p as linkTileTextClasses, g as linkTileTitleClasses };
@@ -0,0 +1,42 @@
1
+ import { type ReactNode } from "react";
2
+ import { type TileGridColumns, type TileGridLayout } from "./tileGridStyles";
3
+ export { tileGridBreakpoints, tileGridDefaultColumns, tileGridLayouts, type TileGridBreakpoint, type TileGridColumns, type TileGridLayout, } from "./tileGridStyles";
4
+ /** Layout-only — width, margin, or grid placement. */
5
+ export type TileGridLayoutClassName = string;
6
+ export interface TileGridProps {
7
+ /**
8
+ * `masonry` (default) — tiles keep their heights and pack upward, each next tile going to the
9
+ * shortest column. `uniform` — rows of equal height; give the tiles a fixed `ratio`.
10
+ */
11
+ layout?: TileGridLayout;
12
+ /**
13
+ * Columns — one number, or one per breakpoint (`{ base, sm, md, lg, xl }`; a breakpoint left out
14
+ * keeps the one below it). Default: `{ base: 1, sm: 2, lg: 3 }`. The gap is the grid gutter.
15
+ */
16
+ columns?: TileGridColumns;
17
+ /** Shown in place of the tiles when there are none — for example "No resources match these filters." */
18
+ empty?: ReactNode;
19
+ /** The tiles are placeholders for content on its way (`aria-busy`). */
20
+ busy?: boolean;
21
+ /** Names the list for screen readers, for example "Resources". */
22
+ "aria-label"?: string;
23
+ "aria-labelledby"?: string;
24
+ /** **TileGrid.Item** children, one per tile, each with a `key`. */
25
+ children?: ReactNode;
26
+ className?: TileGridLayoutClassName;
27
+ }
28
+ export interface TileGridItemProps {
29
+ /** One tile — a **LinkTile**, or a card. */
30
+ children?: ReactNode;
31
+ className?: TileGridLayoutClassName;
32
+ }
33
+ /**
34
+ * A grid of tiles on the page gutter. Reading order and tab order are the order of the items in
35
+ * both layouts: a masonry grid places each item in the shortest column, so the order runs across
36
+ * the top row and then down the page.
37
+ */
38
+ declare function TileGridRoot({ layout, columns, empty, busy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, className, }: TileGridProps): import("react").JSX.Element;
39
+ export declare const TileGrid: typeof TileGridRoot & {
40
+ Item: import("react").ForwardRefExoticComponent<TileGridItemProps & import("react").RefAttributes<HTMLLIElement>>;
41
+ };
42
+ //# sourceMappingURL=TileGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TileGrid.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/TileGrid/TileGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,OAAO,EAOL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAE1B,sDAAsD;AACtD,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB;;;OAGG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,wGAAwG;IACxG,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uEAAuE;IACvE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED;;;;GAIG;AACH,iBAAS,YAAY,CAAC,EACpB,MAAkB,EAClB,OAAO,EACP,KAAK,EACL,IAAY,EACZ,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,GACV,EAAE,aAAa,+BAwFf;AA2BD,eAAO,MAAM,QAAQ;;CAEnB,CAAC"}