@popsure/dirty-swan 20.0.11 → 27.0.2

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 (288) hide show
  1. package/Readme.md +10 -1
  2. package/dist/assets/checkmark.svg +1 -1
  3. package/dist/assets/icon-form-dropdown.svg +1 -1
  4. package/dist/index.css +1169 -137
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.js +8453 -13347
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/components/button/index.d.ts +1 -1
  10. package/dist/lib/components/cards/cardButton/index.d.ts +16 -0
  11. package/dist/lib/components/cards/cardWithLeftIcon/index.d.ts +2 -2
  12. package/dist/lib/components/cards/cardWithTopIcon/index.d.ts +2 -2
  13. package/dist/lib/components/cards/cardWithTopLeftIcon/index.d.ts +2 -2
  14. package/dist/lib/components/cards/icons/index.d.ts +2 -1
  15. package/dist/lib/components/cards/index.d.ts +3 -2
  16. package/dist/lib/components/comparisonTable/components/Chevron.d.ts +5 -0
  17. package/dist/lib/components/comparisonTable/components/Row/index.d.ts +12 -0
  18. package/dist/lib/components/comparisonTable/components/TableArrows/Arrow.d.ts +5 -0
  19. package/dist/lib/components/comparisonTable/components/TableArrows/index.d.ts +9 -0
  20. package/dist/lib/components/comparisonTable/components/TableInfoButton/index.d.ts +6 -0
  21. package/dist/lib/components/comparisonTable/components/TableRating/StarIcon.d.ts +5 -0
  22. package/dist/lib/components/comparisonTable/components/TableRating/ZapIcon.d.ts +5 -0
  23. package/dist/lib/components/comparisonTable/components/TableRating/index.d.ts +8 -0
  24. package/dist/lib/components/comparisonTable/components/TableRowHeader/index.d.ts +8 -0
  25. package/dist/lib/components/comparisonTable/components/TableTrueFalse.d.ts +6 -0
  26. package/dist/lib/components/comparisonTable/hooks/useActiveTableArrows.d.ts +10 -0
  27. package/dist/lib/components/comparisonTable/index.d.ts +45 -0
  28. package/dist/lib/components/downloadButton/index.d.ts +10 -0
  29. package/dist/lib/components/input/autoSuggestInput/index.d.ts +2 -1
  30. package/dist/lib/components/input/autoSuggestMultiSelect/index.d.ts +2 -1
  31. package/dist/lib/components/input/index.d.ts +3 -3
  32. package/dist/lib/components/modal/bottomModal/index.d.ts +1 -1
  33. package/dist/lib/components/modal/hooks/useOnClose.d.ts +7 -0
  34. package/dist/lib/components/modal/index.d.ts +2 -0
  35. package/dist/lib/components/modal/regularModal/index.d.ts +1 -1
  36. package/dist/lib/components/segmentedControl/index.d.ts +12 -0
  37. package/dist/lib/index.d.ts +7 -2
  38. package/dist/lib/models/download.d.ts +1 -0
  39. package/dist/lib/scss/private/_reset.scss +10 -1
  40. package/dist/lib/scss/private/base/_border_radius.scss +15 -0
  41. package/dist/lib/scss/private/base/_display.scss +4 -0
  42. package/dist/lib/scss/private/base/_grid.scss +44 -0
  43. package/dist/lib/scss/private/base/_index.scss +2 -0
  44. package/dist/lib/scss/private/base/_spacing.scss +64 -18
  45. package/dist/lib/scss/private/base/_typography.scss +7 -0
  46. package/dist/lib/scss/private/base/demo.tsx +4 -0
  47. package/dist/lib/scss/private/base/flex/_flex.scss +63 -0
  48. package/dist/lib/scss/private/base/flex/style.module.scss +24 -0
  49. package/dist/lib/scss/private/base/style.module.scss +10 -0
  50. package/dist/lib/scss/private/components/_buttons.scss +4 -4
  51. package/dist/lib/scss/private/components/_input.scss +6 -4
  52. package/dist/lib/scss/private/components/_notices.scss +13 -1
  53. package/dist/lib/scss/private/components/assets/checkmark.svg +1 -1
  54. package/dist/lib/scss/private/components/assets/icon-form-dropdown.svg +1 -1
  55. package/dist/lib/scss/public/colors/default.scss +38 -0
  56. package/dist/lib/scss/public/demo.tsx +109 -22
  57. package/package.json +6 -3
  58. package/src/App.tsx +50 -0
  59. package/src/bin/index.ts +71 -0
  60. package/src/bin/tsconfig.json +13 -0
  61. package/src/bin/util/index.test.ts +85 -0
  62. package/src/bin/util/index.ts +132 -0
  63. package/src/bin/util/test/data.json +13 -0
  64. package/src/colors.scss +1 -0
  65. package/src/font-weight.scss +1 -0
  66. package/src/grid.scss +1 -0
  67. package/src/index.tsx +37 -0
  68. package/src/intro.stories.mdx +41 -0
  69. package/src/lib/components/autocompleteAddress/demo.tsx +38 -0
  70. package/src/lib/components/autocompleteAddress/index.stories.mdx +44 -0
  71. package/src/lib/components/autocompleteAddress/index.tsx +327 -0
  72. package/src/lib/components/autocompleteAddress/mapStyle.ts +187 -0
  73. package/src/lib/components/autocompleteAddress/style.module.scss +82 -0
  74. package/src/lib/components/autocompleteAddress/util/index.test.ts +51 -0
  75. package/src/lib/components/autocompleteAddress/util/index.ts +59 -0
  76. package/src/lib/components/button/icons/index.ts +14 -0
  77. package/src/lib/components/button/icons/send-purple.svg +4 -0
  78. package/src/lib/components/button/icons/send-white.svg +4 -0
  79. package/src/lib/components/button/index.stories.mdx +121 -0
  80. package/src/lib/components/button/index.tsx +64 -0
  81. package/src/lib/components/button/styles.module.scss +5 -0
  82. package/src/lib/components/cards/a.stories.mdx +44 -0
  83. package/src/lib/components/cards/cardButton/index.stories.mdx +47 -0
  84. package/src/lib/components/cards/cardButton/index.tsx +61 -0
  85. package/src/lib/components/cards/cardButton/style.module.scss +33 -0
  86. package/src/lib/components/cards/cardWithLeftIcon/index.stories.mdx +103 -0
  87. package/src/lib/components/cards/cardWithLeftIcon/index.tsx +87 -0
  88. package/src/lib/components/cards/cardWithLeftIcon/style.module.scss +23 -0
  89. package/src/lib/components/cards/cardWithTopIcon/index.stories.mdx +105 -0
  90. package/src/lib/components/cards/cardWithTopIcon/index.tsx +60 -0
  91. package/src/lib/components/cards/cardWithTopIcon/style.module.scss +10 -0
  92. package/src/lib/components/cards/cardWithTopLeftIcon/index.stories.mdx +101 -0
  93. package/src/lib/components/cards/cardWithTopLeftIcon/index.tsx +72 -0
  94. package/src/lib/components/cards/cardWithTopLeftIcon/style.module.scss +21 -0
  95. package/src/lib/components/cards/icons/arrow-right.svg +4 -0
  96. package/src/lib/components/cards/icons/chevron-right.svg +3 -0
  97. package/src/lib/components/cards/icons/feather-logo.svg +10 -0
  98. package/src/lib/components/cards/icons/index.ts +36 -0
  99. package/src/lib/components/cards/icons/info.svg +12 -0
  100. package/src/lib/components/cards/index.test.ts +37 -0
  101. package/src/lib/components/cards/index.tsx +57 -0
  102. package/src/lib/components/cards/infoCard/index.stories.mdx +61 -0
  103. package/src/lib/components/cards/infoCard/index.tsx +47 -0
  104. package/src/lib/components/cards/infoCard/style.module.scss +53 -0
  105. package/src/lib/components/chip/icons/remove-button-highlighted.svg +4 -0
  106. package/src/lib/components/chip/icons/remove-button.svg +4 -0
  107. package/src/lib/components/chip/index.stories.mdx +101 -0
  108. package/src/lib/components/chip/index.tsx +38 -0
  109. package/src/lib/components/chip/style.module.scss +54 -0
  110. package/src/lib/components/comparisonTable/components/Chevron.tsx +19 -0
  111. package/src/lib/components/comparisonTable/components/Row/index.tsx +68 -0
  112. package/src/lib/components/comparisonTable/components/Row/style.module.scss +114 -0
  113. package/src/lib/components/comparisonTable/components/TableArrows/Arrow.tsx +19 -0
  114. package/src/lib/components/comparisonTable/components/TableArrows/index.tsx +52 -0
  115. package/src/lib/components/comparisonTable/components/TableArrows/style.module.scss +53 -0
  116. package/src/lib/components/comparisonTable/components/TableInfoButton/index.tsx +37 -0
  117. package/src/lib/components/comparisonTable/components/TableInfoButton/style.module.scss +30 -0
  118. package/src/lib/components/comparisonTable/components/TableRating/StarIcon.tsx +13 -0
  119. package/src/lib/components/comparisonTable/components/TableRating/ZapIcon.tsx +17 -0
  120. package/src/lib/components/comparisonTable/components/TableRating/index.tsx +45 -0
  121. package/src/lib/components/comparisonTable/components/TableRating/style.module.scss +13 -0
  122. package/src/lib/components/comparisonTable/components/TableRowHeader/index.tsx +35 -0
  123. package/src/lib/components/comparisonTable/components/TableRowHeader/style.module.scss +3 -0
  124. package/src/lib/components/comparisonTable/components/TableTrueFalse.tsx +40 -0
  125. package/src/lib/components/comparisonTable/hooks/useActiveTableArrows.ts +63 -0
  126. package/src/lib/components/comparisonTable/index.stories.mdx +254 -0
  127. package/src/lib/components/comparisonTable/index.tsx +211 -0
  128. package/src/lib/components/comparisonTable/style.module.scss +104 -0
  129. package/src/lib/components/dateSelector/datepicker.scss +406 -0
  130. package/src/lib/components/dateSelector/icons/calendar.svg +6 -0
  131. package/src/lib/components/dateSelector/icons/chevron-left.svg +3 -0
  132. package/src/lib/components/dateSelector/icons/chevron-right.svg +3 -0
  133. package/src/lib/components/dateSelector/index.stories.mdx +62 -0
  134. package/src/lib/components/dateSelector/index.test.ts +33 -0
  135. package/src/lib/components/dateSelector/index.tsx +247 -0
  136. package/src/lib/components/dateSelector/style.module.scss +77 -0
  137. package/src/lib/components/downloadButton/icons/check.svg +3 -0
  138. package/src/lib/components/downloadButton/icons/download.svg +5 -0
  139. package/src/lib/components/downloadButton/index.stories.mdx +59 -0
  140. package/src/lib/components/downloadButton/index.tsx +67 -0
  141. package/src/lib/components/downloadButton/style.module.scss +19 -0
  142. package/src/lib/components/downloadRing/icons/check-outside-circle.tsx +26 -0
  143. package/src/lib/components/downloadRing/icons/download-cloud.tsx +18 -0
  144. package/src/lib/components/downloadRing/icons/style.module.scss +7 -0
  145. package/src/lib/components/downloadRing/index.stories.mdx +35 -0
  146. package/src/lib/components/downloadRing/index.tsx +79 -0
  147. package/src/lib/components/downloadRing/style.module.scss +66 -0
  148. package/src/lib/components/dropzone/images/error.tsx +18 -0
  149. package/src/lib/components/dropzone/images/file.tsx +26 -0
  150. package/src/lib/components/dropzone/images/style.module.scss +7 -0
  151. package/src/lib/components/dropzone/images/upload-complete.tsx +24 -0
  152. package/src/lib/components/dropzone/images/upload.tsx +18 -0
  153. package/src/lib/components/dropzone/index.stories.mdx +44 -0
  154. package/src/lib/components/dropzone/index.tsx +152 -0
  155. package/src/lib/components/dropzone/style.module.scss +90 -0
  156. package/src/lib/components/input/a.stories.mdx +28 -0
  157. package/src/lib/components/input/autoSuggestInput/index.stories.mdx +137 -0
  158. package/src/lib/components/input/autoSuggestInput/index.tsx +81 -0
  159. package/src/lib/components/input/autoSuggestInput/style.module.scss +71 -0
  160. package/src/lib/components/input/autoSuggestMultiSelect/index.stories.mdx +115 -0
  161. package/src/lib/components/input/autoSuggestMultiSelect/index.tsx +75 -0
  162. package/src/lib/components/input/autoSuggestMultiSelect/style.module.scss +4 -0
  163. package/src/lib/components/input/currency/format/index.test.ts +49 -0
  164. package/src/lib/components/input/currency/format/index.ts +15 -0
  165. package/src/lib/components/input/currency/index.stories.mdx +25 -0
  166. package/src/lib/components/input/currency/index.test.tsx +56 -0
  167. package/src/lib/components/input/currency/index.tsx +53 -0
  168. package/src/lib/components/input/iban/formatIban/index.test.ts +11 -0
  169. package/src/lib/components/input/iban/formatIban/index.ts +22 -0
  170. package/src/lib/components/input/iban/index.stories.mdx +21 -0
  171. package/src/lib/components/input/iban/index.tsx +20 -0
  172. package/src/lib/components/input/index.stories.mdx +62 -0
  173. package/src/lib/components/input/index.tsx +51 -0
  174. package/src/lib/components/input/style.module.scss +94 -0
  175. package/src/lib/components/modal/bottomModal/img/close.svg +4 -0
  176. package/src/lib/components/modal/bottomModal/index.tsx +68 -0
  177. package/src/lib/components/modal/bottomModal/style.module.scss +104 -0
  178. package/src/lib/components/modal/bottomOrRegularModal/index.tsx +43 -0
  179. package/src/lib/components/modal/bottomOrRegularModal/style.module.scss +16 -0
  180. package/src/lib/components/modal/hooks/useOnClose.ts +54 -0
  181. package/src/lib/components/modal/index.stories.mdx +313 -0
  182. package/src/lib/components/modal/index.ts +14 -0
  183. package/src/lib/components/modal/regularModal/img/close.svg +4 -0
  184. package/src/lib/components/modal/regularModal/index.tsx +55 -0
  185. package/src/lib/components/modal/regularModal/style.module.scss +114 -0
  186. package/src/lib/components/multiDropzone/UploadFileCell/index.tsx +138 -0
  187. package/src/lib/components/multiDropzone/UploadFileCell/style.module.scss +101 -0
  188. package/src/lib/components/multiDropzone/icons/bmp-complete.svg +10 -0
  189. package/src/lib/components/multiDropzone/icons/bmp.svg +10 -0
  190. package/src/lib/components/multiDropzone/icons/doc-complete.svg +11 -0
  191. package/src/lib/components/multiDropzone/icons/doc.svg +11 -0
  192. package/src/lib/components/multiDropzone/icons/docx-complete.svg +12 -0
  193. package/src/lib/components/multiDropzone/icons/docx.svg +12 -0
  194. package/src/lib/components/multiDropzone/icons/eye.svg +4 -0
  195. package/src/lib/components/multiDropzone/icons/generic-complete.svg +4 -0
  196. package/src/lib/components/multiDropzone/icons/generic-error.svg +7 -0
  197. package/src/lib/components/multiDropzone/icons/generic.svg +4 -0
  198. package/src/lib/components/multiDropzone/icons/heic-complete.svg +11 -0
  199. package/src/lib/components/multiDropzone/icons/heic.svg +11 -0
  200. package/src/lib/components/multiDropzone/icons/index.ts +51 -0
  201. package/src/lib/components/multiDropzone/icons/jpeg-complete.svg +11 -0
  202. package/src/lib/components/multiDropzone/icons/jpeg.svg +11 -0
  203. package/src/lib/components/multiDropzone/icons/jpg-complete.svg +10 -0
  204. package/src/lib/components/multiDropzone/icons/jpg.svg +10 -0
  205. package/src/lib/components/multiDropzone/icons/pdf-complete.svg +8 -0
  206. package/src/lib/components/multiDropzone/icons/pdf.svg +8 -0
  207. package/src/lib/components/multiDropzone/icons/png-complete.svg +10 -0
  208. package/src/lib/components/multiDropzone/icons/png.svg +10 -0
  209. package/src/lib/components/multiDropzone/icons/trash.svg +6 -0
  210. package/src/lib/components/multiDropzone/icons/upload.svg +5 -0
  211. package/src/lib/components/multiDropzone/index.stories.mdx +91 -0
  212. package/src/lib/components/multiDropzone/index.tsx +99 -0
  213. package/src/lib/components/multiDropzone/style.module.scss +32 -0
  214. package/src/lib/components/segmentedControl/index.stories.mdx +47 -0
  215. package/src/lib/components/segmentedControl/index.tsx +105 -0
  216. package/src/lib/components/segmentedControl/style.module.scss +36 -0
  217. package/src/lib/components/signaturePad/img/reset.svg +4 -0
  218. package/src/lib/components/signaturePad/img/sign.svg +3 -0
  219. package/src/lib/components/signaturePad/index.stories.mdx +17 -0
  220. package/src/lib/components/signaturePad/index.tsx +96 -0
  221. package/src/lib/components/signaturePad/style.module.scss +90 -0
  222. package/src/lib/index.tsx +71 -0
  223. package/src/lib/models/autoSuggestInput/index.ts +4 -0
  224. package/src/lib/models/download.ts +1 -0
  225. package/src/lib/models/downloadRing/index.ts +6 -0
  226. package/src/lib/scss/index.scss +22 -0
  227. package/src/lib/scss/private/_reset.scss +154 -0
  228. package/src/lib/scss/private/base/_border_radius.scss +15 -0
  229. package/src/lib/scss/private/base/_colors.scss +19 -0
  230. package/src/lib/scss/private/base/_cursors.scss +31 -0
  231. package/src/lib/scss/private/base/_display.scss +35 -0
  232. package/src/lib/scss/private/base/_grid.scss +60 -0
  233. package/src/lib/scss/private/base/_index.scss +10 -0
  234. package/src/lib/scss/private/base/_shadows.scss +2 -0
  235. package/src/lib/scss/private/base/_spacing.scss +89 -0
  236. package/src/lib/scss/private/base/_typography.scss +135 -0
  237. package/src/lib/scss/private/base/_width_and_height.scss +25 -0
  238. package/src/lib/scss/private/base/border_radius.stories.mdx +43 -0
  239. package/src/lib/scss/private/base/cursors.stories.mdx +18 -0
  240. package/src/lib/scss/private/base/demo.tsx +123 -0
  241. package/src/lib/scss/private/base/display.stories.mdx +19 -0
  242. package/src/lib/scss/private/base/flex/_flex.scss +63 -0
  243. package/src/lib/scss/private/base/flex/flex.stories.mdx +139 -0
  244. package/src/lib/scss/private/base/flex/style.module.scss +24 -0
  245. package/src/lib/scss/private/base/spacing.stories.mdx +185 -0
  246. package/src/lib/scss/private/base/style.module.scss +52 -0
  247. package/src/lib/scss/private/base/typography.stories.mdx +74 -0
  248. package/src/lib/scss/private/base/width_and_height.stories.mdx +172 -0
  249. package/src/lib/scss/private/components/_badge.scss +41 -0
  250. package/src/lib/scss/private/components/_buttons.scss +193 -0
  251. package/src/lib/scss/private/components/_cards.scss +32 -0
  252. package/src/lib/scss/private/components/_index.scss +6 -0
  253. package/src/lib/scss/private/components/_input.scss +238 -0
  254. package/src/lib/scss/private/components/_notices.scss +39 -0
  255. package/src/lib/scss/private/components/_spinner.scss +60 -0
  256. package/src/lib/scss/private/components/assets/checkmark.svg +3 -0
  257. package/src/lib/scss/private/components/assets/icon-form-dropdown.svg +3 -0
  258. package/src/lib/scss/private/components/badge.stories.mdx +37 -0
  259. package/src/lib/scss/private/components/button.stories.mdx +107 -0
  260. package/src/lib/scss/private/components/cards.stories.mdx +35 -0
  261. package/src/lib/scss/private/components/checkbox.stories.mdx +47 -0
  262. package/src/lib/scss/private/components/input.stories.mdx +33 -0
  263. package/src/lib/scss/private/components/notices.stories.mdx +37 -0
  264. package/src/lib/scss/private/components/radio.stories.mdx +47 -0
  265. package/src/lib/scss/private/components/select.stories.mdx +17 -0
  266. package/src/lib/scss/private/components/spinner.stories.mdx +25 -0
  267. package/src/lib/scss/public/colors/_index.scss +2 -0
  268. package/src/lib/scss/public/colors/default.scss +130 -0
  269. package/src/lib/scss/public/colors/overrides.scss +0 -0
  270. package/src/lib/scss/public/colors.stories.mdx +27 -0
  271. package/src/lib/scss/public/demo.tsx +297 -0
  272. package/src/lib/scss/public/font/_index.scss +2 -0
  273. package/src/lib/scss/public/font/default.scss +3 -0
  274. package/src/lib/scss/public/font/overrides.scss +0 -0
  275. package/src/lib/scss/public/font-weight.scss +9 -0
  276. package/src/lib/scss/public/font-weight.stories.mdx +32 -0
  277. package/src/lib/scss/public/grid.scss +21 -0
  278. package/src/lib/scss/public/grid.stories.mdx +41 -0
  279. package/src/lib/scss/third-party/_google_places.scss +62 -0
  280. package/src/lib/scss/third-party/_index.scss +1 -0
  281. package/src/lib/scss/utils/_index.scss +3 -0
  282. package/src/lib/util/calendarDate/index.test.ts +32 -0
  283. package/src/lib/util/calendarDate/index.ts +30 -0
  284. package/src/lib/util/zeroFill.test.ts +15 -0
  285. package/src/lib/util/zeroFill.ts +7 -0
  286. package/src/react-app-env.d.ts +1 -0
  287. package/src/setupTests.js +8 -0
  288. package/src/theme.stories.mdx +54 -0
@@ -0,0 +1,45 @@
1
+ import classNames from 'classnames';
2
+
3
+ import StarIcon from './StarIcon';
4
+ import ZapIcon from './ZapIcon';
5
+
6
+ import styles from './style.module.scss';
7
+
8
+ type RatingTypes = 'star' | 'zap';
9
+
10
+ interface TableRatingProps {
11
+ type: RatingTypes;
12
+ rating: number;
13
+ }
14
+
15
+ const getRatingIcon = (type: RatingTypes) => {
16
+ const iconDictionary = {
17
+ zap: ZapIcon,
18
+ star: StarIcon,
19
+ };
20
+
21
+ return iconDictionary[type] || iconDictionary['star'];
22
+ };
23
+
24
+ const VALID_VALUES = [1, 2, 3];
25
+
26
+ const TableRating = (props: TableRatingProps) => {
27
+ const { rating, type } = props;
28
+ const SelectedIcon = getRatingIcon(type);
29
+
30
+ return (
31
+ <div>
32
+ {VALID_VALUES.map((value) => (
33
+ <SelectedIcon
34
+ key={value}
35
+ className={classNames(
36
+ styles.icon,
37
+ value <= rating ? styles.filled : styles.empty
38
+ )}
39
+ />
40
+ ))}
41
+ </div>
42
+ );
43
+ };
44
+
45
+ export default TableRating;
@@ -0,0 +1,13 @@
1
+ @use "../../../../scss/public/colors" as *;
2
+
3
+ .icon {
4
+ margin-right: 4px;
5
+ }
6
+
7
+ .filled {
8
+ fill: $ds-primary-500;
9
+ }
10
+
11
+ .empty {
12
+ fill: $ds-grey-200;
13
+ }
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import TableInfoButton from '../TableInfoButton';
5
+
6
+ import styles from './style.module.scss';
7
+
8
+ const TableRowHeader = (props: {
9
+ label: string;
10
+ icon?: string;
11
+ subtitle?: string;
12
+ onClickInfo?: () => void;
13
+ }) => {
14
+ const { icon, label, subtitle, onClickInfo } = props;
15
+ return (
16
+ <div className="d-flex">
17
+ <span className={`mr8 ${styles.icon}`}>{icon}</span>
18
+ <div>
19
+ <p className="p-p d-inline">
20
+ <span
21
+ className={classNames({
22
+ mr8: onClickInfo,
23
+ })}
24
+ >
25
+ {label}
26
+ </span>
27
+ {onClickInfo && <TableInfoButton onClick={onClickInfo} />}
28
+ </p>
29
+ {subtitle && <p className="p-p--small tc-grey-500">{subtitle}</p>}
30
+ </div>
31
+ </div>
32
+ );
33
+ };
34
+
35
+ export default TableRowHeader;
@@ -0,0 +1,40 @@
1
+ const TableTrueFalse = ({
2
+ value,
3
+ className = '',
4
+ }: {
5
+ value: boolean;
6
+ className?: string;
7
+ }) => {
8
+ if (value) {
9
+ return (
10
+ <svg
11
+ width="18"
12
+ height="13"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ className={className}
16
+ >
17
+ <path
18
+ d="M15.667 1.833L6.5 11 2.333 6.833"
19
+ stroke="#8E8CEE"
20
+ strokeWidth="3"
21
+ strokeLinecap="round"
22
+ strokeLinejoin="round"
23
+ />
24
+ </svg>
25
+ );
26
+ }
27
+
28
+ return (
29
+ <svg width="12" height="12" fill="none" xmlns="http://www.w3.org/2000/svg">
30
+ <path
31
+ fillRule="evenodd"
32
+ clipRule="evenodd"
33
+ d="M11.707 1.707A1 1 0 0010.293.293L6 4.586 1.707.293A1 1 0 00.293 1.707L4.586 6 .293 10.293a1 1 0 101.414 1.414L6 7.414l4.293 4.293a1 1 0 001.414-1.414L7.414 6l4.293-4.293z"
34
+ fill="#D2D2D8"
35
+ />
36
+ </svg>
37
+ );
38
+ };
39
+
40
+ export default TableTrueFalse;
@@ -0,0 +1,63 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import debounce from 'lodash.debounce';
3
+
4
+ export interface ActiveTableArrows {
5
+ left: boolean;
6
+ right: boolean;
7
+ }
8
+
9
+ export const useActiveTableArrows = (): {
10
+ activeArrows: ActiveTableArrows;
11
+ contentContainerRef: React.Ref<HTMLDivElement>;
12
+ contentWrapperRef: React.Ref<HTMLDivElement>;
13
+ } => {
14
+ const [activeArrows, setActiveArrows] = useState<ActiveTableArrows>({
15
+ left: false,
16
+ right: true,
17
+ });
18
+ const contentContainerRef = useRef<HTMLDivElement | null>(null);
19
+ const contentWrapperRef = useRef<HTMLDivElement | null>(null);
20
+
21
+ const handleTableScroll = (e: Event) => {
22
+ const width = window.innerWidth;
23
+
24
+ if (
25
+ e.target === contentWrapperRef.current &&
26
+ contentContainerRef.current &&
27
+ contentContainerRef.current
28
+ ) {
29
+ const left =
30
+ contentContainerRef.current.getBoundingClientRect().left * -1;
31
+
32
+ setActiveArrows({
33
+ left: left > 0,
34
+ right:
35
+ left + width <
36
+ contentContainerRef.current.getBoundingClientRect().width,
37
+ });
38
+ }
39
+ };
40
+
41
+ const debouncedTableScroll = debounce(handleTableScroll, 150);
42
+
43
+ useEffect(() => {
44
+ contentWrapperRef.current?.addEventListener(
45
+ 'scroll',
46
+ debouncedTableScroll,
47
+ {
48
+ passive: true,
49
+ }
50
+ );
51
+
52
+ return contentWrapperRef.current?.removeEventListener(
53
+ 'scroll',
54
+ handleTableScroll
55
+ );
56
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
57
+
58
+ return {
59
+ activeArrows,
60
+ contentContainerRef,
61
+ contentWrapperRef,
62
+ };
63
+ };
@@ -0,0 +1,254 @@
1
+ import { Meta, Preview } from '@storybook/addon-docs/blocks';
2
+
3
+ import { ComparisonTable, TableRating, TableTrueFalse } from '.';
4
+
5
+ <Meta title="JSX/Comparison Table" component={ComparisonTable} />
6
+
7
+ # Comparison Table
8
+
9
+ The Comparison Table component provides an easy way to compare vast amounts of information in a fast and easy way.
10
+
11
+ <Preview>
12
+ <iframe
13
+ width="100%"
14
+ height="450"
15
+ src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FMKs4cbojdVOBKUxv7okb93%2FDirty-Swan-Design-System%3Fnode-id%3D2025%253A12194"
16
+ allowFullScreen
17
+ />
18
+ </Preview>
19
+
20
+ ## Arguments
21
+
22
+ | attribute | unit | description | default value | required |
23
+ | ----------- | ------------------- | ---------------------------------------------------------- | ------------- | -------- |
24
+ | headers | [Header[]](#header) | The structure of the table | n/a | true |
25
+ | data | array | The title text that needs to be displayed | n/a | true |
26
+ | hideDetails | boolean | Hide table groups that do not have the `default` attribute | false | false |
27
+
28
+ ## Types
29
+
30
+ ### Cell
31
+
32
+ ```typescript
33
+ export interface CellBaseProps<T> {
34
+ label?: React.ReactNode;
35
+ render?: (value: any, element: T) => React.ReactNode;
36
+ key: Extract<keyof T, string>;
37
+ addonId?: string | number;
38
+ }
39
+ ```
40
+
41
+ ### Header
42
+
43
+ ```typescript
44
+ export interface Header<T> {
45
+ id: number;
46
+ label?: React.ReactNode;
47
+ cells: Array<Cell<T>>;
48
+ default?: boolean;
49
+ }
50
+ ```
51
+
52
+ ## Default example
53
+
54
+ export const ComparisonTableWithData = () => {
55
+ const headers = [
56
+ {
57
+ id: 1,
58
+ cells: [
59
+ {
60
+ id: 1,
61
+ key: 'name',
62
+ label: 'Films',
63
+ },
64
+ {
65
+ id: 2,
66
+ key: 'country',
67
+ label: 'Country',
68
+ },
69
+ {
70
+ id: 4,
71
+ key: 'imdb',
72
+ label: 'IMDB rating',
73
+ },
74
+ {
75
+ id: 3,
76
+ key: 'rating',
77
+ label: 'Our rating',
78
+ render: (value) => <TableRating type="star" rating={value} />,
79
+ },
80
+ {
81
+ id: 5,
82
+ key: 'recommended',
83
+ label: 'Recommended',
84
+ render: (value) => <TableRating type="zap" rating={value} />,
85
+ },
86
+ {
87
+ id: 5,
88
+ key: 'familyFriendly',
89
+ label: 'Family friendly',
90
+ render: (value) => <TableTrueFalse value={value} />,
91
+ },
92
+ {
93
+ id: 6,
94
+ key: 'boxOffice',
95
+ label: 'Box office',
96
+ render: (value) =>
97
+ value.toLocaleString('de-DE', {
98
+ style: 'currency',
99
+ currency: 'EUR',
100
+ }),
101
+ },
102
+ ],
103
+ },
104
+ ];
105
+ const data = [
106
+ {
107
+ id: 1,
108
+ name: 'Pulp Fiction',
109
+ country: 'United States',
110
+ year: '1994',
111
+ rating: 3,
112
+ imdb: 8.9,
113
+ recommended: 3,
114
+ familyFriendly: false,
115
+ boxOffice: 213928762,
116
+ },
117
+ {
118
+ id: 2,
119
+ name: 'Parasite',
120
+ country: 'South Korea',
121
+ year: '2019',
122
+ rating: 2,
123
+ imdb: 8.6,
124
+ recommended: 3,
125
+ familyFriendly: false,
126
+ boxOffice: 355475245,
127
+ },
128
+ {
129
+ id: 3,
130
+ name: 'Spirited Away',
131
+ country: 'Japan',
132
+ year: '2001',
133
+ rating: 3,
134
+ imdb: 8.6,
135
+ recommended: 3,
136
+ familyFriendly: true,
137
+ boxOffice: 258908054,
138
+ },
139
+ ];
140
+ return <ComparisonTable data={data} headers={headers} />;
141
+ };
142
+
143
+ <ComparisonTableWithData />
144
+
145
+ ```typescript jsx
146
+ import ComparisonTable, {
147
+ TableRating,
148
+ TableTrueFalse,
149
+ TableHeader,
150
+ } from '@popsure/dirty-swan';
151
+
152
+ interface TableData {
153
+ id: number;
154
+ name: string;
155
+ country: string;
156
+ year: string;
157
+ rating: number;
158
+ imdb: number;
159
+ recommended: number;
160
+ familyFriendly: boolean;
161
+ boxOffice: number;
162
+ }
163
+
164
+ export const ComparisonTableWithData = () => {
165
+ const headers: Array<TableHeader<TableData>> = [
166
+ {
167
+ id: 1,
168
+ cells: [
169
+ {
170
+ id: 1,
171
+ key: 'name',
172
+ label: 'Films',
173
+ },
174
+ {
175
+ id: 2,
176
+ key: 'country',
177
+ label: 'Country',
178
+ },
179
+ {
180
+ id: 4,
181
+ key: 'imdb',
182
+ label: 'IMDB rating',
183
+ },
184
+ {
185
+ id: 3,
186
+ key: 'rating',
187
+ label: 'Our rating',
188
+ render: (value) => <TableRating type="star" rating={value} />,
189
+ },
190
+ {
191
+ id: 5,
192
+ key: 'recommended',
193
+ label: 'Recommended',
194
+ render: (value) => <TableRating type="zap" rating={value} />,
195
+ },
196
+ {
197
+ id: 5,
198
+ key: 'familyFriendly',
199
+ label: 'Family friendly',
200
+ render: (value) => <TableTrueFalse value={value} />,
201
+ },
202
+ {
203
+ id: 6,
204
+ key: 'boxOffice',
205
+ label: 'Box office',
206
+ render: (value) =>
207
+ value.toLocaleString('de-DE', {
208
+ style: 'currency',
209
+ currency: 'EUR',
210
+ }),
211
+ },
212
+ ],
213
+ },
214
+ ];
215
+ const data: Array<TableData> = [
216
+ {
217
+ id: 1,
218
+ name: 'Pulp Fiction',
219
+ country: 'United States',
220
+ year: '1994',
221
+ rating: 3,
222
+ imdb: 8.9,
223
+ recommended: 3,
224
+ familyFriendly: false,
225
+ boxOffice: 213928762,
226
+ },
227
+ {
228
+ id: 2,
229
+ name: 'Parasite',
230
+ country: 'South Korea',
231
+ year: '2019',
232
+ rating: 2,
233
+ imdb: 8.6,
234
+ recommended: 3,
235
+ familyFriendly: false,
236
+ boxOffice: 355475245,
237
+ },
238
+ {
239
+ id: 3,
240
+ name: 'Spirited Away',
241
+ country: 'Japan',
242
+ year: '2001',
243
+ rating: 3,
244
+ imdb: 8.6,
245
+ recommended: 3,
246
+ familyFriendly: true,
247
+ boxOffice: 258908054,
248
+ },
249
+ ];
250
+ return <ComparisonTable data={data} headers={headers} />;
251
+ };
252
+
253
+ <ComparisonTableWithData />;
254
+ ```
@@ -0,0 +1,211 @@
1
+ import React, { useRef, useState } from 'react';
2
+ import { ScrollSync, ScrollSyncPane } from 'react-scroll-sync';
3
+ import classNames from 'classnames';
4
+
5
+ import Row from './components/Row';
6
+ import TableArrows, { ArrowValues } from './components/TableArrows';
7
+ import TableRating from './components/TableRating';
8
+ import TableTrueFalse from './components/TableTrueFalse';
9
+ import TableRowHeader from './components/TableRowHeader';
10
+ import TableInfoButton from './components/TableInfoButton';
11
+ import Chevron from './components/Chevron';
12
+ import { useActiveTableArrows } from './hooks/useActiveTableArrows';
13
+
14
+ import baseStyles from './style.module.scss';
15
+
16
+ export interface CellBaseProps<T> {
17
+ /** Used to display the row's title */
18
+ label?: React.ReactNode;
19
+ /**
20
+ *
21
+ * @param value The current data value
22
+ * @param element The complete data object
23
+ */
24
+ render?: (value: any, element: T) => React.ReactNode; //TODO: add typing to value param
25
+ }
26
+
27
+ interface CellWithId<T> extends CellBaseProps<T> {
28
+ /** Used when adding component add-ons */
29
+ addonId: string | number;
30
+ }
31
+
32
+ export type Cell<T> =
33
+ | ({ key: Extract<keyof T, string> } & CellBaseProps<T>)
34
+ | ({ key?: undefined } & CellWithId<T>);
35
+
36
+ export interface TableHeader<T> {
37
+ /** Required unique id number for each table group */
38
+ id: number;
39
+ /** Used to display a table group subheader */
40
+ label?: React.ReactNode;
41
+ cells: Array<Cell<T>>;
42
+ default?: boolean;
43
+ }
44
+
45
+ export interface ComparisonTableProps<T> {
46
+ headers: Array<TableHeader<T>>;
47
+ data: Array<T>;
48
+ hideDetails?: boolean;
49
+ styles?: {
50
+ header?: string;
51
+ container?: string;
52
+ };
53
+ }
54
+
55
+ const ComparisonTable = <T extends { id: number }>(
56
+ props: ComparisonTableProps<T>
57
+ ) => {
58
+ const { headers, data, hideDetails, styles } = props;
59
+ const [showMore, setShowMore] = useState<boolean>(false);
60
+ const headerContainerRef = useRef<HTMLDivElement | null>(null);
61
+ const { activeArrows, contentContainerRef, contentWrapperRef } =
62
+ useActiveTableArrows();
63
+
64
+ /** narrow types */
65
+ const headerContainer = headerContainerRef
66
+ ? headerContainerRef.current
67
+ : null;
68
+ const contentWrapper =
69
+ typeof contentWrapperRef === 'object' && contentWrapperRef
70
+ ? contentWrapperRef.current
71
+ : null;
72
+
73
+ const handleArrowsClick = (value: ArrowValues) => {
74
+ if (headerContainerRef.current) {
75
+ headerContainerRef.current.scroll({
76
+ top: 0,
77
+ left:
78
+ value === 'next'
79
+ ? headerContainerRef.current.scrollLeft + window.innerWidth
80
+ : headerContainerRef.current.scrollLeft - window.innerWidth,
81
+ behavior: 'smooth',
82
+ });
83
+ }
84
+ };
85
+
86
+ const toggleMoreRows = async () => {
87
+ if (showMore && headerContainer && contentWrapper) {
88
+ window.scroll(
89
+ 0,
90
+ window.scrollY +
91
+ (contentWrapper.getBoundingClientRect().y -
92
+ headerContainer.getBoundingClientRect().bottom)
93
+ );
94
+ }
95
+ setShowMore(!showMore);
96
+ };
97
+
98
+ return (
99
+ <ScrollSync>
100
+ <div>
101
+ <div className={classNames(baseStyles.header, styles?.header)}>
102
+ <ScrollSyncPane>
103
+ <div className={baseStyles.container} ref={headerContainerRef}>
104
+ <div className={classNames(baseStyles['overflow-container'])}>
105
+ <div className={baseStyles['group-container']}>
106
+ <TableArrows
107
+ onClick={handleArrowsClick}
108
+ active={activeArrows}
109
+ />
110
+ <Row<T>
111
+ key="table-header-row"
112
+ rowId="table-header-row"
113
+ cell={headers[0].cells[0]}
114
+ data={data}
115
+ isRowHeader
116
+ />
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </ScrollSyncPane>
121
+ </div>
122
+ <ScrollSyncPane>
123
+ <div
124
+ className={classNames(baseStyles.container, styles?.container)}
125
+ ref={contentWrapperRef}
126
+ >
127
+ <div
128
+ className={classNames(baseStyles['overflow-container'])}
129
+ ref={contentContainerRef}
130
+ >
131
+ <div className={baseStyles['group-container']}>
132
+ {Array.isArray(headers) &&
133
+ headers
134
+ .filter(
135
+ (headerGroup) =>
136
+ !hideDetails || showMore || headerGroup.default
137
+ )
138
+ .map((headerGroup, headerGroupIndex) => (
139
+ <div key={headerGroup.id}>
140
+ {
141
+ /**
142
+ * Print a table subheader if the `label` value is present
143
+ */
144
+ headerGroup.label && (
145
+ <div className={baseStyles['group-title']}>
146
+ <h4 className={`p-h4 ${baseStyles.sticky}`}>
147
+ {headerGroup.label}
148
+ </h4>
149
+ </div>
150
+ )
151
+ }
152
+
153
+ {headerGroup.cells?.map((cell, index) => {
154
+ const rowId = `${headerGroup.id}-${
155
+ cell.key ?? 'addon'
156
+ }-${index}`;
157
+
158
+ /** Do not render the first row */
159
+ if (index === 0 && headerGroupIndex === 0)
160
+ return null;
161
+
162
+ return (
163
+ <Row<T>
164
+ key={rowId}
165
+ rowId={rowId}
166
+ cell={cell}
167
+ data={data}
168
+ />
169
+ );
170
+ })}
171
+ </div>
172
+ ))}
173
+ {hideDetails && (
174
+ <div
175
+ className={classNames(
176
+ baseStyles['show-details-container'],
177
+ baseStyles.sticky,
178
+ 'mt48'
179
+ )}
180
+ >
181
+ <div>
182
+ <button
183
+ className={`w100 d-flex p-a p-h4 c-pointer ${baseStyles['show-details-button']}`}
184
+ onClick={toggleMoreRows}
185
+ >
186
+ {showMore ? 'Hide details' : 'Show details'}
187
+ <Chevron
188
+ className={
189
+ showMore ? '' : baseStyles['icon-inverted']
190
+ }
191
+ />
192
+ </button>
193
+ </div>
194
+ </div>
195
+ )}
196
+ </div>
197
+ </div>
198
+ </div>
199
+ </ScrollSyncPane>
200
+ </div>
201
+ </ScrollSync>
202
+ );
203
+ };
204
+
205
+ export {
206
+ ComparisonTable,
207
+ TableRating,
208
+ TableTrueFalse,
209
+ TableRowHeader,
210
+ TableInfoButton,
211
+ };