@drivenets/design-system 0.0.1

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 (242) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +201 -0
  3. package/dist/index.cjs +5394 -0
  4. package/dist/index.css +1 -0
  5. package/dist/index.d.cts +9157 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.ts +9157 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +5335 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +104 -0
  12. package/src/components/ds-alert-banner/ds-alert-banner.module.scss +116 -0
  13. package/src/components/ds-alert-banner/ds-alert-banner.tsx +115 -0
  14. package/src/components/ds-alert-banner/ds-alert-banner.types.tsx +47 -0
  15. package/src/components/ds-alert-banner/index.tsx +2 -0
  16. package/src/components/ds-breadcrumb/ds-breadcrumb.module.scss +99 -0
  17. package/src/components/ds-breadcrumb/ds-breadcrumb.tsx +94 -0
  18. package/src/components/ds-breadcrumb/ds-breadcrumb.types.tsx +32 -0
  19. package/src/components/ds-breadcrumb/index.tsx +2 -0
  20. package/src/components/ds-button/ds-button.tsx +12 -0
  21. package/src/components/ds-button/ds-button.types.ts +6 -0
  22. package/src/components/ds-button/index.ts +2 -0
  23. package/src/components/ds-button/versions/ds-button-legacy/ds-button-legacy.module.scss +257 -0
  24. package/src/components/ds-button/versions/ds-button-legacy/ds-button-legacy.tsx +34 -0
  25. package/src/components/ds-button/versions/ds-button-legacy/ds-button-legacy.types.ts +41 -0
  26. package/src/components/ds-button/versions/ds-button-legacy/index.ts +2 -0
  27. package/src/components/ds-button/versions/ds-button-new/ds-button-new.module.scss +580 -0
  28. package/src/components/ds-button/versions/ds-button-new/ds-button-new.tsx +49 -0
  29. package/src/components/ds-button/versions/ds-button-new/ds-button-new.types.ts +41 -0
  30. package/src/components/ds-button/versions/ds-button-new/index.ts +2 -0
  31. package/src/components/ds-checkbox/ds-checkbox.module.scss +130 -0
  32. package/src/components/ds-checkbox/ds-checkbox.tsx +55 -0
  33. package/src/components/ds-checkbox/ds-checkbox.types.tsx +27 -0
  34. package/src/components/ds-checkbox/index.tsx +2 -0
  35. package/src/components/ds-chip/ds-chip.module.scss +71 -0
  36. package/src/components/ds-chip/ds-chip.tsx +73 -0
  37. package/src/components/ds-chip/ds-chip.types.tsx +46 -0
  38. package/src/components/ds-chip/index.tsx +2 -0
  39. package/src/components/ds-chip-group/ds-chip-group.module.scss +59 -0
  40. package/src/components/ds-chip-group/ds-chip-group.tsx +122 -0
  41. package/src/components/ds-chip-group/ds-chip-group.types.ts +52 -0
  42. package/src/components/ds-chip-group/hooks/use-chip-row-calculation.ts +76 -0
  43. package/src/components/ds-chip-group/index.ts +2 -0
  44. package/src/components/ds-confirmation/ds-confirmation.module.scss +58 -0
  45. package/src/components/ds-confirmation/ds-confirmation.tsx +121 -0
  46. package/src/components/ds-confirmation/ds-confirmation.types.tsx +28 -0
  47. package/src/components/ds-confirmation/index.ts +2 -0
  48. package/src/components/ds-dialog/ds-dialog.module.scss +50 -0
  49. package/src/components/ds-dialog/ds-dialog.tsx +70 -0
  50. package/src/components/ds-dialog/ds-dialog.types.tsx +48 -0
  51. package/src/components/ds-dialog/index.tsx +2 -0
  52. package/src/components/ds-drawer/ds-drawer.module.scss +212 -0
  53. package/src/components/ds-drawer/ds-drawer.tsx +160 -0
  54. package/src/components/ds-drawer/ds-drawer.types.tsx +54 -0
  55. package/src/components/ds-drawer/index.ts +2 -0
  56. package/src/components/ds-dropdown-menu/ds-dropdown-menu.module.scss +123 -0
  57. package/src/components/ds-dropdown-menu/ds-dropdown-menu.tsx +396 -0
  58. package/src/components/ds-dropdown-menu/ds-dropdown-menu.types.tsx +262 -0
  59. package/src/components/ds-dropdown-menu/index.tsx +2 -0
  60. package/src/components/ds-expandable-text-input/ds-expandable-text-input.module.scss +70 -0
  61. package/src/components/ds-expandable-text-input/ds-expandable-text-input.tsx +106 -0
  62. package/src/components/ds-expandable-text-input/ds-expandable-text-input.types.tsx +19 -0
  63. package/src/components/ds-expandable-text-input/index.ts +2 -0
  64. package/src/components/ds-file-upload/components/file-upload/file-upload.module.scss +90 -0
  65. package/src/components/ds-file-upload/components/file-upload/file-upload.tsx +106 -0
  66. package/src/components/ds-file-upload/components/file-upload/file-upload.types.tsx +94 -0
  67. package/src/components/ds-file-upload/components/file-upload/index.ts +2 -0
  68. package/src/components/ds-file-upload/components/file-upload-item/file-upload-item.module.scss +125 -0
  69. package/src/components/ds-file-upload/components/file-upload-item/file-upload-item.tsx +143 -0
  70. package/src/components/ds-file-upload/components/file-upload-item/file-upload-item.types.tsx +26 -0
  71. package/src/components/ds-file-upload/components/file-upload-item/index.ts +2 -0
  72. package/src/components/ds-file-upload/ds-file-upload-api.types.ts +38 -0
  73. package/src/components/ds-file-upload/ds-file-upload.tsx +46 -0
  74. package/src/components/ds-file-upload/ds-file-upload.types.tsx +54 -0
  75. package/src/components/ds-file-upload/errors/file-upload-errors.ts +27 -0
  76. package/src/components/ds-file-upload/hooks/index.ts +2 -0
  77. package/src/components/ds-file-upload/hooks/use-file-upload.ts +350 -0
  78. package/src/components/ds-file-upload/index.ts +7 -0
  79. package/src/components/ds-file-upload/types/accept-types.ts +106 -0
  80. package/src/components/ds-file-upload/utils/accept-utils.ts +25 -0
  81. package/src/components/ds-file-upload/utils/constants.ts +21 -0
  82. package/src/components/ds-file-upload/utils/file-factory.ts +18 -0
  83. package/src/components/ds-file-upload/utils/format-file-size.ts +15 -0
  84. package/src/components/ds-file-upload/utils/generate-helper-text.ts +39 -0
  85. package/src/components/ds-file-upload/utils/get-error-message.ts +17 -0
  86. package/src/components/ds-file-upload/utils/is-file-equal.ts +8 -0
  87. package/src/components/ds-form-control/ds-form-control.module.scss +135 -0
  88. package/src/components/ds-form-control/ds-form-control.tsx +94 -0
  89. package/src/components/ds-form-control/ds-form-control.types.tsx +58 -0
  90. package/src/components/ds-form-control/index.tsx +2 -0
  91. package/src/components/ds-grid/ds-grid.module.scss +0 -0
  92. package/src/components/ds-grid/ds-grid.tsx +43 -0
  93. package/src/components/ds-grid/ds-grid.types.ts +55 -0
  94. package/src/components/ds-grid/index.ts +2 -0
  95. package/src/components/ds-icon/ds-icon.module.scss +25 -0
  96. package/src/components/ds-icon/ds-icon.tsx +33 -0
  97. package/src/components/ds-icon/ds-icon.types.ts +53 -0
  98. package/src/components/ds-icon/index.ts +2 -0
  99. package/src/components/ds-icon/material-icons.ts +6203 -0
  100. package/src/components/ds-modal/ds-modal.module.scss +100 -0
  101. package/src/components/ds-modal/ds-modal.tsx +136 -0
  102. package/src/components/ds-modal/ds-modal.types.tsx +44 -0
  103. package/src/components/ds-modal/index.tsx +2 -0
  104. package/src/components/ds-number-input/ds-number-input.module.scss +15 -0
  105. package/src/components/ds-number-input/ds-number-input.tsx +74 -0
  106. package/src/components/ds-number-input/ds-number-input.types.tsx +76 -0
  107. package/src/components/ds-number-input/index.tsx +2 -0
  108. package/src/components/ds-panel/ds-panel.module.scss +95 -0
  109. package/src/components/ds-panel/ds-panel.tsx +46 -0
  110. package/src/components/ds-panel/ds-panel.types.ts +17 -0
  111. package/src/components/ds-panel/index.tsx +2 -0
  112. package/src/components/ds-password-input/ds-password-input.module.scss +10 -0
  113. package/src/components/ds-password-input/ds-password-input.tsx +67 -0
  114. package/src/components/ds-password-input/ds-password-input.types.tsx +62 -0
  115. package/src/components/ds-password-input/index.tsx +2 -0
  116. package/src/components/ds-popover/ds-popover.module.scss +23 -0
  117. package/src/components/ds-popover/ds-popover.tsx +33 -0
  118. package/src/components/ds-popover/ds-popover.types.tsx +24 -0
  119. package/src/components/ds-popover/index.tsx +2 -0
  120. package/src/components/ds-radio-group/ds-radio-group.module.scss +138 -0
  121. package/src/components/ds-radio-group/ds-radio-group.tsx +115 -0
  122. package/src/components/ds-radio-group/ds-radio-group.types.tsx +93 -0
  123. package/src/components/ds-radio-group/index.tsx +2 -0
  124. package/src/components/ds-select/ds-select.module.scss +66 -0
  125. package/src/components/ds-select/ds-select.tsx +239 -0
  126. package/src/components/ds-select/ds-select.types.tsx +80 -0
  127. package/src/components/ds-select/index.tsx +2 -0
  128. package/src/components/ds-select/select-items-chips.tsx +56 -0
  129. package/src/components/ds-smart-tabs/ds-smart-tabs.module.scss +69 -0
  130. package/src/components/ds-smart-tabs/ds-smart-tabs.tsx +113 -0
  131. package/src/components/ds-smart-tabs/ds-smart-tabs.types.tsx +74 -0
  132. package/src/components/ds-smart-tabs/index.tsx +2 -0
  133. package/src/components/ds-spinner/ds-spinner.module.scss +39 -0
  134. package/src/components/ds-spinner/ds-spinner.tsx +51 -0
  135. package/src/components/ds-spinner/ds-spinner.types.tsx +20 -0
  136. package/src/components/ds-spinner/index.tsx +2 -0
  137. package/src/components/ds-status-badge/ds-status-badge.module.scss +79 -0
  138. package/src/components/ds-status-badge/ds-status-badge.tsx +42 -0
  139. package/src/components/ds-status-badge/ds-status-badge.types.tsx +46 -0
  140. package/src/components/ds-status-badge/index.tsx +2 -0
  141. package/src/components/ds-stepper/components/ds-step-content.tsx +32 -0
  142. package/src/components/ds-stepper/components/ds-step-description.tsx +6 -0
  143. package/src/components/ds-stepper/components/ds-step-label.tsx +6 -0
  144. package/src/components/ds-stepper/components/ds-step-next-button.tsx +13 -0
  145. package/src/components/ds-stepper/components/ds-step.tsx +59 -0
  146. package/src/components/ds-stepper/ds-stepper.module.scss +134 -0
  147. package/src/components/ds-stepper/ds-stepper.tsx +34 -0
  148. package/src/components/ds-stepper/ds-stepper.types.ts +12 -0
  149. package/src/components/ds-stepper/hooks/use-stepper.ts +20 -0
  150. package/src/components/ds-stepper/hooks/use-steps.ts +18 -0
  151. package/src/components/ds-stepper/index.tsx +6 -0
  152. package/src/components/ds-system-status/ds-system-status.module.scss +87 -0
  153. package/src/components/ds-system-status/ds-system-status.tsx +33 -0
  154. package/src/components/ds-system-status/ds-system-status.types.tsx +37 -0
  155. package/src/components/ds-system-status/index.tsx +10 -0
  156. package/src/components/ds-table/components/core-table/core-table.module.scss +32 -0
  157. package/src/components/ds-table/components/core-table/core-table.tsx +83 -0
  158. package/src/components/ds-table/components/core-table/index.ts +1 -0
  159. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss +115 -0
  160. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.tsx +70 -0
  161. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.types.ts +41 -0
  162. package/src/components/ds-table/components/ds-table-bulk-actions/index.ts +2 -0
  163. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.module.scss +53 -0
  164. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.tsx +95 -0
  165. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.types.ts +67 -0
  166. package/src/components/ds-table/components/ds-table-cell/index.ts +2 -0
  167. package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +81 -0
  168. package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +99 -0
  169. package/src/components/ds-table/components/ds-table-header/ds-table-header.types.ts +11 -0
  170. package/src/components/ds-table/components/ds-table-header/index.ts +2 -0
  171. package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +137 -0
  172. package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +205 -0
  173. package/src/components/ds-table/components/ds-table-row/ds-table-row.types.ts +22 -0
  174. package/src/components/ds-table/components/ds-table-row/index.ts +2 -0
  175. package/src/components/ds-table/context/ds-table-context.tsx +39 -0
  176. package/src/components/ds-table/ds-table.module.scss +60 -0
  177. package/src/components/ds-table/ds-table.tsx +312 -0
  178. package/src/components/ds-table/ds-table.types.ts +377 -0
  179. package/src/components/ds-table/filters/adapters/create-checkbox-filter-adapter.tsx +116 -0
  180. package/src/components/ds-table/filters/adapters/create-dual-range-filter-adapter.tsx +171 -0
  181. package/src/components/ds-table/filters/adapters/create-filter-adapter.ts +131 -0
  182. package/src/components/ds-table/filters/adapters/index.ts +12 -0
  183. package/src/components/ds-table/filters/components/checkbox-filter/checkbox-filter.tsx +43 -0
  184. package/src/components/ds-table/filters/components/checkbox-filter/index.ts +2 -0
  185. package/src/components/ds-table/filters/components/range-filter/index.ts +2 -0
  186. package/src/components/ds-table/filters/components/range-filter/range-filter.module.scss +25 -0
  187. package/src/components/ds-table/filters/components/range-filter/range-filter.tsx +79 -0
  188. package/src/components/ds-table/filters/hooks/index.ts +1 -0
  189. package/src/components/ds-table/filters/hooks/use-table-filters.ts +234 -0
  190. package/src/components/ds-table/filters/index.ts +50 -0
  191. package/src/components/ds-table/filters/types/filter-adapter.types.ts +111 -0
  192. package/src/components/ds-table/hooks/use-drag-and-drop.tsx +107 -0
  193. package/src/components/ds-table/index.ts +4 -0
  194. package/src/components/ds-table/styles/_variables.scss +17 -0
  195. package/src/components/ds-table/styles/shared/ds-table-shared.module.scss +16 -0
  196. package/src/components/ds-table/utils/column-styling.ts +30 -0
  197. package/src/components/ds-table/utils/create-columns-grid-template.ts +23 -0
  198. package/src/components/ds-table/utils/merge-refs.ts +15 -0
  199. package/src/components/ds-table/utils/story-data-generator.ts +91 -0
  200. package/src/components/ds-text-input/ds-text-input.module.scss +27 -0
  201. package/src/components/ds-text-input/ds-text-input.tsx +75 -0
  202. package/src/components/ds-text-input/ds-text-input.types.tsx +110 -0
  203. package/src/components/ds-text-input/index.ts +2 -0
  204. package/src/components/ds-textarea/ds-textarea.module.scss +5 -0
  205. package/src/components/ds-textarea/ds-textarea.tsx +49 -0
  206. package/src/components/ds-textarea/ds-textarea.types.tsx +67 -0
  207. package/src/components/ds-textarea/index.tsx +2 -0
  208. package/src/components/ds-toast/ds-toast-context.tsx +79 -0
  209. package/src/components/ds-toast/ds-toast.module.scss +134 -0
  210. package/src/components/ds-toast/ds-toast.tsx +54 -0
  211. package/src/components/ds-toast/ds-toast.types.tsx +53 -0
  212. package/src/components/ds-toast/index.ts +3 -0
  213. package/src/components/ds-tooltip/ds-tooltip.module.scss +19 -0
  214. package/src/components/ds-tooltip/ds-tooltip.tsx +33 -0
  215. package/src/components/ds-tooltip/ds-tooltip.types.tsx +12 -0
  216. package/src/components/ds-tooltip/index.tsx +2 -0
  217. package/src/components/ds-typography/ds-typography.config.ts +32 -0
  218. package/src/components/ds-typography/ds-typography.module.scss +93 -0
  219. package/src/components/ds-typography/ds-typography.tsx +27 -0
  220. package/src/components/ds-typography/ds-typography.types.tsx +27 -0
  221. package/src/components/ds-typography/index.tsx +2 -0
  222. package/src/components/ds-vertical-tabs/ds-vertical-tabs.module.scss +60 -0
  223. package/src/components/ds-vertical-tabs/ds-vertical-tabs.tsx +80 -0
  224. package/src/components/ds-vertical-tabs/ds-vertical-tabs.types.ts +69 -0
  225. package/src/components/ds-vertical-tabs/index.ts +7 -0
  226. package/src/index.ts +34 -0
  227. package/src/styles/_colors.scss +65 -0
  228. package/src/styles/_grid.scss +111 -0
  229. package/src/styles/_mixin.scss +1 -0
  230. package/src/styles/_reset.scss +38 -0
  231. package/src/styles/_root.scss +390 -0
  232. package/src/styles/_scrollbars.scss +41 -0
  233. package/src/styles/_spacing.scss +47 -0
  234. package/src/styles/_typography.scss +301 -0
  235. package/src/styles/_utilities.scss +33 -0
  236. package/src/styles/_variables.scss +44 -0
  237. package/src/styles/mixins/_bounding-box.scss +53 -0
  238. package/src/styles/mixins/_list.scss +74 -0
  239. package/src/styles/shared/_dropdown.scss +89 -0
  240. package/src/styles/shared/_input.scss +365 -0
  241. package/src/styles/shared/_modal.scss +123 -0
  242. package/src/styles/styles.scss +12 -0
@@ -0,0 +1,106 @@
1
+ /* cspell:disable */
2
+ import type { FileUploadFileMimeType } from '@ark-ui/react';
3
+
4
+ /**
5
+ * File extension with leading dot
6
+ * @example '.pdf', '.jpg', '.csv'
7
+ */
8
+ export type FileExtension = `.${string}`;
9
+
10
+ /**
11
+ * Accepted file type configuration
12
+ * - Use string shorthand for common MIME types (uses built-in extensions map)
13
+ * - Use object form to override or provide custom extensions
14
+ */
15
+ export type AcceptedFileType =
16
+ | FileUploadFileMimeType
17
+ | {
18
+ mimeType: FileUploadFileMimeType;
19
+ extensions: [FileExtension, ...FileExtension[]];
20
+ };
21
+
22
+ /**
23
+ * Built-in extensions map for common MIME types
24
+ */
25
+ export const EXTENSIONS_MAP: Record<FileUploadFileMimeType, FileExtension[]> = {
26
+ // Images - specific types
27
+ 'image/png': ['.png'],
28
+ 'image/gif': ['.gif'],
29
+ 'image/jpeg': ['.jpg', '.jpeg'],
30
+ 'image/svg+xml': ['.svg'],
31
+ 'image/webp': ['.webp'],
32
+ 'image/avif': ['.avif'],
33
+ 'image/heic': ['.heic', '.heif'],
34
+ 'image/bmp': ['.bmp'],
35
+
36
+ // Applications
37
+ 'application/pdf': ['.pdf'],
38
+ 'application/zip': ['.zip'],
39
+ 'application/json': ['.json'],
40
+ 'application/xml': ['.xml'],
41
+ 'application/msword': ['.doc'],
42
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
43
+ 'application/vnd.ms-excel': ['.xls'],
44
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'],
45
+ 'application/vnd.ms-powerpoint': ['.ppt'],
46
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['.pptx'],
47
+ 'application/rtf': ['.rtf'],
48
+ 'application/x-rar': ['.rar'],
49
+ 'application/x-7z-compressed': ['.7z'],
50
+ 'application/x-tar': ['.tar'],
51
+ 'application/vnd.microsoft.portable-executable': ['.exe', '.dll'],
52
+
53
+ // Text
54
+ 'text/css': ['.css'],
55
+ 'text/csv': ['.csv'],
56
+ 'text/html': ['.html', '.htm'],
57
+ 'text/markdown': ['.md', '.markdown'],
58
+ 'text/plain': ['.txt'],
59
+
60
+ // Fonts
61
+ 'font/ttf': ['.ttf'],
62
+ 'font/otf': ['.otf'],
63
+ 'font/woff': ['.woff'],
64
+ 'font/woff2': ['.woff2'],
65
+ 'font/eot': ['.eot'],
66
+ 'font/svg': ['.svg'],
67
+
68
+ // Video
69
+ 'video/mp4': ['.mp4'],
70
+ 'video/webm': ['.webm'],
71
+ 'video/ogg': ['.ogv'],
72
+ 'video/quicktime': ['.mov'],
73
+ 'video/x-msvideo': ['.avi'],
74
+
75
+ // Audio
76
+ 'audio/mpeg': ['.mp3'],
77
+ 'audio/ogg': ['.ogg', '.oga'],
78
+ 'audio/wav': ['.wav'],
79
+ 'audio/webm': ['.weba'],
80
+ 'audio/aac': ['.aac'],
81
+ 'audio/flac': ['.flac'],
82
+ 'audio/x-m4a': ['.m4a'],
83
+
84
+ // Wildcards
85
+ 'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.avif', '.heic', '.heif'],
86
+ 'audio/*': ['.mp3', '.wav', '.ogg', '.oga', '.m4a', '.flac', '.aac', '.weba'],
87
+ 'video/*': ['.mp4', '.webm', '.ogv', '.mov', '.avi'],
88
+ 'text/*': ['.txt', '.html', '.htm', '.css', '.csv', '.md', '.markdown'],
89
+ 'application/*': [
90
+ '.pdf',
91
+ '.zip',
92
+ '.json',
93
+ '.xml',
94
+ '.doc',
95
+ '.docx',
96
+ '.xls',
97
+ '.xlsx',
98
+ '.ppt',
99
+ '.pptx',
100
+ '.rtf',
101
+ '.rar',
102
+ '.7z',
103
+ '.tar',
104
+ ],
105
+ 'font/*': ['.ttf', '.otf', '.woff', '.woff2', '.eot'],
106
+ } as const;
@@ -0,0 +1,25 @@
1
+ import type { FileUploadFileMimeType } from '@ark-ui/react';
2
+ import { type AcceptedFileType, type FileExtension, EXTENSIONS_MAP } from '../types/accept-types';
3
+
4
+ /**
5
+ * Extract file extensions from accept configuration
6
+ * @param accept Array of accepted file types
7
+ * @returns Array of file extensions
8
+ */
9
+ export function getFileExtensions(accept: AcceptedFileType[]): FileExtension[] {
10
+ return accept.flatMap((item) => {
11
+ if (typeof item === 'string') {
12
+ return EXTENSIONS_MAP[item] ?? [];
13
+ }
14
+ return item.extensions;
15
+ });
16
+ }
17
+
18
+ /**
19
+ * Extract MIME types from accept configuration
20
+ * @param accept Array of accepted file types
21
+ * @returns Array of MIME types
22
+ */
23
+ export function getMimeTypes(accept: AcceptedFileType[]): FileUploadFileMimeType[] {
24
+ return accept.map((item) => (typeof item === 'string' ? item : item.mimeType));
25
+ }
@@ -0,0 +1,21 @@
1
+ import type { AcceptedFileType } from '../types/accept-types';
2
+
3
+ /**
4
+ * Default allowed file types for the file upload component
5
+ */
6
+ export const DEFAULT_ALLOWED_FILE_TYPES: AcceptedFileType[] = [
7
+ 'application/pdf',
8
+ 'text/csv',
9
+ 'application/zip',
10
+ 'application/x-zip-compressed',
11
+ ];
12
+
13
+ /**
14
+ * Default maximum file size in bytes (25MB)
15
+ */
16
+ export const DEFAULT_MAX_FILE_SIZE = 25_000_000;
17
+
18
+ /**
19
+ * Default maximum number of files allowed
20
+ */
21
+ export const DEFAULT_MAX_FILES = 5;
@@ -0,0 +1,18 @@
1
+ import type { FileError, UploadedFile, UploadFileStatus } from '../ds-file-upload-api.types';
2
+
3
+ /**
4
+ * Creates an UploadedFile object from a File with additional metadata
5
+ */
6
+ export function createUploadedFile(file: File, status: UploadFileStatus, errors?: FileError[]): UploadedFile {
7
+ return {
8
+ // eslint-disable-next-line @typescript-eslint/no-misused-spread -- We're fine with losing the prototype here
9
+ ...file,
10
+ id: `${file.name}-${String(Date.now())}-${String(Math.random())}`,
11
+ name: file.name,
12
+ size: file.size,
13
+ type: file.type,
14
+ progress: 0,
15
+ status,
16
+ errors,
17
+ } satisfies UploadedFile;
18
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Format file size to human-readable format using SI units (decimal base)
3
+ */
4
+ export function formatFileSize(bytes: number): string {
5
+ if (bytes === 0) {
6
+ return '0 B';
7
+ }
8
+
9
+ const k = 1000; // Decimal base (SI standard)
10
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
11
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
12
+ const size = bytes / Math.pow(k, i);
13
+
14
+ return `${size.toFixed(2)} ${sizes[i]}`;
15
+ }
@@ -0,0 +1,39 @@
1
+ import type { AcceptedFileType } from '../types/accept-types';
2
+ import { getFileExtensions } from './accept-utils';
3
+ import { formatFileSize } from './format-file-size';
4
+
5
+ /**
6
+ * Generate helper text based on validation props
7
+ */
8
+ export function generateHelperText(
9
+ accept: AcceptedFileType[],
10
+ maxFileSize: number,
11
+ maxFiles: number,
12
+ ): string {
13
+ // Extract file extensions from accept configuration
14
+ const extensions = getFileExtensions(accept);
15
+ const uniqueExtensions = [...new Set(extensions)];
16
+ const fileTypes = uniqueExtensions.map((ext) => ext.toUpperCase()).join(', ');
17
+
18
+ // Format file size
19
+ const maxSizeText = formatFileSize(maxFileSize);
20
+
21
+ // Build helper text
22
+ const parts: string[] = [];
23
+
24
+ if (fileTypes) {
25
+ parts.push(`Only ${fileTypes} files`);
26
+ }
27
+
28
+ if (maxFileSize < Infinity) {
29
+ parts.push(`File size ${maxSizeText} max`);
30
+ }
31
+
32
+ if (maxFiles === 1) {
33
+ parts.push('Only 1 file');
34
+ } else if (maxFiles > 1) {
35
+ parts.push(`Up to ${String(maxFiles)} files`);
36
+ }
37
+
38
+ return parts.join('. ') + '.';
39
+ }
@@ -0,0 +1,17 @@
1
+ import type { FileError } from '../ds-file-upload-api.types';
2
+
3
+ const FILE_ERROR_MESSAGES: Record<FileError, string> = {
4
+ FILE_TOO_LARGE: 'File size exceeds the maximum limit',
5
+ FILE_INVALID_TYPE: 'File type is not allowed',
6
+ TOO_MANY_FILES: 'Too many files selected',
7
+ FILE_TOO_SMALL: 'File size is too small',
8
+ FILE_INVALID: 'File is invalid',
9
+ FILE_EXISTS: 'File already exists',
10
+ };
11
+
12
+ /**
13
+ * Map FileUploadFileError to user-friendly error message
14
+ */
15
+ export function getErrorMessage(error: FileError): string {
16
+ return FILE_ERROR_MESSAGES[error] || error || 'File validation failed';
17
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Check if two files are equal based on name, size, and type
3
+ *
4
+ * @see https://github.com/chakra-ui/zag/blob/698fff1d2/packages/utilities/file-utils/src/is-file-equal.ts
5
+ */
6
+ export function isFileEqual(file1: File, file2: File): boolean {
7
+ return file1.name === file2.name && file1.size === file2.size && file1.type === file2.type;
8
+ }
@@ -0,0 +1,135 @@
1
+ @use '../../styles/typography';
2
+
3
+ $form-control-description-max-lines: 2;
4
+ $form-control-description-line-height: 1.4;
5
+ $form-control-description-max-height: calc(
6
+ $form-control-description-line-height * $form-control-description-max-lines * 1em
7
+ );
8
+
9
+ .container {
10
+ display: flex;
11
+ flex-direction: column;
12
+ gap: var(--spacing-4xs);
13
+
14
+ &.success {
15
+ .message {
16
+ color: var(--color-background-success-strong);
17
+ }
18
+ }
19
+
20
+ &.warning {
21
+ .message {
22
+ color: var(--color-font-warning);
23
+ }
24
+ }
25
+
26
+ &.error {
27
+ --form-control-border-color: var(--color-background-danger-strong);
28
+ --form-control-selection-color: var(--color-background-danger-weak);
29
+
30
+ .message {
31
+ color: var(--color-background-danger-strong);
32
+ }
33
+ }
34
+ }
35
+
36
+ .labelContainer {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: var(--spacing-4xs);
40
+ }
41
+
42
+ .label {
43
+ @include typography.body-sm-reg;
44
+ color: var(--color-font-main);
45
+
46
+ &.required::after {
47
+ @include typography.body-sm-reg;
48
+ content: '*';
49
+ position: relative;
50
+ top: -1px;
51
+ right: -1px;
52
+ color: var(--color-icon-danger);
53
+ }
54
+
55
+ &.disabled {
56
+ color: var(--color-background-disabled);
57
+
58
+ &::after {
59
+ color: var(--color-font-disabled);
60
+ }
61
+ }
62
+ }
63
+
64
+ .endAdornment {
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ }
69
+
70
+ .description {
71
+ @include typography.p-s;
72
+ color: var(--neutral-2);
73
+ line-height: $form-control-description-line-height;
74
+ max-height: $form-control-description-max-height;
75
+ overflow: hidden;
76
+ display: -webkit-box;
77
+ -webkit-line-clamp: $form-control-description-max-lines;
78
+ -webkit-box-orient: vertical;
79
+ word-wrap: break-word;
80
+ }
81
+
82
+ .controlWrapper {
83
+ position: relative;
84
+
85
+ &.input {
86
+ .control {
87
+ padding: 7px 16px;
88
+ line-height: 24px;
89
+ font-style: normal;
90
+ }
91
+
92
+ .icon {
93
+ top: 50%;
94
+ transform: translateY(-50%);
95
+ }
96
+ }
97
+
98
+ &.textarea {
99
+ .control {
100
+ padding: 12px 16px;
101
+ min-height: 100px;
102
+
103
+ &:disabled {
104
+ resize: none;
105
+ }
106
+ }
107
+
108
+ .icon {
109
+ top: 10px;
110
+ }
111
+ }
112
+
113
+ .control.withIcon {
114
+ padding-left: 40px;
115
+ }
116
+
117
+ .icon {
118
+ position: absolute;
119
+ pointer-events: none;
120
+ color: var(--neutral-3);
121
+ }
122
+
123
+ .icon {
124
+ left: 12px;
125
+ }
126
+ }
127
+
128
+ .message {
129
+ @include typography.body-xs-reg;
130
+ color: var(--color-font-secondary);
131
+ display: flex;
132
+ align-items: center;
133
+ gap: 4px;
134
+ padding-top: 2px;
135
+ }
@@ -0,0 +1,94 @@
1
+ import { type ComponentType, createContext, useContext, useId } from 'react';
2
+ import type React from 'react';
3
+ import classNames from 'classnames';
4
+ import { DsIcon } from '../ds-icon';
5
+ import { DsSelect } from '../ds-select';
6
+ import { DsTextInput } from '../ds-text-input';
7
+ import { DsTextarea } from '../ds-textarea';
8
+ import { DsNumberInput } from '../ds-number-input';
9
+ import { DsPasswordInput } from '../ds-password-input';
10
+ import type { DsFormControlDescriptionProps, DsFormControlProps } from './ds-form-control.types';
11
+ import styles from './ds-form-control.module.scss';
12
+
13
+ const FormControlContext = createContext<{ controlId: string } | null>(null);
14
+
15
+ const useFormControlContext = () => {
16
+ const context = useContext(FormControlContext);
17
+ if (!context) {
18
+ throw new Error('useFormControlContext must be used within DsFormControl');
19
+ }
20
+ return context;
21
+ };
22
+
23
+ /**
24
+ * HOC that automatically injects the controlId from form control context
25
+ * into any component that expects an 'id' prop.
26
+ *
27
+ * @param Component - The component to wrap with form control context
28
+ * @returns A new component that automatically receives the controlId
29
+ */
30
+ const controlify = <TProps extends { id?: string }>(Component: ComponentType<TProps>) => {
31
+ return function WrappedFormControl(props: TProps) {
32
+ const { controlId } = useFormControlContext();
33
+ return <Component id={controlId} {...props} />;
34
+ };
35
+ };
36
+
37
+ const DsFormControlDescription: React.FC<DsFormControlDescriptionProps> = ({ children, className }) => {
38
+ return <div className={classNames(styles.description, className)}>{children}</div>;
39
+ };
40
+
41
+ const DsFormControl = ({
42
+ id,
43
+ status,
44
+ label,
45
+ required = false,
46
+ slots,
47
+ message,
48
+ messageIcon = 'info',
49
+ className,
50
+ style,
51
+ children,
52
+ }: DsFormControlProps) => {
53
+ const generatedId = useId();
54
+ const controlId = id || generatedId;
55
+
56
+ return (
57
+ <FormControlContext.Provider value={{ controlId }}>
58
+ <div
59
+ className={classNames(styles.container, status && message && styles[status], className)}
60
+ style={style}
61
+ >
62
+ <div className={styles.labelContainer}>
63
+ <label
64
+ htmlFor={controlId}
65
+ className={classNames(styles.label, {
66
+ [styles.required]: required,
67
+ })}
68
+ >
69
+ {label}
70
+ </label>
71
+ {slots?.endAdornment && <div className={styles.endAdornment}>{slots.endAdornment}</div>}
72
+ </div>
73
+
74
+ {children}
75
+
76
+ {message && (
77
+ <div className={styles.message}>
78
+ <DsIcon icon={messageIcon} size="tiny" filled />
79
+ <span className={styles.messageText}>{message}</span>
80
+ </div>
81
+ )}
82
+ </div>
83
+ </FormControlContext.Provider>
84
+ );
85
+ };
86
+
87
+ DsFormControl.TextInput = controlify(DsTextInput);
88
+ DsFormControl.NumberInput = controlify(DsNumberInput);
89
+ DsFormControl.PasswordInput = controlify(DsPasswordInput);
90
+ DsFormControl.Textarea = controlify(DsTextarea);
91
+ DsFormControl.Select = controlify(DsSelect);
92
+ DsFormControl.Description = DsFormControlDescription;
93
+
94
+ export default DsFormControl;
@@ -0,0 +1,58 @@
1
+ import type React from 'react';
2
+ import type { IconType } from '../ds-icon';
3
+
4
+ export const controlStatuses = ['info', 'success', 'error', 'warning'] as const;
5
+ export type ControlStatus = (typeof controlStatuses)[number];
6
+
7
+ export interface DsFormControlProps extends React.PropsWithChildren {
8
+ /**
9
+ * Unique identifier for the control
10
+ */
11
+ id?: string;
12
+ /**
13
+ * Visual status
14
+ */
15
+ status?: ControlStatus;
16
+ /**
17
+ * Label text
18
+ */
19
+ label: string;
20
+ /**
21
+ * Marks the field as required
22
+ */
23
+ required?: boolean;
24
+
25
+ slots?: {
26
+ /**
27
+ * Adornment to display at the end of the label
28
+ */
29
+ endAdornment?: React.ReactNode;
30
+ };
31
+ /**
32
+ * Message under the control
33
+ */
34
+ message?: string;
35
+ /**
36
+ * Icon shown next to message
37
+ */
38
+ messageIcon?: IconType;
39
+ /**
40
+ * Additional CSS class names
41
+ */
42
+ className?: string;
43
+ /**
44
+ * Additional styles to apply to the component
45
+ */
46
+ style?: React.CSSProperties;
47
+ }
48
+
49
+ export interface DsFormControlDescriptionProps {
50
+ /**
51
+ * The description content
52
+ */
53
+ children: React.ReactNode;
54
+ /**
55
+ * Additional CSS class names
56
+ */
57
+ className?: string;
58
+ }
@@ -0,0 +1,2 @@
1
+ export { default as DsFormControl } from './ds-form-control';
2
+ export * from './ds-form-control.types';
File without changes
@@ -0,0 +1,43 @@
1
+ import type React from 'react';
2
+ import classNames from 'classnames';
3
+ import type { DsGridItemProps, DsGridProps } from './ds-grid.types';
4
+
5
+ /**
6
+ * Design system Grid component
7
+ */
8
+ export const DsGrid: React.FC<DsGridProps> = ({ children, columns, rows, className }) => {
9
+ const gridClass = classNames(
10
+ 'ds-grid',
11
+ {
12
+ [`ds-grid-cols-${String(columns)}`]: columns,
13
+ [`ds-grid-rows-${String(rows)}`]: rows,
14
+ },
15
+ className,
16
+ );
17
+
18
+ return <div className={gridClass}>{children}</div>;
19
+ };
20
+
21
+ /**
22
+ * Design system GridItem component
23
+ */
24
+ export const DsGridItem: React.FC<DsGridItemProps> = ({
25
+ children,
26
+ colSpan,
27
+ colStart,
28
+ rowSpan,
29
+ rowStart,
30
+ className,
31
+ }) => {
32
+ const gridItemClass = classNames(
33
+ {
34
+ [`ds-grid-col-span-${String(colSpan)}`]: colSpan,
35
+ [`ds-grid-col-start-${String(colStart)}`]: colStart,
36
+ [`ds-grid-row-span-${String(rowSpan)}`]: rowSpan,
37
+ [`ds-grid-row-start-${String(rowStart)}`]: rowStart,
38
+ },
39
+ className,
40
+ );
41
+
42
+ return <div className={gridItemClass}>{children}</div>;
43
+ };
@@ -0,0 +1,55 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface DsGridProps {
4
+ /**
5
+ * The content to be rendered inside the grid
6
+ */
7
+ children: ReactNode;
8
+
9
+ /**
10
+ * Number of rows in the grid (defaults to 1)
11
+ */
12
+ rows?: 1 | 2 | 4 | 6 | 8;
13
+
14
+ /**
15
+ * Number of columns in the grid (defaults to 12)
16
+ */
17
+ columns?: 2 | 4 | 6 | 8 | 10 | 12;
18
+
19
+ /**
20
+ * Custom class names to apply to the grid
21
+ */
22
+ className?: string;
23
+ }
24
+
25
+ export interface DsGridItemProps {
26
+ /**
27
+ * The content to be rendered inside the grid item
28
+ */
29
+ children: ReactNode;
30
+
31
+ /**
32
+ * Number of columns the item spans (1-12) or 'full'
33
+ */
34
+ colSpan?: number | 'full';
35
+
36
+ /**
37
+ * Starting column for the item (1-11)
38
+ */
39
+ colStart?: number;
40
+
41
+ /**
42
+ * Number of rows the item spans (1-8) or 'full'
43
+ */
44
+ rowSpan?: number | 'full';
45
+
46
+ /**
47
+ * Starting row for the item (1-7)
48
+ */
49
+ rowStart?: number;
50
+
51
+ /**
52
+ * Custom class names to apply to the grid item
53
+ */
54
+ className?: string;
55
+ }
@@ -0,0 +1,2 @@
1
+ export * from './ds-grid';
2
+ export * from './ds-grid.types';
@@ -0,0 +1,25 @@
1
+ .icon {
2
+ &.extra-large {
3
+ font-size: var(--icon-width-extra-large);
4
+ }
5
+
6
+ &.large {
7
+ font-size: var(--icon-width-large);
8
+ }
9
+
10
+ &.medium {
11
+ font-size: var(--icon-width-medium);
12
+ }
13
+
14
+ &.small {
15
+ font-size: var(--icon-width-small);
16
+ }
17
+
18
+ &.tiny {
19
+ font-size: var(--icon-width-tiny);
20
+ }
21
+ }
22
+
23
+ .filled {
24
+ font-variation-settings: 'FILL' 1;
25
+ }