@cl-light-ds/ui 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/package.json +1 -1
  2. package/src/components/accordion/CHANGELOG.md +41 -41
  3. package/src/components/accordion/index.ts +4 -4
  4. package/src/components/alert/CHANGELOG.md +5 -5
  5. package/src/components/alert/index.ts +4 -4
  6. package/src/components/avatar/CHANGELOG.md +44 -44
  7. package/src/components/avatar/index.ts +6 -6
  8. package/src/components/badge/CHANGELOG.md +49 -49
  9. package/src/components/badge/index.ts +2 -2
  10. package/src/components/breadcrumb/CHANGELOG.md +24 -24
  11. package/src/components/breadcrumb/index.ts +5 -5
  12. package/src/components/button/CHANGELOG.md +41 -41
  13. package/src/components/button/index.ts +2 -2
  14. package/src/components/button-group/CHANGELOG.md +34 -34
  15. package/src/components/button-group/index.ts +3 -3
  16. package/src/components/card/CHANGELOG.md +162 -119
  17. package/src/components/card/Card.astro +23 -8
  18. package/src/components/card/CardContent.astro +1 -1
  19. package/src/components/card/CardDescription.astro +1 -1
  20. package/src/components/card/CardMedia.astro +1 -1
  21. package/src/components/card/CardMediaActions.astro +21 -0
  22. package/src/components/card/CardMediaSelect.astro +21 -0
  23. package/src/components/card/index.ts +12 -10
  24. package/src/components/carousel/CHANGELOG.md +5 -5
  25. package/src/components/carousel/index.ts +3 -3
  26. package/src/components/checkbox/CHANGELOG.md +58 -58
  27. package/src/components/checkbox/Checkbox.astro +2 -2
  28. package/src/components/checkbox/index.ts +1 -1
  29. package/src/components/collapsible/CHANGELOG.md +5 -5
  30. package/src/components/collapsible/index.ts +4 -4
  31. package/src/components/combobox/CHANGELOG.md +27 -27
  32. package/src/components/combobox/index.ts +11 -11
  33. package/src/components/date/CHANGELOG.md +18 -18
  34. package/src/components/date/index.ts +2 -2
  35. package/src/components/dialog/CHANGELOG.md +39 -39
  36. package/src/components/dialog/index.ts +9 -9
  37. package/src/components/dropdown-menu/CHANGELOG.md +194 -194
  38. package/src/components/dropdown-menu/DropdownMenuItemContent.astro +79 -79
  39. package/src/components/dropdown-menu/DropdownMenuPortal.astro +13 -13
  40. package/src/components/dropdown-menu/DropdownMenuRadioGroup.astro +13 -13
  41. package/src/components/dropdown-menu/dropdown-menu-item-variants.ts +24 -24
  42. package/src/components/dropdown-menu/index.ts +12 -12
  43. package/src/components/field/CHANGELOG.md +33 -33
  44. package/src/components/field/index.ts +10 -10
  45. package/src/components/hover-card/CHANGELOG.md +20 -20
  46. package/src/components/hover-card/index.ts +3 -3
  47. package/src/components/input/CHANGELOG.md +29 -29
  48. package/src/components/input/index.ts +2 -2
  49. package/src/components/input-group/CHANGELOG.md +49 -49
  50. package/src/components/input-group/controlClasses.ts +2 -2
  51. package/src/components/input-group/index.ts +6 -6
  52. package/src/components/item/CHANGELOG.md +27 -27
  53. package/src/components/item/index.ts +10 -10
  54. package/src/components/kbd/CHANGELOG.md +5 -5
  55. package/src/components/kbd/index.ts +2 -2
  56. package/src/components/label/CHANGELOG.md +28 -28
  57. package/src/components/label/index.ts +2 -2
  58. package/src/components/link-group/CHANGELOG.md +75 -75
  59. package/src/components/link-group/index.ts +5 -5
  60. package/src/components/link-group/link-group-list-variants.ts +15 -15
  61. package/src/components/marquee/CHANGELOG.md +5 -5
  62. package/src/components/marquee/index.ts +2 -2
  63. package/src/components/native-select/CHANGELOG.md +5 -5
  64. package/src/components/native-select/NativeSelectOption.astro +9 -9
  65. package/src/components/native-select/index.ts +3 -3
  66. package/src/components/navigation-menu/CHANGELOG.md +63 -63
  67. package/src/components/navigation-menu/index.ts +10 -10
  68. package/src/components/organisms/lightning-sidebar-nav/CHANGELOG.md +50 -0
  69. package/src/components/organisms/lightning-sidebar-nav/LightningSidebarNav.astro +176 -0
  70. package/src/components/organisms/lightning-sidebar-nav/SidebarNav.astro +50 -0
  71. package/src/components/organisms/lightning-sidebar-nav/SidebarNavGroup.astro +74 -0
  72. package/src/components/organisms/lightning-sidebar-nav/SidebarNavItem.astro +94 -0
  73. package/src/components/organisms/lightning-sidebar-nav/SidebarNavProBadge.astro +26 -0
  74. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSection.astro +71 -0
  75. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSkeleton.astro +67 -0
  76. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSubItem.astro +69 -0
  77. package/src/components/organisms/lightning-sidebar-nav/SidebarNavUsage.astro +78 -0
  78. package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceAvatar.astro +46 -0
  79. package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceSwitcher.astro +130 -0
  80. package/src/components/organisms/lightning-sidebar-nav/icons.ts +46 -0
  81. package/src/components/organisms/lightning-sidebar-nav/index.ts +18 -0
  82. package/src/components/organisms/lightning-sidebar-nav/types.ts +77 -0
  83. package/src/components/popover/CHANGELOG.md +20 -5
  84. package/src/components/popover/Popover.astro +1 -0
  85. package/src/components/popover/PopoverContent.astro +6 -5
  86. package/src/components/popover/PopoverHeader.astro +1 -1
  87. package/src/components/popover/PopoverTrigger.astro +7 -1
  88. package/src/components/popover/index.ts +7 -7
  89. package/src/components/radio-group/CHANGELOG.md +31 -9
  90. package/src/components/radio-group/RadioGroup.astro +1 -1
  91. package/src/components/radio-group/RadioGroupItem.astro +12 -3
  92. package/src/components/radio-group/index.ts +3 -3
  93. package/src/components/select/CHANGELOG.md +39 -39
  94. package/src/components/select/index.ts +8 -8
  95. package/src/components/separator/CHANGELOG.md +5 -5
  96. package/src/components/separator/index.ts +2 -2
  97. package/src/components/skeleton/CHANGELOG.md +5 -5
  98. package/src/components/skeleton/index.ts +1 -1
  99. package/src/components/slider/CHANGELOG.md +5 -5
  100. package/src/components/slider/index.ts +1 -1
  101. package/src/components/spinner/CHANGELOG.md +18 -5
  102. package/src/components/spinner/Spinner.astro +3 -2
  103. package/src/components/spinner/index.ts +1 -1
  104. package/src/components/sticky-surface/CHANGELOG.md +5 -5
  105. package/src/components/sticky-surface/index.ts +2 -2
  106. package/src/components/switch/CHANGELOG.md +29 -9
  107. package/src/components/switch/Switch.astro +4 -4
  108. package/src/components/switch/index.ts +1 -1
  109. package/src/components/table/CHANGELOG.md +24 -5
  110. package/src/components/table/Table.astro +120 -12
  111. package/src/components/table/TableBody.astro +1 -2
  112. package/src/components/table/TableBulkToolbar.astro +37 -0
  113. package/src/components/table/TableCell.astro +25 -1
  114. package/src/components/table/TableCellText.astro +17 -0
  115. package/src/components/table/TableColumnMenu.astro +50 -0
  116. package/src/components/table/TableEditableCell.astro +287 -0
  117. package/src/components/table/TableEmpty.astro +17 -0
  118. package/src/components/table/TableFolderCell.astro +38 -0
  119. package/src/components/table/TableFooter.astro +1 -1
  120. package/src/components/table/TableHead.astro +71 -2
  121. package/src/components/table/TableHeader.astro +1 -1
  122. package/src/components/table/TablePagination.astro +57 -0
  123. package/src/components/table/TableRow.astro +32 -1
  124. package/src/components/table/TableSelectAllBanner.astro +34 -0
  125. package/src/components/table/TableSelectCell.astro +50 -0
  126. package/src/components/table/TableSkeletonRow.astro +21 -0
  127. package/src/components/table/index.ts +19 -9
  128. package/src/components/table/table-cell-variants.ts +29 -0
  129. package/src/components/tabs/CHANGELOG.md +5 -5
  130. package/src/components/tabs/index.ts +6 -6
  131. package/src/components/textarea/CHANGELOG.md +22 -5
  132. package/src/components/textarea/Textarea.astro +25 -3
  133. package/src/components/textarea/index.ts +2 -2
  134. package/src/components/toggle/CHANGELOG.md +23 -5
  135. package/src/components/toggle/Toggle.astro +13 -1
  136. package/src/components/toggle/index.ts +1 -1
  137. package/src/components/toggle-group/CHANGELOG.md +18 -5
  138. package/src/components/toggle-group/ToggleGroup.astro +14 -2
  139. package/src/components/toggle-group/index.ts +2 -2
  140. package/src/components/tooltip/CHANGELOG.md +22 -5
  141. package/src/components/tooltip/Tooltip.astro +26 -0
  142. package/src/components/tooltip/TooltipContent.astro +34 -9
  143. package/src/components/tooltip/index.ts +3 -3
  144. package/src/lib/table-controller.ts +1090 -0
  145. package/src/lib/toggle-group-controller.ts +113 -113
  146. package/src/lib/toggle-shared.ts +27 -26
  147. package/src/lib/utils.ts +6 -6
  148. package/src/styles/globals.css +197 -177
@@ -1,119 +1,162 @@
1
- # Changelog
2
-
3
- All notable changes to the `Card` component will be documented in this file.
4
-
5
- ## Date 9th Sep 2026
6
- ## Figma alignment (node 54-1310, prop table 7350-1279)
7
-
8
- ### Variants
9
-
10
- - Added an `overlay` variant (`variant: "default" | "ghost" | "overlay"`, was `"default" | "ghost"`). Renders `CardMedia` as a full-bleed background behind the card's content — no separate prop is needed on `CardMedia`, `Card` drives the positioning via a `[&_[data-slot=card-media]]:` selector on its own root, so `<Card variant="overlay">` is the single source of truth.
11
- - **Fixed `ghost`:** previously only added a `data-[variant=ghost]` marker attribute while the root still always applied `border border-border shadow-lg bg-card` unconditionally — visually a no-op, so "ghost" cards rendered identically to default. `border`/`bg`/`shadow` are now scoped to `variant: "default"` only, so `ghost` (and `overlay`) render fully chrome-less as Figma specifies.
12
- - Removed the always-on `ring-1 ring-foreground/10 shadow-sm` legacy base styling, which conflicted with the newer `border border-border shadow-lg` layered on top of it. Figma shows no shadow/ring at rest for `default` — the ring only appears in the Focus state.
13
-
14
- ### States
15
-
16
- - **Focus:** `focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-chart-1`, resolved from Figma's `border-ring` + `shadow-[0px_0px_0px_2px_var(--chart-1,#afcef3)]`. Wired as a real, reachable `:focus-visible` state (not a forced class) now that `Card` can render as a native `<a>` — see `as` below.
17
- - **Pressed** (Overlay only): not exposed as a `state` prop. Approximated purely via CSS `:active` on a scrim layer (`bg-card-overlay-pressed/80 backdrop-blur-[3px]`), demonstrated inline in `CardStory.astro`'s Overlay-Pressed composition rather than as a new prop.
18
-
19
- ### Sizing & Spacing
20
-
21
- - Added `size: "default" | "large"` — replaces dead `data-[size=sm]` infra that nothing ever wired up (and whose `sm` naming was backwards vs. Figma's own prop table, which calls its compact size `"default"`).
22
- - Switched from a root-owned `py-*`/`gap-*` vertical-rhythm model to a self-padded-block model, since Large's content padding is asymmetric (`pt-8 pb-6 px-6`) and can't be expressed by a single root `py-*` value: `CardHeader` `pt-6` → `pt-8` (large), `CardContent` `pt-8 pb-6` (constant both sizes), `CardFooter` `p-6` (constant both sizes).
23
- - `CardMedia` inner image radius fixed from `rounded-lg` (8px) to `rounded-md` (6px) for the inset/padded case, matching Figma's flat `rounded-[6px]` on the image against the card's 8px outer radius. The Overlay full-bleed image keeps `rounded-lg` (8px, matching Figma exactly), since there it touches the card's own edges with no inset padding.
24
- - `CardTitle`: dropped the `md:text-xl` responsive fallback and the wrong-axis `group-data-[size=sm]/card:text-sm`; now a flat `text-xl`, dropping to `text-base` only in `orientation="horizontal"` (title size varies by orientation, not by size).
25
- - `CardDescription`: `text-sm` base, `text-base` only for `size="large"` + `orientation="vertical"` (Large-Horizontal stays `text-sm`).
26
- - `CardContent`: now a real `flex flex-col gap-8` container (was `cva("")`, i.e. no layout at all — consumers previously had to add `space-y-*` manually). **Heads up for existing consumers:** this changes CardContent's default display from block to flex-column; anything relying on block-flow spacing inside it should double check.
27
-
28
- ### New Props
29
-
30
- - `size: "default" | "large"` — see above.
31
- - `orientation: "vertical" | "horizontal"` — horizontal is currently only authored in Figma for `variant="ghost"` + `size="large"`; no `default`/`overlay` horizontal frames exist yet.
32
- - `as: "div" | "a"` (Button-style polymorphic tag, was fixed to `<div>`). Lets `Card` render as a real, natively focusable `<a>` so the whole card can be a clickable unit with a genuine `:focus-visible` state — resolves the gap between Figma's Focus state / Overlay arrow-icon affordance and the previous non-interactive `<div>`-only implementation.
33
-
34
- ### Tokens (`globals.css`)
35
-
36
- - Added `--card-overlay-pressed: #051729` (+ `@theme inline` mapping `--color-card-overlay-pressed`) for the Overlay variant's Pressed-state scrim, used at `bg-card-overlay-pressed/80`. This color doesn't match any existing semantic token (closest was `--foreground` at `#09090b`, a different hue), so a new single-purpose token was added rather than approximated, per design decision.
37
- - No other new tokens needed — every other color already existed: `card`, `border`, `ring`, `chart-1`, `primary`, `primary-foreground`, `secondary`, `secondary-foreground`, `muted-foreground`.
38
-
39
- ### Storybook & Docs
40
-
41
- - New stories: `Large`, `Ghost`, `GhostLarge`, `GhostHorizontal`, `Overlay`, `OverlayLarge`, `OverlayPressed`, `Focus`.
42
- - Replaced the dead `[.border-t]:pt-*`/`[.border-b]:pb-*` marker-class divider convention (grepped — no consumer relied on it) with an explicit `<Separator />` (existing, token-bound `bg-border` component) placed between `CardContent` and `CardFooter`.
43
- - Fixed category `Badge` usages in Card's docs/stories to pass `shape="sharp"` (were rendering as pill, not matching Figma's `rounded-xs`).
44
- - Updated the `apps/web` storybook props table and previews to document `variant` (3 values), `size`, `orientation`, and `as`.
45
-
46
- ### Not changed
47
-
48
- - `CardAction.astro` — no Figma delta identified.
49
- - `CardOverlay.astro` — confirmed distinct/unrelated hover-reveal component (opacity fade on `group-hover/card`), intentionally kept separate from the new `variant="overlay"` (same name, different concept).
50
-
51
- ### Flagged for the designer (Figma-file gaps, not addressed in this pass)
52
-
53
- - Avatar size (32px) and background-image height (285px) don't scale between `default`/`large` Card sizes in the current Figma file — matched as authored (unscaled) rather than inventing scaling behavior the design doesn't show.
54
- - Large-Overlay has no documented Pressed state in Figma (only Small-Overlay does) — worth confirming if intentional.
55
- - `--radius-card` (24px) token exists in `globals.css` but is unused anywhere in the codebase and doesn't match Card's actual 8px radius (`--radius-lg`) — likely dead/mis-specified, worth a separate cleanup pass.
56
-
57
- ## Date 9th Sep 2026 (follow-up)
58
- ## Fix: Ghost/Large/Horizontal spacing (node 2547-9489)
59
-
60
- ### Fixed
61
-
62
- - **Layout bug:** `variant="ghost" size="large" orientation="horizontal"` rendered `CardMedia`, `CardHeader`, and `CardContent` as three separate direct children of `Card`. Since `Card`'s root switches to `flex-row` for horizontal orientation, this produced three side-by-side columns instead of two — `CardHeader`'s avatar/date/badge row floated as its own skinny column between the image and the text, instead of stacking above the title. Figma's own structure for this composition confirms there's no separate header concept here at all — it's a single flex-column "Content" area.
63
- - **Fix:** the horizontal composition (`CardStory.astro`, and the storybook docs preview) now nests the Details row (avatar group + date + badge) directly inside `CardContent`, grouped with the Title/Description block in a `flex flex-col gap-6` wrapper (the 24px gap the designer just retokenized in Figma), with the Buttons row as `CardContent`'s only other child. This gives `Card`'s root exactly two flex-row children (`CardMedia`, `CardContent`), matching Figma, and lets `CardContent`'s existing `justify-between`/`self-stretch` overrides correctly push the Buttons row to the bottom of the image's height.
64
- - Removed the now-dead `group-data-[orientation=horizontal]/card:px-0 group-data-[orientation=horizontal]/card:pt-0` overrides from `CardHeader.astro`, since no composition uses `CardHeader` in a horizontal layout anymore (matches Figma, which never had a header concept there).
65
- - No changes needed to `Card.astro` or `CardContent.astro` — the horizontal overrides already there were correct, they just weren't receiving the right children.
66
-
67
- ## Date 9th Sep 2026 (follow-up)
68
- ## Fix: Overlay's Pressed state removed (node 2544-3164)
69
-
70
- ### Removed
71
-
72
- - The designer updated Figma's Card component set — Overlay now documents exactly two sizes (`Small`/`Large`, matching the existing `default`/`large` prop) and, for now, only **Default** and **Focus** states. The **Pressed** state symbol no longer exists in the file.
73
- - Removed the `pressed` prop, its inline scrim demo (`bg-card-overlay-pressed/80 backdrop-blur-[3px] ... group-active/card:opacity-100`), and the `OverlayPressed` story from `CardStory.astro`/`Card.stories.ts` — there's no longer a corresponding Figma reference to demonstrate.
74
- - Removed the now-unused `--card-overlay-pressed` token (and its `@theme inline` mapping) from `globals.css`, per design decision — no dead tokens left dangling; easy to re-add from this changelog entry if Pressed returns later.
75
- - Overlay's Default/Focus states, both sizes, are otherwise unchanged — this was a pure removal.
76
-
77
- ## Date 9th Sep 2026 (follow-up)
78
- ## Fix: Overlay/Small alignment (node 2547-2175)
79
-
80
- ### Fixed
81
-
82
- - **Font color:** `CardDescription` hardcoded `text-muted-foreground` (gray) unconditionally, overriding the white text `CardContent` already applies for `variant="overlay"`. Added `group-data-[variant=overlay]/card:text-primary-foreground` to `CardDescription.astro` so overlay descriptions render white like Figma, matching how `CardTitle` (no explicit color) already inherited it correctly.
83
- - **Avatar/badge row not pinned to the top:** Figma's Small-Overlay structure pins the avatar/badge row to the top and the name/description to the bottom via a `flex-1` spacer between them. The equivalent code composition (`CardHeader` for the avatar/badge row, `CardContent` for the text) only has two flex children, but `Card.astro`'s `variant="overlay" size="default"` compound variant used `justify-end` — with no spacer and only two children, that pushed the whole `[CardHeader, CardContent]` group to the bottom together instead of spreading them apart. Changed to `justify-between` (matching what `size="large"` already correctly used), which alone fixes the pinning.
84
- - **Missing aspect ratio:** `variant="overlay"` makes `CardMedia` `position: absolute`, taken out of flow — so the card's box height was driven only by `CardHeader`+`CardContent`'s natural content height, collapsing far shorter than Figma's frames. Added `aspect-[360/260]` (small) and `aspect-[481/576]` (large) to `Card.astro`'s overlay compound variants — a real component-level fix, not just a demo tweak, since any consumer of `variant="overlay"` would hit this.
85
-
86
- ### Storybook & Docs
87
-
88
- - Header badges in the Overlay composition (`CardStory.astro` and the docs page) changed from `variant="outline" shape="rounded"` to `variant="secondary" shape="pill" size="sm"`, matching the current Figma frame exactly (confirmed by the designer).
89
- - Added the missing arrow-icon `Button` to the docs page's Overlay preview, matching what `CardStory.astro` and Figma both already show.
90
-
91
- ## Date 9th Sep 2026 (follow-up)
92
- ## Fix: Overlay/Default/Small avatar + icon sizing (node 2547-8683)
93
-
94
- ### Fixed
95
-
96
- - **Avatar wrong size + doubled border:** the Overlay header avatar rendered at `Avatar`'s default size (32px, `border-[1.5px]`) instead of Figma's `24px`. Worse, `Avatar.astro`'s own base class always applies a hardcoded `border-border` (gray), and the composition additionally wrapped it in `ring-2 ring-background` (a white halo pattern meant for avatars on a plain card background) — stacking a gray border and a white ring instead of Figma's single solid white border. Fixed by using `<Avatar size="sm" class="border-primary-foreground">` (24px, white border override) and dropping the redundant `ring-*` wrapper classes, in both `CardStory.astro` and the docs page.
97
- - **Arrow icon undersized:** the inline arrow-up-right SVG was `size-4` (16px); Figma's icon is `size-[24px]`. Changed to `size-6` in both files. The 32px button box around it (`Button size="icon-sm"`) was already correct.
98
-
99
- ## Date 9th Sep 2026 (follow-up)
100
- ## Fix: Visual re-audit against Figma (default/ghost/overlay, node 54-1310)
101
-
102
- ### Fixed
103
-
104
- - **`CardTitle` line-height:** was `leading-normal` (1.5× → 30px for the 20px title, 60px across two lines), overshooting Figma's title text style, which specifies a flat `lineHeight: 24` regardless of font size (confirmed for both the `text-xl` vertical title and the `text-base` horizontal/overlay title). Changed to `leading-6` (a fixed 24px) so two-line titles match Figma's 48px box instead of rendering 12px taller.
105
- - **Focus ring width:** was `focus-visible:ring-3` (3px); Figma's `border-focus` effect is a `DROP_SHADOW` with `spread: 2` (2px) — the same 2px value this component's own changelog already documented as the target (`shadow-[0px_0px_0px_2px_var(--chart-1)]`) but the implementation used `ring-3` instead of `ring-2`. Changed to `ring-2`.
106
- - **Overlay avatar group was missing its second avatar:** Figma's header row (both Small and Large Overlay) shows two overlapping avatar photos (`-space-x-2`, white border); `CardStory.astro` and the docs preview only rendered one `Avatar` with an initials fallback. Added a second `<Avatar>` (`https://github.com/thomkrupa.png` + `https://github.com/bejamas.png`, matching the "Thom Krupa, Co-founder at Bejamas" copy) inside the existing `-space-x-2` wrapper.
107
- - **Overlay avatar/badge sizing now scales with `size`:** Small-Overlay uses 24px avatars + `size="sm"` badges (unchanged); Large-Overlay uses 32px avatars + default-size badges per Figma — previously both were hardcoded to `size="sm"`.
108
- - **Overlay (size="default") title→description gap:** was `gap-3` (12px); Figma's Small-Overlay "Thom Krupa"/"Co-funder at Bejamas" spacing measures 8px from node positions. Changed to `gap-2`.
109
- - **Overlay (size="default") description weight/size:** "Co-funder at Bejamas" is a 16px/semibold profile byline in Figma (a local override on that text node, distinct from the shared 14px/regular `CardDescription`), not the plain paragraph style. Added `class="text-base font-semibold"` to that specific `CardDescription` instance in `CardStory.astro` and the docs preview — not a `CardDescription.astro` component change, since Large-Overlay reuses the plain paragraph description as-is (see next point).
110
- - **Overlay badges were invisible, hidden behind the background photo:** caught during visual verification of the fixes above. `CardMedia` is `position:absolute` (`z-0`) for `variant="overlay"`, and `CardContent` already compensates with `relative z-10` — but `CardHeader` never got the same treatment. Per CSS stacking rules, a positioned `z-index:0` box (`CardMedia`) paints *above* an unpositioned in-flow sibling's static descendants (`Badge`, which has no `position` of its own), regardless of DOM order — so the header's badges silently rendered underneath the photo. `Avatar` happened to survive because it's independently `position:relative`, which is what exposed the bug (avatars visible, badges gone). Added the same `group-data-[variant=overlay]/card:relative group-data-[variant=overlay]/card:z-10` to `CardHeader.astro` that `CardContent.astro` already has. Verified via a live render (Playwright screenshot + `elementFromPoint` at the badge's screen coordinates, which resolved to the `<img>` before the fix and to the badge `<span>` after).
111
- - **Overlay `size="large"` was rendering the wrong content pattern:** Figma's Large-Overlay is a headline + full paragraph + single icon-only button (same copy pattern as `Default`, just over an image), not the Small-Overlay's name/role profile pattern. `CardStory.astro`'s overlay branch wasn't gated on `size`, so `OverlayLarge` incorrectly showed "Thom Krupa" / "Co-founder at Bejamas". Branched the composition on `size` so `size="large"` now renders the headline/paragraph pattern (reusing the existing `gap-6 group-data-[size=large]/card:gap-3` title/description convention).
112
-
113
- - **Overlay `CardContent` layout — text and arrow button belong on one row, not stacked:** re-checked against the Figma node positions for both Overlay sizes (Small: "Text" frame has the name/role `Group 1` and the arrow `Button` as side-by-side siblings, `Button` bottom-aligned with the two-line text block; Large: same pattern — "Text" and "Button" siblings inside "Bottom", `Button` bottom-aligned with the text block). `CardContent` was still using its base `flex-col` (text block above, button below) for overlay. Added `group-data-[variant=overlay]/card:flex-row group-data-[variant=overlay]/card:items-end group-data-[variant=overlay]/card:justify-between` so the arrow button now sits to the right of the text block, bottom-aligned, on both Overlay sizes.
114
-
115
- ### Storybook & Docs
116
-
117
- - Added an `Overlay, large` preview to the `apps/web` docs page (previously only the Storybook `OverlayLarge` story existed; the docs page never showcased the large-overlay composition, and was showing the same — now-fixed — mismatched content as `CardStory.astro`).
118
-
119
- ## Unreleased
1
+ # Changelog
2
+
3
+ All notable changes to the `Card` component will be documented in this file.
4
+
5
+ ## Date 9th Sep 2026
6
+ ## Figma alignment (node 54-1310, prop table 7350-1279)
7
+
8
+ ### Variants
9
+
10
+ - Added an `overlay` variant (`variant: "default" | "ghost" | "overlay"`, was `"default" | "ghost"`). Renders `CardMedia` as a full-bleed background behind the card's content — no separate prop is needed on `CardMedia`, `Card` drives the positioning via a `[&_[data-slot=card-media]]:` selector on its own root, so `<Card variant="overlay">` is the single source of truth.
11
+ - **Fixed `ghost`:** previously only added a `data-[variant=ghost]` marker attribute while the root still always applied `border border-border shadow-lg bg-card` unconditionally — visually a no-op, so "ghost" cards rendered identically to default. `border`/`bg`/`shadow` are now scoped to `variant: "default"` only, so `ghost` (and `overlay`) render fully chrome-less as Figma specifies.
12
+ - Removed the always-on `ring-1 ring-foreground/10 shadow-sm` legacy base styling, which conflicted with the newer `border border-border shadow-lg` layered on top of it. Figma shows no shadow/ring at rest for `default` — the ring only appears in the Focus state.
13
+
14
+ ### States
15
+
16
+ - **Focus:** `focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-chart-1`, resolved from Figma's `border-ring` + `shadow-[0px_0px_0px_2px_var(--chart-1,#afcef3)]`. Wired as a real, reachable `:focus-visible` state (not a forced class) now that `Card` can render as a native `<a>` — see `as` below.
17
+ - **Pressed** (Overlay only): not exposed as a `state` prop. Approximated purely via CSS `:active` on a scrim layer (`bg-card-overlay-pressed/80 backdrop-blur-[3px]`), demonstrated inline in `CardStory.astro`'s Overlay-Pressed composition rather than as a new prop.
18
+
19
+ ### Sizing & Spacing
20
+
21
+ - Added `size: "default" | "large"` — replaces dead `data-[size=sm]` infra that nothing ever wired up (and whose `sm` naming was backwards vs. Figma's own prop table, which calls its compact size `"default"`).
22
+ - Switched from a root-owned `py-*`/`gap-*` vertical-rhythm model to a self-padded-block model, since Large's content padding is asymmetric (`pt-8 pb-6 px-6`) and can't be expressed by a single root `py-*` value: `CardHeader` `pt-6` → `pt-8` (large), `CardContent` `pt-8 pb-6` (constant both sizes), `CardFooter` `p-6` (constant both sizes).
23
+ - `CardMedia` inner image radius fixed from `rounded-lg` (8px) to `rounded-md` (6px) for the inset/padded case, matching Figma's flat `rounded-[6px]` on the image against the card's 8px outer radius. The Overlay full-bleed image keeps `rounded-lg` (8px, matching Figma exactly), since there it touches the card's own edges with no inset padding.
24
+ - `CardTitle`: dropped the `md:text-xl` responsive fallback and the wrong-axis `group-data-[size=sm]/card:text-sm`; now a flat `text-xl`, dropping to `text-base` only in `orientation="horizontal"` (title size varies by orientation, not by size).
25
+ - `CardDescription`: `text-sm` base, `text-base` only for `size="large"` + `orientation="vertical"` (Large-Horizontal stays `text-sm`).
26
+ - `CardContent`: now a real `flex flex-col gap-8` container (was `cva("")`, i.e. no layout at all — consumers previously had to add `space-y-*` manually). **Heads up for existing consumers:** this changes CardContent's default display from block to flex-column; anything relying on block-flow spacing inside it should double check.
27
+
28
+ ### New Props
29
+
30
+ - `size: "default" | "large"` — see above.
31
+ - `orientation: "vertical" | "horizontal"` — horizontal is currently only authored in Figma for `variant="ghost"` + `size="large"`; no `default`/`overlay` horizontal frames exist yet.
32
+ - `as: "div" | "a"` (Button-style polymorphic tag, was fixed to `<div>`). Lets `Card` render as a real, natively focusable `<a>` so the whole card can be a clickable unit with a genuine `:focus-visible` state — resolves the gap between Figma's Focus state / Overlay arrow-icon affordance and the previous non-interactive `<div>`-only implementation.
33
+
34
+ ### Tokens (`globals.css`)
35
+
36
+ - Added `--card-overlay-pressed: #051729` (+ `@theme inline` mapping `--color-card-overlay-pressed`) for the Overlay variant's Pressed-state scrim, used at `bg-card-overlay-pressed/80`. This color doesn't match any existing semantic token (closest was `--foreground` at `#09090b`, a different hue), so a new single-purpose token was added rather than approximated, per design decision.
37
+ - No other new tokens needed — every other color already existed: `card`, `border`, `ring`, `chart-1`, `primary`, `primary-foreground`, `secondary`, `secondary-foreground`, `muted-foreground`.
38
+
39
+ ### Storybook & Docs
40
+
41
+ - New stories: `Large`, `Ghost`, `GhostLarge`, `GhostHorizontal`, `Overlay`, `OverlayLarge`, `OverlayPressed`, `Focus`.
42
+ - Replaced the dead `[.border-t]:pt-*`/`[.border-b]:pb-*` marker-class divider convention (grepped — no consumer relied on it) with an explicit `<Separator />` (existing, token-bound `bg-border` component) placed between `CardContent` and `CardFooter`.
43
+ - Fixed category `Badge` usages in Card's docs/stories to pass `shape="sharp"` (were rendering as pill, not matching Figma's `rounded-xs`).
44
+ - Updated the `apps/web` storybook props table and previews to document `variant` (3 values), `size`, `orientation`, and `as`.
45
+
46
+ ### Not changed
47
+
48
+ - `CardAction.astro` — no Figma delta identified.
49
+ - `CardOverlay.astro` — confirmed distinct/unrelated hover-reveal component (opacity fade on `group-hover/card`), intentionally kept separate from the new `variant="overlay"` (same name, different concept).
50
+
51
+ ### Flagged for the designer (Figma-file gaps, not addressed in this pass)
52
+
53
+ - Avatar size (32px) and background-image height (285px) don't scale between `default`/`large` Card sizes in the current Figma file — matched as authored (unscaled) rather than inventing scaling behavior the design doesn't show.
54
+ - Large-Overlay has no documented Pressed state in Figma (only Small-Overlay does) — worth confirming if intentional.
55
+ - `--radius-card` (24px) token exists in `globals.css` but is unused anywhere in the codebase and doesn't match Card's actual 8px radius (`--radius-lg`) — likely dead/mis-specified, worth a separate cleanup pass.
56
+
57
+ ## Date 9th Sep 2026 (follow-up)
58
+ ## Fix: Ghost/Large/Horizontal spacing (node 2547-9489)
59
+
60
+ ### Fixed
61
+
62
+ - **Layout bug:** `variant="ghost" size="large" orientation="horizontal"` rendered `CardMedia`, `CardHeader`, and `CardContent` as three separate direct children of `Card`. Since `Card`'s root switches to `flex-row` for horizontal orientation, this produced three side-by-side columns instead of two — `CardHeader`'s avatar/date/badge row floated as its own skinny column between the image and the text, instead of stacking above the title. Figma's own structure for this composition confirms there's no separate header concept here at all — it's a single flex-column "Content" area.
63
+ - **Fix:** the horizontal composition (`CardStory.astro`, and the storybook docs preview) now nests the Details row (avatar group + date + badge) directly inside `CardContent`, grouped with the Title/Description block in a `flex flex-col gap-6` wrapper (the 24px gap the designer just retokenized in Figma), with the Buttons row as `CardContent`'s only other child. This gives `Card`'s root exactly two flex-row children (`CardMedia`, `CardContent`), matching Figma, and lets `CardContent`'s existing `justify-between`/`self-stretch` overrides correctly push the Buttons row to the bottom of the image's height.
64
+ - Removed the now-dead `group-data-[orientation=horizontal]/card:px-0 group-data-[orientation=horizontal]/card:pt-0` overrides from `CardHeader.astro`, since no composition uses `CardHeader` in a horizontal layout anymore (matches Figma, which never had a header concept there).
65
+ - No changes needed to `Card.astro` or `CardContent.astro` — the horizontal overrides already there were correct, they just weren't receiving the right children.
66
+
67
+ ## Date 9th Sep 2026 (follow-up)
68
+ ## Fix: Overlay's Pressed state removed (node 2544-3164)
69
+
70
+ ### Removed
71
+
72
+ - The designer updated Figma's Card component set — Overlay now documents exactly two sizes (`Small`/`Large`, matching the existing `default`/`large` prop) and, for now, only **Default** and **Focus** states. The **Pressed** state symbol no longer exists in the file.
73
+ - Removed the `pressed` prop, its inline scrim demo (`bg-card-overlay-pressed/80 backdrop-blur-[3px] ... group-active/card:opacity-100`), and the `OverlayPressed` story from `CardStory.astro`/`Card.stories.ts` — there's no longer a corresponding Figma reference to demonstrate.
74
+ - Removed the now-unused `--card-overlay-pressed` token (and its `@theme inline` mapping) from `globals.css`, per design decision — no dead tokens left dangling; easy to re-add from this changelog entry if Pressed returns later.
75
+ - Overlay's Default/Focus states, both sizes, are otherwise unchanged — this was a pure removal.
76
+
77
+ ## Date 9th Sep 2026 (follow-up)
78
+ ## Fix: Overlay/Small alignment (node 2547-2175)
79
+
80
+ ### Fixed
81
+
82
+ - **Font color:** `CardDescription` hardcoded `text-muted-foreground` (gray) unconditionally, overriding the white text `CardContent` already applies for `variant="overlay"`. Added `group-data-[variant=overlay]/card:text-primary-foreground` to `CardDescription.astro` so overlay descriptions render white like Figma, matching how `CardTitle` (no explicit color) already inherited it correctly.
83
+ - **Avatar/badge row not pinned to the top:** Figma's Small-Overlay structure pins the avatar/badge row to the top and the name/description to the bottom via a `flex-1` spacer between them. The equivalent code composition (`CardHeader` for the avatar/badge row, `CardContent` for the text) only has two flex children, but `Card.astro`'s `variant="overlay" size="default"` compound variant used `justify-end` — with no spacer and only two children, that pushed the whole `[CardHeader, CardContent]` group to the bottom together instead of spreading them apart. Changed to `justify-between` (matching what `size="large"` already correctly used), which alone fixes the pinning.
84
+ - **Missing aspect ratio:** `variant="overlay"` makes `CardMedia` `position: absolute`, taken out of flow — so the card's box height was driven only by `CardHeader`+`CardContent`'s natural content height, collapsing far shorter than Figma's frames. Added `aspect-[360/260]` (small) and `aspect-[481/576]` (large) to `Card.astro`'s overlay compound variants — a real component-level fix, not just a demo tweak, since any consumer of `variant="overlay"` would hit this.
85
+
86
+ ### Storybook & Docs
87
+
88
+ - Header badges in the Overlay composition (`CardStory.astro` and the docs page) changed from `variant="outline" shape="rounded"` to `variant="secondary" shape="pill" size="sm"`, matching the current Figma frame exactly (confirmed by the designer).
89
+ - Added the missing arrow-icon `Button` to the docs page's Overlay preview, matching what `CardStory.astro` and Figma both already show.
90
+
91
+ ## Date 9th Sep 2026 (follow-up)
92
+ ## Fix: Overlay/Default/Small avatar + icon sizing (node 2547-8683)
93
+
94
+ ### Fixed
95
+
96
+ - **Avatar wrong size + doubled border:** the Overlay header avatar rendered at `Avatar`'s default size (32px, `border-[1.5px]`) instead of Figma's `24px`. Worse, `Avatar.astro`'s own base class always applies a hardcoded `border-border` (gray), and the composition additionally wrapped it in `ring-2 ring-background` (a white halo pattern meant for avatars on a plain card background) — stacking a gray border and a white ring instead of Figma's single solid white border. Fixed by using `<Avatar size="sm" class="border-primary-foreground">` (24px, white border override) and dropping the redundant `ring-*` wrapper classes, in both `CardStory.astro` and the docs page.
97
+ - **Arrow icon undersized:** the inline arrow-up-right SVG was `size-4` (16px); Figma's icon is `size-[24px]`. Changed to `size-6` in both files. The 32px button box around it (`Button size="icon-sm"`) was already correct.
98
+
99
+ ## Date 9th Sep 2026 (follow-up)
100
+ ## Fix: Visual re-audit against Figma (default/ghost/overlay, node 54-1310)
101
+
102
+ ### Fixed
103
+
104
+ - **`CardTitle` line-height:** was `leading-normal` (1.5× → 30px for the 20px title, 60px across two lines), overshooting Figma's title text style, which specifies a flat `lineHeight: 24` regardless of font size (confirmed for both the `text-xl` vertical title and the `text-base` horizontal/overlay title). Changed to `leading-6` (a fixed 24px) so two-line titles match Figma's 48px box instead of rendering 12px taller.
105
+ - **Focus ring width:** was `focus-visible:ring-3` (3px); Figma's `border-focus` effect is a `DROP_SHADOW` with `spread: 2` (2px) — the same 2px value this component's own changelog already documented as the target (`shadow-[0px_0px_0px_2px_var(--chart-1)]`) but the implementation used `ring-3` instead of `ring-2`. Changed to `ring-2`.
106
+ - **Overlay avatar group was missing its second avatar:** Figma's header row (both Small and Large Overlay) shows two overlapping avatar photos (`-space-x-2`, white border); `CardStory.astro` and the docs preview only rendered one `Avatar` with an initials fallback. Added a second `<Avatar>` (`https://github.com/thomkrupa.png` + `https://github.com/bejamas.png`, matching the "Thom Krupa, Co-founder at Bejamas" copy) inside the existing `-space-x-2` wrapper.
107
+ - **Overlay avatar/badge sizing now scales with `size`:** Small-Overlay uses 24px avatars + `size="sm"` badges (unchanged); Large-Overlay uses 32px avatars + default-size badges per Figma — previously both were hardcoded to `size="sm"`.
108
+ - **Overlay (size="default") title→description gap:** was `gap-3` (12px); Figma's Small-Overlay "Thom Krupa"/"Co-funder at Bejamas" spacing measures 8px from node positions. Changed to `gap-2`.
109
+ - **Overlay (size="default") description weight/size:** "Co-funder at Bejamas" is a 16px/semibold profile byline in Figma (a local override on that text node, distinct from the shared 14px/regular `CardDescription`), not the plain paragraph style. Added `class="text-base font-semibold"` to that specific `CardDescription` instance in `CardStory.astro` and the docs preview — not a `CardDescription.astro` component change, since Large-Overlay reuses the plain paragraph description as-is (see next point).
110
+ - **Overlay badges were invisible, hidden behind the background photo:** caught during visual verification of the fixes above. `CardMedia` is `position:absolute` (`z-0`) for `variant="overlay"`, and `CardContent` already compensates with `relative z-10` — but `CardHeader` never got the same treatment. Per CSS stacking rules, a positioned `z-index:0` box (`CardMedia`) paints *above* an unpositioned in-flow sibling's static descendants (`Badge`, which has no `position` of its own), regardless of DOM order — so the header's badges silently rendered underneath the photo. `Avatar` happened to survive because it's independently `position:relative`, which is what exposed the bug (avatars visible, badges gone). Added the same `group-data-[variant=overlay]/card:relative group-data-[variant=overlay]/card:z-10` to `CardHeader.astro` that `CardContent.astro` already has. Verified via a live render (Playwright screenshot + `elementFromPoint` at the badge's screen coordinates, which resolved to the `<img>` before the fix and to the badge `<span>` after).
111
+ - **Overlay `size="large"` was rendering the wrong content pattern:** Figma's Large-Overlay is a headline + full paragraph + single icon-only button (same copy pattern as `Default`, just over an image), not the Small-Overlay's name/role profile pattern. `CardStory.astro`'s overlay branch wasn't gated on `size`, so `OverlayLarge` incorrectly showed "Thom Krupa" / "Co-founder at Bejamas". Branched the composition on `size` so `size="large"` now renders the headline/paragraph pattern (reusing the existing `gap-6 group-data-[size=large]/card:gap-3` title/description convention).
112
+
113
+ - **Overlay `CardContent` layout — text and arrow button belong on one row, not stacked:** re-checked against the Figma node positions for both Overlay sizes (Small: "Text" frame has the name/role `Group 1` and the arrow `Button` as side-by-side siblings, `Button` bottom-aligned with the two-line text block; Large: same pattern — "Text" and "Button" siblings inside "Bottom", `Button` bottom-aligned with the text block). `CardContent` was still using its base `flex-col` (text block above, button below) for overlay. Added `group-data-[variant=overlay]/card:flex-row group-data-[variant=overlay]/card:items-end group-data-[variant=overlay]/card:justify-between` so the arrow button now sits to the right of the text block, bottom-aligned, on both Overlay sizes.
114
+
115
+ ### Storybook & Docs
116
+
117
+ - Added an `Overlay, large` preview to the `apps/web` docs page (previously only the Storybook `OverlayLarge` story existed; the docs page never showcased the large-overlay composition, and was showing the same — now-fixed — mismatched content as `CardStory.astro`).
118
+
119
+ ## Date 27th Sep 2026
120
+ ## Figma re-sync: Hover state + detail alignment (node 54-1310, component set 2544-3164)
121
+
122
+ ### Added
123
+
124
+ - **Hover state** (Figma `7546:3534`, `variant="default"`, applied to both sizes):
125
+ - `CardMedia` fades in a `card-hover` scrim (`#112843` @ 70%) over the image on `group-hover/card` and `group-focus-within/card`.
126
+ - `Card` gets `shadow-card-light` (`0 1px 1px rgba(5,23,41,.06)`) on hover and focus-within.
127
+ - Ghost and overlay are unaffected.
128
+ - **New slots `CardMediaSelect` and `CardMediaActions`.** Both go inside `CardMedia`, are hidden until hover or focus-within, and are always visible under `@media (hover: none)`.
129
+ - `CardMediaSelect` is the top-left slot for `<Checkbox size="lg" />`.
130
+ - `CardMediaActions` is the top-right icon toolbar: `rounded-md`, a `slider-background-disabled` border, a `card-hover` background, and 20px icons.
131
+ - Figma's fractional values from the scaled component (19.38px offsets, a 14.77px gap, a 1.231px border) were normalized to 20px / 16px / 1px.
132
+ - They are composable slots rather than props, so consumers wire their own actions.
133
+ - **Tokens (`globals.css`):**
134
+ - `--card-hover` (`color-mix(primary-950 70%)`) with a `--color-card-hover` mapping.
135
+ - `--shadow-card-light` with a `shadow-card-light` utility.
136
+
137
+ ### Fixed
138
+
139
+ - **Overlay Focus border was invisible.** `focus-visible:border-ring` had no border width to color on ghost and overlay. Both now have `border border-transparent`, so Figma's 1px `ring` border shows together with the 2px `chart-1` ring.
140
+ - **Overlay Large content row:**
141
+ - Added `gap-10` (40px) between the text block and the arrow button.
142
+ - The description is now 14px (it was picking up 16px from the large + vertical rule). The rule now uses `not-in-data-[variant=overlay]`.
143
+ - **Overlay arrow icon (docs page) rendered at 14px.** `Button size="icon-sm"`'s `[&_svg]:size-3.5` outranked the SVG's own `size-6`. It now passes `[&_svg]:size-6` on the Button.
144
+
145
+ ### Storybook & Docs
146
+
147
+ - Avatars now show the status dot (`status="active"`), matching Figma's `showStatus=true`.
148
+ - Overlay (both sizes) now uses a **single** default-size (32px) avatar with the default `border-border`. This replaces the two stacked avatars with the `border-primary-foreground` override.
149
+ - Footer copy changed to "31 steps · 10 min" (semibold). It now has three **pill** badges (Marketing, UI Design, AI) instead of two `shape="sharp"` ones.
150
+ - The Date in the Details row is semibold.
151
+ - The first preview now matches Figma's defaults: 400px wide, title only, no description or buttons (`description=false`, `buttons=false`). The richer composition moved to "With description & actions".
152
+ - New previews: **Hover** and **Overlay focus**. There is also a new "Sub-components" table for the new slots.
153
+
154
+ ### Flagged for the designer (not changed)
155
+
156
+ - There's no Large-Hover frame. The Small behaviour was applied to Large.
157
+ - Large-Focus (`2545:950`) still uses sharp (2px) badges and `p-6` content padding, while Large-Default uses `pt-8`. These look like stale instances.
158
+ - Ghost-Large (`2547:9398`) uses small-size spacing (`p-6`, `gap-6`, 14px description), while code applies the large rules. It also has a trailing separator with no footer.
159
+ - The toolbar background `rgba(32,41,57,.7)` isn't a token, so `card-hover` is reused. The toolbar border is bound to `slider-background-disabled`, which isn't a semantic match.
160
+ - The description text inherits Semibold from Figma's "Text" frame. Confirm whether it should be regular weight, as the code has it now.
161
+
162
+ ## Unreleased
@@ -13,14 +13,14 @@
13
13
  * <CardHeader>
14
14
  * <div class="flex items-center gap-2 justify-between">
15
15
  * <div class="*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2">
16
- * <Avatar>
16
+ * <Avatar status="active">
17
17
  * <AvatarImage>
18
18
  * <img src="https://gradient.bejamas.com/presets/bejamas/marine.png" alt="grdient avatar" />
19
19
  * </AvatarImage>
20
20
  * <AvatarFallback>AW</AvatarFallback>
21
21
  * </Avatar>
22
22
  * </div>
23
- * <Date date="2025-08-24T12:00:00Z" class="text-sm text-muted-foreground" />
23
+ * <Date date="2025-08-24T12:00:00Z" class="text-sm font-semibold text-muted-foreground" />
24
24
  * </div>
25
25
  * </CardHeader>
26
26
  * <CardContent>
@@ -32,10 +32,11 @@
32
32
  * </CardContent>
33
33
  * <Separator />
34
34
  * <CardFooter>
35
- * <p class="text-sm text-muted-foreground">Categories</p>
35
+ * <p class="text-sm font-semibold text-muted-foreground">31 steps · 10 min</p>
36
36
  * <div class="flex items-center gap-1">
37
- * <Badge variant="secondary" shape="sharp">Marketing</Badge>
38
- * <Badge variant="secondary" shape="sharp">UI Design</Badge>
37
+ * <Badge variant="secondary">Marketing</Badge>
38
+ * <Badge variant="secondary">UI Design</Badge>
39
+ * <Badge variant="secondary">AI</Badge>
39
40
  * </div>
40
41
  * </CardFooter>
41
42
  * </Card>
@@ -83,6 +84,19 @@
83
84
  *
84
85
  * <Card variant="overlay">...</Card>
85
86
  *
87
+ * ### Hover actions
88
+ *
89
+ * On `variant="default"`, hovering the card (or focusing anything inside it) fades a `card-hover` scrim over `<CardMedia>` and lifts the card with `shadow-card-light`. Place `<CardMediaSelect>` (top-left, e.g. `<Checkbox size="lg" />`) and/or `<CardMediaActions>` (top-right icon toolbar) inside `<CardMedia>` — both stay hidden until hover/focus-within, and are always visible on touch devices. Don't combine them with `as="a"`: interactive children inside an anchor are invalid HTML.
90
+ *
91
+ * <CardMedia>
92
+ * <img ... />
93
+ * <CardMediaSelect><Checkbox size="lg" aria-label="Select card" /></CardMediaSelect>
94
+ * <CardMediaActions>
95
+ * <button aria-label="Copy link"><Link /></button>
96
+ * <button aria-label="More actions"><Ellipsis /></button>
97
+ * </CardMediaActions>
98
+ * </CardMedia>
99
+ *
86
100
  * ### As a link
87
101
  *
88
102
  * Pass `as="a"` (with `href`) to render the whole card as a real, natively focusable anchor — this is how to make Figma's Focus state reachable via keyboard, since a plain `<div>` can't receive `:focus-visible`.
@@ -128,9 +142,10 @@ const cardVariants = cva(
128
142
  {
129
143
  variants: {
130
144
  variant: {
131
- default: "bg-card border border-border",
132
- ghost: "",
133
- overlay: "",
145
+ default:
146
+ "bg-card border border-border transition-shadow hover:shadow-card-light focus-within:shadow-card-light",
147
+ ghost: "border border-transparent",
148
+ overlay: "border border-transparent",
134
149
  },
135
150
  size: {
136
151
  default: "",
@@ -19,7 +19,7 @@ const contentVariants = cva("");
19
19
  {...rest}
20
20
  data-slot="card-content"
21
21
  class={cn(
22
- "flex flex-col gap-8 px-6 pt-8 pb-6 group-data-[orientation=horizontal]/card:flex-1 group-data-[orientation=horizontal]/card:justify-between group-data-[orientation=horizontal]/card:self-stretch group-data-[orientation=horizontal]/card:px-0 group-data-[orientation=horizontal]/card:py-3 group-data-[variant=overlay]/card:relative group-data-[variant=overlay]/card:z-10 group-data-[variant=overlay]/card:flex-row group-data-[variant=overlay]/card:items-end group-data-[variant=overlay]/card:justify-between group-data-[variant=overlay]/card:px-0 group-data-[variant=overlay]/card:pt-0 group-data-[variant=overlay]/card:pb-0 group-data-[variant=overlay]/card:text-primary-foreground",
22
+ "flex flex-col gap-8 px-6 pt-8 pb-6 group-data-[orientation=horizontal]/card:flex-1 group-data-[orientation=horizontal]/card:justify-between group-data-[orientation=horizontal]/card:self-stretch group-data-[orientation=horizontal]/card:px-0 group-data-[orientation=horizontal]/card:py-3 group-data-[variant=overlay]/card:relative group-data-[variant=overlay]/card:z-10 group-data-[variant=overlay]/card:flex-row group-data-[variant=overlay]/card:items-end group-data-[variant=overlay]/card:justify-between group-data-[variant=overlay]/card:px-0 group-data-[variant=overlay]/card:pt-0 group-data-[variant=overlay]/card:pb-0 group-data-[variant=overlay]/card:text-primary-foreground group-data-[variant=overlay]/card:group-data-[size=large]/card:gap-10",
23
23
  contentVariants(),
24
24
  className,
25
25
  )}
@@ -19,7 +19,7 @@ const descriptionVariants = cva("");
19
19
  {...rest}
20
20
  data-slot="card-description"
21
21
  class={cn(
22
- "text-muted-foreground text-sm group-data-[size=large]/card:group-data-[orientation=vertical]/card:text-base group-data-[variant=overlay]/card:text-primary-foreground",
22
+ "text-muted-foreground text-sm group-data-[size=large]/card:group-data-[orientation=vertical]/card:not-in-data-[variant=overlay]:text-base group-data-[variant=overlay]/card:text-primary-foreground",
23
23
  descriptionVariants(),
24
24
  className,
25
25
  )}
@@ -13,7 +13,7 @@ const {
13
13
  } = Astro.props as Props;
14
14
 
15
15
  const mediaVariants = cva(
16
- "relative z-0 overflow-hidden pt-2 px-2 [&_img]:size-full [&_img]:rounded-md [&_img]:object-cover group-data-[orientation=horizontal]/card:w-2/5 group-data-[orientation=horizontal]/card:self-stretch group-data-[orientation=horizontal]/card:p-0",
16
+ "relative z-0 overflow-hidden pt-2 px-2 [&_img]:size-full [&_img]:rounded-md [&_img]:object-cover group-data-[orientation=horizontal]/card:w-2/5 group-data-[orientation=horizontal]/card:self-stretch group-data-[orientation=horizontal]/card:p-0 group-data-[variant=default]/card:after:pointer-events-none group-data-[variant=default]/card:after:absolute group-data-[variant=default]/card:after:inset-x-2 group-data-[variant=default]/card:after:top-2 group-data-[variant=default]/card:after:bottom-0 group-data-[variant=default]/card:after:rounded-md group-data-[variant=default]/card:after:bg-card-hover group-data-[variant=default]/card:after:opacity-0 group-data-[variant=default]/card:after:transition-opacity group-data-[variant=default]/card:after:duration-200 group-data-[variant=default]/card:group-hover/card:after:opacity-100 group-data-[variant=default]/card:group-focus-within/card:after:opacity-100",
17
17
  );
18
18
  ---
19
19
 
@@ -0,0 +1,21 @@
1
+ ---
2
+ import { cn } from "@cl-light-ds/ui/lib/utils";
3
+ import type { HTMLAttributes } from "astro/types";
4
+
5
+ interface Props extends HTMLAttributes<"div"> {
6
+ class?: string;
7
+ }
8
+
9
+ const { class: className = "", ...rest } = Astro.props as Props;
10
+ ---
11
+
12
+ <div
13
+ {...rest}
14
+ data-slot="card-media-actions"
15
+ class={cn(
16
+ "absolute top-5 right-5 z-10 flex items-center gap-4 rounded-md border border-slider-background-disabled bg-card-hover py-1 pr-1.5 pl-2.5 text-primary-foreground opacity-0 transition-opacity duration-200 group-hover/card:opacity-100 group-focus-within/card:opacity-100 [@media(hover:none)]:opacity-100 [&_svg]:size-5",
17
+ className,
18
+ )}
19
+ >
20
+ <slot />
21
+ </div>
@@ -0,0 +1,21 @@
1
+ ---
2
+ import { cn } from "@cl-light-ds/ui/lib/utils";
3
+ import type { HTMLAttributes } from "astro/types";
4
+
5
+ interface Props extends HTMLAttributes<"div"> {
6
+ class?: string;
7
+ }
8
+
9
+ const { class: className = "", ...rest } = Astro.props as Props;
10
+ ---
11
+
12
+ <div
13
+ {...rest}
14
+ data-slot="card-media-select"
15
+ class={cn(
16
+ "absolute top-5 left-5 z-10 flex opacity-0 transition-opacity duration-200 group-hover/card:opacity-100 group-focus-within/card:opacity-100 [@media(hover:none)]:opacity-100",
17
+ className,
18
+ )}
19
+ >
20
+ <slot />
21
+ </div>
@@ -1,10 +1,12 @@
1
- export { default as Card } from "./Card.astro";
2
- export { default as CardMedia } from "./CardMedia.astro";
3
- export { default as CardHeader } from "./CardHeader.astro";
4
- export { default as CardTitle } from "./CardTitle.astro";
5
- export { default as CardDescription } from "./CardDescription.astro";
6
- export { default as CardAction } from "./CardAction.astro";
7
- export { default as CardContent } from "./CardContent.astro";
8
- export { default as CardFooter } from "./CardFooter.astro";
9
- export { default as CardOverlay } from "./CardOverlay.astro";
10
-
1
+ export { default as Card } from "./Card.astro";
2
+ export { default as CardMedia } from "./CardMedia.astro";
3
+ export { default as CardMediaSelect } from "./CardMediaSelect.astro";
4
+ export { default as CardMediaActions } from "./CardMediaActions.astro";
5
+ export { default as CardHeader } from "./CardHeader.astro";
6
+ export { default as CardTitle } from "./CardTitle.astro";
7
+ export { default as CardDescription } from "./CardDescription.astro";
8
+ export { default as CardAction } from "./CardAction.astro";
9
+ export { default as CardContent } from "./CardContent.astro";
10
+ export { default as CardFooter } from "./CardFooter.astro";
11
+ export { default as CardOverlay } from "./CardOverlay.astro";
12
+
@@ -1,5 +1,5 @@
1
- # Changelog
2
-
3
- All notable changes to the `Carousel` component will be documented in this file.
4
-
5
- ## Unreleased
1
+ # Changelog
2
+
3
+ All notable changes to the `Carousel` component will be documented in this file.
4
+
5
+ ## Unreleased
@@ -1,3 +1,3 @@
1
- export { default as Carousel } from "./Carousel.astro";
2
- export { default as CarouselSlide } from "./CarouselSlide.astro";
3
-
1
+ export { default as Carousel } from "./Carousel.astro";
2
+ export { default as CarouselSlide } from "./CarouselSlide.astro";
3
+