@popsure/dirty-swan 0.26.10 → 0.26.13

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 (240) hide show
  1. package/dist/index.css +62 -0
  2. package/dist/index.css.map +1 -1
  3. package/dist/lib/scss/private/base/_border_radius.scss +15 -0
  4. package/dist/lib/scss/private/base/_grid.scss +8 -0
  5. package/dist/lib/scss/private/base/_index.scss +1 -0
  6. package/dist/lib/scss/private/base/style.module.scss +10 -0
  7. package/dist/lib/scss/public/colors/default.scss +5 -0
  8. package/dist/lib/scss/public/demo.tsx +13 -1
  9. package/package.json +2 -1
  10. package/src/App.tsx +50 -0
  11. package/src/bin/index.ts +71 -0
  12. package/src/bin/tsconfig.json +13 -0
  13. package/src/bin/util/index.test.ts +85 -0
  14. package/src/bin/util/index.ts +132 -0
  15. package/src/bin/util/test/data.json +13 -0
  16. package/src/colors.scss +1 -0
  17. package/src/font-weight.scss +1 -0
  18. package/src/grid.scss +1 -0
  19. package/src/index.tsx +37 -0
  20. package/src/intro.stories.mdx +41 -0
  21. package/src/lib/components/autocompleteAddress/demo.tsx +38 -0
  22. package/src/lib/components/autocompleteAddress/index.stories.mdx +44 -0
  23. package/src/lib/components/autocompleteAddress/index.tsx +316 -0
  24. package/src/lib/components/autocompleteAddress/mapStyle.ts +187 -0
  25. package/src/lib/components/autocompleteAddress/style.module.scss +82 -0
  26. package/src/lib/components/autocompleteAddress/util/index.test.ts +51 -0
  27. package/src/lib/components/autocompleteAddress/util/index.ts +55 -0
  28. package/src/lib/components/button/icons/index.ts +14 -0
  29. package/src/lib/components/button/icons/send-purple.svg +4 -0
  30. package/src/lib/components/button/icons/send-white.svg +4 -0
  31. package/src/lib/components/button/index.stories.mdx +121 -0
  32. package/src/lib/components/button/index.tsx +64 -0
  33. package/src/lib/components/button/styles.module.scss +5 -0
  34. package/src/lib/components/cards/a.stories.mdx +44 -0
  35. package/src/lib/components/cards/cardButton/index.stories.mdx +47 -0
  36. package/src/lib/components/cards/cardButton/index.tsx +61 -0
  37. package/src/lib/components/cards/cardButton/style.module.scss +33 -0
  38. package/src/lib/components/cards/cardWithLeftIcon/index.stories.mdx +103 -0
  39. package/src/lib/components/cards/cardWithLeftIcon/index.tsx +87 -0
  40. package/src/lib/components/cards/cardWithLeftIcon/style.module.scss +23 -0
  41. package/src/lib/components/cards/cardWithTopIcon/index.stories.mdx +105 -0
  42. package/src/lib/components/cards/cardWithTopIcon/index.tsx +60 -0
  43. package/src/lib/components/cards/cardWithTopIcon/style.module.scss +10 -0
  44. package/src/lib/components/cards/cardWithTopLeftIcon/index.stories.mdx +101 -0
  45. package/src/lib/components/cards/cardWithTopLeftIcon/index.tsx +72 -0
  46. package/src/lib/components/cards/cardWithTopLeftIcon/style.module.scss +21 -0
  47. package/src/lib/components/cards/icons/arrow-right.svg +4 -0
  48. package/src/lib/components/cards/icons/chevron-right.svg +3 -0
  49. package/src/lib/components/cards/icons/feather-logo.svg +10 -0
  50. package/src/lib/components/cards/icons/index.ts +36 -0
  51. package/src/lib/components/cards/icons/info.svg +12 -0
  52. package/src/lib/components/cards/index.test.ts +37 -0
  53. package/src/lib/components/cards/index.tsx +57 -0
  54. package/src/lib/components/cards/infoCard/index.stories.mdx +61 -0
  55. package/src/lib/components/cards/infoCard/index.tsx +47 -0
  56. package/src/lib/components/cards/infoCard/style.module.scss +53 -0
  57. package/src/lib/components/chip/icons/remove-button-highlighted.svg +4 -0
  58. package/src/lib/components/chip/icons/remove-button.svg +4 -0
  59. package/src/lib/components/chip/index.stories.mdx +101 -0
  60. package/src/lib/components/chip/index.tsx +38 -0
  61. package/src/lib/components/chip/style.module.scss +54 -0
  62. package/src/lib/components/comparisonTable/components/Chevron.tsx +19 -0
  63. package/src/lib/components/comparisonTable/components/Row/index.tsx +68 -0
  64. package/src/lib/components/comparisonTable/components/Row/style.module.scss +114 -0
  65. package/src/lib/components/comparisonTable/components/TableArrows/Arrow.tsx +19 -0
  66. package/src/lib/components/comparisonTable/components/TableArrows/index.tsx +52 -0
  67. package/src/lib/components/comparisonTable/components/TableArrows/style.module.scss +53 -0
  68. package/src/lib/components/comparisonTable/components/TableInfoButton/index.tsx +37 -0
  69. package/src/lib/components/comparisonTable/components/TableInfoButton/style.module.scss +30 -0
  70. package/src/lib/components/comparisonTable/components/TableRating/StarIcon.tsx +13 -0
  71. package/src/lib/components/comparisonTable/components/TableRating/ZapIcon.tsx +17 -0
  72. package/src/lib/components/comparisonTable/components/TableRating/index.tsx +45 -0
  73. package/src/lib/components/comparisonTable/components/TableRating/style.module.scss +13 -0
  74. package/src/lib/components/comparisonTable/components/TableRowHeader/index.tsx +35 -0
  75. package/src/lib/components/comparisonTable/components/TableRowHeader/style.module.scss +3 -0
  76. package/src/lib/components/comparisonTable/components/TableTrueFalse.tsx +40 -0
  77. package/src/lib/components/comparisonTable/hooks/useActiveTableArrows.ts +63 -0
  78. package/src/lib/components/comparisonTable/index.stories.mdx +254 -0
  79. package/src/lib/components/comparisonTable/index.tsx +211 -0
  80. package/src/lib/components/comparisonTable/style.module.scss +104 -0
  81. package/src/lib/components/dateSelector/datepicker.scss +406 -0
  82. package/src/lib/components/dateSelector/icons/calendar.svg +6 -0
  83. package/src/lib/components/dateSelector/icons/chevron-left.svg +3 -0
  84. package/src/lib/components/dateSelector/icons/chevron-right.svg +3 -0
  85. package/src/lib/components/dateSelector/index.stories.mdx +62 -0
  86. package/src/lib/components/dateSelector/index.test.ts +33 -0
  87. package/src/lib/components/dateSelector/index.tsx +247 -0
  88. package/src/lib/components/dateSelector/style.module.scss +77 -0
  89. package/src/lib/components/downloadButton/icons/check.svg +3 -0
  90. package/src/lib/components/downloadButton/icons/download.svg +5 -0
  91. package/src/lib/components/downloadButton/index.stories.mdx +59 -0
  92. package/src/lib/components/downloadButton/index.tsx +67 -0
  93. package/src/lib/components/downloadButton/style.module.scss +19 -0
  94. package/src/lib/components/downloadRing/icons/check-outside-circle.tsx +26 -0
  95. package/src/lib/components/downloadRing/icons/download-cloud.tsx +18 -0
  96. package/src/lib/components/downloadRing/icons/style.module.scss +7 -0
  97. package/src/lib/components/downloadRing/index.stories.mdx +35 -0
  98. package/src/lib/components/downloadRing/index.tsx +79 -0
  99. package/src/lib/components/downloadRing/style.module.scss +66 -0
  100. package/src/lib/components/dropzone/images/error.tsx +18 -0
  101. package/src/lib/components/dropzone/images/file.tsx +26 -0
  102. package/src/lib/components/dropzone/images/style.module.scss +7 -0
  103. package/src/lib/components/dropzone/images/upload-complete.tsx +24 -0
  104. package/src/lib/components/dropzone/images/upload.tsx +18 -0
  105. package/src/lib/components/dropzone/index.stories.mdx +44 -0
  106. package/src/lib/components/dropzone/index.tsx +152 -0
  107. package/src/lib/components/dropzone/style.module.scss +90 -0
  108. package/src/lib/components/input/a.stories.mdx +28 -0
  109. package/src/lib/components/input/autoSuggestInput/index.stories.mdx +137 -0
  110. package/src/lib/components/input/autoSuggestInput/index.tsx +81 -0
  111. package/src/lib/components/input/autoSuggestInput/style.module.scss +71 -0
  112. package/src/lib/components/input/autoSuggestMultiSelect/index.stories.mdx +115 -0
  113. package/src/lib/components/input/autoSuggestMultiSelect/index.tsx +75 -0
  114. package/src/lib/components/input/autoSuggestMultiSelect/style.module.scss +4 -0
  115. package/src/lib/components/input/currency/format/index.test.ts +49 -0
  116. package/src/lib/components/input/currency/format/index.ts +15 -0
  117. package/src/lib/components/input/currency/index.stories.mdx +25 -0
  118. package/src/lib/components/input/currency/index.test.tsx +56 -0
  119. package/src/lib/components/input/currency/index.tsx +53 -0
  120. package/src/lib/components/input/iban/formatIban/index.test.ts +11 -0
  121. package/src/lib/components/input/iban/formatIban/index.ts +22 -0
  122. package/src/lib/components/input/iban/index.stories.mdx +21 -0
  123. package/src/lib/components/input/iban/index.tsx +20 -0
  124. package/src/lib/components/input/index.stories.mdx +62 -0
  125. package/src/lib/components/input/index.tsx +51 -0
  126. package/src/lib/components/input/style.module.scss +94 -0
  127. package/src/lib/components/modal/bottomModal/img/close.svg +4 -0
  128. package/src/lib/components/modal/bottomModal/index.tsx +68 -0
  129. package/src/lib/components/modal/bottomModal/style.module.scss +104 -0
  130. package/src/lib/components/modal/bottomOrRegularModal/index.tsx +43 -0
  131. package/src/lib/components/modal/bottomOrRegularModal/style.module.scss +16 -0
  132. package/src/lib/components/modal/hooks/useOnClose.ts +51 -0
  133. package/src/lib/components/modal/index.stories.mdx +316 -0
  134. package/src/lib/components/modal/index.ts +14 -0
  135. package/src/lib/components/modal/regularModal/img/close.svg +4 -0
  136. package/src/lib/components/modal/regularModal/index.tsx +55 -0
  137. package/src/lib/components/modal/regularModal/style.module.scss +106 -0
  138. package/src/lib/components/multiDropzone/UploadFileCell/index.tsx +138 -0
  139. package/src/lib/components/multiDropzone/UploadFileCell/style.module.scss +101 -0
  140. package/src/lib/components/multiDropzone/icons/bmp-complete.svg +10 -0
  141. package/src/lib/components/multiDropzone/icons/bmp.svg +10 -0
  142. package/src/lib/components/multiDropzone/icons/doc-complete.svg +11 -0
  143. package/src/lib/components/multiDropzone/icons/doc.svg +11 -0
  144. package/src/lib/components/multiDropzone/icons/docx-complete.svg +12 -0
  145. package/src/lib/components/multiDropzone/icons/docx.svg +12 -0
  146. package/src/lib/components/multiDropzone/icons/eye.svg +4 -0
  147. package/src/lib/components/multiDropzone/icons/generic-complete.svg +4 -0
  148. package/src/lib/components/multiDropzone/icons/generic-error.svg +7 -0
  149. package/src/lib/components/multiDropzone/icons/generic.svg +4 -0
  150. package/src/lib/components/multiDropzone/icons/heic-complete.svg +11 -0
  151. package/src/lib/components/multiDropzone/icons/heic.svg +11 -0
  152. package/src/lib/components/multiDropzone/icons/index.ts +51 -0
  153. package/src/lib/components/multiDropzone/icons/jpeg-complete.svg +11 -0
  154. package/src/lib/components/multiDropzone/icons/jpeg.svg +11 -0
  155. package/src/lib/components/multiDropzone/icons/jpg-complete.svg +10 -0
  156. package/src/lib/components/multiDropzone/icons/jpg.svg +10 -0
  157. package/src/lib/components/multiDropzone/icons/pdf-complete.svg +8 -0
  158. package/src/lib/components/multiDropzone/icons/pdf.svg +8 -0
  159. package/src/lib/components/multiDropzone/icons/png-complete.svg +10 -0
  160. package/src/lib/components/multiDropzone/icons/png.svg +10 -0
  161. package/src/lib/components/multiDropzone/icons/trash.svg +6 -0
  162. package/src/lib/components/multiDropzone/icons/upload.svg +5 -0
  163. package/src/lib/components/multiDropzone/index.stories.mdx +91 -0
  164. package/src/lib/components/multiDropzone/index.tsx +99 -0
  165. package/src/lib/components/multiDropzone/style.module.scss +32 -0
  166. package/src/lib/components/segmentedControl/index.stories.mdx +47 -0
  167. package/src/lib/components/segmentedControl/index.tsx +105 -0
  168. package/src/lib/components/segmentedControl/style.module.scss +36 -0
  169. package/src/lib/components/signaturePad/img/reset.svg +4 -0
  170. package/src/lib/components/signaturePad/img/sign.svg +3 -0
  171. package/src/lib/components/signaturePad/index.stories.mdx +17 -0
  172. package/src/lib/components/signaturePad/index.tsx +96 -0
  173. package/src/lib/components/signaturePad/style.module.scss +90 -0
  174. package/src/lib/index.tsx +71 -0
  175. package/src/lib/models/autoSuggestInput/index.ts +4 -0
  176. package/src/lib/models/download.ts +1 -0
  177. package/src/lib/models/downloadRing/index.ts +6 -0
  178. package/src/lib/scss/index.scss +22 -0
  179. package/src/lib/scss/private/_reset.scss +149 -0
  180. package/src/lib/scss/private/base/_border_radius.scss +15 -0
  181. package/src/lib/scss/private/base/_colors.scss +19 -0
  182. package/src/lib/scss/private/base/_cursors.scss +31 -0
  183. package/src/lib/scss/private/base/_display.scss +35 -0
  184. package/src/lib/scss/private/base/_grid.scss +60 -0
  185. package/src/lib/scss/private/base/_index.scss +10 -0
  186. package/src/lib/scss/private/base/_shadows.scss +2 -0
  187. package/src/lib/scss/private/base/_spacing.scss +89 -0
  188. package/src/lib/scss/private/base/_typography.scss +128 -0
  189. package/src/lib/scss/private/base/_width_and_height.scss +25 -0
  190. package/src/lib/scss/private/base/border_radius.stories.mdx +43 -0
  191. package/src/lib/scss/private/base/cursors.stories.mdx +18 -0
  192. package/src/lib/scss/private/base/demo.tsx +119 -0
  193. package/src/lib/scss/private/base/display.stories.mdx +19 -0
  194. package/src/lib/scss/private/base/flex/_flex.scss +63 -0
  195. package/src/lib/scss/private/base/flex/flex.stories.mdx +139 -0
  196. package/src/lib/scss/private/base/flex/style.module.scss +24 -0
  197. package/src/lib/scss/private/base/spacing.stories.mdx +185 -0
  198. package/src/lib/scss/private/base/style.module.scss +52 -0
  199. package/src/lib/scss/private/base/typography.stories.mdx +71 -0
  200. package/src/lib/scss/private/base/width_and_height.stories.mdx +172 -0
  201. package/src/lib/scss/private/components/_badge.scss +41 -0
  202. package/src/lib/scss/private/components/_buttons.scss +193 -0
  203. package/src/lib/scss/private/components/_cards.scss +32 -0
  204. package/src/lib/scss/private/components/_index.scss +6 -0
  205. package/src/lib/scss/private/components/_input.scss +241 -0
  206. package/src/lib/scss/private/components/_notices.scss +39 -0
  207. package/src/lib/scss/private/components/_spinner.scss +60 -0
  208. package/src/lib/scss/private/components/assets/checkmark.svg +3 -0
  209. package/src/lib/scss/private/components/assets/icon-form-dropdown.svg +3 -0
  210. package/src/lib/scss/private/components/badge.stories.mdx +37 -0
  211. package/src/lib/scss/private/components/button.stories.mdx +107 -0
  212. package/src/lib/scss/private/components/cards.stories.mdx +35 -0
  213. package/src/lib/scss/private/components/checkbox.stories.mdx +47 -0
  214. package/src/lib/scss/private/components/input.stories.mdx +33 -0
  215. package/src/lib/scss/private/components/notices.stories.mdx +37 -0
  216. package/src/lib/scss/private/components/radio.stories.mdx +47 -0
  217. package/src/lib/scss/private/components/select.stories.mdx +17 -0
  218. package/src/lib/scss/private/components/spinner.stories.mdx +25 -0
  219. package/src/lib/scss/public/colors/_index.scss +2 -0
  220. package/src/lib/scss/public/colors/default.scss +130 -0
  221. package/src/lib/scss/public/colors/overrides.scss +0 -0
  222. package/src/lib/scss/public/colors.stories.mdx +27 -0
  223. package/src/lib/scss/public/demo.tsx +297 -0
  224. package/src/lib/scss/public/font/_index.scss +2 -0
  225. package/src/lib/scss/public/font/default.scss +3 -0
  226. package/src/lib/scss/public/font/overrides.scss +0 -0
  227. package/src/lib/scss/public/font-weight.scss +9 -0
  228. package/src/lib/scss/public/font-weight.stories.mdx +32 -0
  229. package/src/lib/scss/public/grid.scss +21 -0
  230. package/src/lib/scss/public/grid.stories.mdx +41 -0
  231. package/src/lib/scss/third-party/_google_places.scss +62 -0
  232. package/src/lib/scss/third-party/_index.scss +1 -0
  233. package/src/lib/scss/utils/_index.scss +3 -0
  234. package/src/lib/util/calendarDate/index.test.ts +32 -0
  235. package/src/lib/util/calendarDate/index.ts +30 -0
  236. package/src/lib/util/zeroFill.test.ts +15 -0
  237. package/src/lib/util/zeroFill.ts +7 -0
  238. package/src/react-app-env.d.ts +1 -0
  239. package/src/setupTests.js +8 -0
  240. package/src/theme.stories.mdx +54 -0
@@ -0,0 +1,316 @@
1
+ import { useState } from 'react';
2
+
3
+ import { Meta } from '@storybook/addon-docs/blocks';
4
+
5
+ import { BottomModal, RegularModal, BottomOrRegularModal } from '.';
6
+
7
+ <Meta title="JSX/Modals" />
8
+
9
+ # Modals
10
+
11
+ Modals are dialog overlays that prevent the user from interacting with the rest of the website until an action is taken or the dialog is dismissed. Modals are purposefully disruptive and should be used thoughtfully and sparingly.
12
+
13
+ <Preview>
14
+ <iframe
15
+ width="100%"
16
+ height="450"
17
+ src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FMKs4cbojdVOBKUxv7okb93%2FDirty-Swan-Design-System%3Fnode-id%3D283%253A1"
18
+ allowFullScreen
19
+ ></iframe>
20
+ </Preview>
21
+
22
+ | attribute | unit | description | default value | required |
23
+ | ----------- | --------------------- | -------------------------------------------------------------------------------------- | ------------- | -------- |
24
+ | title | string | The title that needs to be displayed on the modal | n/a | true |
25
+ | isOpen | boolean | When set to `true`, the modal is displayed. When set to `false` the modal gets removed | n/a | true |
26
+ | onClose | `function () => void` | Callback when the user close the modal | n/a | true |
27
+ | children | React.jsx | The content that gets displayed on the modal | n/a | true |
28
+ | className | string | Any additional className | n/a | false |
29
+ | dismissible | boolean | When set to `false` prevents the user from closing the modal | true | false |
30
+
31
+ export const RegularModalStory = () => {
32
+ const [display, setDisplay] = useState(false);
33
+ return (
34
+ <>
35
+ <button
36
+ className="p-btn--primary wmn2"
37
+ onClick={() => {
38
+ setDisplay(!display);
39
+ }}
40
+ >
41
+ Regular modal
42
+ </button>
43
+ <RegularModal
44
+ title="Regular modal title"
45
+ isOpen={display}
46
+ onClose={() => {
47
+ setDisplay(false);
48
+ }}
49
+ >
50
+ <div style={{ padding: '0 24px 24px 24px' }}>
51
+ <p className="p-p">
52
+ This is a regular modal that is mostly meant to be used on desktop.
53
+ Need to use it on mobile? Check my friend BottomModal instead! Not
54
+ sure? Just use BottomOrRegularModal <br /> Do you like this modal?
55
+ Tell us by answering this short survey!
56
+ </p>
57
+ <div className="p-label-container wmx4">
58
+ <input id="bordered-1" className="p-radio" type="radio" />
59
+ <label htmlFor="bordered-1" className="p-label p-label--bordered">
60
+ Yes
61
+ </label>
62
+ <input id="bordered-2" className="p-radio" type="radio" />
63
+ <label
64
+ htmlFor="bordered-2"
65
+ className="p-label p-label--bordered mt16"
66
+ >
67
+ No
68
+ </label>
69
+ </div>
70
+ <button
71
+ className="p-btn--primary mt24 wmn3"
72
+ onClick={() => setDisplay(false)}
73
+ >
74
+ Continue
75
+ </button>
76
+ </div>
77
+ </RegularModal>
78
+ </>
79
+ );
80
+ };
81
+
82
+ export const BottomModalStory = () => {
83
+ const [display, setDisplay] = useState(false);
84
+ return (
85
+ <>
86
+ <button
87
+ className="p-btn--primary wmn2 d-block"
88
+ onClick={() => {
89
+ setDisplay(!display);
90
+ }}
91
+ >
92
+ Bottom modal
93
+ </button>
94
+ <BottomModal
95
+ title="Bottom modal title"
96
+ isOpen={display}
97
+ onClose={() => {
98
+ setDisplay(false);
99
+ }}
100
+ >
101
+ <div style={{ padding: '0 16px 16px 16px' }}>
102
+ <p className="p-p">
103
+ This is a bottom modal that is mostly meant to be used on mobile, do
104
+ you like this modal? Tell us by answering this short survey!
105
+ </p>
106
+ <div className="p-label-container wmx4">
107
+ <input id="bordered-1" className="p-radio" type="radio" />
108
+ <label htmlFor="bordered-1" className="p-label p-label--bordered">
109
+ Yes
110
+ </label>
111
+ <input id="bordered-2" className="p-radio" type="radio" />
112
+ <label
113
+ htmlFor="bordered-2"
114
+ className="p-label p-label--bordered mt16"
115
+ >
116
+ No
117
+ </label>
118
+ </div>
119
+ <button
120
+ className="p-btn--primary mt24 wmn3"
121
+ onClick={() => setDisplay(false)}
122
+ >
123
+ Continue
124
+ </button>
125
+ </div>
126
+ </BottomModal>
127
+ </>
128
+ );
129
+ };
130
+
131
+ export const NonDismissibleModal = () => {
132
+ const [display, setDisplay] = useState(false);
133
+ return (
134
+ <>
135
+ <button
136
+ className="p-btn--primary wmn2"
137
+ onClick={() => {
138
+ setDisplay(!display);
139
+ }}
140
+ >
141
+ Open modal
142
+ </button>
143
+ <RegularModal
144
+ title="Non-dismissible modal title"
145
+ isOpen={display}
146
+ onClose={() => {
147
+ setDisplay(false);
148
+ }}
149
+ dismissible={false}
150
+ >
151
+ <div style={{ padding: '0 24px 24px 24px' }}>
152
+ <p className="p-p">
153
+ This modal requires clear user interaction to dismiss it. The close
154
+ button is hidden, and it cannot be closed using the keyboard nor
155
+ clicking outside.
156
+ </p>
157
+ <button
158
+ className="p-btn--primary bg-red-500 mt24 wmn3"
159
+ onClick={() => setDisplay(false)}
160
+ >
161
+ Reject
162
+ </button>
163
+ <button
164
+ className="p-btn--primary mt24 wmn3 ml16"
165
+ onClick={() => setDisplay(false)}
166
+ >
167
+ Accept
168
+ </button>
169
+ </div>
170
+ </RegularModal>
171
+ </>
172
+ );
173
+ };
174
+
175
+ ## Regular modal
176
+
177
+ Regular modals are primary meant to be used on Desktop or Tablet environment. The modal will appear in the middle of the screen and the user will be able to dismiss them using the top left "X" icon.
178
+
179
+ If you want to use it for Mobile only, you should check [Bottom modal](##Bottom-modal) instead.
180
+
181
+ Want to use either Regular Modal or Bottom Modal based on the screen width? You can use [Bottom or Regular modal](##Bottom-or-Regular-modal).
182
+
183
+ <RegularModalStory />
184
+
185
+ ```typescript
186
+ import React, { useState } from 'react';
187
+ import { BottomModal } from '@popsure/dirty-swan';
188
+
189
+ export default () => {
190
+ const [display, setDisplay] = useState(false);
191
+
192
+ return (
193
+ <>
194
+ <button
195
+ className="p-btn--primary wmn2 d-block"
196
+ onClick={() => {
197
+ setDisplay(!display);
198
+ }}
199
+ >
200
+ Bottom modal
201
+ </button>
202
+ <BottomModal
203
+ title="Bottom modal title"
204
+ isOpen={display}
205
+ onClose={() => {
206
+ setDisplay(false);
207
+ }}
208
+ >
209
+ <div style={{ padding: '0 16px 16px 16px' }}>
210
+ <p className="p-p">
211
+ This is a bottom modal that is mostly meant to be used on mobile, do
212
+ you like this modal? Tell us by answering this short survey!
213
+ </p>
214
+ <div className="p-label-container wmx4">
215
+ <input id="bordered-1" className="p-radio" type="radio" />
216
+ <label htmlFor="bordered-1" className="p-label p-label--bordered">
217
+ Yes
218
+ </label>
219
+ <input id="bordered-2" className="p-radio" type="radio" />
220
+ <label
221
+ htmlFor="bordered-2"
222
+ className="p-label p-label--bordered mt16"
223
+ >
224
+ No
225
+ </label>
226
+ </div>
227
+ <button
228
+ className="p-btn--primary mt24 wmn3"
229
+ onClick={() => setDisplay(false)}
230
+ >
231
+ Continue
232
+ </button>
233
+ </div>
234
+ </BottomModal>
235
+ </>
236
+ );
237
+ };
238
+ ```
239
+
240
+ ## Bottom modal
241
+
242
+ Regular modals are primary meant to be used on Mobile environment. The modal will appear from the bottom of the screen and the user will be able to dismiss them using the top left "X" icon.
243
+
244
+ If you want to use it for Desktop only, you should check [Regular modal](##Regular-modal) instead.
245
+
246
+ Want to use either Regular Modal or Bottom Modal based on the screen width? You can use [Bottom or Regular modal](##Bottom-or-Regular-modal).
247
+
248
+ <BottomModalStory />
249
+
250
+ ```typescript
251
+ import React, { useState } from 'react';
252
+ import { BottomModal } from '@popsure/dirty-swan';
253
+
254
+ export default () => {
255
+ const [display, setDisplay] = useState(false);
256
+
257
+ return (
258
+ <>
259
+ <button
260
+ className="p-btn--primary wmn2 d-block"
261
+ onClick={() => {
262
+ setDisplay(!display);
263
+ }}
264
+ >
265
+ Bottom modal
266
+ </button>
267
+ <BottomModal
268
+ title="Bottom modal title"
269
+ isOpen={display}
270
+ onClose={() => {
271
+ setDisplay(false);
272
+ }}
273
+ >
274
+ <div style={{ padding: '0 16px 16px 16px' }}>
275
+ <p className="p-p">
276
+ This is a bottom modal that is mostly meant to be used on mobile, do
277
+ you like this modal? Tell us by answering this short survey!
278
+ </p>
279
+ <div className="p-label-container wmx4">
280
+ <input id="bordered-1" className="p-radio" type="radio" />
281
+ <label htmlFor="bordered-1" className="p-label p-label--bordered">
282
+ Yes
283
+ </label>
284
+ <input id="bordered-2" className="p-radio" type="radio" />
285
+ <label
286
+ htmlFor="bordered-2"
287
+ className="p-label p-label--bordered mt16"
288
+ >
289
+ No
290
+ </label>
291
+ </div>
292
+ <button
293
+ className="p-btn--primary mt24 wmn3"
294
+ onClick={() => setDisplay(false)}
295
+ >
296
+ Continue
297
+ </button>
298
+ </div>
299
+ </BottomModal>
300
+ </>
301
+ );
302
+ };
303
+ ```
304
+
305
+ ## Bottom or Regular modal
306
+
307
+ Bottom or Regular modal will automatically choose what’s best to display based on the users screen width.
308
+
309
+ ## Non-dismissible modal
310
+
311
+ Setting the `dismissible` prop to false will hide the close button and prevent the user from closing it using the escape key or clicking outside.
312
+ This prop can be useful if we want the user to explicitly interact with the modal options.
313
+
314
+ **Warning:** a modal with the `dismissible` prop can only be closed by changing the `isOpen` prop to `false`.
315
+
316
+ <NonDismissibleModal />
@@ -0,0 +1,14 @@
1
+ import BottomModal from './bottomModal';
2
+ import RegularModal from './regularModal';
3
+ import BottomOrRegularModal from './bottomOrRegularModal';
4
+
5
+ export interface Props {
6
+ title: string;
7
+ isOpen: boolean;
8
+ children: React.ReactNode;
9
+ onClose: () => void;
10
+ className?: string;
11
+ dismissible?: boolean;
12
+ }
13
+
14
+ export { BottomModal, RegularModal, BottomOrRegularModal };
@@ -0,0 +1,4 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M18 6L6 18" stroke="#26262E" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
3
+ <path d="M6 6L18 18" stroke="#26262E" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
4
+ </svg>
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+
3
+ import { Props } from '..';
4
+ import useOnClose from '../hooks/useOnClose';
5
+
6
+ import styles from './style.module.scss';
7
+
8
+ import imageClose from './img/close.svg';
9
+
10
+ export default ({
11
+ title,
12
+ isOpen,
13
+ children,
14
+ onClose,
15
+ className = '',
16
+ dismissible = true,
17
+ }: Props) => {
18
+ const { isClosing, handleContainerClick, handleOnClose } = useOnClose(
19
+ onClose,
20
+ isOpen,
21
+ dismissible
22
+ );
23
+
24
+ if (!isOpen) {
25
+ return <></>;
26
+ }
27
+
28
+ return (
29
+ <div
30
+ className={isClosing ? styles['overlay--close'] : styles.overlay}
31
+ onClick={handleOnClose}
32
+ >
33
+ <div
34
+ className={`${
35
+ isClosing ? styles['container--close'] : styles.container
36
+ } ${className}`}
37
+ onClick={handleContainerClick}
38
+ >
39
+ <div className={styles.header}>
40
+ <div className={`p-h2 ${styles.title}`}>{title}</div>
41
+ {dismissible && (
42
+ <button
43
+ type="button"
44
+ className={styles.close}
45
+ onClick={handleOnClose}
46
+ >
47
+ <img src={imageClose} alt="Close" />
48
+ </button>
49
+ )}
50
+ </div>
51
+ {children}
52
+ </div>
53
+ </div>
54
+ );
55
+ };
@@ -0,0 +1,106 @@
1
+ @keyframes fade-in {
2
+ 0% {
3
+ background-color: rgba($color: #000000, $alpha: 0);
4
+ }
5
+ 100% {
6
+ background-color: rgba($color: #000000, $alpha: 0.3);
7
+ }
8
+ }
9
+
10
+ @keyframes fade-out {
11
+ from {
12
+ background-color: rgba($color: #000000, $alpha: 0.3);
13
+ }
14
+ to {
15
+ background-color: rgba($color: #000000, $alpha: 0);
16
+ }
17
+ }
18
+
19
+ @keyframes appear-in {
20
+ 0% {
21
+ transform: translateY(24px) translateX(-50%);
22
+ opacity: 0;
23
+ }
24
+ 100% {
25
+ transform: translateY(0) translateX(-50%);
26
+ opacity: 1;
27
+ }
28
+ }
29
+
30
+ @keyframes disappear-out {
31
+ 0% {
32
+ transform: translateY(0) translateX(-50%);
33
+ opacity: 1;
34
+ }
35
+ 100% {
36
+ transform: translateY(24px) translateX(-50%);
37
+ opacity: 0;
38
+ }
39
+ }
40
+
41
+ .overlay {
42
+ position: fixed;
43
+
44
+ z-index: 100;
45
+
46
+ overflow: auto;
47
+
48
+ top: 0;
49
+ bottom: 0;
50
+ left: 0;
51
+ right: 0;
52
+
53
+ animation: fade-in 0.3s both;
54
+
55
+ &--close {
56
+ @extend .overlay;
57
+ animation-delay: 0.1s;
58
+ animation: fade-out 0.3s both;
59
+ }
60
+ }
61
+
62
+ .container {
63
+ position: relative;
64
+
65
+ background-color: white;
66
+
67
+ border-radius: 8px;
68
+
69
+ max-width: 592px;
70
+ width: fit-content;
71
+ width: -moz-fit-content;
72
+
73
+ animation-name: appear-in;
74
+ animation-duration: 0.4s;
75
+ animation-fill-mode: both;
76
+ animation-timing-function: ease-out;
77
+
78
+ top: calc(100vh / 2 - 50% / 2);
79
+ left: 50%;
80
+ transform: translateX(-50%);
81
+
82
+ margin-bottom: 80px;
83
+
84
+ &--close {
85
+ @extend .container;
86
+ animation-name: disappear-out;
87
+ animation-duration: 0.4s;
88
+ animation-delay: 0s;
89
+ animation-fill-mode: both;
90
+ animation-timing-function: ease-out;
91
+ }
92
+ }
93
+
94
+ .header {
95
+ display: flex;
96
+ justify-content: space-between;
97
+ align-items: center;
98
+
99
+ padding: 24px 24px 0 24px;
100
+ }
101
+
102
+ .close {
103
+ border: none;
104
+ background-color: transparent;
105
+ cursor: pointer;
106
+ }
@@ -0,0 +1,138 @@
1
+ import React from 'react';
2
+ import classnames from 'classnames';
3
+
4
+ import styles from './style.module.scss';
5
+ import icons from '../icons/index';
6
+ import { UploadStatus, UploadedFile, FileType } from '..';
7
+
8
+ const getUploadingIcon = (type: FileType | string): string => {
9
+ switch (type) {
10
+ case 'heic':
11
+ return icons.heicIcon;
12
+ case 'bmp':
13
+ return icons.bmpIcon;
14
+ case 'doc':
15
+ return icons.docIcon;
16
+ case 'docx':
17
+ return icons.docxIcon;
18
+ case 'jpeg':
19
+ return icons.jpegIcon;
20
+ case 'jpg':
21
+ return icons.jpgIcon;
22
+ case 'pdf':
23
+ return icons.pdfIcon;
24
+ case 'png':
25
+ return icons.pngIcon;
26
+ default:
27
+ return icons.genericIcon;
28
+ }
29
+ };
30
+
31
+ const getCompleteIcon = (type: FileType | string): string => {
32
+ switch (type) {
33
+ case 'heic':
34
+ return icons.heicCompleteIcon;
35
+ case 'bmp':
36
+ return icons.bmpCompleteIcon;
37
+ case 'doc':
38
+ return icons.docCompleteIcon;
39
+ case 'docx':
40
+ return icons.docxCompleteIcon;
41
+ case 'jpeg':
42
+ return icons.jpegCompleteIcon;
43
+ case 'jpg':
44
+ return icons.jpgCompleteIcon;
45
+ case 'pdf':
46
+ return icons.pdfCompleteIcon;
47
+ case 'png':
48
+ return icons.pngCompleteIcon;
49
+ default:
50
+ return icons.genericCompleteIcon;
51
+ }
52
+ };
53
+
54
+ export default ({
55
+ uploadStatus,
56
+ file,
57
+ onRemoveFile,
58
+ uploading,
59
+ }: {
60
+ uploadStatus: UploadStatus;
61
+ file: UploadedFile;
62
+ onRemoveFile: (id: string) => void;
63
+ uploading: boolean;
64
+ }) => {
65
+ const { id, error, type, name, progress, previewUrl } = file;
66
+
67
+ const mapFileIcon: { [k in UploadStatus]: string } = {
68
+ UPLOADING: getUploadingIcon(type),
69
+ COMPLETE: getCompleteIcon(type),
70
+ ERROR: icons.errorIcon,
71
+ };
72
+
73
+ const mapDisplayText: { [s in UploadStatus]: string } = {
74
+ UPLOADING: 'Uploading...',
75
+ COMPLETE: name,
76
+ ERROR: error ?? 'Something went wrong. Try uploading again.',
77
+ };
78
+
79
+ return (
80
+ <div
81
+ className={classnames(`mt8 ${styles['upload-file-cell']}`, {
82
+ [styles['upload-file-cell-error']]: uploadStatus === 'ERROR',
83
+ })}
84
+ >
85
+ <div className={`w100 ${styles['cell-left-section']}`}>
86
+ <img
87
+ className={styles['main-icon']}
88
+ src={mapFileIcon[uploadStatus]}
89
+ alt=""
90
+ />
91
+ <div className="w100">
92
+ <div className={`p-p wmx5 ${styles['upload-display-text']}`}>
93
+ {mapDisplayText[uploadStatus]}
94
+ </div>
95
+ {uploadStatus === 'UPLOADING' && (
96
+ <div className={`mt8 w100 ${styles['progress-bar-container']}`}>
97
+ <div className={`${styles['progress-bar']}`} />
98
+ <div
99
+ className={`${styles['progress-bar-filler']}`}
100
+ style={{ width: `${progress}%` }}
101
+ />
102
+ </div>
103
+ )}
104
+ </div>
105
+ </div>
106
+ <div
107
+ className={classnames(styles['cell-right-section'], {
108
+ [styles['cell-right-section-complete']]: uploadStatus === 'COMPLETE',
109
+ })}
110
+ >
111
+ {uploadStatus === 'UPLOADING' ? (
112
+ <div className={`p-spinner p-spinner__m ${styles.spinner}`} />
113
+ ) : (
114
+ <div>
115
+ {uploadStatus === 'COMPLETE' && (
116
+ <a
117
+ className={styles['view-icon']}
118
+ href={previewUrl}
119
+ target="_blank"
120
+ rel="noopener noreferrer"
121
+ >
122
+ <img src={icons.eyeIcon} alt="preview" />
123
+ </a>
124
+ )}
125
+ <img
126
+ className={classnames(styles['remove-icon'], {
127
+ [styles.disabled]: uploading,
128
+ })}
129
+ src={icons.trashIcon}
130
+ onClick={() => onRemoveFile(id)}
131
+ alt="remove"
132
+ />
133
+ </div>
134
+ )}
135
+ </div>
136
+ </div>
137
+ );
138
+ };