@acronis-platform/ui-react 3.0.0 → 4.0.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 (219) hide show
  1. package/dist/components/ui/accordion-container/accordion-container.js +14 -14
  2. package/dist/components/ui/accordion-container/accordion-container.js.map +1 -1
  3. package/dist/components/ui/app-shell-chat/app-shell-chat.js.map +1 -1
  4. package/dist/components/ui/area-chart/area-chart.js +141 -139
  5. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  6. package/dist/components/ui/bar-chart/bar-chart.js +295 -293
  7. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  8. package/dist/components/ui/category-bar/category-bar.js +109 -93
  9. package/dist/components/ui/category-bar/category-bar.js.map +1 -1
  10. package/dist/components/ui/chart/chart-palette.js +113 -0
  11. package/dist/components/ui/chart/chart-palette.js.map +1 -0
  12. package/dist/components/ui/chart/chart.js +176 -129
  13. package/dist/components/ui/chart/chart.js.map +1 -1
  14. package/dist/components/ui/chart-state/chart-state-illustrations.js +310 -0
  15. package/dist/components/ui/chart-state/chart-state-illustrations.js.map +1 -0
  16. package/dist/components/ui/chart-state/chart-state.js +48 -34
  17. package/dist/components/ui/chart-state/chart-state.js.map +1 -1
  18. package/dist/components/ui/chart-widget/chart-widget.js +87 -0
  19. package/dist/components/ui/chart-widget/chart-widget.js.map +1 -0
  20. package/dist/components/ui/composed-chart/composed-chart.js +117 -115
  21. package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
  22. package/dist/components/ui/confidence-cone/confidence-cone.js +166 -158
  23. package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
  24. package/dist/components/ui/funnel-chart/funnel-chart.js +162 -161
  25. package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
  26. package/dist/components/ui/histogram/histogram.js +94 -92
  27. package/dist/components/ui/histogram/histogram.js.map +1 -1
  28. package/dist/components/ui/input/input.js.map +1 -1
  29. package/dist/components/ui/label/label.js +2 -9
  30. package/dist/components/ui/label/label.js.map +1 -1
  31. package/dist/components/ui/line-chart/line-chart.js +143 -141
  32. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  33. package/dist/components/ui/metric/metric.js +74 -185
  34. package/dist/components/ui/metric/metric.js.map +1 -1
  35. package/dist/components/ui/page-content/page-content.js.map +1 -1
  36. package/dist/components/ui/pie-chart/pie-chart.js +201 -195
  37. package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
  38. package/dist/components/ui/radar-chart/radar-chart.js +133 -131
  39. package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
  40. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +297 -265
  41. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
  42. package/dist/components/ui/sankey-chart/sankey-chart.js +123 -101
  43. package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -1
  44. package/dist/components/ui/scatter-chart/scatter-chart.js +76 -74
  45. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  46. package/dist/components/ui/section/section.js +157 -31
  47. package/dist/components/ui/section/section.js.map +1 -1
  48. package/dist/components/ui/stepper/stepper.js +24 -24
  49. package/dist/components/ui/stepper/stepper.js.map +1 -1
  50. package/dist/components/ui/stepper-item/stepper-item.js +43 -24
  51. package/dist/components/ui/stepper-item/stepper-item.js.map +1 -1
  52. package/dist/components/ui/treemap/treemap.js +133 -124
  53. package/dist/components/ui/treemap/treemap.js.map +1 -1
  54. package/dist/components/ui/trend-indicator/trend-indicator.js +34 -69
  55. package/dist/components/ui/trend-indicator/trend-indicator.js.map +1 -1
  56. package/dist/components/ui/wizard/wizard.js +59 -0
  57. package/dist/components/ui/wizard/wizard.js.map +1 -0
  58. package/dist/hooks/use-wizard.js +75 -0
  59. package/dist/hooks/use-wizard.js.map +1 -0
  60. package/dist/index.js +502 -497
  61. package/dist/index.js.map +1 -1
  62. package/dist/llms/accordion-container.md +181 -0
  63. package/dist/llms/accordion.md +124 -0
  64. package/dist/llms/alert.md +225 -0
  65. package/dist/llms/app-shell-chat.md +415 -0
  66. package/dist/llms/area-chart.md +355 -0
  67. package/dist/llms/avatar.md +208 -0
  68. package/dist/llms/bar-chart.md +406 -0
  69. package/dist/llms/breadcrumb.md +326 -0
  70. package/dist/llms/button-group.md +298 -0
  71. package/dist/llms/button-icon-input.md +142 -0
  72. package/dist/llms/button-icon-menu.md +209 -0
  73. package/dist/llms/button-icon.md +128 -0
  74. package/dist/llms/button-menu.md +172 -0
  75. package/dist/llms/button.md +185 -0
  76. package/dist/llms/calendar-panel.md +733 -0
  77. package/dist/llms/calendar.md +188 -0
  78. package/dist/llms/card-filter.md +214 -0
  79. package/dist/llms/card-section.md +293 -0
  80. package/dist/llms/card.md +447 -0
  81. package/dist/llms/carousel-dialog.md +156 -0
  82. package/dist/llms/category-bar.md +193 -0
  83. package/dist/llms/chart-state.md +190 -0
  84. package/dist/llms/chart-widget.md +209 -0
  85. package/dist/llms/chart.md +182 -0
  86. package/dist/llms/checkbox.md +257 -0
  87. package/dist/llms/chip.md +195 -0
  88. package/dist/llms/combobox.md +164 -0
  89. package/dist/llms/composed-chart.md +508 -0
  90. package/dist/llms/confidence-cone.md +277 -0
  91. package/dist/llms/data-table.md +474 -0
  92. package/dist/llms/date-range-picker.md +272 -0
  93. package/dist/llms/description-list.md +131 -0
  94. package/dist/llms/dialog-footer-carousel.md +147 -0
  95. package/dist/llms/dialog-footer-default.md +142 -0
  96. package/dist/llms/dialog-root.md +246 -0
  97. package/dist/llms/dialog-welcome.md +223 -0
  98. package/dist/llms/dialog.md +403 -0
  99. package/dist/llms/dropdown-menu.md +193 -0
  100. package/dist/llms/empty-overlay.md +146 -0
  101. package/dist/llms/empty.md +156 -0
  102. package/dist/llms/field.md +185 -0
  103. package/dist/llms/filter-cards.md +157 -0
  104. package/dist/llms/filter-chips.md +323 -0
  105. package/dist/llms/filter-search.md +512 -0
  106. package/dist/llms/form.md +154 -0
  107. package/dist/llms/funnel-chart.md +333 -0
  108. package/dist/llms/grid.md +80 -0
  109. package/dist/llms/histogram.md +190 -0
  110. package/dist/llms/input-date-picker.md +203 -0
  111. package/dist/llms/input-otp.md +173 -0
  112. package/dist/llms/input-password.md +197 -0
  113. package/dist/llms/input-search.md +170 -0
  114. package/dist/llms/input-select.md +278 -0
  115. package/dist/llms/input-text-area.md +271 -0
  116. package/dist/llms/input-text.md +192 -0
  117. package/dist/llms/line-chart.md +369 -0
  118. package/dist/llms/link.md +209 -0
  119. package/dist/llms/loading.md +130 -0
  120. package/dist/llms/meter.md +177 -0
  121. package/dist/llms/metric.md +204 -0
  122. package/dist/llms/number-field.md +122 -0
  123. package/dist/llms/page-content.md +69 -0
  124. package/dist/llms/page-header.md +182 -0
  125. package/dist/llms/pagination.md +133 -0
  126. package/dist/llms/pie-chart.md +307 -0
  127. package/dist/llms/popover.md +252 -0
  128. package/dist/llms/progress-circle.md +126 -0
  129. package/dist/llms/progress.md +111 -0
  130. package/dist/llms/radar-chart.md +316 -0
  131. package/dist/llms/radial-bar-chart.md +319 -0
  132. package/dist/llms/radio.md +255 -0
  133. package/dist/llms/resizable.md +195 -0
  134. package/dist/llms/sankey-chart.md +208 -0
  135. package/dist/llms/scatter-chart.md +239 -0
  136. package/dist/llms/scroll-area.md +183 -0
  137. package/dist/llms/section.md +401 -0
  138. package/dist/llms/select.md +210 -0
  139. package/dist/llms/separator.md +87 -0
  140. package/dist/llms/sheet.md +202 -0
  141. package/dist/llms/sidebar-primary.md +360 -0
  142. package/dist/llms/sidebar-secondary.md +417 -0
  143. package/dist/llms/skeleton.md +81 -0
  144. package/dist/llms/slider.md +97 -0
  145. package/dist/llms/spinner.md +100 -0
  146. package/dist/llms/stack.md +80 -0
  147. package/dist/llms/stepper-item.md +309 -0
  148. package/dist/llms/stepper.md +251 -0
  149. package/dist/llms/switch.md +140 -0
  150. package/dist/llms/table.md +436 -0
  151. package/dist/llms/tabs.md +197 -0
  152. package/dist/llms/tag.md +139 -0
  153. package/dist/llms/timeline.md +361 -0
  154. package/dist/llms/timer.md +259 -0
  155. package/dist/llms/toast.md +241 -0
  156. package/dist/llms/toggle-group.md +121 -0
  157. package/dist/llms/toolbar.md +453 -0
  158. package/dist/llms/tooltip.md +164 -0
  159. package/dist/llms/treemap.md +254 -0
  160. package/dist/llms/trend-indicator.md +132 -0
  161. package/dist/llms/widget-placeholder.md +169 -0
  162. package/dist/llms/wizard.md +412 -0
  163. package/dist/llms.txt +142 -0
  164. package/dist/react.js +502 -497
  165. package/dist/react.js.map +1 -1
  166. package/dist/src/components/ui/area-chart/area-chart.d.ts +9 -4
  167. package/dist/src/components/ui/avatar/avatar.d.ts +1 -1
  168. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +9 -4
  169. package/dist/src/components/ui/category-bar/category-bar.d.ts +10 -4
  170. package/dist/src/components/ui/chart/__stories__/palette-control.d.ts +48 -0
  171. package/dist/src/components/ui/chart/__tests__/chart-palette.test.d.ts +1 -0
  172. package/dist/src/components/ui/chart/chart-palette.d.ts +128 -0
  173. package/dist/src/components/ui/chart/chart.d.ts +66 -15
  174. package/dist/src/components/ui/chart/index.d.ts +4 -2
  175. package/dist/src/components/ui/chart-state/chart-state-illustrations.d.ts +6 -0
  176. package/dist/src/components/ui/chart-state/chart-state.d.ts +13 -2
  177. package/dist/src/components/ui/chart-state/index.d.ts +1 -0
  178. package/dist/src/components/ui/chart-widget/chart-widget.d.ts +64 -0
  179. package/dist/src/components/ui/chart-widget/index.d.ts +1 -0
  180. package/dist/src/components/ui/composed-chart/composed-chart.d.ts +12 -7
  181. package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +10 -5
  182. package/dist/src/components/ui/empty-overlay/empty-overlay.d.ts +1 -1
  183. package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +11 -5
  184. package/dist/src/components/ui/histogram/histogram.d.ts +10 -4
  185. package/dist/src/components/ui/label/index.d.ts +1 -1
  186. package/dist/src/components/ui/label/label.d.ts +1 -5
  187. package/dist/src/components/ui/line-chart/line-chart.d.ts +9 -4
  188. package/dist/src/components/ui/metric/metric.d.ts +13 -14
  189. package/dist/src/components/ui/pie-chart/pie-chart.d.ts +17 -8
  190. package/dist/src/components/ui/radar-chart/radar-chart.d.ts +10 -5
  191. package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +17 -6
  192. package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +10 -5
  193. package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +10 -5
  194. package/dist/src/components/ui/section/index.d.ts +1 -1
  195. package/dist/src/components/ui/section/section.d.ts +75 -6
  196. package/dist/src/components/ui/stepper-item/stepper-item.d.ts +6 -5
  197. package/dist/src/components/ui/tag/tag.d.ts +1 -1
  198. package/dist/src/components/ui/treemap/treemap.d.ts +11 -5
  199. package/dist/src/components/ui/trend-indicator/trend-indicator.d.ts +3 -7
  200. package/dist/src/components/ui/wizard/index.d.ts +1 -0
  201. package/dist/src/components/ui/wizard/wizard.d.ts +6 -0
  202. package/dist/src/hooks/index.d.ts +1 -0
  203. package/dist/src/hooks/use-wizard.d.ts +80 -0
  204. package/dist/src/index.d.ts +2 -3
  205. package/dist/ui-react.css +1 -1
  206. package/package.json +9 -3
  207. package/dist/components/ui/app-shell/app-shell.js +0 -75
  208. package/dist/components/ui/app-shell/app-shell.js.map +0 -1
  209. package/dist/components/ui/auth-layout/auth-layout.js +0 -56
  210. package/dist/components/ui/auth-layout/auth-layout.js.map +0 -1
  211. package/dist/components/ui/collapsible/collapsible.js +0 -22
  212. package/dist/components/ui/collapsible/collapsible.js.map +0 -1
  213. package/dist/src/components/ui/app-shell/app-shell.d.ts +0 -8
  214. package/dist/src/components/ui/app-shell/index.d.ts +0 -1
  215. package/dist/src/components/ui/auth-layout/auth-layout.d.ts +0 -6
  216. package/dist/src/components/ui/auth-layout/index.d.ts +0 -1
  217. package/dist/src/components/ui/collapsible/collapsible.d.ts +0 -5
  218. package/dist/src/components/ui/collapsible/index.d.ts +0 -1
  219. package/dist/src/components/ui/label/label.docs.d.ts +0 -10
@@ -0,0 +1,293 @@
1
+ # CardSection
2
+
3
+ > A band of content stacked inside a `Card`'s body, below `CardHeader`. Six variants pick the body shape — an arbitrary slot, a wrapping tag row, a title/description list, a flush table with row actions, or a nested `Card` on the primary or secondary surface. An optional 14px mini-header (distinct from `CardHeader`) carries a title, inline extras, and end-aligned actions; an optional bottom divider separates one section from the next.
4
+
5
+ **Status:** ready · **Category:** layout · **Since:** v2.1.0
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { CardSection } from '@acronis-platform/ui-react'
11
+ ```
12
+
13
+ ## Quick example
14
+
15
+ ```tsx
16
+ <Card>
17
+ <CardHeader title="Workload" />
18
+ <CardContent className="p-0 pb-4">
19
+ <CardSection
20
+ variant="list"
21
+ hasHeader
22
+ title="Network details"
23
+ hasBottomBorder
24
+ contentList={rows}
25
+ />
26
+ <CardSection variant="tag" hasHeader title="Labels" contentTag={tags} />
27
+ </CardContent>
28
+ </Card>
29
+
30
+ // Nested card on the secondary surface.
31
+ <CardSection variant="card-secondary" hasHeader title="Retention">
32
+ <CardHeader title="Policy" />
33
+ <CardContent>Keep daily backups for 30 days.</CardContent>
34
+ </CardSection>
35
+ ```
36
+
37
+ A band of content stacked inside a `Card`'s body, below `CardHeader`. Where
38
+ `Card` owns the surface and the card-level header/footer, `CardSection` divides
39
+ the body into labelled bands — a tag row here, a key-value list there, a flush
40
+ table below — each with an optional 14px mini-header and an optional divider.
41
+
42
+ ## When to use
43
+
44
+ - A card body that holds **several distinct groupings** that each deserve their
45
+ own small label (e.g. "Network details", "Labels", "Subnets").
46
+ - A card that needs a **table running edge-to-edge** inside it — the
47
+ `table-actions` variant drops the horizontal inset for exactly this.
48
+ - A card that **nests another card**, on either the primary or the secondary
49
+ surface (`card-primary` / `card-secondary`).
50
+
51
+ ## When not to use
52
+
53
+ - A card with a single, undifferentiated body. Put the content straight in
54
+ `CardContent` — a lone section adds a wrapper and no meaning.
55
+ - As a page-level section. This is card chrome; use `PageContent` / `Section`
56
+ for page structure.
57
+ - As a standalone surface. `CardSection` paints no background of its own and
58
+ relies on the enclosing card's surface and inset rhythm.
59
+
60
+ ## Parts
61
+
62
+ | Part | Element | Notes |
63
+ | --------------- | ------- | ------------------------------------------------------------------------------------- |
64
+ | `root` | `div` | Flex column, 12px gap. Inset (`px-4 pt-4`) for every variant except `table-actions`. |
65
+ | `header` | `div` | Optional, shown by `hasHeader`. Re-applies the inset under `table-actions`. |
66
+ | `title` | `p` | 14px medium, truncating. Required whenever `hasHeader` is set. |
67
+ | `extras` | slot | Inline after the title. |
68
+ | `actions` | slot | End of the header row. |
69
+ | `content` | `div` | Body of `variant="slot"` — arbitrary passthrough. |
70
+ | `content-tag` | `div` | Body of `variant="tag"` — wrapping tag row; no built-in default. |
71
+ | `content-list` | `div` | Body of `variant="list"` — title/description rows; no built-in default. |
72
+ | `content-table` | `div` | Body of `variant="table-actions"` — flush table with row actions. |
73
+ | `nested-card` | `div` | Body of `card-primary` / `card-secondary` — a nested `Card` composed from `children`. |
74
+
75
+ ## Examples
76
+
77
+ Stacked sections in one card body — every section but the last draws a divider:
78
+
79
+ ```tsx
80
+ <Card>
81
+ <CardHeader title="Workload" />
82
+ <CardContent className="p-0 pb-4">
83
+ <CardSection
84
+ variant="list"
85
+ hasHeader
86
+ title="Network details"
87
+ hasBottomBorder
88
+ contentList={rows}
89
+ />
90
+ <CardSection variant="tag" hasHeader title="Labels" contentTag={tags} />
91
+ </CardContent>
92
+ </Card>
93
+ ```
94
+
95
+ A flush table with header actions:
96
+
97
+ ```tsx
98
+ <CardSection
99
+ variant="table-actions"
100
+ hasHeader
101
+ title="Subnets"
102
+ actions={
103
+ <ButtonIcon variant="ghost" aria-label="More">
104
+ <EllipsisIcon size={16} />
105
+ </ButtonIcon>
106
+ }
107
+ contentTable={<SubnetsTable />}
108
+ />
109
+ ```
110
+
111
+ A nested card on the secondary surface — compose the nested card from `Card`'s
112
+ own parts:
113
+
114
+ ```tsx
115
+ <CardSection variant="card-secondary" hasHeader title="Retention">
116
+ <CardHeader title="Policy" />
117
+ <CardContent>Keep daily backups for 30 days.</CardContent>
118
+ </CardSection>
119
+ ```
120
+
121
+ ## Notes
122
+
123
+ - **`hasHeader` requires `title`.** The two props are a discriminated union in
124
+ React, so turning the header on without a title (or passing a title with no
125
+ header) fails to compile rather than rendering a blank row.
126
+ - **`card-primary` vs. `card-secondary`** differ in exactly one thing: the
127
+ nested card's surface token. Pick by how much the nested card should recede
128
+ from the parent surface.
129
+ - **The `list` variant has no default rows.** Figma's `ListItem` fallback
130
+ references `--ui-card-body-section-item-*` variables that do not exist in
131
+ `@acronis-platform/design-tokens`; rather than hardcode those values, the
132
+ variant ships empty and the consumer supplies `contentList`. Once the design
133
+ team lands that token tier, a default row rendering can follow.
134
+ - **The default tag row is example content.** Replace it with real, localized
135
+ tags via `contentTag` before shipping.
136
+
137
+ ## Props
138
+
139
+ | Prop | Type | Default | Required | Description |
140
+ |------|------|---------|----------|-------------|
141
+ | `variant` | `'slot' | 'tag' | 'list' | 'table-actions' | 'card-primary' | 'card-secondary'` | `slot` | no | Which body shape the section renders. `slot` takes arbitrary content; `tag` a wrapping row of tags; `list` title/description key-value rows; `table-actions` a table with row actions, rendered flush so its rows run edge-to-edge; `card-primary` / `card-secondary` a nested `Card` on the primary or secondary surface. Maps to Figma's `Slot` / `Tag` / `List` / `Table + Actions` / `Card (primary)` / `Card (secondary)`. |
142
+ | `hasBottomBorder` | `boolean` | `false` | no | Adds a bottom divider plus the matching bottom padding, separating this section from the next one stacked below it in the same card body. |
143
+ | `hasHeader` | `boolean` | `false` | no | Shows the section's own mini-header row (14px medium title), distinct from the card-level `CardHeader`. Requires `title`. |
144
+ | `title` | `string` | `undefined` | no | The section header's title. Required whenever `hasHeader` is set, and rejected when it is not — the title has nowhere to render without the header row. |
145
+ | `extras` | `ReactNode` | `undefined` | no | Content rendered inline next to the title in the header row. |
146
+ | `actions` | `ReactNode` | `undefined` | no | Actions rendered at the end of the header row (e.g. a menu button). |
147
+ | `content` | `ReactNode` | `undefined` | no | Body of the `slot` variant — arbitrary passthrough content. |
148
+ | `contentTag` | `ReactNode` | `undefined` | no | Body of the `tag` variant. Has no built-in default: like `contentList`, the consumer supplies the tags. |
149
+ | `contentList` | `ReactNode` | `undefined` | no | Body of the `list` variant — title/description key-value rows. Has no built-in default: the `ListItem` tokens the design references (`--ui-card-body-section-item-*`) do not exist in tokens-pd yet. |
150
+ | `contentTable` | `ReactNode` | `undefined` | no | Body of the `table-actions` variant. |
151
+ | `render` | `RenderProp` | `undefined` | no | Base UI composition prop — replaces the rendered element with another component (e.g. a `<section>`) while merging props and classes. React-only; other frameworks use their own polymorphism. |
152
+
153
+ ## Content slots
154
+
155
+ | Slot | Description |
156
+ |------|-------------|
157
+ | `default` | For `card-primary` / `card-secondary`, the nested card's parts (`CardHeader`, `CardContent`, …). For every other variant, extra content appended after the variant body. |
158
+
159
+ ## Behavior
160
+
161
+ ### Rendering the body
162
+
163
+ **Given** a `CardSection` with no `variant`
164
+ **When** it renders
165
+ **Then** it uses the `slot` variant and renders `content` as-is, with no
166
+ built-in layout.
167
+
168
+ **Given** `variant="tag"` and no `contentTag`
169
+ **When** it renders
170
+ **Then** the body is empty — this variant has no built-in fallback.
171
+
172
+ **Given** `variant="tag"` and a `contentTag` slot
173
+ **When** it renders
174
+ **Then** the supplied tags are shown, wrapping onto further lines when the
175
+ section is too narrow.
176
+
177
+ **Given** `variant="list"` and a `contentList` slot
178
+ **When** it renders
179
+ **Then** the rows are stacked in a column. With no `contentList` the body is
180
+ empty — this variant has no built-in fallback.
181
+
182
+ **Given** `variant="table-actions"`
183
+ **When** it renders
184
+ **Then** the root drops its horizontal inset so the table rows run edge-to-edge
185
+ inside the card, and the header row (if shown) re-applies the inset so the title
186
+ stays aligned with the table's first cell.
187
+
188
+ **Given** `variant="card-primary"` or `variant="card-secondary"`
189
+ **When** it renders
190
+ **Then** `children` are composed into a nested `Card` filling the section width.
191
+ The two variants are identical apart from the nested card's surface token —
192
+ primary uses the card surface, secondary the secondary surface.
193
+
194
+ ### The header
195
+
196
+ **Given** `hasHeader` is not set
197
+ **When** it renders
198
+ **Then** no header row exists and the body is the section's only child.
199
+
200
+ **Given** `hasHeader` is set
201
+ **When** it renders
202
+ **Then** a single row shows the title (truncating with an ellipsis when it
203
+ overflows), `extras` inline after it, and `actions` pushed to the end.
204
+
205
+ **Given** `hasHeader` is set
206
+ **When** the consumer omits `title`
207
+ **Then** this is a **compile-time error** in the React adapter — the two props
208
+ form a discriminated union, because the header row always renders a title.
209
+ Passing `title` without `hasHeader` is likewise rejected.
210
+
211
+ ### Stacking sections
212
+
213
+ **Given** several sections stacked in one card body
214
+ **When** every section except the last sets `hasBottomBorder`
215
+ **Then** each is separated by a divider with matching bottom padding, and the
216
+ last one closes flush against the card's own edge.
217
+
218
+ **Given** a section with `hasBottomBorder` unset
219
+ **When** it renders
220
+ **Then** no border is painted and no bottom padding is reserved.
221
+
222
+ ### Composition
223
+
224
+ **Given** a `render` prop
225
+ **When** it renders
226
+ **Then** the root element is replaced by the supplied element/component, with
227
+ props and classes merged (Base UI composition) — e.g. to render the section as
228
+ a semantic `<section>`.
229
+
230
+ ## Accessibility
231
+
232
+ ## Roles and semantics
233
+
234
+ - The root is a plain `<div>` with no implicit role — the section is a visual
235
+ grouping inside a card, not a landmark. Nothing is announced for the wrapper
236
+ itself.
237
+ - To expose the grouping to assistive technology, render it as a real region:
238
+
239
+ ```tsx
240
+ <CardSection render={<section aria-label="Network details" />} … />
241
+ ```
242
+
243
+ Prefer this only when the grouping is genuinely navigable content; a decorative
244
+ band of key-value rows does not need a landmark, and over-using regions makes
245
+ the landmark list noisy.
246
+
247
+ - The header title is a `<p>`, not a heading. A section inside a card sits below
248
+ the card's own title in the document outline, and guessing at a heading level
249
+ (`h3`? `h4`?) would produce a broken hierarchy in most compositions. When the
250
+ section really is a document section, pair `render` with your own heading:
251
+
252
+ ```tsx
253
+ <CardSection render={<section aria-labelledby="net-heading" />} … />
254
+ ```
255
+
256
+ - The `card-primary` / `card-secondary` variants nest a full `Card`. Its parts
257
+ carry their own semantics; see the `Card` spec.
258
+
259
+ ## Keyboard
260
+
261
+ - The section itself is not focusable and has no keyboard behavior.
262
+ - Focusable content is whatever the consumer places in `extras`, `actions`, or
263
+ the body slots. Those follow DOM order: title/extras first, then actions, then
264
+ the body. Nothing is trapped or re-ordered.
265
+
266
+ ## Screen reader
267
+
268
+ - The `title` is read as ordinary text when the user reaches it. Because it may
269
+ be visually truncated, keep it short enough to be meaningful — truncation is
270
+ visual only, the full string stays in the accessible name/text.
271
+ - Icon-only controls placed in `actions` must supply their own accessible name
272
+ (`aria-label` on the button); the section adds none.
273
+ - `variant="tag"` has no built-in default content — the consumer always
274
+ supplies real, localized tags via `contentTag`.
275
+
276
+ ## Contrast
277
+
278
+ - The title uses `--ui-text-on-surface-primary` against the enclosing card
279
+ surface, which meets WCAG AA in every shipped brand and in both light and dark
280
+ themes.
281
+ - The `hasBottomBorder` divider uses `--ui-border-on-surface-divider`. It is a
282
+ decorative separator, not a meaningful boundary, so it is exempt from the 3:1
283
+ non-text contrast requirement — the grouping is also conveyed by the header
284
+ and spacing.
285
+
286
+ ## Localization
287
+
288
+ - Every string the component can render on its own — the `title` and the default
289
+ tag labels — is a prop, or a prop's default. The component ships no inlined
290
+ literals.
291
+ - Layout uses logical spacing only, so the section mirrors correctly under
292
+ `dir="rtl"`: the title/extras group starts at the inline start and `actions`
293
+ sit at the inline end.