@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,76 @@
1
+ import { type RefObject, useLayoutEffect, useState } from 'react';
2
+
3
+ interface UseChipRowCalculationProps {
4
+ chipsWrapperRef: RefObject<HTMLDivElement | null>;
5
+ totalFilters: number;
6
+ }
7
+
8
+ /**
9
+ * Custom hook to calculate how many chips can fit in 2 rows
10
+ * Uses a simple approach: render all, measure positions, hide overflow
11
+ */
12
+ export const useChipRowCalculation = ({ chipsWrapperRef, totalFilters }: UseChipRowCalculationProps) => {
13
+ const [visibleCount, setVisibleCount] = useState(totalFilters);
14
+
15
+ useLayoutEffect(() => {
16
+ const calculateVisibleChips = () => {
17
+ if (!chipsWrapperRef.current) {
18
+ return;
19
+ }
20
+
21
+ const wrapper = chipsWrapperRef.current;
22
+ const children = Array.from(wrapper.children) as HTMLElement[];
23
+
24
+ if (children.length === 0) {
25
+ return;
26
+ }
27
+
28
+ const cs = getComputedStyle(wrapper);
29
+ const gap = parseFloat(cs.columnGap || cs.gap || '0') || 8;
30
+ let index;
31
+ let line = 0;
32
+ let total = 0;
33
+
34
+ for (index = 0; index < children.length; index++) {
35
+ const current = children[index];
36
+ const offset = current.offsetWidth === wrapper.clientWidth ? 0 : gap;
37
+ const next = offset + current.offsetWidth;
38
+
39
+ if (total + next >= wrapper.clientWidth) {
40
+ line++;
41
+ if (line >= 2) {
42
+ break;
43
+ }
44
+ total = next;
45
+ } else {
46
+ total += next;
47
+ }
48
+ }
49
+
50
+ const result = Math.max(1, line < 2 ? index : index - 1);
51
+ setVisibleCount(result);
52
+ };
53
+
54
+ // Use requestAnimationFrame to ensure DOM is fully laid out
55
+ const rafId = requestAnimationFrame(() => {
56
+ calculateVisibleChips();
57
+ });
58
+
59
+ const resizeObserver = new ResizeObserver(() => {
60
+ requestAnimationFrame(() => {
61
+ calculateVisibleChips();
62
+ });
63
+ });
64
+
65
+ if (chipsWrapperRef.current) {
66
+ resizeObserver.observe(chipsWrapperRef.current);
67
+ }
68
+
69
+ return () => {
70
+ cancelAnimationFrame(rafId);
71
+ resizeObserver.disconnect();
72
+ };
73
+ }, [chipsWrapperRef, totalFilters]);
74
+
75
+ return visibleCount;
76
+ };
@@ -0,0 +1,2 @@
1
+ export { default as DsChipGroup } from './ds-chip-group';
2
+ export type { DsChipGroupProps, ChipItem } from './ds-chip-group.types';
@@ -0,0 +1,58 @@
1
+ @use '../../styles/typography';
2
+ @use '../../styles/shared/modal' as shared;
3
+
4
+ $max-width: 400px;
5
+ $min-height: 188px;
6
+ $max-height: 244px;
7
+
8
+ .overlay {
9
+ @include shared.overlay-base;
10
+ }
11
+
12
+ .modal {
13
+ @include shared.modal-base;
14
+ inline-size: $max-width;
15
+ }
16
+
17
+ .content {
18
+ @include shared.content-base;
19
+ min-block-size: $min-height;
20
+ max-block-size: $max-height;
21
+ padding: var(--spacing-md) var(--spacing-lg);
22
+ gap: var(--spacing-standard);
23
+ }
24
+
25
+ .header {
26
+ @include shared.header-base;
27
+ gap: var(--spacing-xs);
28
+ padding-bottom: var(--spacing-xs);
29
+ }
30
+
31
+ .footer {
32
+ @include shared.footer-base(false);
33
+ display: flex;
34
+
35
+ .actions {
36
+ @include shared.actions-base;
37
+ flex-grow: 1;
38
+ }
39
+ }
40
+
41
+ .title {
42
+ @include shared.title-base;
43
+ flex-grow: 1;
44
+ }
45
+
46
+ .icon {
47
+ flex-shrink: 0;
48
+ }
49
+
50
+ .body {
51
+ @include shared.body-base;
52
+ @include typography.body-sm-reg;
53
+ color: var(--color-font-main);
54
+ }
55
+
56
+ .cancel {
57
+ margin-right: auto;
58
+ }
@@ -0,0 +1,121 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ import { Dialog } from '@ark-ui/react/dialog';
3
+ import { Portal } from '@ark-ui/react/portal';
4
+ import classNames from 'classnames';
5
+ import { DsIcon } from '../ds-icon';
6
+ import type { DsConfirmationProps } from './ds-confirmation.types';
7
+ import styles from './ds-confirmation.module.scss';
8
+ import DsTypography from '../ds-typography/ds-typography';
9
+
10
+ /**
11
+ * Composable confirmation modal dialog.
12
+ */
13
+ export const DsConfirmation = ({ open, onOpenChange, style, className, children }: DsConfirmationProps) => {
14
+ const handleOpenChange = (details: { open: boolean }) => {
15
+ onOpenChange(details.open);
16
+ };
17
+
18
+ return (
19
+ <Dialog.Root
20
+ open={open}
21
+ onOpenChange={handleOpenChange}
22
+ modal={true}
23
+ closeOnEscape={true}
24
+ closeOnInteractOutside={true}
25
+ >
26
+ <Portal>
27
+ <Dialog.Backdrop className={styles.overlay} />
28
+ <Dialog.Positioner>
29
+ <Dialog.Content className={classNames(styles.modal, className)}>
30
+ <div style={style} className={styles.content}>
31
+ {children}
32
+ </div>
33
+ </Dialog.Content>
34
+ </Dialog.Positioner>
35
+ </Portal>
36
+ </Dialog.Root>
37
+ );
38
+ };
39
+
40
+ const Header = ({
41
+ style,
42
+ className,
43
+ children,
44
+ }: {
45
+ style?: CSSProperties;
46
+ className?: string;
47
+ children: ReactNode;
48
+ }) => (
49
+ <div style={style} className={classNames(styles.header, className)}>
50
+ {children}
51
+ </div>
52
+ );
53
+
54
+ const Title = ({
55
+ style,
56
+ className,
57
+ children,
58
+ }: {
59
+ style?: CSSProperties;
60
+ className?: string;
61
+ children: ReactNode;
62
+ }) => (
63
+ <Dialog.Title className={classNames(styles.title, className)} style={style} asChild>
64
+ <DsTypography variant="heading4">{children}</DsTypography>
65
+ </Dialog.Title>
66
+ );
67
+
68
+ const CloseTrigger = ({ style, className }: { style?: CSSProperties; className?: string }) => (
69
+ <Dialog.CloseTrigger style={style} className={className}>
70
+ <DsIcon icon="close" size="small"></DsIcon>
71
+ </Dialog.CloseTrigger>
72
+ );
73
+
74
+ const Body = ({
75
+ style,
76
+ className,
77
+ children,
78
+ }: {
79
+ style?: CSSProperties;
80
+ className?: string;
81
+ children: ReactNode;
82
+ }) => (
83
+ <div style={style} className={classNames(styles.body, className)}>
84
+ {children}
85
+ </div>
86
+ );
87
+
88
+ const Footer = ({
89
+ style,
90
+ className,
91
+ children,
92
+ }: {
93
+ style?: CSSProperties;
94
+ className?: string;
95
+ children: ReactNode;
96
+ }) => (
97
+ <div style={style} className={classNames(styles.footer, className)}>
98
+ {children}
99
+ </div>
100
+ );
101
+
102
+ const Actions = ({
103
+ style,
104
+ className,
105
+ children,
106
+ }: {
107
+ style?: CSSProperties;
108
+ className?: string;
109
+ children: ReactNode;
110
+ }) => (
111
+ <div style={style} className={classNames(styles.actions, className)}>
112
+ {children}
113
+ </div>
114
+ );
115
+
116
+ DsConfirmation.Header = Header;
117
+ DsConfirmation.Title = Title;
118
+ DsConfirmation.CloseTrigger = CloseTrigger;
119
+ DsConfirmation.Body = Body;
120
+ DsConfirmation.Footer = Footer;
121
+ DsConfirmation.Actions = Actions;
@@ -0,0 +1,28 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+
3
+ /**
4
+ * Props for the DsConfirmation component
5
+ */
6
+ export interface DsConfirmationProps {
7
+ /**
8
+ * Whether the modal is open
9
+ */
10
+ open: boolean;
11
+ /**
12
+ * Callback when modal open state changes
13
+ * @param open - whether the modal is open
14
+ */
15
+ onOpenChange: (open: boolean) => void;
16
+ /**
17
+ * Additional CSS styles
18
+ */
19
+ style?: CSSProperties;
20
+ /**
21
+ * Additional CSS class name
22
+ */
23
+ className?: string;
24
+ /**
25
+ * Modal body content
26
+ */
27
+ children: ReactNode;
28
+ }
@@ -0,0 +1,2 @@
1
+ export { DsConfirmation } from './ds-confirmation';
2
+ export type { DsConfirmationProps } from './ds-confirmation.types';
@@ -0,0 +1,50 @@
1
+ @use '../../styles/typography';
2
+ @use '../../styles/mixins/bounding-box';
3
+
4
+ .overlay {
5
+ position: fixed;
6
+ inset: 0;
7
+ background: rgba(0, 0, 0, 0.32);
8
+ z-index: 1199;
9
+ }
10
+
11
+ .dialog {
12
+ @include bounding-box.bounding-box-vars;
13
+
14
+ --_shadow-size: 18px;
15
+ --_shadow-y-offset: 6px;
16
+
17
+ background: var(--white, #fff);
18
+ border-radius: 8px;
19
+ box-shadow: 0 var(--_shadow-y-offset) var(--_shadow-size) 0 rgba(4, 69, 204, 0.3);
20
+ padding: 12px;
21
+ min-width: 320px;
22
+ min-height: 120px;
23
+ z-index: 1200;
24
+ position: fixed;
25
+ top: 50%;
26
+ left: 50%;
27
+ transform: translate(-50%, -50%);
28
+ max-width: 90vw;
29
+ max-height: 90vh;
30
+ display: flex;
31
+ flex-direction: column;
32
+ }
33
+
34
+ .title {
35
+ @include typography.p-base;
36
+ @include typography.medium;
37
+ color: var(--neutral-1);
38
+ }
39
+
40
+ .description {
41
+ @include typography.p-base;
42
+ color: var(--neutral-3);
43
+ margin-bottom: 16px;
44
+ }
45
+
46
+ .customPlacement {
47
+ transform: none !important;
48
+ max-width: none;
49
+ max-height: none;
50
+ }
@@ -0,0 +1,70 @@
1
+ import type React from 'react';
2
+ import * as RadixDialog from '@radix-ui/react-dialog';
3
+ import { Root as VisuallyHidden } from '@radix-ui/react-visually-hidden';
4
+ import classNames from 'classnames';
5
+ import styles from './ds-dialog.module.scss';
6
+ import type { DsDialogProps } from './ds-dialog.types';
7
+
8
+ const DsDialog: React.FC<DsDialogProps> = ({
9
+ open,
10
+ onOpenChange,
11
+ title,
12
+ hideTitle,
13
+ description,
14
+ hideDescription,
15
+ children,
16
+ className,
17
+ anchorRef,
18
+ customPosition,
19
+ modal = true,
20
+ }) => {
21
+ let style: React.CSSProperties = {};
22
+ if (customPosition) {
23
+ style = { position: 'fixed', ...customPosition };
24
+ } else if (anchorRef?.current) {
25
+ const rect = anchorRef.current.getBoundingClientRect();
26
+ style = { position: 'fixed', top: rect.bottom, left: rect.left };
27
+ }
28
+
29
+ return (
30
+ <RadixDialog.Root open={open} onOpenChange={onOpenChange}>
31
+ <RadixDialog.Portal>
32
+ {modal && <RadixDialog.Overlay className={styles.overlay} />}
33
+ <RadixDialog.Content
34
+ className={classNames(styles.dialog, className, {
35
+ [styles.customPlacement]: customPosition || anchorRef,
36
+ })}
37
+ style={customPosition || anchorRef ? style : undefined}
38
+ >
39
+ <RadixDialog.Title asChild>
40
+ {hideTitle ? (
41
+ <VisuallyHidden>
42
+ <RadixDialog.Title className={styles.title}>{title}</RadixDialog.Title>
43
+ </VisuallyHidden>
44
+ ) : (
45
+ <RadixDialog.Title className={styles.title}>{title}</RadixDialog.Title>
46
+ )}
47
+ </RadixDialog.Title>
48
+ {description && (
49
+ <RadixDialog.Description asChild>
50
+ {hideDescription ? (
51
+ <VisuallyHidden>
52
+ <RadixDialog.Description className={styles.description}>
53
+ {description}
54
+ </RadixDialog.Description>
55
+ </VisuallyHidden>
56
+ ) : (
57
+ <RadixDialog.Description className={styles.description}>
58
+ {description}
59
+ </RadixDialog.Description>
60
+ )}
61
+ </RadixDialog.Description>
62
+ )}
63
+ {children}
64
+ </RadixDialog.Content>
65
+ </RadixDialog.Portal>
66
+ </RadixDialog.Root>
67
+ );
68
+ };
69
+
70
+ export default DsDialog;
@@ -0,0 +1,48 @@
1
+ import type React from 'react';
2
+
3
+ export interface DsDialogProps {
4
+ /**
5
+ * Controls whether the dialog is open.
6
+ */
7
+ open: boolean;
8
+ /**
9
+ * Callback fired when the open state should change.
10
+ */
11
+ onOpenChange?: (open: boolean) => void;
12
+ /**
13
+ * The accessible title for the dialog. Required for accessibility.
14
+ */
15
+ title: string;
16
+ /**
17
+ * If true, the dialog title will be visually hidden but accessible to screen readers.
18
+ */
19
+ hideTitle?: boolean;
20
+ /**
21
+ * The accessible description for the dialog. Optional, but recommended for accessibility.
22
+ */
23
+ description?: string;
24
+ /**
25
+ * If true, the dialog description will be visually hidden but accessible to screen readers.
26
+ */
27
+ hideDescription?: boolean;
28
+ /**
29
+ * The content to render inside the dialog.
30
+ */
31
+ children: React.ReactNode;
32
+ /**
33
+ * Additional CSS class names for the dialog container.
34
+ */
35
+ className?: string;
36
+ /**
37
+ * Ref to the element the dialog should be anchored to (for relative placement)
38
+ */
39
+ anchorRef?: React.RefObject<HTMLElement>;
40
+ /**
41
+ * Custom fixed position (e.g., { top: number, left: number })
42
+ */
43
+ customPosition?: { top: number; left: number };
44
+ /**
45
+ * If true, show modal overlay and center dialog (default: true)
46
+ */
47
+ modal?: boolean;
48
+ }
@@ -0,0 +1,2 @@
1
+ export { default as DsDialog } from './ds-dialog';
2
+ export * from './ds-dialog.types';
@@ -0,0 +1,212 @@
1
+ @use '../../styles/grid';
2
+
3
+ .backdrop {
4
+ position: absolute;
5
+ inset: 0;
6
+ background: var(--Background-background-overlay, rgba(0, 26, 71, 0.2));
7
+ z-index: 1000;
8
+
9
+ &[data-state='open'] {
10
+ animation: 0.3s fade-in-backdrop ease-in-out both;
11
+ }
12
+
13
+ &[data-state='closed'] {
14
+ animation: 0.2s fade-out-backdrop ease-in-out both;
15
+ }
16
+ }
17
+
18
+ @keyframes fade-in-backdrop {
19
+ 0% {
20
+ opacity: 0;
21
+ }
22
+
23
+ 100% {
24
+ opacity: 1;
25
+ }
26
+ }
27
+
28
+ @keyframes fade-out-backdrop {
29
+ 0% {
30
+ opacity: 1;
31
+ }
32
+
33
+ 100% {
34
+ opacity: 0;
35
+ }
36
+ }
37
+
38
+ .positioner {
39
+ position: absolute;
40
+ inset: 0;
41
+ overflow: hidden;
42
+ pointer-events: none;
43
+ }
44
+
45
+ .drawer {
46
+ position: absolute;
47
+ display: block;
48
+ top: 0;
49
+ bottom: 0;
50
+ background: var(--color-background);
51
+ box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.22);
52
+ z-index: 1200;
53
+ pointer-events: auto;
54
+ overflow: hidden;
55
+ transition:
56
+ transform 0.2s ease,
57
+ width 0.2s ease;
58
+
59
+ &.position-end {
60
+ right: 0;
61
+ transform-origin: 100% 50%;
62
+ transform: translateX(100%);
63
+
64
+ &[data-state='open'] {
65
+ animation: 0.5s slide-in-drawer-end ease-out both;
66
+ }
67
+
68
+ &[data-state='closed'] {
69
+ animation: 0.25s slide-out-drawer-end both;
70
+ }
71
+ }
72
+
73
+ &.position-start {
74
+ left: 0;
75
+ transform: translateX(-100%);
76
+ transform-origin: 0 50%;
77
+
78
+ &[data-state='open'] {
79
+ animation: 0.5s slide-in-drawer-start ease-out both;
80
+ }
81
+
82
+ &[data-state='closed'] {
83
+ animation: 0.25s slide-out-drawer-start both;
84
+ }
85
+ }
86
+
87
+ @for $i from 1 through grid.$columns {
88
+ &.cols-#{$i} {
89
+ width: var(--col-span-#{$i});
90
+ }
91
+ }
92
+ }
93
+
94
+ @keyframes slide-in-drawer-end {
95
+ 0% {
96
+ opacity: 0;
97
+ transform: translateX(100%);
98
+ }
99
+
100
+ 50% {
101
+ opacity: 1;
102
+ transform: translateX(0);
103
+ }
104
+
105
+ 100% {
106
+ transform: translateX(0);
107
+ }
108
+ }
109
+
110
+ @keyframes slide-out-drawer-end {
111
+ 0% {
112
+ opacity: 1;
113
+ transform: translateX(0);
114
+ }
115
+
116
+ 40% {
117
+ transform: translateX(0);
118
+ }
119
+
120
+ 100% {
121
+ opacity: 0;
122
+ transform: translateX(100%);
123
+ }
124
+ }
125
+
126
+ @keyframes slide-in-drawer-start {
127
+ 0% {
128
+ opacity: 0;
129
+ transform: translateX(-100%);
130
+ }
131
+
132
+ 50% {
133
+ opacity: 1;
134
+ transform: translateX(0);
135
+ }
136
+
137
+ 100% {
138
+ transform: translateX(0);
139
+ }
140
+ }
141
+
142
+ @keyframes slide-out-drawer-start {
143
+ 0% {
144
+ opacity: 1;
145
+ transform: translateX(0);
146
+ }
147
+
148
+ 40% {
149
+ transform: translateX(0);
150
+ }
151
+
152
+ 100% {
153
+ opacity: 0;
154
+ transform: translateX(-100%);
155
+ }
156
+ }
157
+
158
+ .content {
159
+ display: flex;
160
+ flex-direction: column;
161
+ height: 100%;
162
+ overflow: hidden;
163
+ }
164
+
165
+ .header {
166
+ display: flex;
167
+ align-items: center;
168
+ justify-content: space-between;
169
+ flex-wrap: wrap;
170
+ border-bottom: 1px solid var(--color-border);
171
+ padding: var(--spacing-sm) var(--spacing-standard);
172
+ gap: var(--spacing-3xs);
173
+ }
174
+
175
+ .title {
176
+ margin: 0;
177
+ color: var(--color-font-main);
178
+ }
179
+
180
+ .closeTrigger {
181
+ display: flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ color: var(--color-icon-secondary);
185
+ }
186
+
187
+ .toolbar {
188
+ display: flex;
189
+ align-items: center;
190
+ border-bottom: 1px solid var(--color-border);
191
+ padding: var(--spacing-sm) var(--spacing-standard);
192
+ gap: var(--spacing-3xs);
193
+ }
194
+
195
+ .body {
196
+ flex: 1;
197
+ overflow: auto;
198
+ }
199
+
200
+ .footer {
201
+ display: flex;
202
+ align-items: center;
203
+ padding: var(--spacing-standard);
204
+ border-top: 1px solid var(--color-border);
205
+ }
206
+
207
+ .actions {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: var(--spacing-xs);
211
+ margin-left: auto;
212
+ }