@robr0/design-system 0.1.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 (223) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -0
  3. package/charts.d.ts +14 -0
  4. package/charts.js +20 -0
  5. package/components/Accordion/Accordion.css +119 -0
  6. package/components/Accordion/Accordion.d.ts +24 -0
  7. package/components/Accordion/Accordion.js +76 -0
  8. package/components/Alert/Alert.css +252 -0
  9. package/components/Alert/Alert.d.ts +24 -0
  10. package/components/Alert/Alert.js +53 -0
  11. package/components/AlertDialog/AlertDialog.css +131 -0
  12. package/components/AlertDialog/AlertDialog.d.ts +29 -0
  13. package/components/AlertDialog/AlertDialog.js +143 -0
  14. package/components/AppLayout/AppLayout.css +52 -0
  15. package/components/AppLayout/AppLayout.d.ts +27 -0
  16. package/components/AppLayout/AppLayout.js +45 -0
  17. package/components/AppSidebar/AppSidebar.css +434 -0
  18. package/components/AppSidebar/AppSidebar.d.ts +67 -0
  19. package/components/AppSidebar/AppSidebar.js +272 -0
  20. package/components/Avatar/Avatar.css +133 -0
  21. package/components/Avatar/Avatar.d.ts +20 -0
  22. package/components/Avatar/Avatar.js +56 -0
  23. package/components/Avatar/demoAvatars.d.ts +14 -0
  24. package/components/Avatar/demoAvatars.js +16 -0
  25. package/components/Badge/Badge.css +68 -0
  26. package/components/Badge/Badge.d.ts +13 -0
  27. package/components/Badge/Badge.js +15 -0
  28. package/components/Breadcrumb/Breadcrumb.css +92 -0
  29. package/components/Breadcrumb/Breadcrumb.d.ts +19 -0
  30. package/components/Breadcrumb/Breadcrumb.js +39 -0
  31. package/components/Button/Button.css +381 -0
  32. package/components/Button/Button.d.ts +39 -0
  33. package/components/Button/Button.js +71 -0
  34. package/components/ButtonGroup/ButtonGroup.css +39 -0
  35. package/components/ButtonGroup/ButtonGroup.d.ts +13 -0
  36. package/components/ButtonGroup/ButtonGroup.js +37 -0
  37. package/components/Card/Card.css +169 -0
  38. package/components/Card/Card.d.ts +30 -0
  39. package/components/Card/Card.js +90 -0
  40. package/components/Carousel/Carousel.css +112 -0
  41. package/components/Carousel/Carousel.d.ts +25 -0
  42. package/components/Carousel/Carousel.js +126 -0
  43. package/components/Chart/AreaChart.d.ts +36 -0
  44. package/components/Chart/AreaChart.js +99 -0
  45. package/components/Chart/BarChart.d.ts +34 -0
  46. package/components/Chart/BarChart.js +107 -0
  47. package/components/Chart/Chart.css +176 -0
  48. package/components/Chart/LineChart.d.ts +34 -0
  49. package/components/Chart/LineChart.js +90 -0
  50. package/components/Chart/PieChart.d.ts +34 -0
  51. package/components/Chart/PieChart.js +106 -0
  52. package/components/Chart/RadarChart.d.ts +34 -0
  53. package/components/Chart/RadarChart.js +91 -0
  54. package/components/Chart/RadialChart.d.ts +37 -0
  55. package/components/Chart/RadialChart.js +119 -0
  56. package/components/Chart/ScatterChart.d.ts +36 -0
  57. package/components/Chart/ScatterChart.js +109 -0
  58. package/components/Chart/StackedBarChart.d.ts +34 -0
  59. package/components/Chart/StackedBarChart.js +111 -0
  60. package/components/Chart/Treemap.d.ts +33 -0
  61. package/components/Chart/Treemap.js +109 -0
  62. package/components/Checkbox/Checkbox.css +164 -0
  63. package/components/Checkbox/Checkbox.d.ts +45 -0
  64. package/components/Checkbox/Checkbox.js +125 -0
  65. package/components/Chip/Chip.css +195 -0
  66. package/components/Chip/Chip.d.ts +27 -0
  67. package/components/Chip/Chip.js +80 -0
  68. package/components/CircularButton/CircularButton.css +206 -0
  69. package/components/CircularButton/CircularButton.d.ts +30 -0
  70. package/components/CircularButton/CircularButton.js +54 -0
  71. package/components/CodeBlock/CodeBlock.css +180 -0
  72. package/components/CodeBlock/CodeBlock.d.ts +23 -0
  73. package/components/CodeBlock/CodeBlock.js +85 -0
  74. package/components/ColourSwatch/ColourSwatch.css +88 -0
  75. package/components/ColourSwatch/ColourSwatch.d.ts +34 -0
  76. package/components/ColourSwatch/ColourSwatch.js +42 -0
  77. package/components/Combobox/Combobox.css +411 -0
  78. package/components/Combobox/Combobox.d.ts +73 -0
  79. package/components/Combobox/Combobox.js +312 -0
  80. package/components/CommandPalette/CommandPalette.css +310 -0
  81. package/components/CommandPalette/CommandPalette.d.ts +60 -0
  82. package/components/CommandPalette/CommandPalette.js +263 -0
  83. package/components/ContactCard/ContactCard.css +123 -0
  84. package/components/ContactCard/ContactCard.d.ts +23 -0
  85. package/components/ContactCard/ContactCard.js +78 -0
  86. package/components/ContributionGraph/ContributionGraph.css +142 -0
  87. package/components/ContributionGraph/ContributionGraph.d.ts +26 -0
  88. package/components/ContributionGraph/ContributionGraph.js +125 -0
  89. package/components/DateInput/DateInput.css +163 -0
  90. package/components/DateInput/DateInput.d.ts +43 -0
  91. package/components/DateInput/DateInput.js +69 -0
  92. package/components/DatePicker/DatePicker.css +198 -0
  93. package/components/DatePicker/DatePicker.d.ts +22 -0
  94. package/components/DatePicker/DatePicker.js +170 -0
  95. package/components/Dialog/Dialog.css +176 -0
  96. package/components/Dialog/Dialog.d.ts +28 -0
  97. package/components/Dialog/Dialog.js +132 -0
  98. package/components/Divider/Divider.css +100 -0
  99. package/components/Divider/Divider.d.ts +18 -0
  100. package/components/Divider/Divider.js +31 -0
  101. package/components/Drawer/Drawer.css +262 -0
  102. package/components/Drawer/Drawer.d.ts +30 -0
  103. package/components/Drawer/Drawer.js +134 -0
  104. package/components/Dropdown/Dropdown.css +300 -0
  105. package/components/Dropdown/Dropdown.d.ts +48 -0
  106. package/components/Dropdown/Dropdown.js +196 -0
  107. package/components/DropdownMenu/DropdownMenu.css +303 -0
  108. package/components/DropdownMenu/DropdownMenu.d.ts +42 -0
  109. package/components/DropdownMenu/DropdownMenu.js +322 -0
  110. package/components/EmptyState/EmptyState.css +115 -0
  111. package/components/EmptyState/EmptyState.d.ts +27 -0
  112. package/components/EmptyState/EmptyState.js +32 -0
  113. package/components/EntityCard/EntityCard.css +69 -0
  114. package/components/EntityCard/EntityCard.d.ts +18 -0
  115. package/components/EntityCard/EntityCard.js +26 -0
  116. package/components/Figure/Figure.css +61 -0
  117. package/components/Figure/Figure.d.ts +17 -0
  118. package/components/Figure/Figure.js +35 -0
  119. package/components/FileInput/FileInput.css +308 -0
  120. package/components/FileInput/FileInput.d.ts +54 -0
  121. package/components/FileInput/FileInput.js +177 -0
  122. package/components/Input/Input.css +193 -0
  123. package/components/Input/Input.d.ts +40 -0
  124. package/components/Input/Input.js +71 -0
  125. package/components/Instructions/Instructions.css +216 -0
  126. package/components/Instructions/Instructions.d.ts +28 -0
  127. package/components/Instructions/Instructions.js +32 -0
  128. package/components/LinkList/LinkList.css +71 -0
  129. package/components/LinkList/LinkList.d.ts +20 -0
  130. package/components/LinkList/LinkList.js +41 -0
  131. package/components/MotionSwatch/MotionSwatch.css +176 -0
  132. package/components/MotionSwatch/MotionSwatch.d.ts +25 -0
  133. package/components/MotionSwatch/MotionSwatch.js +74 -0
  134. package/components/Nav/Nav.css +51 -0
  135. package/components/Nav/Nav.d.ts +19 -0
  136. package/components/Nav/Nav.js +26 -0
  137. package/components/Pagination/Pagination.css +126 -0
  138. package/components/Pagination/Pagination.d.ts +22 -0
  139. package/components/Pagination/Pagination.js +83 -0
  140. package/components/Popover/Popover.css +99 -0
  141. package/components/Popover/Popover.d.ts +28 -0
  142. package/components/Popover/Popover.js +102 -0
  143. package/components/ProgressBar/ProgressBar.css +60 -0
  144. package/components/ProgressBar/ProgressBar.d.ts +16 -0
  145. package/components/ProgressBar/ProgressBar.js +27 -0
  146. package/components/Quote/Quote.css +79 -0
  147. package/components/Quote/Quote.d.ts +18 -0
  148. package/components/Quote/Quote.js +26 -0
  149. package/components/RadioButton/RadioButton.css +132 -0
  150. package/components/RadioButton/RadioButton.d.ts +43 -0
  151. package/components/RadioButton/RadioButton.js +77 -0
  152. package/components/SectionTitle/SectionTitle.css +37 -0
  153. package/components/SectionTitle/SectionTitle.d.ts +10 -0
  154. package/components/SectionTitle/SectionTitle.js +17 -0
  155. package/components/SegmentedControl/SegmentedControl.css +129 -0
  156. package/components/SegmentedControl/SegmentedControl.d.ts +33 -0
  157. package/components/SegmentedControl/SegmentedControl.js +91 -0
  158. package/components/SelectionCard/SelectionCard.css +251 -0
  159. package/components/SelectionCard/SelectionCard.d.ts +26 -0
  160. package/components/SelectionCard/SelectionCard.js +85 -0
  161. package/components/Skeleton/Skeleton.css +79 -0
  162. package/components/Skeleton/Skeleton.d.ts +16 -0
  163. package/components/Skeleton/Skeleton.js +30 -0
  164. package/components/Slider/Slider.css +86 -0
  165. package/components/Slider/Slider.d.ts +25 -0
  166. package/components/Slider/Slider.js +46 -0
  167. package/components/SpacingSwatch/SpacingSwatch.css +108 -0
  168. package/components/SpacingSwatch/SpacingSwatch.d.ts +20 -0
  169. package/components/SpacingSwatch/SpacingSwatch.js +50 -0
  170. package/components/Spinner/Spinner.css +73 -0
  171. package/components/Spinner/Spinner.d.ts +14 -0
  172. package/components/Spinner/Spinner.js +42 -0
  173. package/components/Stat/Stat.css +78 -0
  174. package/components/Stat/Stat.d.ts +19 -0
  175. package/components/Stat/Stat.js +30 -0
  176. package/components/Table/Table.css +186 -0
  177. package/components/Table/Table.d.ts +45 -0
  178. package/components/Table/Table.js +65 -0
  179. package/components/Tabs/Tabs.css +140 -0
  180. package/components/Tabs/Tabs.d.ts +28 -0
  181. package/components/Tabs/Tabs.js +77 -0
  182. package/components/Textarea/Textarea.css +152 -0
  183. package/components/Textarea/Textarea.d.ts +40 -0
  184. package/components/Textarea/Textarea.js +74 -0
  185. package/components/Timeline/Timeline.css +339 -0
  186. package/components/Timeline/Timeline.d.ts +63 -0
  187. package/components/Timeline/Timeline.js +69 -0
  188. package/components/Toast/Toast.css +342 -0
  189. package/components/Toast/Toast.d.ts +63 -0
  190. package/components/Toast/Toast.js +213 -0
  191. package/components/ToggleGroup/ToggleGroup.css +84 -0
  192. package/components/ToggleGroup/ToggleGroup.d.ts +30 -0
  193. package/components/ToggleGroup/ToggleGroup.js +53 -0
  194. package/components/ToggleSwitch/ToggleSwitch.css +139 -0
  195. package/components/ToggleSwitch/ToggleSwitch.d.ts +23 -0
  196. package/components/ToggleSwitch/ToggleSwitch.js +50 -0
  197. package/components/Tooltip/Tooltip.css +122 -0
  198. package/components/Tooltip/Tooltip.d.ts +21 -0
  199. package/components/Tooltip/Tooltip.js +63 -0
  200. package/components/TypographySwatch/TypographySwatch.css +81 -0
  201. package/components/TypographySwatch/TypographySwatch.d.ts +24 -0
  202. package/components/TypographySwatch/TypographySwatch.js +40 -0
  203. package/components/registry.d.ts +20 -0
  204. package/components/registry.js +7 -0
  205. package/components/registry.json +67 -0
  206. package/components/registry.json.d.ts +70 -0
  207. package/components/registry.json.js +8 -0
  208. package/fonts/MaterialSymbolsRounded-VariableFont_FILL,GRAD,opsz,wght.woff2 +0 -0
  209. package/fonts/material-symbols.css +94 -0
  210. package/index.d.ts +62 -0
  211. package/index.js +123 -0
  212. package/package.json +63 -0
  213. package/tokens/registry.d.ts +22 -0
  214. package/tokens/registry.js +14 -0
  215. package/tokens/registry.json +203 -0
  216. package/tokens/registry.json.d.ts +206 -0
  217. package/tokens/registry.json.js +8 -0
  218. package/tokens/tokens-dark.css +119 -0
  219. package/tokens/tokens-light.css +159 -0
  220. package/tokens/tokens-motion.css +68 -0
  221. package/tokens/tokens-primitives.css +176 -0
  222. package/tokens/tokens-typography.css +116 -0
  223. package/tokens/tokens.css +11 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rob Ritacca
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # robr0 — Portfolio + Design System
2
+
3
+ [![CI](https://github.com/robritacca-dotcom/design-system/actions/workflows/ci.yml/badge.svg)](https://github.com/robritacca-dotcom/design-system/actions/workflows/ci.yml)
4
+
5
+ A personal portfolio site built on a custom React design system I designed and engineered from scratch. The DS isn't a side project — it's the backbone every portfolio page is built on, ensuring the work is presented consistently and with the same craft standards I apply professionally.
6
+
7
+ **[→ Live site](https://robertritacca.com/)** · **[→ Storybook](https://design-system-iota-one.vercel.app/?path=/docs/robr0-ds--docs)**
8
+
9
+ The **live site** is the portfolio built on the design system. **Storybook** is the interactive component explorer for the design system itself — two separate parts of this repo.
10
+
11
+ ---
12
+
13
+ ## Two things, one repo
14
+
15
+ | Part | Description |
16
+ |---|---|
17
+ | **Portfolio website** (`/website`) | Next.js app with case studies, work history, writing, and about pages — all built exclusively with the design system components below. **[Live site →](https://robertritacca.com/)** |
18
+ | **Design system** (`/src`) | <!-- component-count -->56<!-- /component-count --> React components, a three-tier token architecture, dark mode, and a full documentation site. Built to production standards. **[Storybook →](https://design-system-iota-one.vercel.app/?path=/docs/robr0-ds--docs)** |
19
+
20
+ ---
21
+
22
+ ## Design system
23
+
24
+ ### Components
25
+
26
+ <!-- component-list:start -->
27
+ Accordion · Alert · Alert dialog · App layout · App sidebar · Avatar · Badge · Breadcrumb · Button · Button group · Card · Carousel · Chart · Checkbox · Chip · Circular button · Code block · Combobox · Command palette · Contact card · Contribution graph · Date input · Date picker · Dialog · Divider · Drawer · Dropdown · Dropdown menu · Empty state · Entity card · Figure · File input · Input · Instructions · Link list · Nav · Pagination · Popover · Progress bar · Quote · Radio button · Section title · Segmented control · Selection card · Skeleton · Slider · Spinner · Stat · Table · Tabs · Textarea · Timeline · Toast · Toggle group · Toggle switch · Tooltip
28
+ <!-- component-list:end -->
29
+
30
+ ### Using the package
31
+
32
+ The design system is published as [`@robr0/design-system`](https://www.npmjs.com/package/@robr0/design-system) (React 19+ is a peer dependency):
33
+
34
+ ```bash
35
+ npm install @robr0/design-system
36
+ ```
37
+
38
+ Import the token stylesheet once (it carries the primitives, semantic tokens, and both themes), then use components:
39
+
40
+ ```tsx
41
+ import '@robr0/design-system/tokens/tokens.css';
42
+ import { Button, Card, Badge } from '@robr0/design-system';
43
+ ```
44
+
45
+ Deep imports work too (`@robr0/design-system/components/Button/Button`). Chart components live behind a separate entry so the optional `recharts` peer dependency is only needed if you use them:
46
+
47
+ ```tsx
48
+ import { BarChart, LineChart } from '@robr0/design-system/charts';
49
+ ```
50
+
51
+ **Theming and customization** happen through CSS variables — no configuration API:
52
+
53
+ - **Dark mode**: set `data-theme="dark"` on the root element (light is the default).
54
+ - **Font**: the whole type scale chains to one token. Load any font you like and override it:
55
+ ```css
56
+ :root { --font-family-primary: 'Inter', sans-serif; }
57
+ ```
58
+ - **Colors, radius, spacing**: every semantic token chains to a primitive, so overriding a primitive re-themes everything built on it:
59
+ ```css
60
+ :root {
61
+ --primitive-teal-07: #7C3AED; /* your brand color becomes the action color */
62
+ --primitive-radius-full: 12px; /* pill buttons become rounded rectangles */
63
+ }
64
+ ```
65
+
66
+ Icons use a bundled Material Symbols Rounded variable font (woff2) — no extra setup. Nunito Sans, the system's default typeface, is intentionally *not* bundled: load it yourself (e.g. Google Fonts or `next/font`) or override `--font-family-primary`.
67
+
68
+ ### Token architecture
69
+
70
+ Tokens flow in one direction — primitives are never referenced directly in components:
71
+
72
+ ```
73
+ tokens-primitives.css --primitive-teal-07: #118AB2
74
+
75
+ tokens-light/dark.css --color-action-primary-bg: var(--primitive-teal-07)
76
+
77
+ Component CSS background-color: var(--color-action-primary-bg)
78
+ ```
79
+
80
+ Dark mode is driven by `data-theme="dark"` on the root element — no `prefers-color-scheme` queries in components.
81
+
82
+ ### Design principles
83
+
84
+ - **Single typeface**: Nunito Sans (weight 300 for display, 600 for headings, 400/500 for body)
85
+ - **White-floor UI**: depth comes from a container color ramp, not box shadows
86
+ - **Teal is the action color**: primary buttons and focus rings only — never decorative
87
+ - **Five status variants**: info, positive, warning, error, neutral — shared tokens across Badge, Alert, Toast, ProgressBar
88
+ - **Material Symbols Rounded** for all icons
89
+
90
+ Full spec in [`design.md`](design.md).
91
+
92
+ ---
93
+
94
+ ## Tech
95
+
96
+ - **React 19 + TypeScript** — component library
97
+ - **Vite 7** — dev server and library build
98
+ - **Next.js 16** — portfolio site and DS documentation
99
+ - **Storybook 10** — component explorer
100
+ - **Vitest + Playwright** — every Storybook story runs as a render test in headless Chromium
101
+ - **CSS custom properties** — all theming via semantic tokens, no CSS-in-JS
102
+
103
+ ---
104
+
105
+ ## Quality & CI
106
+
107
+ Every push and pull request runs a GitHub Actions pipeline ([`ci.yml`](.github/workflows/ci.yml)) with four jobs: **lint + library build**, **story tests** (every Storybook story rendered in headless Chromium via Vitest), **Storybook build**, and **website build**. The same checklist runs locally with one command:
108
+
109
+ ```bash
110
+ npm run verify # lint + library build + story tests + Storybook build + website build
111
+ ```
112
+
113
+ CI also guards against documentation drift: generated surfaces (this README's component count and list, the website's skills pages, the published CLAUDE.md/design.md blueprints) are rebuilt from their source registries on every build, and CI fails if the committed copies are stale. The numbers on the site are never hand-written.
114
+
115
+ ---
116
+
117
+ ## Running locally
118
+
119
+ ```bash
120
+ # Storybook (the library's dev sandbox)
121
+ npm run storybook # http://localhost:6006
122
+
123
+ # Portfolio + documentation website
124
+ cd website
125
+ npm install
126
+ npm run dev # http://localhost:3000
127
+ ```
package/charts.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * GENERATED FILE — do not edit.
3
+ * Built from src/components/registry.json by scripts/generate-library-barrel.mjs
4
+ * (validate-registry chain). The recharts-backed components; requires the optional recharts peer dependency.
5
+ */
6
+ export * from './components/Chart/AreaChart';
7
+ export * from './components/Chart/BarChart';
8
+ export * from './components/Chart/LineChart';
9
+ export * from './components/Chart/PieChart';
10
+ export * from './components/Chart/RadarChart';
11
+ export * from './components/Chart/RadialChart';
12
+ export * from './components/Chart/ScatterChart';
13
+ export * from './components/Chart/StackedBarChart';
14
+ export * from './components/Chart/Treemap';
package/charts.js ADDED
@@ -0,0 +1,20 @@
1
+ import { AreaChart } from "./components/Chart/AreaChart.js";
2
+ import { BarChart } from "./components/Chart/BarChart.js";
3
+ import { LineChart } from "./components/Chart/LineChart.js";
4
+ import { PieChart } from "./components/Chart/PieChart.js";
5
+ import { RadarChart } from "./components/Chart/RadarChart.js";
6
+ import { RadialChart } from "./components/Chart/RadialChart.js";
7
+ import { ScatterChart } from "./components/Chart/ScatterChart.js";
8
+ import { StackedBarChart } from "./components/Chart/StackedBarChart.js";
9
+ import { Treemap } from "./components/Chart/Treemap.js";
10
+ export {
11
+ AreaChart,
12
+ BarChart,
13
+ LineChart,
14
+ PieChart,
15
+ RadarChart,
16
+ RadialChart,
17
+ ScatterChart,
18
+ StackedBarChart,
19
+ Treemap
20
+ };
@@ -0,0 +1,119 @@
1
+ /* ============================================
2
+ ACCORDION COMPONENT
3
+ Collapsible content sections
4
+ ============================================ */
5
+
6
+ .ds-accordion {
7
+ display: flex;
8
+ flex-direction: column;
9
+ width: 100%;
10
+ border: var(--border-xs) solid var(--color-bg-container-border);
11
+ border-radius: var(--radius-sm);
12
+ overflow: hidden;
13
+ }
14
+
15
+ /* ============================================
16
+ ITEM
17
+ ============================================ */
18
+
19
+ .ds-accordion__item {
20
+ border-bottom: var(--border-xs) solid var(--color-bg-container-border);
21
+ }
22
+
23
+ .ds-accordion__item:last-child {
24
+ border-bottom: none;
25
+ }
26
+
27
+ /* ============================================
28
+ TRIGGER
29
+ ============================================ */
30
+
31
+ .ds-accordion__trigger {
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: space-between;
35
+ width: 100%;
36
+ gap: var(--gap-sm);
37
+ padding: var(--padding-md) var(--padding-lg);
38
+ background: none;
39
+ border: none;
40
+ cursor: pointer;
41
+ text-align: left;
42
+ transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
43
+ }
44
+
45
+ .ds-accordion__trigger:hover {
46
+ background-color: var(--color-action-passive-bg-hover);
47
+ }
48
+
49
+ .ds-accordion__trigger:focus-visible {
50
+ outline: 2px solid var(--color-action-primary-bg);
51
+ outline-offset: -2px;
52
+ border-radius: var(--radius-sm);
53
+ }
54
+
55
+ /* ============================================
56
+ TITLE
57
+ ============================================ */
58
+
59
+ .ds-accordion__title {
60
+ font-family: var(--font-paragraph-em-family);
61
+ font-size: var(--font-paragraph-em-size);
62
+ font-weight: var(--font-paragraph-em-weight);
63
+ line-height: var(--font-paragraph-em-line-height);
64
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
65
+ color: var(--color-text-primary);
66
+ }
67
+
68
+ /* ============================================
69
+ ICON
70
+ ============================================ */
71
+
72
+ .ds-accordion__icon {
73
+ flex-shrink: 0;
74
+ --icon-size: var(--icon-size-sm);
75
+ color: var(--color-icon-primary);
76
+ transition: transform var(--motion-duration-slow) var(--motion-ease-standard);
77
+ }
78
+
79
+ .ds-accordion__item--open .ds-accordion__icon {
80
+ transform: rotate(180deg);
81
+ }
82
+
83
+ /* ============================================
84
+ PANEL
85
+ ============================================ */
86
+
87
+ .ds-accordion__panel {
88
+ display: grid;
89
+ grid-template-rows: 0fr;
90
+ transition: grid-template-rows var(--motion-duration-slow) var(--motion-ease-standard);
91
+ }
92
+
93
+ .ds-accordion__item--open .ds-accordion__panel {
94
+ grid-template-rows: 1fr;
95
+ }
96
+
97
+ /* ============================================
98
+ CONTENT
99
+ ============================================ */
100
+
101
+ .ds-accordion__content {
102
+ overflow: hidden;
103
+ padding: 0 var(--padding-lg);
104
+ transition: padding var(--motion-duration-slow) var(--motion-ease-standard);
105
+ }
106
+
107
+ .ds-accordion__item--open .ds-accordion__content {
108
+ padding: 0 var(--padding-lg) var(--padding-md);
109
+ }
110
+
111
+ .ds-accordion__content p {
112
+ font-family: var(--font-paragraph-family);
113
+ font-size: var(--font-paragraph-size);
114
+ font-weight: var(--font-paragraph-weight);
115
+ line-height: var(--font-paragraph-line-height);
116
+ letter-spacing: var(--font-paragraph-letter-spacing);
117
+ color: var(--color-text-secondary);
118
+ margin: 0;
119
+ }
@@ -0,0 +1,24 @@
1
+ import { default as React } from 'react';
2
+ export interface AccordionItem {
3
+ /** Unique identifier */
4
+ id: string;
5
+ /** Header text */
6
+ title: string;
7
+ /** Body content */
8
+ content: React.ReactNode;
9
+ }
10
+ export interface AccordionProps {
11
+ /** List of accordion items */
12
+ items: AccordionItem[];
13
+ /** Allow multiple items open at once */
14
+ multiple?: boolean;
15
+ /** IDs of initially expanded items */
16
+ defaultExpanded?: string[];
17
+ /** Additional CSS classes */
18
+ className?: string;
19
+ }
20
+ /**
21
+ * Accordion organises content into collapsible sections.
22
+ * Supports single or multiple open panels.
23
+ */
24
+ export declare const Accordion: ({ items, multiple, defaultExpanded, className, }: AccordionProps) => React.JSX.Element;
@@ -0,0 +1,76 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback } from "react";
3
+ import "./Accordion.css";
4
+ import "../../fonts/material-symbols.css";
5
+ const Accordion = ({
6
+ items,
7
+ multiple = false,
8
+ defaultExpanded = [],
9
+ className = ""
10
+ }) => {
11
+ const [expanded, setExpanded] = useState(new Set(defaultExpanded));
12
+ const baseClass = "ds-accordion";
13
+ const classes = [baseClass, className].filter(Boolean).join(" ");
14
+ const toggle = useCallback(
15
+ (id) => {
16
+ setExpanded((prev) => {
17
+ const next = new Set(prev);
18
+ if (next.has(id)) {
19
+ next.delete(id);
20
+ } else {
21
+ if (!multiple) next.clear();
22
+ next.add(id);
23
+ }
24
+ return next;
25
+ });
26
+ },
27
+ [multiple]
28
+ );
29
+ return /* @__PURE__ */ jsx("div", { className: classes, children: items.map((item) => {
30
+ const isOpen = expanded.has(item.id);
31
+ return /* @__PURE__ */ jsxs(
32
+ "div",
33
+ {
34
+ className: `${baseClass}__item${isOpen ? ` ${baseClass}__item--open` : ""}`,
35
+ children: [
36
+ /* @__PURE__ */ jsxs(
37
+ "button",
38
+ {
39
+ type: "button",
40
+ className: `${baseClass}__trigger`,
41
+ "aria-expanded": isOpen,
42
+ "aria-controls": `${baseClass}-panel-${item.id}`,
43
+ id: `${baseClass}-header-${item.id}`,
44
+ onClick: () => toggle(item.id),
45
+ children: [
46
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__title`, children: item.title }),
47
+ /* @__PURE__ */ jsx(
48
+ "span",
49
+ {
50
+ className: `${baseClass}__icon material-symbols-rounded`,
51
+ "aria-hidden": "true",
52
+ children: "expand_more"
53
+ }
54
+ )
55
+ ]
56
+ }
57
+ ),
58
+ /* @__PURE__ */ jsx(
59
+ "div",
60
+ {
61
+ id: `${baseClass}-panel-${item.id}`,
62
+ role: "region",
63
+ "aria-labelledby": `${baseClass}-header-${item.id}`,
64
+ className: `${baseClass}__panel`,
65
+ children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children: item.content })
66
+ }
67
+ )
68
+ ]
69
+ },
70
+ item.id
71
+ );
72
+ }) });
73
+ };
74
+ export {
75
+ Accordion
76
+ };
@@ -0,0 +1,252 @@
1
+ /* ============================================
2
+ ALERT COMPONENT
3
+ Contextual feedback with status variants
4
+ ============================================ */
5
+
6
+ .ds-alert {
7
+ display: flex;
8
+ align-items: flex-start;
9
+ gap: var(--gap-sm); /* 8px */
10
+ padding: var(--padding-md); /* 16px */
11
+ border: var(--border-xs) solid transparent;
12
+ border-radius: var(--radius-sm); /* 8px */
13
+ width: 100%;
14
+ }
15
+
16
+ /* ============================================
17
+ SIZE — DEFAULT
18
+ ============================================ */
19
+
20
+ .ds-alert--default {
21
+ padding: var(--padding-md); /* 16px */
22
+ }
23
+
24
+ /* ============================================
25
+ SIZE — COMPACT
26
+ ============================================ */
27
+
28
+ .ds-alert--compact {
29
+ padding: var(--padding-xs) var(--padding-sm-md); /* 6px 12px */
30
+ }
31
+
32
+ .ds-alert--compact .ds-alert__icon {
33
+ --icon-size: var(--icon-size-sm);
34
+ }
35
+
36
+ .ds-alert--compact .ds-alert__title {
37
+ font-size: var(--font-paragraph-sm-size);
38
+ line-height: var(--font-paragraph-sm-line-height);
39
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
40
+ }
41
+
42
+ .ds-alert--compact .ds-alert__description {
43
+ font-size: var(--font-paragraph-sm-size);
44
+ line-height: var(--font-paragraph-sm-line-height);
45
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
46
+ }
47
+
48
+ .ds-alert--compact .ds-alert__dismiss {
49
+ width: 20px;
50
+ height: 20px;
51
+ }
52
+
53
+ .ds-alert--compact .ds-alert__dismiss .material-symbols-rounded {
54
+ --icon-size: var(--icon-size-sm);
55
+ }
56
+
57
+ /* ============================================
58
+ ICON
59
+ ============================================ */
60
+
61
+ .ds-alert__icon {
62
+ flex-shrink: 0;
63
+ --icon-size: var(--icon-size-md);
64
+ line-height: 1;
65
+ }
66
+
67
+ /* ============================================
68
+ CONTENT
69
+ ============================================ */
70
+
71
+ .ds-alert__content {
72
+ flex: 1;
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: var(--gap-xxs); /* 2px */
76
+ min-width: 0;
77
+ }
78
+
79
+ .ds-alert__title {
80
+ font-family: var(--font-paragraph-em-family);
81
+ font-size: var(--font-paragraph-em-size);
82
+ font-weight: var(--font-paragraph-em-weight);
83
+ line-height: var(--font-paragraph-em-line-height);
84
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
85
+ margin: 0;
86
+ }
87
+
88
+ .ds-alert__description {
89
+ font-family: var(--font-paragraph-family);
90
+ font-size: var(--font-paragraph-size);
91
+ font-weight: var(--font-paragraph-weight);
92
+ line-height: var(--font-paragraph-line-height);
93
+ letter-spacing: var(--font-paragraph-letter-spacing);
94
+ margin: 0;
95
+ }
96
+
97
+ /* ============================================
98
+ DISMISS BUTTON
99
+ ============================================ */
100
+
101
+ .ds-alert__dismiss {
102
+ flex-shrink: 0;
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: center;
106
+ width: 24px;
107
+ height: 24px;
108
+ padding: 0;
109
+ border: none;
110
+ background: none;
111
+ cursor: pointer;
112
+ border-radius: var(--radius-sm); /* 8px */
113
+ transition: background-color var(--motion-duration-base) var(--motion-ease-standard);
114
+ }
115
+
116
+ .ds-alert__dismiss .material-symbols-rounded {
117
+ --icon-size: var(--icon-size-md);
118
+ }
119
+
120
+ .ds-alert__dismiss:hover {
121
+ background-color: var(--color-action-passive-bg-hover);
122
+ }
123
+
124
+ .ds-alert__dismiss:focus-visible {
125
+ outline: 2px solid var(--color-action-primary-bg);
126
+ outline-offset: 2px;
127
+ }
128
+
129
+ /* ============================================
130
+ VARIANT — INFO
131
+ ============================================ */
132
+
133
+ .ds-alert--info {
134
+ background-color: var(--color-status-info-bg);
135
+ border-color: var(--color-status-info-border);
136
+ }
137
+
138
+ .ds-alert--info .ds-alert__icon {
139
+ color: var(--color-status-info-border);
140
+ }
141
+
142
+ .ds-alert--info .ds-alert__title {
143
+ color: var(--color-status-info-text);
144
+ }
145
+
146
+ .ds-alert--info .ds-alert__description {
147
+ color: var(--color-status-info-text);
148
+ }
149
+
150
+ .ds-alert--info .ds-alert__dismiss {
151
+ color: var(--color-status-info-text);
152
+ }
153
+
154
+ /* ============================================
155
+ VARIANT — POSITIVE
156
+ ============================================ */
157
+
158
+ .ds-alert--positive {
159
+ background-color: var(--color-status-positive-bg);
160
+ border-color: var(--color-status-positive-border);
161
+ }
162
+
163
+ .ds-alert--positive .ds-alert__icon {
164
+ color: var(--color-status-positive-border);
165
+ }
166
+
167
+ .ds-alert--positive .ds-alert__title {
168
+ color: var(--color-status-positive-text);
169
+ }
170
+
171
+ .ds-alert--positive .ds-alert__description {
172
+ color: var(--color-status-positive-text);
173
+ }
174
+
175
+ .ds-alert--positive .ds-alert__dismiss {
176
+ color: var(--color-status-positive-text);
177
+ }
178
+
179
+ /* ============================================
180
+ VARIANT — WARNING
181
+ ============================================ */
182
+
183
+ .ds-alert--warning {
184
+ background-color: var(--color-status-warning-bg);
185
+ border-color: var(--color-status-warning-border);
186
+ }
187
+
188
+ .ds-alert--warning .ds-alert__icon {
189
+ color: var(--color-status-warning-border);
190
+ }
191
+
192
+ .ds-alert--warning .ds-alert__title {
193
+ color: var(--color-status-warning-text);
194
+ }
195
+
196
+ .ds-alert--warning .ds-alert__description {
197
+ color: var(--color-status-warning-text);
198
+ }
199
+
200
+ .ds-alert--warning .ds-alert__dismiss {
201
+ color: var(--color-status-warning-text);
202
+ }
203
+
204
+ /* ============================================
205
+ VARIANT — ERROR
206
+ ============================================ */
207
+
208
+ .ds-alert--error {
209
+ background-color: var(--color-status-error-bg);
210
+ border-color: var(--color-status-error-border);
211
+ }
212
+
213
+ .ds-alert--error .ds-alert__icon {
214
+ color: var(--color-status-error-border);
215
+ }
216
+
217
+ .ds-alert--error .ds-alert__title {
218
+ color: var(--color-status-error-text);
219
+ }
220
+
221
+ .ds-alert--error .ds-alert__description {
222
+ color: var(--color-status-error-text);
223
+ }
224
+
225
+ .ds-alert--error .ds-alert__dismiss {
226
+ color: var(--color-status-error-text);
227
+ }
228
+
229
+ /* ============================================
230
+ VARIANT — NEUTRAL
231
+ ============================================ */
232
+
233
+ .ds-alert--neutral {
234
+ background-color: var(--color-status-neutral-bg);
235
+ border-color: var(--color-status-neutral-border);
236
+ }
237
+
238
+ .ds-alert--neutral .ds-alert__icon {
239
+ color: var(--color-status-neutral-text);
240
+ }
241
+
242
+ .ds-alert--neutral .ds-alert__title {
243
+ color: var(--color-status-neutral-text);
244
+ }
245
+
246
+ .ds-alert--neutral .ds-alert__description {
247
+ color: var(--color-status-neutral-text);
248
+ }
249
+
250
+ .ds-alert--neutral .ds-alert__dismiss {
251
+ color: var(--color-status-neutral-text);
252
+ }
@@ -0,0 +1,24 @@
1
+ export interface AlertProps {
2
+ /** Alert title text */
3
+ title?: string;
4
+ /** Alert description / body text */
5
+ description?: string;
6
+ /** Alert variant determines colour and icon */
7
+ variant?: 'info' | 'positive' | 'warning' | 'error' | 'neutral';
8
+ /** Component size */
9
+ size?: 'default' | 'compact';
10
+ /** Whether the alert can be dismissed */
11
+ dismissible?: boolean;
12
+ /** Custom icon override — Material Symbol name */
13
+ icon?: string;
14
+ /** Callback when dismiss button is clicked */
15
+ onDismiss?: () => void;
16
+ /** Additional CSS classes */
17
+ className?: string;
18
+ }
19
+ /**
20
+ * Alert component for contextual feedback messages.
21
+ * Supports info, positive, warning, error, and neutral variants
22
+ * with optional dismiss functionality.
23
+ */
24
+ export declare const Alert: ({ title, description, variant, size, dismissible, icon, onDismiss, className, }: AlertProps) => import("react").JSX.Element;