polpo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/.eslintrc.cjs +9 -0
  2. package/.storybook/decorators.tsx +61 -0
  3. package/.storybook/main.ts +47 -0
  4. package/.storybook/manager-head.html +2 -0
  5. package/.storybook/manager.ts +7 -0
  6. package/.storybook/preview-head.html +2 -0
  7. package/.storybook/preview.ts +38 -0
  8. package/.storybook/theme.ts +47 -0
  9. package/.turbo/daemon/f5c5c8fb195b01d0-turbo.log.2024-05-26 +0 -0
  10. package/.turbo/turbo-build$colon$watch.log +96 -0
  11. package/.turbo/turbo-build-storybook.log +0 -0
  12. package/.turbo/turbo-build.log +77 -0
  13. package/.turbo/turbo-lint$colon$fix.log +2 -0
  14. package/.turbo/turbo-lint.log +4 -0
  15. package/README.md +68 -0
  16. package/dist/chunk-M4KRSYE7.js +3 -0
  17. package/dist/chunk-M4KRSYE7.js.map +1 -0
  18. package/dist/chunk-U5XSMSKZ.js +3 -0
  19. package/dist/chunk-U5XSMSKZ.js.map +1 -0
  20. package/dist/get-modal-position-DPftPoU2.d.cts +28 -0
  21. package/dist/get-modal-position-DPftPoU2.d.ts +28 -0
  22. package/dist/helpers.cjs +3 -0
  23. package/dist/helpers.cjs.map +1 -0
  24. package/dist/helpers.d.cts +15 -0
  25. package/dist/helpers.d.ts +15 -0
  26. package/dist/helpers.js +3 -0
  27. package/dist/helpers.js.map +1 -0
  28. package/dist/hooks.cjs +3 -0
  29. package/dist/hooks.cjs.map +1 -0
  30. package/dist/hooks.d.cts +121 -0
  31. package/dist/hooks.d.ts +121 -0
  32. package/dist/hooks.js +3 -0
  33. package/dist/hooks.js.map +1 -0
  34. package/dist/ui.cjs +1987 -0
  35. package/dist/ui.cjs.map +1 -0
  36. package/dist/ui.d.cts +3932 -0
  37. package/dist/ui.d.ts +3932 -0
  38. package/dist/ui.js +1987 -0
  39. package/dist/ui.js.map +1 -0
  40. package/package.json +98 -0
  41. package/src/components/accordion/accordion-item.stories.tsx +128 -0
  42. package/src/components/accordion/accordion-item.tsx +119 -0
  43. package/src/components/accordion/accordion.stories.tsx +74 -0
  44. package/src/components/accordion/accordion.style.ts +42 -0
  45. package/src/components/accordion/accordion.tsx +56 -0
  46. package/src/components/accordion/index.ts +2 -0
  47. package/src/components/buttons/button/button.stories.tsx +103 -0
  48. package/src/components/buttons/button/button.style.ts +147 -0
  49. package/src/components/buttons/button/button.tsx +119 -0
  50. package/src/components/buttons/button/index.ts +1 -0
  51. package/src/components/buttons/index.ts +1 -0
  52. package/src/components/cards/flip-card/flip-card.stories.tsx +61 -0
  53. package/src/components/cards/flip-card/flip-card.style.ts +45 -0
  54. package/src/components/cards/flip-card/flip-card.tsx +55 -0
  55. package/src/components/cards/flip-card/index.ts +1 -0
  56. package/src/components/cards/hover-card/hover-card.stories.tsx +45 -0
  57. package/src/components/cards/hover-card/hover-card.style.ts +13 -0
  58. package/src/components/cards/hover-card/hover-card.tsx +71 -0
  59. package/src/components/cards/hover-card/index.ts +1 -0
  60. package/src/components/cards/index.ts +3 -0
  61. package/src/components/cards/slide-card/index.ts +1 -0
  62. package/src/components/cards/slide-card/slide-card.stories.tsx +47 -0
  63. package/src/components/cards/slide-card/slide-card.tsx +42 -0
  64. package/src/components/form/checkbox/checkbox.stories.tsx +34 -0
  65. package/src/components/form/checkbox/checkbox.style.ts +75 -0
  66. package/src/components/form/checkbox/checkbox.tsx +76 -0
  67. package/src/components/form/checkbox/index.ts +1 -0
  68. package/src/components/form/controller/controller.tsx +42 -0
  69. package/src/components/form/controller/index.ts +1 -0
  70. package/src/components/form/date-picker/date-picker.stories.tsx +38 -0
  71. package/src/components/form/date-picker/date-picker.tsx +67 -0
  72. package/src/components/form/date-picker/index.ts +1 -0
  73. package/src/components/form/field/field.stories.tsx +49 -0
  74. package/src/components/form/field/field.style.ts +79 -0
  75. package/src/components/form/field/field.tsx +83 -0
  76. package/src/components/form/field/field.types.ts +28 -0
  77. package/src/components/form/field/index.ts +2 -0
  78. package/src/components/form/form.stories.types.tsx +50 -0
  79. package/src/components/form/form.types.ts +37 -0
  80. package/src/components/form/index.ts +14 -0
  81. package/src/components/form/input/index.ts +1 -0
  82. package/src/components/form/input/input.stories.tsx +41 -0
  83. package/src/components/form/input/input.tsx +73 -0
  84. package/src/components/form/input-color/index.ts +1 -0
  85. package/src/components/form/input-color/input-color.stories.tsx +46 -0
  86. package/src/components/form/input-color/input-color.style.ts +93 -0
  87. package/src/components/form/input-color/input-color.tsx +159 -0
  88. package/src/components/form/input-file/index.ts +1 -0
  89. package/src/components/form/input-file/input-file.stories.tsx +40 -0
  90. package/src/components/form/input-file/input-file.style.ts +143 -0
  91. package/src/components/form/input-file/input-file.tsx +214 -0
  92. package/src/components/form/input-password/index.ts +1 -0
  93. package/src/components/form/input-password/input-password.stories.tsx +37 -0
  94. package/src/components/form/input-password/input-password.tsx +83 -0
  95. package/src/components/form/radio/index.ts +1 -0
  96. package/src/components/form/radio/radio.stories.tsx +43 -0
  97. package/src/components/form/radio/radio.style.ts +58 -0
  98. package/src/components/form/radio/radio.tsx +76 -0
  99. package/src/components/form/select/index.ts +1 -0
  100. package/src/components/form/select/options.tsx +140 -0
  101. package/src/components/form/select/select-option.tsx +84 -0
  102. package/src/components/form/select/select.stories.tsx +89 -0
  103. package/src/components/form/select/select.style.ts +164 -0
  104. package/src/components/form/select/select.tsx +327 -0
  105. package/src/components/form/select/select.types.ts +93 -0
  106. package/src/components/form/slider/index.ts +1 -0
  107. package/src/components/form/slider/slider.stories.tsx +40 -0
  108. package/src/components/form/slider/slider.style.ts +90 -0
  109. package/src/components/form/slider/slider.tsx +108 -0
  110. package/src/components/form/switch/index.ts +1 -0
  111. package/src/components/form/switch/switch.stories.tsx +38 -0
  112. package/src/components/form/switch/switch.style.ts +120 -0
  113. package/src/components/form/switch/switch.tsx +111 -0
  114. package/src/components/form/textarea/index.ts +1 -0
  115. package/src/components/form/textarea/textarea.stories.tsx +43 -0
  116. package/src/components/form/textarea/textarea.style.ts +7 -0
  117. package/src/components/form/textarea/textarea.tsx +76 -0
  118. package/src/components/icon/icon.stories.tsx +63 -0
  119. package/src/components/icon/icon.tsx +64 -0
  120. package/src/components/icon/icons/index.ts +18 -0
  121. package/src/components/icon/icons/object.tsx +482 -0
  122. package/src/components/icon/icons/social.tsx +72 -0
  123. package/src/components/icon/icons/symbol.tsx +776 -0
  124. package/src/components/icon/index.ts +5 -0
  125. package/src/components/image/image.stories.tsx +25 -0
  126. package/src/components/image/image.tsx +7 -0
  127. package/src/components/image/index.ts +1 -0
  128. package/src/components/index.ts +16 -0
  129. package/src/components/infinity-scroll/index.ts +1 -0
  130. package/src/components/infinity-scroll/infinity-scroll.stories.tsx +75 -0
  131. package/src/components/infinity-scroll/infinity-scroll.style.ts +30 -0
  132. package/src/components/infinity-scroll/infinity-scroll.tsx +56 -0
  133. package/src/components/line/index.ts +1 -0
  134. package/src/components/line/line.stories.tsx +67 -0
  135. package/src/components/line/line.style.ts +57 -0
  136. package/src/components/line/line.tsx +76 -0
  137. package/src/components/loaders/index.ts +1 -0
  138. package/src/components/loaders/simple-loader/index.ts +1 -0
  139. package/src/components/loaders/simple-loader/simple-loader.stories.tsx +21 -0
  140. package/src/components/loaders/simple-loader/simple-loader.style.ts +13 -0
  141. package/src/components/loaders/simple-loader/simple-loader.tsx +15 -0
  142. package/src/components/modals/action-modal/action-modal.stories.tsx +134 -0
  143. package/src/components/modals/action-modal/action-modal.style.ts +129 -0
  144. package/src/components/modals/action-modal/action-modal.tsx +150 -0
  145. package/src/components/modals/action-modal/index.ts +1 -0
  146. package/src/components/modals/aside-modal/aside-modal.stories.tsx +82 -0
  147. package/src/components/modals/aside-modal/aside-modal.style.ts +108 -0
  148. package/src/components/modals/aside-modal/aside-modal.tsx +66 -0
  149. package/src/components/modals/aside-modal/index.ts +1 -0
  150. package/src/components/modals/confirmation-modal/confirmation-modal.stories.tsx +50 -0
  151. package/src/components/modals/confirmation-modal/confirmation-modal.style.ts +17 -0
  152. package/src/components/modals/confirmation-modal/confirmation-modal.tsx +43 -0
  153. package/src/components/modals/confirmation-modal/index.ts +1 -0
  154. package/src/components/modals/index.ts +4 -0
  155. package/src/components/modals/modal/index.ts +1 -0
  156. package/src/components/modals/modal/modal.style.ts +10 -0
  157. package/src/components/modals/modal/modal.tsx +132 -0
  158. package/src/components/ripple/index.ts +1 -0
  159. package/src/components/ripple/ripple.stories.tsx +38 -0
  160. package/src/components/ripple/ripple.style.ts +33 -0
  161. package/src/components/ripple/ripple.tsx +63 -0
  162. package/src/components/smart-table/index.ts +1 -0
  163. package/src/components/smart-table/smart-table.column.tsx +63 -0
  164. package/src/components/smart-table/smart-table.helpers.tsx +59 -0
  165. package/src/components/smart-table/smart-table.hooks.ts +27 -0
  166. package/src/components/smart-table/smart-table.row.tsx +29 -0
  167. package/src/components/smart-table/smart-table.stories.tsx +301 -0
  168. package/src/components/smart-table/smart-table.style.ts +102 -0
  169. package/src/components/smart-table/smart-table.tsx +112 -0
  170. package/src/components/smart-table/smart-table.types.ts +41 -0
  171. package/src/components/tabs/index.ts +1 -0
  172. package/src/components/tabs/tabs-container.stories.tsx +159 -0
  173. package/src/components/tabs/tabs-list.tsx +131 -0
  174. package/src/components/tabs/tabs.stories.tsx +68 -0
  175. package/src/components/tabs/tabs.style.ts +132 -0
  176. package/src/components/tabs/tabs.tsx +117 -0
  177. package/src/components/tag/index.ts +1 -0
  178. package/src/components/tag/tag.stories.tsx +49 -0
  179. package/src/components/tag/tag.style.ts +24 -0
  180. package/src/components/tag/tag.tsx +44 -0
  181. package/src/components/tooltips/click-to-copy/click-to-copy.stories.tsx +39 -0
  182. package/src/components/tooltips/click-to-copy/click-to-copy.tsx +41 -0
  183. package/src/components/tooltips/click-to-copy/index.ts +1 -0
  184. package/src/components/tooltips/index.ts +2 -0
  185. package/src/components/tooltips/tooltip/index.ts +1 -0
  186. package/src/components/tooltips/tooltip/tooltip.stories.tsx +35 -0
  187. package/src/components/tooltips/tooltip/tooltip.style.ts +62 -0
  188. package/src/components/tooltips/tooltip/tooltip.tsx +45 -0
  189. package/src/components/typography/index.ts +2 -0
  190. package/src/components/typography/typography.constants.ts +43 -0
  191. package/src/components/typography/typography.stories.tsx +106 -0
  192. package/src/components/typography/typography.style.ts +76 -0
  193. package/src/components/typography/typography.tsx +79 -0
  194. package/src/contexts/fetch-context/fetch-context.tsx +114 -0
  195. package/src/contexts/fetch-context/index.ts +1 -0
  196. package/src/contexts/form-context/form-context.tsx +43 -0
  197. package/src/contexts/form-context/index.ts +1 -0
  198. package/src/contexts/index.ts +3 -0
  199. package/src/contexts/theme-context/index.ts +3 -0
  200. package/src/contexts/theme-context/theme-context.tsx +158 -0
  201. package/src/contexts/theme-context/theme.animations.ts +180 -0
  202. package/src/contexts/theme-context/theme.defaults.ts +205 -0
  203. package/src/contexts/theme-context/theme.style.ts +78 -0
  204. package/src/contexts/theme-context/themes.ts +96 -0
  205. package/src/core/http-client.d.ts +11 -0
  206. package/src/core/http-client.d.ts.map +1 -0
  207. package/src/core/http-client.ts +47 -0
  208. package/src/core/index.d.ts +2 -0
  209. package/src/core/index.d.ts.map +1 -0
  210. package/src/core/index.ts +1 -0
  211. package/src/core/variants/color.ts +36 -0
  212. package/src/core/variants/index.ts +3 -0
  213. package/src/core/variants/radius.ts +56 -0
  214. package/src/core/variants/size.ts +44 -0
  215. package/src/helpers/format-bytes.ts +11 -0
  216. package/src/helpers/format-dates.ts +11 -0
  217. package/src/helpers/get-modal-position.ts +66 -0
  218. package/src/helpers/index.ts +4 -0
  219. package/src/helpers/text/index.ts +1 -0
  220. package/src/helpers/text/to-capitalize.ts +17 -0
  221. package/src/hooks/index.ts +23 -0
  222. package/src/hooks/use-async.ts +88 -0
  223. package/src/hooks/use-classnames.ts +13 -0
  224. package/src/hooks/use-constant.ts +3 -0
  225. package/src/hooks/use-debounce.ts +15 -0
  226. package/src/hooks/use-dimensions.ts +22 -0
  227. package/src/hooks/use-event-listener.ts +71 -0
  228. package/src/hooks/use-file-reader.ts +69 -0
  229. package/src/hooks/use-hover.ts +17 -0
  230. package/src/hooks/use-in-view.ts +20 -0
  231. package/src/hooks/use-input-handlers.ts +49 -0
  232. package/src/hooks/use-media-query.ts +25 -0
  233. package/src/hooks/use-modal-in-container.ts +94 -0
  234. package/src/hooks/use-mouse-position.ts +16 -0
  235. package/src/hooks/use-observer.ts +18 -0
  236. package/src/hooks/use-on-click-outside-ref.ts +17 -0
  237. package/src/hooks/use-online-status.ts +12 -0
  238. package/src/hooks/use-render-count.ts +11 -0
  239. package/src/hooks/use-safe-dispatch.ts +22 -0
  240. package/src/hooks/use-scroll.ts +31 -0
  241. package/src/hooks/use-state-history.ts +22 -0
  242. package/src/hooks/use-toggle-values.ts +14 -0
  243. package/src/hooks/use-toggle.ts +11 -0
  244. package/src/hooks/use-viewport.ts +38 -0
  245. package/src/index.ts +5 -0
  246. package/src/layouts/flex/flex.tsx +75 -0
  247. package/src/layouts/flex/index.ts +1 -0
  248. package/src/layouts/grid/grid.tsx +86 -0
  249. package/src/layouts/grid/index.ts +1 -0
  250. package/src/layouts/index.ts +3 -0
  251. package/src/layouts/section-layout/index.ts +1 -0
  252. package/src/layouts/section-layout/section-layout.stories.tsx +55 -0
  253. package/src/layouts/section-layout/section-layout.style.ts +21 -0
  254. package/src/layouts/section-layout/section-layout.tsx +46 -0
  255. package/src/stories/GettingStarted.mdx +66 -0
  256. package/src/types/generics.ts +68 -0
  257. package/src/types/index.ts +1 -0
  258. package/svg/Name=airplane, Category=object.svg +3 -0
  259. package/svg/Name=arrow-circle, Category=symbol.svg +3 -0
  260. package/svg/Name=arrow-down, Category=symbol.svg +3 -0
  261. package/svg/Name=arrow-left, Category=symbol.svg +3 -0
  262. package/svg/Name=arrow-right, Category=symbol.svg +3 -0
  263. package/svg/Name=arrow-up, Category=symbol.svg +3 -0
  264. package/svg/Name=bell, Category=object.svg +3 -0
  265. package/svg/Name=bicycle, Category=object.svg +3 -0
  266. package/svg/Name=book-open, Category=object.svg +3 -0
  267. package/svg/Name=book-solid, Category=object.svg +6 -0
  268. package/svg/Name=box-shadow, Category=symbol.svg +5 -0
  269. package/svg/Name=calendar, Category=object.svg +3 -0
  270. package/svg/Name=camera, Category=object.svg +3 -0
  271. package/svg/Name=caret-down, Category=symbol.svg +3 -0
  272. package/svg/Name=caret-left, Category=symbol.svg +3 -0
  273. package/svg/Name=caret-right, Category=symbol.svg +3 -0
  274. package/svg/Name=caret-up, Category=symbol.svg +3 -0
  275. package/svg/Name=checkmark, Category=symbol.svg +3 -0
  276. package/svg/Name=clean-computer, Category=object.svg +10 -0
  277. package/svg/Name=codepen, Category=social.svg +3 -0
  278. package/svg/Name=creative, Category=symbol.svg +5 -0
  279. package/svg/Name=cross, Category=symbol.svg +4 -0
  280. package/svg/Name=crossed-flags, Category=object.svg +4 -0
  281. package/svg/Name=cv, Category=symbol.svg +5 -0
  282. package/svg/Name=design-ui, Category=symbol.svg +9 -0
  283. package/svg/Name=document, Category=object.svg +3 -0
  284. package/svg/Name=door-closed, Category=object.svg +3 -0
  285. package/svg/Name=door-open, Category=object.svg +3 -0
  286. package/svg/Name=double-caret-down, Category=symbol.svg +4 -0
  287. package/svg/Name=double-caret-left, Category=symbol.svg +4 -0
  288. package/svg/Name=double-caret-righ, Category=symbol.svg +4 -0
  289. package/svg/Name=double-caret-up, Category=symbol.svg +4 -0
  290. package/svg/Name=download, Category=symbol.svg +5 -0
  291. package/svg/Name=dropper, Category=object.svg +5 -0
  292. package/svg/Name=envelope, Category=object.svg +3 -0
  293. package/svg/Name=exclamation-close, Category=symbol.svg +4 -0
  294. package/svg/Name=exclamation-open, Category=symbol.svg +4 -0
  295. package/svg/Name=external-link, Category=symbol.svg +3 -0
  296. package/svg/Name=eye, Category=object.svg +4 -0
  297. package/svg/Name=eye-hidden, Category=object.svg +7 -0
  298. package/svg/Name=facebook, Category=social.svg +3 -0
  299. package/svg/Name=form, Category=symbol.svg +8 -0
  300. package/svg/Name=game-control, Category=object.svg +3 -0
  301. package/svg/Name=gear, Category=object.svg +3 -0
  302. package/svg/Name=github, Category=social.svg +3 -0
  303. package/svg/Name=house, Category=object.svg +3 -0
  304. package/svg/Name=hyphen, Category=symbol.svg +3 -0
  305. package/svg/Name=info, Category=symbol.svg +3 -0
  306. package/svg/Name=instagram, Category=social.svg +3 -0
  307. package/svg/Name=link, Category=symbol.svg +5 -0
  308. package/svg/Name=linkedin, Category=social.svg +3 -0
  309. package/svg/Name=magnifying-glass, Category=object.svg +3 -0
  310. package/svg/Name=message, Category=symbol.svg +4 -0
  311. package/svg/Name=moon, Category=object.svg +5 -0
  312. package/svg/Name=order-list, Category=symbol.svg +7 -0
  313. package/svg/Name=pencil, Category=object.svg +3 -0
  314. package/svg/Name=pin-location, Category=symbol.svg +3 -0
  315. package/svg/Name=question-mark-close, Category=symbol.svg +3 -0
  316. package/svg/Name=question-mark-open, Category=symbol.svg +3 -0
  317. package/svg/Name=share, Category=symbol.svg +5 -0
  318. package/svg/Name=spinner, Category=symbol.svg +9 -0
  319. package/svg/Name=star, Category=object.svg +3 -0
  320. package/svg/Name=star-empty, Category=object.svg +3 -0
  321. package/svg/Name=sun, Category=object.svg +11 -0
  322. package/svg/Name=text-shadow, Category=symbol.svg +4 -0
  323. package/svg/Name=thinking, Category=symbol.svg +3 -0
  324. package/svg/Name=trash-can, Category=object.svg +4 -0
  325. package/svg/Name=upload, Category=symbol.svg +5 -0
  326. package/svg/Name=user, Category=symbol.svg +4 -0
  327. package/svg/Name=warning, Category=symbol.svg +5 -0
  328. package/svg/Name=whatsapp, Category=social.svg +3 -0
  329. package/svgconfig.json +4 -0
  330. package/tsconfig.json +14 -0
  331. package/tsup.config.cjs +21 -0
  332. package/vite.config.ts +13 -0
@@ -0,0 +1,129 @@
1
+ import { styled } from 'styled-components';
2
+
3
+ export const ActionModalContainerStyle = styled.section`
4
+ position: fixed;
5
+ top: 50%;
6
+ left: 50%;
7
+ transform: translate(-50%, -50%);
8
+ z-index: 10000;
9
+
10
+ .open-animation {
11
+ animation: bounceIn 500ms ease;
12
+ position: relative;
13
+ }
14
+
15
+ .close-animation {
16
+ animation: bounceOut 500ms ease;
17
+ }
18
+
19
+ .shake-animation {
20
+ animation: headShake 600ms linear;
21
+ }
22
+ `;
23
+
24
+ export const ActionModalStyle = styled.section`
25
+ position: relative;
26
+
27
+ .action-modal-body {
28
+ border-radius: 10px;
29
+ overflow: hidden;
30
+ display: grid;
31
+ }
32
+
33
+ .action-modal-content {
34
+ background: ${props => props.theme.colors.background.main};
35
+ padding: 3em 4em 2em;
36
+ display: grid;
37
+ gap: 1em;
38
+ }
39
+
40
+ &.no-padding .action-modal-content {
41
+ padding: 2em 0 0;
42
+ }
43
+
44
+ &:has(.action-modal-icon) .action-modal-content {
45
+ padding-top: 4em;
46
+ }
47
+
48
+ &.back-card {
49
+ &::before {
50
+ content: '';
51
+ position: absolute;
52
+ width: 90%;
53
+ height: 100%;
54
+ top: 8px;
55
+ left: 50%;
56
+ transform: translate(-50%);
57
+ z-index: -1;
58
+ background: ${props => props.theme.colors.primary.main};
59
+ border-radius: 10px;
60
+ display: block;
61
+ transition: top 300ms cubic-bezier(0.81, -0.52, 0.42, 2.5);
62
+ }
63
+ }
64
+
65
+ .action-modal-icon {
66
+ position: absolute;
67
+ top: 0;
68
+ left: 50%;
69
+ transform: translate(-50%, -50%);
70
+ background: ${props => props.theme.colors.primary.main};
71
+ color: ${props => props.theme.colors.primary.contrast};
72
+ padding: 0;
73
+ border-radius: 50%;
74
+ width: 2em;
75
+ height: 2em;
76
+ display: grid;
77
+ place-content: center;
78
+ transition: box-shadow 300ms cubic-bezier(0.81, -0.52, 0.42, 2.5);
79
+ z-index: 1;
80
+ box-shadow:
81
+ 0 0 0 0 ${props => props.theme.colors.primary.main}88,
82
+ 0 0 0 0 ${props => props.theme.colors.primary.main}66,
83
+ 0 0 0 0 ${props => props.theme.colors.primary.main}44,
84
+ 0 0 0 0 ${props => props.theme.colors.primary.main}22;
85
+ }
86
+
87
+ .close-modal-button {
88
+ width: 2em;
89
+ height: 2em;
90
+ border-radius: 50%;
91
+ border: 1px solid;
92
+ cursor: pointer;
93
+ display: grid;
94
+ place-content: center;
95
+ background: ${props => props.theme.colors.background.main};
96
+ position: absolute;
97
+ left: 100%;
98
+ bottom: 100%;
99
+ font-size: ${props => props.theme.constants.typography.small.fontSize};
100
+ opacity: 0;
101
+ transition: opacity 300ms ease;
102
+ z-index: 1;
103
+ transform: translate(-50%, 50%);
104
+ }
105
+
106
+ &.line-on-top {
107
+ .action-modal-content {
108
+ border-top: 5px solid ${props => props.theme.colors.primary.main};
109
+ }
110
+ }
111
+
112
+ &:hover {
113
+ .action-modal-icon {
114
+ box-shadow:
115
+ 0 0 0 7px ${props => props.theme.colors.primary.main}88,
116
+ 0 0 0 14px ${props => props.theme.colors.primary.main}66,
117
+ 0 0 0 21px ${props => props.theme.colors.primary.main}44,
118
+ 0 0 0 28px ${props => props.theme.colors.primary.main}22;
119
+ }
120
+
121
+ .close-modal-button {
122
+ opacity: 1;
123
+ }
124
+
125
+ &::before {
126
+ top: 15px;
127
+ }
128
+ }
129
+ `;
@@ -0,0 +1,150 @@
1
+ import { createContext, useCallback, useContext, useRef, useState } from 'react';
2
+
3
+ import { Button, ButtonProps } from '../../buttons';
4
+ import { Icon, IconNameT } from '../../icon';
5
+ import { Typography } from '../../typography';
6
+ import { Modal } from '../modal';
7
+
8
+ import { ActionModalContainerStyle, ActionModalStyle } from './action-modal.style';
9
+
10
+ import { useClassNames } from '@polpo/hooks';
11
+
12
+ export type ActionModalProps = {
13
+ children: React.ReactNode;
14
+ isOpen: boolean;
15
+ onClose: () => void;
16
+ actionRequired?: boolean;
17
+ icon?: IconNameT;
18
+ noCloseButton?: boolean;
19
+ className?: string;
20
+ style?: React.CSSProperties;
21
+ lineOnTop?: boolean;
22
+ backCard?: boolean;
23
+ noPadding?: boolean;
24
+ };
25
+
26
+ type ActionModalContextEntity = {
27
+ onClose: () => void;
28
+ };
29
+
30
+ const ActionModalContext = createContext<ActionModalContextEntity | null>(null);
31
+
32
+ const useActionModal = () => {
33
+ const context = useContext(ActionModalContext);
34
+
35
+ if (context === null) {
36
+ throw new Error('useActionModal must be used with in a ActionModal');
37
+ }
38
+
39
+ return context;
40
+ };
41
+
42
+ export const ActionModal = ({
43
+ children,
44
+ isOpen,
45
+ onClose,
46
+ actionRequired,
47
+ icon,
48
+ noCloseButton,
49
+ className = '',
50
+ style = {},
51
+ lineOnTop = false,
52
+ backCard = false,
53
+ noPadding = false,
54
+ }: ActionModalProps) => {
55
+ const ref = useRef<HTMLElement>(null);
56
+
57
+ const handleOnClose = useCallback((callback: () => void) => {
58
+ ref.current?.classList.remove('open-animation');
59
+ ref.current?.classList.add('close-animation');
60
+ setTimeout(() => {
61
+ callback();
62
+ ref.current?.classList.remove('close-animation');
63
+ }, 490);
64
+ }, []);
65
+
66
+ const remainAction = useCallback(() => {
67
+ ref.current?.classList.remove('open-animation');
68
+ ref.current?.classList.add('shake-animation');
69
+ setTimeout(() => {
70
+ ref.current?.classList.remove('shake-animation');
71
+ }, 500);
72
+ }, []);
73
+
74
+ const actionModalClassName = useClassNames({
75
+ 'back-card': backCard,
76
+ 'line-on-top': lineOnTop,
77
+ 'no-padding': noPadding,
78
+ });
79
+
80
+ const contentClassName = useClassNames({
81
+ 'action-modal-content': true,
82
+ [className]: Boolean(className),
83
+ });
84
+
85
+ return (
86
+ <Modal
87
+ id='action-modal'
88
+ opacity={0.8}
89
+ isOpen={isOpen}
90
+ zIndex={9999}
91
+ onClick={actionRequired ? remainAction : () => handleOnClose(onClose)}
92
+ >
93
+ <ActionModalContext.Provider value={{ onClose: () => handleOnClose(onClose) }}>
94
+ <ActionModalContainerStyle>
95
+ <section ref={ref} className='open-animation'>
96
+ <ActionModalStyle className={actionModalClassName}>
97
+ {!noCloseButton && !actionRequired && (
98
+ <section className='close-modal-button' onClick={() => handleOnClose(onClose)}>
99
+ <Icon name='cross' />
100
+ </section>
101
+ )}
102
+ {icon ? (
103
+ <Typography variant='header4' className='action-modal-icon'>
104
+ <Icon name={icon} />
105
+ </Typography>
106
+ ) : null}
107
+ <section className='action-modal-body'>
108
+ <section className={contentClassName} style={style}>
109
+ {children}
110
+ </section>
111
+ </section>
112
+ </ActionModalStyle>
113
+ </section>
114
+ </ActionModalContainerStyle>
115
+ </ActionModalContext.Provider>
116
+ </Modal>
117
+ );
118
+ };
119
+
120
+ type ActionButtonProps = Omit<ButtonProps, 'onClick'> & {
121
+ onClick: (() => Promise<void>) | (() => void);
122
+ };
123
+
124
+ const ActionButton = ({ onClick, children, isLoading: manualIsLoading, ...buttonProps }: ActionButtonProps) => {
125
+ const { onClose } = useActionModal();
126
+ const [isLoading, setIsLoading] = useState(false);
127
+
128
+ const handleAction = useCallback(() => {
129
+ setIsLoading(true);
130
+ const result = onClick();
131
+
132
+ if (result instanceof Promise) {
133
+ result.then(() => {
134
+ onClose();
135
+ setIsLoading(false);
136
+ });
137
+ } else {
138
+ onClose();
139
+ setIsLoading(false);
140
+ }
141
+ }, [onClick, onClose]);
142
+
143
+ return (
144
+ <Button {...buttonProps} onClick={handleAction} isLoading={manualIsLoading || isLoading}>
145
+ {children}
146
+ </Button>
147
+ );
148
+ };
149
+
150
+ ActionModal.ActionButton = ActionButton;
@@ -0,0 +1 @@
1
+ export * from './action-modal';
@@ -0,0 +1,82 @@
1
+ import { useState } from 'react';
2
+
3
+ import { Button } from '../../buttons';
4
+ import { Image } from '../../image';
5
+ import { Typography } from '../../typography';
6
+
7
+ import { AsideModal, AsidePosition } from './aside-modal';
8
+
9
+ import type { Meta, StoryObj } from '@storybook/react';
10
+
11
+ const meta: Meta<typeof AsideModal> = {
12
+ title: 'Modals/AsideModal',
13
+ component: AsideModal,
14
+ argTypes: {
15
+ isOpen: { control: false },
16
+ onClose: { control: false },
17
+ position: { control: 'inline-radio', options: Object.values(AsidePosition) },
18
+ children: { control: 'text' },
19
+ size: { control: { type: 'range', min: 100, max: 500, step: 10 } },
20
+ className: { control: false },
21
+ style: { control: false },
22
+ zIndex: { control: false },
23
+ },
24
+ decorators: [
25
+ Story => {
26
+ const [isOpen, setIsOpen] = useState(false);
27
+
28
+ return (
29
+ <>
30
+ <Button onClick={() => setIsOpen(true)}>Open modal</Button>
31
+ <Story isOpen={isOpen} onClose={() => setIsOpen(false)} />
32
+ </>
33
+ );
34
+ },
35
+ ],
36
+ render: (args, { isOpen, onClose }) => {
37
+ return <AsideModal {...args} isOpen={isOpen} onClose={onClose} />;
38
+ },
39
+ };
40
+
41
+ export default meta;
42
+ type Story = StoryObj<typeof AsideModal>;
43
+
44
+ export const Aside: Story = {
45
+ argTypes: {
46
+ children: { control: false },
47
+ },
48
+ args: {
49
+ size: 500,
50
+ },
51
+ render: (args, { isOpen, onClose }) => {
52
+ return (
53
+ <AsideModal {...args} isOpen={isOpen} onClose={onClose}>
54
+ <Typography variant='header4'>Aside modal</Typography>
55
+ <Typography>
56
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam amet at cupiditate dolorum eaque eligendi
57
+ error est fugit harum illo incidunt ipsum itaque labore nulla quaerat quam recusandae repellat sequi
58
+ similique, sit unde vel veniam? Aliquam dicta ipsum voluptates voluptatum.
59
+ </Typography>
60
+ <Image src='https://picsum.photos/500/300' />
61
+ <Typography>
62
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloremque illum quas recusandae? Adipisci alias
63
+ corporis, cumque doloribus ducimus ea enim, et hic id non nulla quae quis sed temporibus vero.
64
+ </Typography>
65
+ <Typography>
66
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor doloribus error excepturi minima quae, quia
67
+ quod voluptatem? Consectetur, enim exercitationem hic illo iusto obcaecati odio?
68
+ </Typography>
69
+ <Typography>
70
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio ducimus necessitatibus officiis optio
71
+ quaerat qui, reiciendis tempora totam ut veniam. At blanditiis cupiditate dolor dolorum ipsum laboriosam natus
72
+ quisquam quo soluta ut? Accusamus aspernatur at beatae neque nisi possimus rerum!
73
+ </Typography>
74
+ <Typography>
75
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus asperiores aspernatur at debitis delectus
76
+ error excepturi fuga, harum in laboriosam laudantium minus, neque omnis, optio praesentium quidem recusandae
77
+ reiciendis reprehenderit rerum sunt voluptatem.
78
+ </Typography>
79
+ </AsideModal>
80
+ );
81
+ },
82
+ };
@@ -0,0 +1,108 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const AsideModalStyle = styled.section`
4
+ position: absolute;
5
+ background: ${props => props.theme.colors.background.main};
6
+ color: ${props => props.theme.colors.text.main};
7
+
8
+ .aside-modal-content {
9
+ overflow: auto;
10
+ height: 100%;
11
+ padding: 2em;
12
+ }
13
+
14
+ .close-modal-button {
15
+ border-radius: 50%;
16
+ cursor: pointer;
17
+ display: grid;
18
+ place-content: center;
19
+ background: ${props => props.theme.colors.background.main};
20
+ border: 4px solid ${props => props.theme.colors.primary.main};
21
+ position: absolute;
22
+ padding: 0.5em;
23
+ }
24
+
25
+ &.left {
26
+ height: 100%;
27
+ top: 0;
28
+ left: 0;
29
+ border-right: 4px solid ${props => props.theme.colors.primary.main};
30
+
31
+ &.open-animation {
32
+ animation: slideIn-left 300ms ease;
33
+ }
34
+
35
+ &.close-animation {
36
+ animation: slideOut-left 300ms ease;
37
+ }
38
+
39
+ .close-modal-button {
40
+ top: 2em;
41
+ left: 100%;
42
+ transform: translate(calc(-50% + 2px));
43
+ }
44
+ }
45
+
46
+ &.right {
47
+ height: 100%;
48
+ top: 0;
49
+ right: 0;
50
+ border-left: 4px solid ${props => props.theme.colors.primary.main};
51
+
52
+ &.open-animation {
53
+ animation: slideIn-right 300ms ease;
54
+ }
55
+
56
+ &.close-animation {
57
+ animation: slideOut-right 300ms ease;
58
+ }
59
+
60
+ .close-modal-button {
61
+ top: 2em;
62
+ right: 100%;
63
+ transform: translate(calc(50% - 2px));
64
+ }
65
+ }
66
+
67
+ &.top {
68
+ top: 0;
69
+ right: 0;
70
+ width: 100%;
71
+ border-bottom: 4px solid ${props => props.theme.colors.primary.main};
72
+
73
+ &.open-animation {
74
+ animation: slideIn-top 300ms ease;
75
+ }
76
+
77
+ &.close-animation {
78
+ animation: slideOut-top 300ms ease;
79
+ }
80
+
81
+ .close-modal-button {
82
+ bottom: 0;
83
+ right: 2em;
84
+ transform: translate(0, calc(50% - 2px));
85
+ }
86
+ }
87
+
88
+ &.bottom {
89
+ bottom: 0;
90
+ right: 0;
91
+ width: 100%;
92
+ border-top: 4px solid ${props => props.theme.colors.primary.main};
93
+
94
+ &.open-animation {
95
+ animation: slideIn-bottom 300ms ease;
96
+ }
97
+
98
+ &.close-animation {
99
+ animation: slideOut-bottom 300ms ease;
100
+ }
101
+
102
+ .close-modal-button {
103
+ top: 0;
104
+ right: 2em;
105
+ transform: translate(0, calc(-50% + 2px));
106
+ }
107
+ }
108
+ `;
@@ -0,0 +1,66 @@
1
+ import { useCallback, useRef } from 'react';
2
+
3
+ import { Icon } from '../../icon';
4
+ import { Modal } from '../modal';
5
+
6
+ import { AsideModalStyle } from './aside-modal.style';
7
+
8
+ export enum AsidePosition {
9
+ LEFT = 'left',
10
+ RIGHT = 'right',
11
+ TOP = 'top',
12
+ BOTTOM = 'bottom',
13
+ }
14
+
15
+ type AsideModalProps = {
16
+ children: React.ReactNode;
17
+ isOpen: boolean;
18
+ onClose: () => void;
19
+ position?: `${AsidePosition}`;
20
+ size?: number | `${number}px` | `${number}em`;
21
+ className?: string;
22
+ style?: React.CSSProperties;
23
+ zIndex?: number;
24
+ };
25
+
26
+ export const AsideModal = ({
27
+ children,
28
+ isOpen,
29
+ onClose,
30
+ position = AsidePosition.LEFT,
31
+ size,
32
+ className = '',
33
+ zIndex = 100,
34
+ style = {},
35
+ }: AsideModalProps) => {
36
+ const ref = useRef<HTMLElement>(null);
37
+
38
+ const handleOnClose = useCallback((callback: () => void) => {
39
+ ref.current?.classList.remove('open-animation');
40
+ ref.current?.classList.add('close-animation');
41
+ setTimeout(() => {
42
+ callback();
43
+ ref.current?.classList.remove('close-animation');
44
+ }, 290);
45
+ }, []);
46
+
47
+ return (
48
+ <Modal id='aside' isOpen={isOpen} opacity={0.6} onClick={() => handleOnClose(onClose)} zIndex={100}>
49
+ <AsideModalStyle
50
+ className={`open-animation ${position} ${className}`}
51
+ ref={ref}
52
+ style={{
53
+ ...style,
54
+ zIndex,
55
+ width: position === 'left' || position === 'right' ? size : undefined,
56
+ height: position === 'top' || position === 'bottom' ? size : undefined,
57
+ }}
58
+ >
59
+ <span className='close-modal-button' onClick={() => handleOnClose(onClose)}>
60
+ <Icon name='cross' />
61
+ </span>
62
+ <section className='aside-modal-content'>{children}</section>
63
+ </AsideModalStyle>
64
+ </Modal>
65
+ );
66
+ };
@@ -0,0 +1 @@
1
+ export * from './aside-modal';
@@ -0,0 +1,50 @@
1
+ import { useState } from 'react';
2
+
3
+ import { Button } from '../../buttons';
4
+ import ActionModalStory from '../action-modal/action-modal.stories';
5
+
6
+ import { ConfirmationModal } from './confirmation-modal';
7
+
8
+ import type { Meta, StoryObj } from '@storybook/react';
9
+
10
+ const meta: Meta<typeof ConfirmationModal> = {
11
+ title: 'Modals/ConfirmationModal',
12
+ component: ConfirmationModal,
13
+ argTypes: {
14
+ ...ActionModalStory.argTypes,
15
+ title: { control: 'text' },
16
+ onAccept: { control: false },
17
+ onReject: { control: false },
18
+ acceptText: { control: 'text' },
19
+ rejectText: { control: 'text' },
20
+ isLoading: { control: 'boolean' },
21
+ },
22
+ args: {
23
+ title: 'Are you sure?',
24
+ acceptText: 'Accept',
25
+ rejectText: 'Reject',
26
+ children: 'Are you sure want to execute an action?',
27
+ },
28
+ decorators: [
29
+ Story => {
30
+ const [isOpen, setIsOpen] = useState(false);
31
+
32
+ return (
33
+ <>
34
+ <Button onClick={() => setIsOpen(true)}>Open modal</Button>
35
+ <Story isOpen={isOpen} onClose={() => setIsOpen(false)} />
36
+ </>
37
+ );
38
+ },
39
+ ],
40
+ render: (args, { isOpen, onClose }) => {
41
+ return <ConfirmationModal {...args} isOpen={isOpen} onClose={onClose} />;
42
+ },
43
+ };
44
+
45
+ export default meta;
46
+ type Story = StoryObj<typeof ConfirmationModal>;
47
+
48
+ export const Default: Story = {
49
+ args: {},
50
+ };
@@ -0,0 +1,17 @@
1
+ import { styled } from 'styled-components';
2
+
3
+ export const ConfirmationModalStyle = styled.section`
4
+ display: grid;
5
+ max-width: 450px;
6
+ gap: 1em;
7
+ place-content: center;
8
+ justify-items: center;
9
+ text-align: center;
10
+
11
+ .confirmation-modal-actions {
12
+ display: grid;
13
+ grid-auto-flow: column;
14
+ justify-content: center;
15
+ gap: 1em;
16
+ }
17
+ `;
@@ -0,0 +1,43 @@
1
+ import { Typography } from '../../typography';
2
+ import { ActionModal, ActionModalProps } from '../action-modal';
3
+
4
+ import { ConfirmationModalStyle } from './confirmation-modal.style';
5
+
6
+ type ConfirmationModalProps = ActionModalProps & {
7
+ title: string;
8
+ onAccept: (() => Promise<void>) | (() => void);
9
+ onReject?: (() => Promise<void>) | (() => void);
10
+ acceptText: string;
11
+ rejectText: string;
12
+ isLoading?: boolean;
13
+ };
14
+
15
+ export const ConfirmationModal = ({
16
+ title,
17
+ onAccept,
18
+ onReject = () => null,
19
+ acceptText,
20
+ rejectText,
21
+ children,
22
+ isLoading,
23
+ ...actionModalProps
24
+ }: ConfirmationModalProps) => {
25
+ return (
26
+ <ActionModal {...actionModalProps} backCard>
27
+ <ConfirmationModalStyle>
28
+ <Typography variant='header4'>{title}</Typography>
29
+ <section>{children}</section>
30
+ <section className='confirmation-modal-actions'>
31
+ {!isLoading && (
32
+ <ActionModal.ActionButton variant='ghost' onClick={onReject}>
33
+ {rejectText}
34
+ </ActionModal.ActionButton>
35
+ )}
36
+ <ActionModal.ActionButton isLoading={isLoading} onClick={onAccept}>
37
+ {acceptText}
38
+ </ActionModal.ActionButton>
39
+ </section>
40
+ </ConfirmationModalStyle>
41
+ </ActionModal>
42
+ );
43
+ };
@@ -0,0 +1 @@
1
+ export * from './confirmation-modal';
@@ -0,0 +1,4 @@
1
+ export * from './action-modal';
2
+ export * from './aside-modal';
3
+ export * from './confirmation-modal';
4
+ export * from './modal';
@@ -0,0 +1 @@
1
+ export * from './modal';
@@ -0,0 +1,10 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const ModalOverlayStyle = styled.section`
4
+ animation: fadeIn 300ms ease;
5
+ position: fixed;
6
+ width: 100%;
7
+ height: 100%;
8
+ top: 0;
9
+ left: 0;
10
+ `;