@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
@@ -0,0 +1,78 @@
1
+ /* ============================================
2
+ STAT COMPONENT
3
+ A single headline metric with label and an
4
+ optional trend delta. Compose in a row for
5
+ a metrics band.
6
+ ============================================ */
7
+
8
+ .ds-stat {
9
+ display: inline-flex;
10
+ flex-direction: column;
11
+ align-items: flex-start;
12
+ gap: var(--gap-xxs);
13
+ }
14
+
15
+ /* ============================================
16
+ VALUE — display weight (300), per the
17
+ weight-contrast rule for display numerals
18
+ ============================================ */
19
+
20
+ .ds-stat__value {
21
+ font-family: var(--font-sub-display-family);
22
+ font-size: var(--font-sub-display-size);
23
+ font-weight: var(--font-sub-display-weight);
24
+ line-height: var(--font-sub-display-line-height);
25
+ letter-spacing: var(--font-sub-display-letter-spacing);
26
+ color: var(--color-text-primary);
27
+ }
28
+
29
+ .ds-stat--large .ds-stat__value {
30
+ font-size: var(--font-display-2-size);
31
+ line-height: var(--font-display-2-line-height);
32
+ letter-spacing: var(--font-display-2-letter-spacing);
33
+ }
34
+
35
+ /* ============================================
36
+ LABEL
37
+ ============================================ */
38
+
39
+ .ds-stat__label {
40
+ font-family: var(--font-paragraph-sm-family);
41
+ font-size: var(--font-paragraph-sm-size);
42
+ font-weight: var(--font-paragraph-sm-weight);
43
+ line-height: var(--font-paragraph-sm-line-height);
44
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
45
+ color: var(--color-text-tertiary);
46
+ }
47
+
48
+ /* ============================================
49
+ DELTA — trend-coloured annotation
50
+ ============================================ */
51
+
52
+ .ds-stat__delta {
53
+ display: inline-flex;
54
+ align-items: center;
55
+ gap: var(--gap-xxs);
56
+ font-family: var(--font-paragraph-sm-em-family);
57
+ font-size: var(--font-paragraph-sm-em-size);
58
+ font-weight: var(--font-paragraph-sm-em-weight);
59
+ line-height: var(--font-paragraph-sm-em-line-height);
60
+ letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
61
+ }
62
+
63
+ .ds-stat__delta .material-symbols-rounded {
64
+ --icon-size: var(--icon-size-sm);
65
+ line-height: 1;
66
+ }
67
+
68
+ .ds-stat__delta--up {
69
+ color: var(--color-status-positive-text);
70
+ }
71
+
72
+ .ds-stat__delta--down {
73
+ color: var(--color-status-error-text);
74
+ }
75
+
76
+ .ds-stat__delta--neutral {
77
+ color: var(--color-text-tertiary);
78
+ }
@@ -0,0 +1,19 @@
1
+ export interface StatProps {
2
+ /** The headline number, e.g. "~900%" or "3.8M" */
3
+ value: string;
4
+ /** What the number measures */
5
+ label: string;
6
+ /** Optional change annotation, e.g. "+42% vs last quarter" */
7
+ delta?: string;
8
+ /** Direction of the delta — colours it and adds an arrow */
9
+ trend?: 'up' | 'down' | 'neutral';
10
+ /** Stat size */
11
+ size?: 'default' | 'large';
12
+ /** Additional CSS classes */
13
+ className?: string;
14
+ }
15
+ /**
16
+ * Stat component — a single headline metric with a label and an
17
+ * optional trend delta. Compose several in a row for a metrics band.
18
+ */
19
+ export declare const Stat: ({ value, label, delta, trend, size, className, }: StatProps) => import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import "./Stat.css";
3
+ import "../../fonts/material-symbols.css";
4
+ const TREND_ICONS = {
5
+ up: "arrow_upward",
6
+ down: "arrow_downward",
7
+ neutral: "remove"
8
+ };
9
+ const Stat = ({
10
+ value,
11
+ label,
12
+ delta,
13
+ trend = "neutral",
14
+ size = "default",
15
+ className = ""
16
+ }) => {
17
+ const baseClass = "ds-stat";
18
+ const classes = [baseClass, `${baseClass}--${size}`, className].filter(Boolean).join(" ");
19
+ return /* @__PURE__ */ jsxs("div", { className: classes, children: [
20
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__value`, children: value }),
21
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label }),
22
+ delta && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__delta ${baseClass}__delta--${trend}`, children: [
23
+ /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", "aria-hidden": "true", children: TREND_ICONS[trend] }),
24
+ delta
25
+ ] })
26
+ ] });
27
+ };
28
+ export {
29
+ Stat
30
+ };
@@ -0,0 +1,186 @@
1
+ /* ============================================
2
+ TABLE COMPONENT
3
+ Data table with flexible cell content
4
+ ============================================ */
5
+
6
+ .ds-table {
7
+ width: 100%;
8
+ border-collapse: separate;
9
+ border-spacing: 0;
10
+ border-radius: var(--radius-sm); /* 8px */
11
+ overflow: hidden;
12
+
13
+ /* Typography */
14
+ font-family: var(--font-paragraph-family);
15
+ font-size: var(--font-paragraph-size);
16
+ font-weight: var(--font-paragraph-weight);
17
+ line-height: var(--font-paragraph-line-height);
18
+ letter-spacing: var(--font-paragraph-letter-spacing);
19
+ color: var(--color-text-primary);
20
+ }
21
+
22
+ /* ============================================
23
+ CAPTION
24
+ ============================================ */
25
+
26
+ .ds-table__caption {
27
+ font-family: var(--font-paragraph-em-family);
28
+ font-size: var(--font-paragraph-em-size);
29
+ font-weight: var(--font-paragraph-em-weight);
30
+ line-height: var(--font-paragraph-em-line-height);
31
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
32
+ color: var(--color-text-secondary);
33
+ text-align: left;
34
+ caption-side: top;
35
+ padding-bottom: var(--padding-sm); /* 8px */
36
+ }
37
+
38
+ .ds-table__caption--hidden {
39
+ position: absolute;
40
+ width: 1px;
41
+ height: 1px;
42
+ padding: 0;
43
+ margin: -1px;
44
+ overflow: hidden;
45
+ clip: rect(0, 0, 0, 0);
46
+ white-space: nowrap;
47
+ border: 0;
48
+ }
49
+
50
+ /* ============================================
51
+ ROW
52
+ ============================================ */
53
+
54
+ .ds-table__row {
55
+ border-bottom: var(--border-xs) solid var(--color-bg-container-border);
56
+ transition: background-color var(--motion-duration-base) var(--motion-ease-standard);
57
+ }
58
+
59
+ /* ============================================
60
+ HEADER CELL
61
+ ============================================ */
62
+
63
+ .ds-table__header-cell {
64
+ padding: var(--padding-sm) var(--padding-md); /* 8px 16px */
65
+ vertical-align: middle;
66
+
67
+ /* paragraph-em (500 weight / label style) */
68
+ font-family: var(--font-paragraph-em-family);
69
+ font-size: var(--font-paragraph-em-size);
70
+ font-weight: var(--font-paragraph-em-weight);
71
+ line-height: var(--font-paragraph-em-line-height);
72
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
73
+ color: var(--color-text-secondary);
74
+ text-align: left;
75
+ }
76
+
77
+ /* ============================================
78
+ DATA CELL
79
+ ============================================ */
80
+
81
+ .ds-table__cell {
82
+ padding: var(--padding-sm) var(--padding-md); /* 8px 16px */
83
+ vertical-align: middle;
84
+ color: var(--color-text-primary);
85
+ }
86
+
87
+ /* Inner wrapper ensures all cell content is perfectly vertically centred */
88
+ .ds-table__cell-content {
89
+ display: flex;
90
+ align-items: center;
91
+ min-height: 0;
92
+ }
93
+
94
+ /* ============================================
95
+ ROW HOVER (body rows only)
96
+ ============================================ */
97
+
98
+ .ds-table__body .ds-table__row:hover {
99
+ background-color: var(--color-bg-container-primary-semi);
100
+ }
101
+
102
+ /* ============================================
103
+ STRIPED ROWS
104
+ ============================================ */
105
+
106
+ .ds-table--striped .ds-table__body .ds-table__row:nth-child(even) {
107
+ background-color: var(--color-bg-container-primary-semi);
108
+ }
109
+
110
+ .ds-table--striped .ds-table__body .ds-table__row:nth-child(even):hover {
111
+ background-color: var(--color-action-passive-bg-hover);
112
+ }
113
+
114
+ /* ============================================
115
+ SIZE — DEFAULT (base styles apply)
116
+ ============================================ */
117
+
118
+ .ds-table--default {
119
+ /* Base padding & typography inherited from .ds-table */
120
+ }
121
+
122
+ /* ============================================
123
+ BORDERED VARIANT
124
+ Outer border box + tinted thead + divider row lines.
125
+ Matches the table style used on markdown content pages.
126
+ ============================================ */
127
+
128
+ .ds-table__wrapper {
129
+ overflow-x: auto;
130
+ border: 1px solid var(--color-divider);
131
+ border-radius: var(--radius-md); /* 12px */
132
+ background: var(--color-bg-page-primary);
133
+ }
134
+
135
+ /* When bordered, the table fills the wrapper — no radius needed on the table itself */
136
+ .ds-table--bordered {
137
+ border-radius: 0;
138
+ }
139
+
140
+ /* Thead gets a tinted background to distinguish it from body rows */
141
+ .ds-table--bordered .ds-table__head {
142
+ background: var(--color-bg-container-primary);
143
+ }
144
+
145
+ /* Remove row-level border — border-collapse: separate ignores it */
146
+ .ds-table--bordered .ds-table__row {
147
+ border-bottom: none;
148
+ }
149
+
150
+ /* Header cells: bottom divider */
151
+ .ds-table--bordered .ds-table__header-cell {
152
+ border-bottom: 1px solid var(--color-divider);
153
+ }
154
+
155
+ /* Body cells: bottom divider */
156
+ .ds-table--bordered .ds-table__cell {
157
+ border-bottom: 1px solid var(--color-divider);
158
+ }
159
+
160
+ /* Last body row: no bottom border (the wrapper border handles it) */
161
+ .ds-table--bordered .ds-table__body .ds-table__row:last-child .ds-table__cell {
162
+ border-bottom: none;
163
+ }
164
+
165
+ /* Row hover on bordered variant */
166
+ .ds-table--bordered .ds-table__body .ds-table__row:hover {
167
+ background-color: var(--color-bg-container-primary);
168
+ }
169
+
170
+ /* ============================================
171
+ SIZE — COMPACT
172
+ ============================================ */
173
+
174
+ .ds-table--compact .ds-table__header-cell {
175
+ padding: var(--padding-xs) var(--padding-sm-md); /* 6px 12px */
176
+ font-size: var(--font-paragraph-sm-size);
177
+ line-height: var(--font-paragraph-sm-line-height);
178
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
179
+ }
180
+
181
+ .ds-table--compact .ds-table__cell {
182
+ padding: var(--padding-xs) var(--padding-sm-md); /* 6px 12px */
183
+ font-size: var(--font-paragraph-sm-size);
184
+ line-height: var(--font-paragraph-sm-line-height);
185
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
186
+ }
@@ -0,0 +1,45 @@
1
+ import { default as React } from 'react';
2
+ export interface TableColumn {
3
+ /** Unique column identifier, used as the key into each row's cells */
4
+ key: string;
5
+ /** Header label displayed in the column header */
6
+ header: React.ReactNode;
7
+ /** Optional column width (CSS value like '200px', '30%', 'auto') */
8
+ width?: string;
9
+ /** Text alignment for cells in this column */
10
+ align?: 'left' | 'center' | 'right';
11
+ }
12
+ export interface TableRow {
13
+ /** Unique row identifier */
14
+ id: string;
15
+ /** Cell values keyed by column key — each accepts any React node */
16
+ cells: Record<string, React.ReactNode>;
17
+ }
18
+ export interface TableProps {
19
+ /** Column definitions */
20
+ columns: TableColumn[];
21
+ /** Row data */
22
+ rows: TableRow[];
23
+ /** Visual size */
24
+ size?: 'default' | 'compact';
25
+ /** Alternating row background colours */
26
+ striped?: boolean;
27
+ /**
28
+ * Adds an outer border + border-radius container, a tinted thead background,
29
+ * and `--color-divider` row lines — matching the bordered table style used on
30
+ * markdown content pages.
31
+ */
32
+ bordered?: boolean;
33
+ /** Accessible caption for the table */
34
+ caption?: string;
35
+ /** Whether to visually hide the caption (still available to screen readers) */
36
+ captionHidden?: boolean;
37
+ /** Additional CSS classes */
38
+ className?: string;
39
+ }
40
+ /**
41
+ * Table component from Figma design system.
42
+ * Data table with flexible cell content — supports text, icons,
43
+ * inputs, buttons, and any other React nodes inside cells.
44
+ */
45
+ export declare const Table: ({ columns, rows, size, striped, bordered, caption, captionHidden, className, }: TableProps) => React.JSX.Element;
@@ -0,0 +1,65 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import "react";
3
+ import "./Table.css";
4
+ const Table = ({
5
+ columns,
6
+ rows,
7
+ size = "default",
8
+ striped = false,
9
+ bordered = false,
10
+ caption,
11
+ captionHidden = false,
12
+ className = ""
13
+ }) => {
14
+ const baseClass = "ds-table";
15
+ const sizeClass = `${baseClass}--${size}`;
16
+ const stripedClass = striped ? `${baseClass}--striped` : "";
17
+ const borderedClass = bordered ? `${baseClass}--bordered` : "";
18
+ const classes = [baseClass, sizeClass, stripedClass, borderedClass, className].filter(Boolean).join(" ");
19
+ const table = /* @__PURE__ */ jsxs("table", { className: classes, children: [
20
+ caption && /* @__PURE__ */ jsx(
21
+ "caption",
22
+ {
23
+ className: captionHidden ? `${baseClass}__caption--hidden` : `${baseClass}__caption`,
24
+ children: caption
25
+ }
26
+ ),
27
+ /* @__PURE__ */ jsx("thead", { className: `${baseClass}__head`, children: /* @__PURE__ */ jsx("tr", { className: `${baseClass}__row ${baseClass}__row--header`, children: columns.map((col) => /* @__PURE__ */ jsx(
28
+ "th",
29
+ {
30
+ className: `${baseClass}__header-cell`,
31
+ scope: "col",
32
+ style: {
33
+ width: col.width,
34
+ textAlign: col.align || "left"
35
+ },
36
+ children: col.header
37
+ },
38
+ col.key
39
+ )) }) }),
40
+ /* @__PURE__ */ jsx("tbody", { className: `${baseClass}__body`, children: rows.map((row) => /* @__PURE__ */ jsx("tr", { className: `${baseClass}__row`, children: columns.map((col) => /* @__PURE__ */ jsx(
41
+ "td",
42
+ {
43
+ className: `${baseClass}__cell`,
44
+ children: /* @__PURE__ */ jsx(
45
+ "div",
46
+ {
47
+ className: `${baseClass}__cell-content`,
48
+ style: {
49
+ justifyContent: col.align === "center" ? "center" : col.align === "right" ? "flex-end" : "flex-start"
50
+ },
51
+ children: row.cells[col.key]
52
+ }
53
+ )
54
+ },
55
+ col.key
56
+ )) }, row.id)) })
57
+ ] });
58
+ if (bordered) {
59
+ return /* @__PURE__ */ jsx("div", { className: `${baseClass}__wrapper`, children: table });
60
+ }
61
+ return table;
62
+ };
63
+ export {
64
+ Table
65
+ };
@@ -0,0 +1,140 @@
1
+ /* ============================================
2
+ TABS COMPONENT
3
+ Horizontal tab navigation with underline
4
+ ============================================ */
5
+
6
+ .ds-tabs {
7
+ display: inline-flex;
8
+ align-items: stretch;
9
+ gap: 0;
10
+ border-bottom: var(--border-xs) solid var(--color-bg-container-border);
11
+ }
12
+
13
+ /* ============================================
14
+ FULL WIDTH
15
+ ============================================ */
16
+
17
+ .ds-tabs--full-width {
18
+ display: flex;
19
+ width: 100%;
20
+ }
21
+
22
+ .ds-tabs--full-width .ds-tabs__tab {
23
+ flex: 1;
24
+ }
25
+
26
+ /* ============================================
27
+ TAB BUTTON
28
+ ============================================ */
29
+
30
+ .ds-tabs__tab {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ gap: var(--gap-sm); /* 8px */
35
+ padding: var(--padding-sm) var(--padding-md); /* 8px 16px */
36
+ border: none;
37
+ border-bottom: var(--border-md) solid transparent;
38
+ margin-bottom: calc(var(--border-xs) * -1); /* Overlap the container border */
39
+ background: none;
40
+ cursor: pointer;
41
+ position: relative;
42
+
43
+ /* Typography — paragraph em (medium weight) for clickable controls */
44
+ font-family: var(--font-paragraph-em-family);
45
+ font-size: var(--font-paragraph-em-size);
46
+ font-weight: var(--font-paragraph-em-weight);
47
+ line-height: var(--font-paragraph-em-line-height);
48
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
49
+
50
+ transition: color var(--motion-duration-base) var(--motion-ease-standard), border-color var(--motion-duration-base) var(--motion-ease-standard);
51
+ }
52
+
53
+ /* ============================================
54
+ SIZE — COMPACT
55
+ ============================================ */
56
+
57
+ .ds-tabs--compact .ds-tabs__tab {
58
+ padding: var(--padding-xs) var(--padding-sm-md); /* 6px 12px */
59
+ font-size: var(--font-paragraph-sm-em-size);
60
+ line-height: var(--font-paragraph-sm-em-line-height);
61
+ letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
62
+ }
63
+
64
+ .ds-tabs--compact .ds-tabs__icon {
65
+ --icon-size: var(--icon-size-sm);
66
+ }
67
+
68
+ /* ============================================
69
+ LABEL
70
+ ============================================ */
71
+
72
+ .ds-tabs__label {
73
+ color: var(--color-text-tertiary);
74
+ transition: color var(--motion-duration-base) var(--motion-ease-standard);
75
+ }
76
+
77
+ /* ============================================
78
+ ICON
79
+ ============================================ */
80
+
81
+ .ds-tabs__icon {
82
+ --icon-size: var(--icon-size-md);
83
+ color: var(--color-icon-secondary);
84
+ transition: color var(--motion-duration-base) var(--motion-ease-standard);
85
+ }
86
+
87
+ /* ============================================
88
+ DEFAULT (inactive) TAB
89
+ ============================================ */
90
+
91
+ .ds-tabs__tab:not(.ds-tabs__tab--disabled):hover .ds-tabs__label {
92
+ color: var(--color-text-primary);
93
+ }
94
+
95
+ .ds-tabs__tab:not(.ds-tabs__tab--disabled):hover .ds-tabs__icon {
96
+ color: var(--color-icon-primary);
97
+ }
98
+
99
+ .ds-tabs__tab:not(.ds-tabs__tab--disabled):hover {
100
+ border-bottom-color: var(--color-bg-container-secondary);
101
+ }
102
+
103
+ /* ============================================
104
+ ACTIVE TAB
105
+ ============================================ */
106
+
107
+ .ds-tabs__tab--active {
108
+ border-bottom-color: var(--color-action-primary-bg);
109
+ }
110
+
111
+ .ds-tabs__tab--active .ds-tabs__label {
112
+ color: var(--color-text-primary);
113
+ }
114
+
115
+ .ds-tabs__tab--active .ds-tabs__icon {
116
+ color: var(--color-action-primary-bg);
117
+ }
118
+
119
+ .ds-tabs__tab--active:not(.ds-tabs__tab--disabled):hover {
120
+ border-bottom-color: var(--color-action-primary-bg);
121
+ }
122
+
123
+ /* ============================================
124
+ FOCUS STATE
125
+ ============================================ */
126
+
127
+ .ds-tabs__tab:focus-visible {
128
+ outline: 2px solid var(--color-action-primary-bg);
129
+ outline-offset: -2px;
130
+ border-radius: var(--radius-sm);
131
+ }
132
+
133
+ /* ============================================
134
+ DISABLED STATE
135
+ ============================================ */
136
+
137
+ .ds-tabs__tab--disabled {
138
+ opacity: 0.4;
139
+ cursor: not-allowed;
140
+ }
@@ -0,0 +1,28 @@
1
+ import { default as React } from 'react';
2
+ export interface Tab {
3
+ /** Unique tab identifier */
4
+ value: string;
5
+ /** Display label */
6
+ label: string;
7
+ /** Optional Material Symbol icon name */
8
+ icon?: string;
9
+ /** Whether this tab is disabled */
10
+ disabled?: boolean;
11
+ }
12
+ export interface TabsProps {
13
+ /** Array of tab definitions */
14
+ tabs: Tab[];
15
+ /** Currently active tab value */
16
+ activeTab: string;
17
+ /** Callback when tab is selected */
18
+ onTabChange?: (value: string) => void;
19
+ /** Visual size */
20
+ size?: 'default' | 'compact';
21
+ /** Whether tabs fill the available width */
22
+ fullWidth?: boolean;
23
+ /** Additional CSS classes */
24
+ className?: string;
25
+ /** Accessible label for the tab list */
26
+ ariaLabel?: string;
27
+ }
28
+ export declare const Tabs: ({ tabs, activeTab, onTabChange, size, fullWidth, className, ariaLabel, }: TabsProps) => React.JSX.Element;
@@ -0,0 +1,77 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import "react";
3
+ import "./Tabs.css";
4
+ import "../../fonts/material-symbols.css";
5
+ const Tabs = ({
6
+ tabs,
7
+ activeTab,
8
+ onTabChange,
9
+ size = "default",
10
+ fullWidth = false,
11
+ className = "",
12
+ ariaLabel = "Tabs"
13
+ }) => {
14
+ const baseClass = "ds-tabs";
15
+ const sizeClass = `${baseClass}--${size}`;
16
+ const fullWidthClass = fullWidth ? `${baseClass}--full-width` : "";
17
+ const classes = [baseClass, sizeClass, fullWidthClass, className].filter(Boolean).join(" ");
18
+ const handleKeyDown = (e, index) => {
19
+ const enabledTabs = tabs.filter((t) => !t.disabled);
20
+ const currentEnabledIndex = enabledTabs.findIndex((t) => t.value === tabs[index].value);
21
+ let targetTab;
22
+ switch (e.key) {
23
+ case "ArrowRight":
24
+ e.preventDefault();
25
+ targetTab = enabledTabs[(currentEnabledIndex + 1) % enabledTabs.length];
26
+ break;
27
+ case "ArrowLeft":
28
+ e.preventDefault();
29
+ targetTab = enabledTabs[(currentEnabledIndex - 1 + enabledTabs.length) % enabledTabs.length];
30
+ break;
31
+ case "Home":
32
+ e.preventDefault();
33
+ targetTab = enabledTabs[0];
34
+ break;
35
+ case "End":
36
+ e.preventDefault();
37
+ targetTab = enabledTabs[enabledTabs.length - 1];
38
+ break;
39
+ }
40
+ if (targetTab && onTabChange) {
41
+ onTabChange(targetTab.value);
42
+ const tabList = e.target.parentElement;
43
+ const targetEl = tabList?.querySelector(`[data-tab-value="${targetTab.value}"]`);
44
+ targetEl?.focus();
45
+ }
46
+ };
47
+ return /* @__PURE__ */ jsx("div", { className: classes, role: "tablist", "aria-label": ariaLabel, children: tabs.map((tab, index) => {
48
+ const isActive = tab.value === activeTab;
49
+ const tabClass = [
50
+ `${baseClass}__tab`,
51
+ isActive ? `${baseClass}__tab--active` : "",
52
+ tab.disabled ? `${baseClass}__tab--disabled` : ""
53
+ ].filter(Boolean).join(" ");
54
+ return /* @__PURE__ */ jsxs(
55
+ "button",
56
+ {
57
+ type: "button",
58
+ className: tabClass,
59
+ role: "tab",
60
+ "aria-selected": isActive,
61
+ "aria-disabled": tab.disabled,
62
+ tabIndex: isActive ? 0 : -1,
63
+ "data-tab-value": tab.value,
64
+ onClick: () => !tab.disabled && onTabChange?.(tab.value),
65
+ onKeyDown: (e) => handleKeyDown(e, index),
66
+ children: [
67
+ tab.icon && /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon material-symbols-rounded`, "aria-hidden": "true", children: tab.icon }),
68
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: tab.label })
69
+ ]
70
+ },
71
+ tab.value
72
+ );
73
+ }) });
74
+ };
75
+ export {
76
+ Tabs
77
+ };