@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,308 @@
1
+ /* ============================================
2
+ FILE INPUT COMPONENT
3
+ Click-or-drop zone plus a controlled file list
4
+ ============================================ */
5
+
6
+ .ds-file-input {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--gap-sm); /* 8px */
10
+ width: 100%;
11
+ }
12
+
13
+ /* ============================================
14
+ LABEL
15
+ ============================================ */
16
+
17
+ .ds-file-input__label {
18
+ font-family: var(--font-paragraph-em-family);
19
+ font-size: var(--font-paragraph-em-size);
20
+ font-weight: var(--font-paragraph-em-weight);
21
+ line-height: var(--font-paragraph-em-line-height);
22
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
23
+ color: var(--color-text-primary);
24
+ }
25
+
26
+ .ds-file-input__required {
27
+ color: var(--color-core-accent-coral);
28
+ }
29
+
30
+ /* ============================================
31
+ DROPZONE
32
+ ============================================ */
33
+
34
+ .ds-file-input__dropzone {
35
+ position: relative;
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: center;
39
+ justify-content: center;
40
+ text-align: center;
41
+ gap: var(--gap-xs); /* 4px */
42
+ padding: var(--padding-xl); /* 32px */
43
+ border: var(--border-xs) dashed var(--color-input-border-primary);
44
+ border-radius: var(--radius-md); /* 12px */
45
+ background-color: var(--color-input-bg-primary);
46
+ cursor: pointer;
47
+ transition: border-color var(--motion-duration-base) var(--motion-ease-standard), background-color var(--motion-duration-base) var(--motion-ease-standard);
48
+ }
49
+
50
+ .ds-file-input__dropzone:hover {
51
+ border-color: var(--color-input-border-hover);
52
+ }
53
+
54
+ .ds-file-input__dropzone:focus-visible {
55
+ outline: 2px solid var(--color-action-primary-bg);
56
+ outline-offset: 2px;
57
+ }
58
+
59
+ .ds-file-input--dragging .ds-file-input__dropzone {
60
+ border-color: var(--color-input-border-selected);
61
+ background-color: var(--color-bg-container-primary);
62
+ }
63
+
64
+ .ds-file-input__dropzone-icon {
65
+ --icon-size: var(--icon-size-md);
66
+ color: var(--color-icon-primary);
67
+ }
68
+
69
+ .ds-file-input__dropzone-text {
70
+ font-family: var(--font-paragraph-em-family);
71
+ font-size: var(--font-paragraph-em-size);
72
+ font-weight: var(--font-paragraph-em-weight);
73
+ line-height: var(--font-paragraph-em-line-height);
74
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
75
+ color: var(--color-text-primary);
76
+ }
77
+
78
+ .ds-file-input__dropzone-hint {
79
+ font-family: var(--font-paragraph-sm-family);
80
+ font-size: var(--font-paragraph-sm-size);
81
+ font-weight: var(--font-paragraph-sm-weight);
82
+ line-height: var(--font-paragraph-sm-line-height);
83
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
84
+ color: var(--color-text-tertiary);
85
+ }
86
+
87
+ /* The real input stays in the DOM for form semantics but is never shown */
88
+ .ds-file-input__native {
89
+ position: absolute;
90
+ width: 1px;
91
+ height: 1px;
92
+ padding: 0;
93
+ margin: -1px;
94
+ overflow: hidden;
95
+ clip: rect(0, 0, 0, 0);
96
+ white-space: nowrap;
97
+ border: 0;
98
+ }
99
+
100
+ /* ============================================
101
+ FILE LIST
102
+ ============================================ */
103
+
104
+ .ds-file-input__list {
105
+ display: flex;
106
+ flex-direction: column;
107
+ gap: var(--gap-xs); /* 4px */
108
+ list-style: none;
109
+ margin: 0;
110
+ padding: 0;
111
+ }
112
+
113
+ .ds-file-input__file {
114
+ display: flex;
115
+ align-items: center;
116
+ gap: var(--gap-sm-md);
117
+ padding: var(--padding-sm) var(--padding-sm-md); /* 8px 12px */
118
+ border: var(--border-xs) solid var(--color-bg-container-border);
119
+ border-radius: var(--radius-md); /* 12px */
120
+ background-color: var(--color-bg-page-primary);
121
+ }
122
+
123
+ .ds-file-input__file--error {
124
+ border-color: var(--color-status-error-border);
125
+ background-color: var(--color-status-error-bg);
126
+ }
127
+
128
+ .ds-file-input__file-icon {
129
+ --icon-size: var(--icon-size-sm);
130
+ color: var(--color-icon-primary);
131
+ flex-shrink: 0;
132
+ }
133
+
134
+ .ds-file-input__file--error .ds-file-input__file-icon {
135
+ color: var(--color-status-error-border);
136
+ }
137
+
138
+ .ds-file-input__file-details {
139
+ display: flex;
140
+ flex-direction: column;
141
+ gap: var(--gap-xxs);
142
+ flex: 1;
143
+ min-width: 0;
144
+ }
145
+
146
+ .ds-file-input__file-name {
147
+ font-family: var(--font-paragraph-em-family);
148
+ font-size: var(--font-paragraph-em-size);
149
+ font-weight: var(--font-paragraph-em-weight);
150
+ line-height: var(--font-paragraph-em-line-height);
151
+ letter-spacing: var(--font-paragraph-em-letter-spacing);
152
+ color: var(--color-text-primary);
153
+ overflow: hidden;
154
+ text-overflow: ellipsis;
155
+ white-space: nowrap;
156
+ }
157
+
158
+ .ds-file-input__file-size {
159
+ font-family: var(--font-paragraph-sm-family);
160
+ font-size: var(--font-paragraph-sm-size);
161
+ font-weight: var(--font-paragraph-sm-weight);
162
+ line-height: var(--font-paragraph-sm-line-height);
163
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
164
+ color: var(--color-text-tertiary);
165
+ }
166
+
167
+ .ds-file-input__file-error {
168
+ font-family: var(--font-paragraph-sm-family);
169
+ font-size: var(--font-paragraph-sm-size);
170
+ font-weight: var(--font-paragraph-sm-weight);
171
+ line-height: var(--font-paragraph-sm-line-height);
172
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
173
+ color: var(--color-status-error-text);
174
+ }
175
+
176
+ /* ============================================
177
+ PER-FILE PROGRESS
178
+ ============================================ */
179
+
180
+ .ds-file-input__progress {
181
+ display: block;
182
+ width: 100%;
183
+ height: 4px;
184
+ margin-top: var(--gap-xxs);
185
+ border-radius: var(--radius-full);
186
+ background-color: var(--color-bg-container-primary);
187
+ overflow: hidden;
188
+ }
189
+
190
+ .ds-file-input__progress-fill {
191
+ display: block;
192
+ height: 100%;
193
+ border-radius: var(--radius-full);
194
+ background-color: var(--color-action-primary-bg);
195
+ transition: width var(--motion-duration-base) var(--motion-ease-standard);
196
+ }
197
+
198
+ /* ============================================
199
+ REMOVE BUTTON
200
+ ============================================ */
201
+
202
+ .ds-file-input__file-remove {
203
+ display: inline-flex;
204
+ align-items: center;
205
+ justify-content: center;
206
+ width: 32px;
207
+ height: 32px;
208
+ padding: 0;
209
+ border: none;
210
+ border-radius: var(--radius-full);
211
+ background-color: transparent;
212
+ color: var(--color-icon-primary);
213
+ cursor: pointer;
214
+ flex-shrink: 0;
215
+ transition: background-color var(--motion-duration-base) var(--motion-ease-standard);
216
+ }
217
+
218
+ .ds-file-input__file-remove:hover {
219
+ background-color: var(--color-action-passive-bg-hover);
220
+ }
221
+
222
+ .ds-file-input__file-remove:focus-visible {
223
+ outline: 2px solid var(--color-action-primary-bg);
224
+ outline-offset: 2px;
225
+ }
226
+
227
+ .ds-file-input__file-remove:disabled {
228
+ opacity: 0.4;
229
+ cursor: not-allowed;
230
+ }
231
+
232
+ .ds-file-input__file-remove .material-symbols-rounded {
233
+ --icon-size: var(--icon-size-sm);
234
+ }
235
+
236
+ /* ============================================
237
+ HELPER TEXT
238
+ ============================================ */
239
+
240
+ .ds-file-input__helper {
241
+ font-family: var(--font-paragraph-sm-family);
242
+ font-size: var(--font-paragraph-sm-size);
243
+ font-weight: var(--font-paragraph-sm-weight);
244
+ line-height: var(--font-paragraph-sm-line-height);
245
+ letter-spacing: var(--font-paragraph-sm-letter-spacing);
246
+ color: var(--color-text-tertiary);
247
+ margin: 0;
248
+ }
249
+
250
+ /* ============================================
251
+ ERROR STATE
252
+ ============================================ */
253
+
254
+ .ds-file-input--error .ds-file-input__dropzone {
255
+ border-color: var(--color-status-error-border);
256
+ }
257
+
258
+ .ds-file-input--error .ds-file-input__helper {
259
+ color: var(--color-status-error-border);
260
+ }
261
+
262
+ /* ============================================
263
+ DISABLED STATE
264
+ ============================================ */
265
+
266
+ .ds-file-input--disabled .ds-file-input__label {
267
+ color: var(--color-input-text-disabled);
268
+ }
269
+
270
+ .ds-file-input--disabled .ds-file-input__dropzone {
271
+ background-color: var(--color-input-bg-disabled);
272
+ border-color: var(--color-input-border-disabled);
273
+ cursor: not-allowed;
274
+ }
275
+
276
+ .ds-file-input--disabled .ds-file-input__dropzone-text,
277
+ .ds-file-input--disabled .ds-file-input__dropzone-hint,
278
+ .ds-file-input--disabled .ds-file-input__dropzone-icon {
279
+ color: var(--color-input-text-disabled);
280
+ }
281
+
282
+ /* ============================================
283
+ SIZE — COMPACT
284
+ ============================================ */
285
+
286
+ .ds-file-input--compact .ds-file-input__dropzone {
287
+ padding: var(--padding-lg); /* 20px */
288
+ }
289
+
290
+ .ds-file-input--compact .ds-file-input__label {
291
+ font-size: var(--font-paragraph-sm-size);
292
+ line-height: var(--font-paragraph-sm-line-height);
293
+ }
294
+
295
+ .ds-file-input--compact .ds-file-input__dropzone-icon {
296
+ --icon-size: var(--icon-size-sm);
297
+ }
298
+
299
+ .ds-file-input--compact .ds-file-input__dropzone-text,
300
+ .ds-file-input--compact .ds-file-input__file-name {
301
+ font-size: var(--font-paragraph-sm-em-size);
302
+ line-height: var(--font-paragraph-sm-em-line-height);
303
+ letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
304
+ }
305
+
306
+ .ds-file-input--compact .ds-file-input__file {
307
+ padding: var(--padding-xs) var(--padding-sm); /* 6px 8px */
308
+ }
@@ -0,0 +1,54 @@
1
+ import { default as React } from 'react';
2
+ export interface FileInputFile {
3
+ /** Stable identifier */
4
+ id: string;
5
+ /** File name shown in the list */
6
+ name: string;
7
+ /** Size in bytes — rendered human-readable */
8
+ size?: number;
9
+ /** Upload progress 0–100. Omit for files that are already stored. */
10
+ progress?: number;
11
+ /** Per-file error message — replaces the size line */
12
+ error?: string;
13
+ }
14
+ export interface FileInputProps {
15
+ /** Field label above the dropzone */
16
+ label?: string;
17
+ /** Instructional copy inside the dropzone */
18
+ placeholder?: string;
19
+ /** Comma-separated accept list, e.g. 'image/*,.pdf' */
20
+ accept?: string;
21
+ /** Allow selecting more than one file */
22
+ multiple?: boolean;
23
+ /** Files to list under the dropzone */
24
+ files?: FileInputFile[];
25
+ /** Component size */
26
+ size?: 'default' | 'compact';
27
+ /** Whether the input is disabled */
28
+ disabled?: boolean;
29
+ /** Whether the input is required */
30
+ required?: boolean;
31
+ /** Error state — shows error styling and message */
32
+ error?: boolean;
33
+ /** Helper or error message displayed below the field */
34
+ helperText?: string;
35
+ /** Called with the newly selected files */
36
+ onFilesSelected?: (files: File[]) => void;
37
+ /** Called with the id of a file whose remove button was pressed */
38
+ onFileRemove?: (id: string) => void;
39
+ /** Additional CSS classes */
40
+ className?: string;
41
+ /** Accessible name override */
42
+ ariaLabel?: string;
43
+ /** HTML name attribute */
44
+ name?: string;
45
+ /** HTML id attribute */
46
+ id?: string;
47
+ }
48
+ /**
49
+ * FileInput component — a click-or-drop zone paired with a list of the
50
+ * chosen files. The list is fully controlled: pass `files` and handle
51
+ * `onFilesSelected` / `onFileRemove` so upload progress and per-file
52
+ * errors stay owned by the host app.
53
+ */
54
+ export declare const FileInput: ({ label, placeholder, accept, multiple, files, size, disabled, required, error, helperText, onFilesSelected, onFileRemove, className, ariaLabel, name, id, }: FileInputProps) => React.JSX.Element;
@@ -0,0 +1,177 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useState, useRef, useId } from "react";
3
+ import "./FileInput.css";
4
+ import "../../fonts/material-symbols.css";
5
+ const formatBytes = (bytes) => {
6
+ if (bytes === 0) return "0 B";
7
+ const units = ["B", "KB", "MB", "GB", "TB"];
8
+ const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
9
+ const value = bytes / Math.pow(1024, exponent);
10
+ return `${exponent === 0 ? value : value.toFixed(1)} ${units[exponent]}`;
11
+ };
12
+ const FileInput = ({
13
+ label,
14
+ placeholder = "Drag and drop, or click to browse",
15
+ accept,
16
+ multiple = false,
17
+ files = [],
18
+ size = "default",
19
+ disabled = false,
20
+ required = false,
21
+ error = false,
22
+ helperText,
23
+ onFilesSelected,
24
+ onFileRemove,
25
+ className = "",
26
+ ariaLabel,
27
+ name,
28
+ id
29
+ }) => {
30
+ const [isDragging, setIsDragging] = useState(false);
31
+ const inputRef = useRef(null);
32
+ const generatedId = useId();
33
+ const inputId = id || name || generatedId;
34
+ const baseClass = "ds-file-input";
35
+ const emitFiles = (fileList) => {
36
+ if (!fileList || fileList.length === 0) return;
37
+ onFilesSelected?.(Array.from(fileList));
38
+ };
39
+ const handleChange = (e) => {
40
+ emitFiles(e.target.files);
41
+ e.target.value = "";
42
+ };
43
+ const handleDrop = (e) => {
44
+ e.preventDefault();
45
+ setIsDragging(false);
46
+ if (disabled) return;
47
+ emitFiles(e.dataTransfer.files);
48
+ };
49
+ const handleDragOver = (e) => {
50
+ e.preventDefault();
51
+ if (!disabled) setIsDragging(true);
52
+ };
53
+ const handleDragLeave = (e) => {
54
+ if (e.currentTarget.contains(e.relatedTarget)) return;
55
+ setIsDragging(false);
56
+ };
57
+ const openPicker = () => {
58
+ if (!disabled) inputRef.current?.click();
59
+ };
60
+ const handleKeyDown = (e) => {
61
+ if (e.key === "Enter" || e.key === " ") {
62
+ e.preventDefault();
63
+ openPicker();
64
+ }
65
+ };
66
+ const classes = [
67
+ baseClass,
68
+ size === "compact" ? `${baseClass}--compact` : "",
69
+ error ? `${baseClass}--error` : "",
70
+ disabled ? `${baseClass}--disabled` : "",
71
+ isDragging ? `${baseClass}--dragging` : "",
72
+ className
73
+ ].filter(Boolean).join(" ");
74
+ return /* @__PURE__ */ jsxs("div", { className: classes, children: [
75
+ label && /* @__PURE__ */ jsxs("label", { className: `${baseClass}__label`, htmlFor: inputId, children: [
76
+ label,
77
+ required && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__required`, "aria-hidden": "true", children: [
78
+ " ",
79
+ "*"
80
+ ] })
81
+ ] }),
82
+ /* @__PURE__ */ jsxs(
83
+ "div",
84
+ {
85
+ className: `${baseClass}__dropzone`,
86
+ role: "button",
87
+ tabIndex: disabled ? -1 : 0,
88
+ "aria-label": ariaLabel || placeholder,
89
+ "aria-describedby": helperText ? `${inputId}-helper` : void 0,
90
+ "aria-disabled": disabled || void 0,
91
+ onClick: openPicker,
92
+ onKeyDown: handleKeyDown,
93
+ onDrop: handleDrop,
94
+ onDragOver: handleDragOver,
95
+ onDragLeave: handleDragLeave,
96
+ children: [
97
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__dropzone-icon material-symbols-rounded`, "aria-hidden": "true", children: "upload_file" }),
98
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__dropzone-text`, children: placeholder }),
99
+ accept && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__dropzone-hint`, children: [
100
+ "Accepts ",
101
+ accept
102
+ ] }),
103
+ /* @__PURE__ */ jsx(
104
+ "input",
105
+ {
106
+ ref: inputRef,
107
+ id: inputId,
108
+ name,
109
+ type: "file",
110
+ className: `${baseClass}__native`,
111
+ accept,
112
+ multiple,
113
+ disabled,
114
+ required,
115
+ tabIndex: -1,
116
+ onChange: handleChange
117
+ }
118
+ )
119
+ ]
120
+ }
121
+ ),
122
+ files.length > 0 && /* @__PURE__ */ jsx("ul", { className: `${baseClass}__list`, children: files.map((file) => /* @__PURE__ */ jsxs(
123
+ "li",
124
+ {
125
+ className: [`${baseClass}__file`, file.error ? `${baseClass}__file--error` : ""].filter(Boolean).join(" "),
126
+ children: [
127
+ /* @__PURE__ */ jsx(
128
+ "span",
129
+ {
130
+ className: `${baseClass}__file-icon material-symbols-rounded`,
131
+ "aria-hidden": "true",
132
+ children: file.error ? "error" : "description"
133
+ }
134
+ ),
135
+ /* @__PURE__ */ jsxs("span", { className: `${baseClass}__file-details`, children: [
136
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__file-name`, children: file.name }),
137
+ file.error ? /* @__PURE__ */ jsx("span", { className: `${baseClass}__file-error`, children: file.error }) : file.size !== void 0 && /* @__PURE__ */ jsx("span", { className: `${baseClass}__file-size`, children: formatBytes(file.size) }),
138
+ file.error === void 0 && file.progress !== void 0 && /* @__PURE__ */ jsx(
139
+ "span",
140
+ {
141
+ className: `${baseClass}__progress`,
142
+ role: "progressbar",
143
+ "aria-valuenow": file.progress,
144
+ "aria-valuemin": 0,
145
+ "aria-valuemax": 100,
146
+ "aria-label": `Uploading ${file.name}`,
147
+ children: /* @__PURE__ */ jsx(
148
+ "span",
149
+ {
150
+ className: `${baseClass}__progress-fill`,
151
+ style: { width: `${Math.min(100, Math.max(0, file.progress))}%` }
152
+ }
153
+ )
154
+ }
155
+ )
156
+ ] }),
157
+ onFileRemove && /* @__PURE__ */ jsx(
158
+ "button",
159
+ {
160
+ type: "button",
161
+ className: `${baseClass}__file-remove`,
162
+ onClick: () => onFileRemove(file.id),
163
+ disabled,
164
+ "aria-label": `Remove ${file.name}`,
165
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", "aria-hidden": "true", children: "close" })
166
+ }
167
+ )
168
+ ]
169
+ },
170
+ file.id
171
+ )) }),
172
+ helperText && /* @__PURE__ */ jsx("p", { className: `${baseClass}__helper`, id: `${inputId}-helper`, children: helperText })
173
+ ] });
174
+ };
175
+ export {
176
+ FileInput
177
+ };