@onepercentio/one-ui 0.28.8 → 0.29.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 (281) hide show
  1. package/dist/utils/e2e.d.ts +13 -0
  2. package/dist/utils/e2e.js +42 -0
  3. package/package.json +4 -1
  4. package/src/assets/img/svg/checkbox.svg +3 -0
  5. package/src/assets/styles/index.scss +2 -0
  6. package/src/assets/styles/mixins.scss +12 -0
  7. package/src/assets/styles/variables.scss +49 -0
  8. package/src/components/AdaptiveButton/AdaptiveButton.module.scss +7 -0
  9. package/src/components/AdaptiveButton/AdaptiveButton.tsx +26 -0
  10. package/src/components/AdaptiveButton/index.tsx +1 -0
  11. package/src/components/AdaptiveContainer/AdaptiveContainer.module.scss +53 -0
  12. package/src/components/AdaptiveContainer/AdaptiveContainer.tsx +200 -0
  13. package/src/components/AdaptiveContainer/index.tsx +1 -0
  14. package/src/components/AdaptiveDialog/AdaptiveDialog.module.scss +147 -0
  15. package/src/components/AdaptiveDialog/AdaptiveDialog.tsx +97 -0
  16. package/src/components/AdaptiveDialog/index.tsx +1 -0
  17. package/src/components/AdaptiveSidebar/AdaptiveSidebar.module.scss +49 -0
  18. package/src/components/AdaptiveSidebar/AdaptiveSidebar.sample.tsx +10 -0
  19. package/src/components/AdaptiveSidebar/AdaptiveSidebar.tsx +123 -0
  20. package/src/components/AdaptiveSidebar/index.tsx +1 -0
  21. package/src/components/AnchoredTooltip/AnchoredTooltip.module.scss +64 -0
  22. package/src/components/AnchoredTooltip/AnchoredTooltip.tsx +250 -0
  23. package/src/components/AnchoredTooltip/index.tsx +1 -0
  24. package/src/components/AnimatedEntrance/AnimatedEntrance.module.scss +108 -0
  25. package/src/components/AnimatedEntrance/AnimatedEntrance.tsx +227 -0
  26. package/src/components/AnimatedEntrance/index.tsx +5 -0
  27. package/src/components/AsyncWrapper/AsyncWrapper.tsx +38 -0
  28. package/src/components/AsyncWrapper/index.tsx +1 -0
  29. package/src/components/Avatar/Avatar.module.scss +22 -0
  30. package/src/components/Avatar/Avatar.tsx +31 -0
  31. package/src/components/Avatar/index.tsx +1 -0
  32. package/src/components/BucketFill/BucketFill.module.scss +36 -0
  33. package/src/components/BucketFill/BucketFill.tsx +65 -0
  34. package/src/components/BucketFill/index.tsx +1 -0
  35. package/src/components/Button/Button.module.scss +45 -0
  36. package/src/components/Button/Button.tsx +40 -0
  37. package/src/components/Button/index.tsx +1 -0
  38. package/src/components/Card/Card.module.scss +12 -0
  39. package/src/components/Card/Card.tsx +9 -0
  40. package/src/components/Card/index.tsx +1 -0
  41. package/src/components/Chart/Chart.e2e.ts +4 -0
  42. package/src/components/Chart/Chart.logic.tsx +8 -0
  43. package/src/components/Chart/Chart.module.scss +58 -0
  44. package/src/components/Chart/Chart.types.ts +35 -0
  45. package/src/components/Chart/Chart.view.tsx +240 -0
  46. package/src/components/Chart/index.tsx +1 -0
  47. package/src/components/CheckBox/CheckBox.module.scss +36 -0
  48. package/src/components/CheckBox/CheckBox.tsx +63 -0
  49. package/src/components/CheckBox/index.tsx +1 -0
  50. package/src/components/CodeInput/CodeInput.module.scss +5 -0
  51. package/src/components/CodeInput/CodeInput.tsx +84 -0
  52. package/src/components/CodeInput/index.tsx +1 -0
  53. package/src/components/Collapsable/Collapsable.module.scss +42 -0
  54. package/src/components/Collapsable/Collapsable.tsx +253 -0
  55. package/src/components/Collapsable/index.tsx +1 -0
  56. package/src/components/Countdown/Countdown.tsx +130 -0
  57. package/src/components/Countdown/index.tsx +1 -0
  58. package/src/components/CurrencyInput/CurrencyInput.hook.ts +37 -0
  59. package/src/components/CurrencyInput/CurrencyInput.tsx +25 -0
  60. package/src/components/CurrencyInput/index.tsx +1 -0
  61. package/src/components/Divider/Divider.module.scss +7 -0
  62. package/src/components/Divider/Divider.tsx +13 -0
  63. package/src/components/Divider/index.tsx +1 -0
  64. package/src/components/EmailInput/EmailInput.module.scss +0 -0
  65. package/src/components/EmailInput/EmailInput.tsx +51 -0
  66. package/src/components/EmailInput/index.tsx +1 -0
  67. package/src/components/FadeIn/FadeIn.module.scss +9 -0
  68. package/src/components/FadeIn/FadeIn.tsx +77 -0
  69. package/src/components/FadeIn/index.tsx +1 -0
  70. package/src/components/FileInput/FileInput.module.scss +6 -0
  71. package/src/components/FileInput/FileInput.tsx +75 -0
  72. package/src/components/FileInput/View/BigFactory/BigFactory.module.scss +20 -0
  73. package/src/components/FileInput/View/BigFactory/BigFactory.tsx +48 -0
  74. package/src/components/FileInput/View/BigFactory/index.tsx +1 -0
  75. package/src/components/FileInput/View/Compact/Compact.module.scss +68 -0
  76. package/src/components/FileInput/View/Compact/Compact.tsx +151 -0
  77. package/src/components/FileInput/View/Compact/index.tsx +1 -0
  78. package/src/components/FileInput/View/View.types.ts +12 -0
  79. package/src/components/FileInput/index.tsx +1 -0
  80. package/src/components/FlowController/FlowController.module.scss +47 -0
  81. package/src/components/FlowController/FlowController.tsx +93 -0
  82. package/src/components/FlowController/index.tsx +1 -0
  83. package/src/components/Form/Form.tsx +243 -0
  84. package/src/components/Form/index.ts +1 -0
  85. package/src/components/Form/v2/Form.hook.ts +341 -0
  86. package/src/components/Form/v2/Form.module.scss +0 -0
  87. package/src/components/Form/v2/Form.tsx +78 -0
  88. package/src/components/Form/v2/Form.types.ts +118 -0
  89. package/src/components/Form/v2/FormField/Extensions/DateField/DateField.module.scss +0 -0
  90. package/src/components/Form/v2/FormField/Extensions/DateField/DateField.tsx +73 -0
  91. package/src/components/Form/v2/FormField/Extensions/DateField/index.tsx +1 -0
  92. package/src/components/Form/v2/FormField/Extensions/PhoneField/PhoneField.module.scss +0 -0
  93. package/src/components/Form/v2/FormField/Extensions/PhoneField/PhoneField.tsx +91 -0
  94. package/src/components/Form/v2/FormField/Extensions/PhoneField/index.tsx +1 -0
  95. package/src/components/Form/v2/FormField/FormField.module.scss +0 -0
  96. package/src/components/Form/v2/FormField/FormField.tsx +378 -0
  97. package/src/components/Form/v2/FormField/FormField.types.ts +129 -0
  98. package/src/components/Form/v2/FormField/index.tsx +1 -0
  99. package/src/components/Form/v2/index.tsx +1 -0
  100. package/src/components/Freeze/Freeze.tsx +9 -0
  101. package/src/components/Freeze/index.tsx +1 -0
  102. package/src/components/HSForms/HSForms.tsx +57 -0
  103. package/src/components/HSForms/index.tsx +1 -0
  104. package/src/components/Header/Header.module.scss +119 -0
  105. package/src/components/Header/Header.tsx +138 -0
  106. package/src/components/Header/index.tsx +1 -0
  107. package/src/components/HeaderCloseBtn/HeaderCloseBtn.module.scss +44 -0
  108. package/src/components/HeaderCloseBtn/HeaderCloseBtn.tsx +28 -0
  109. package/src/components/HeaderCloseBtn/index.tsx +1 -0
  110. package/src/components/InfinityScroll/InfinityScroll.module.scss +30 -0
  111. package/src/components/InfinityScroll/InfinityScroll.tsx +187 -0
  112. package/src/components/InfinityScroll/index.tsx +1 -0
  113. package/src/components/Input/Input.module.scss +71 -0
  114. package/src/components/Input/Input.tsx +134 -0
  115. package/src/components/Input/index.tsx +1 -0
  116. package/src/components/InstantCounter/InstantCounter.tsx +77 -0
  117. package/src/components/InstantCounter/index.tsx +1 -0
  118. package/src/components/LavaLamp/LavaLamp.data.tsx +114 -0
  119. package/src/components/LavaLamp/LavaLamp.module.scss +26 -0
  120. package/src/components/LavaLamp/LavaLamp.tsx +131 -0
  121. package/src/components/LavaLamp/index.tsx +1 -0
  122. package/src/components/LavaLamp/v2/LavaLamp.module.scss +23 -0
  123. package/src/components/LavaLamp/v2/LavaLamp.tsx +197 -0
  124. package/src/components/LinkToId/LinkToId.module.scss +4 -0
  125. package/src/components/LinkToId/LinkToId.tsx +51 -0
  126. package/src/components/LinkToId/index.tsx +1 -0
  127. package/src/components/Loader/Loader.module.scss +40 -0
  128. package/src/components/Loader/Loader.tsx +18 -0
  129. package/src/components/Loader/index.tsx +1 -0
  130. package/src/components/LoaderDotsIndicator/LoaderDotsIndicator.tsx +34 -0
  131. package/src/components/LoaderDotsIndicator/index.tsx +1 -0
  132. package/src/components/LoopableVideo/LoopableVideo.tsx +37 -0
  133. package/src/components/LoopableVideo/index.tsx +1 -0
  134. package/src/components/MainGrid/MainGrid.module.scss +28 -0
  135. package/src/components/MainGrid/MainGrid.tsx +68 -0
  136. package/src/components/MainGrid/index.tsx +1 -0
  137. package/src/components/MutableHamburgerButton/MutableHamburgerButton.module.scss +220 -0
  138. package/src/components/MutableHamburgerButton/MutableHamburgerButton.tsx +38 -0
  139. package/src/components/MutableHamburgerButton/index.tsx +1 -0
  140. package/src/components/Notification/Notification.module.scss +25 -0
  141. package/src/components/Notification/Notification.tsx +13 -0
  142. package/src/components/Notification/index.tsx +1 -0
  143. package/src/components/OrderableList/OrderableList.module.scss +98 -0
  144. package/src/components/OrderableList/OrderableList.tsx +564 -0
  145. package/src/components/OrderableList/index.tsx +1 -0
  146. package/src/components/PaginationIndicator/PaginationIndicator.tsx +365 -0
  147. package/src/components/PaginationIndicator/index.tsx +1 -0
  148. package/src/components/Parallax/Parallax.module.scss +28 -0
  149. package/src/components/Parallax/Parallax.tsx +248 -0
  150. package/src/components/Parallax/index.tsx +1 -0
  151. package/src/components/Parallax/math/helpers.ts +289 -0
  152. package/src/components/PasswordInput/PasswordInput.module.scss +17 -0
  153. package/src/components/PasswordInput/PasswordInput.tsx +154 -0
  154. package/src/components/PasswordInput/index.tsx +1 -0
  155. package/src/components/PingPongText/PingPongText.module.scss +4 -0
  156. package/src/components/PingPongText/PingPongText.tsx +83 -0
  157. package/src/components/PingPongText/index.tsx +1 -0
  158. package/src/components/PixelatedScan/PixelatedScan.module.scss +86 -0
  159. package/src/components/PixelatedScan/PixelatedScan.tsx +175 -0
  160. package/src/components/PixelatedScan/index.tsx +1 -0
  161. package/src/components/Portal/Portal.module.scss +3 -0
  162. package/src/components/Portal/Portal.tsx +68 -0
  163. package/src/components/Portal/index.tsx +1 -0
  164. package/src/components/ProgressBar/ProgressBar.module.scss +44 -0
  165. package/src/components/ProgressBar/ProgressBar.tsx +124 -0
  166. package/src/components/ProgressBar/index.tsx +1 -0
  167. package/src/components/ProgressTexts/ProgressTexts.module.scss +37 -0
  168. package/src/components/ProgressTexts/ProgressTexts.tsx +85 -0
  169. package/src/components/ProgressTexts/index.tsx +1 -0
  170. package/src/components/Radio/Radio.module.scss +36 -0
  171. package/src/components/Radio/Radio.tsx +53 -0
  172. package/src/components/Radio/index.tsx +1 -0
  173. package/src/components/SectionContainer/SectionContainer.module.scss +30 -0
  174. package/src/components/SectionContainer/SectionContainer.tsx +49 -0
  175. package/src/components/SectionContainer/index.tsx +1 -0
  176. package/src/components/Select/Select.module.scss +58 -0
  177. package/src/components/Select/Select.tsx +192 -0
  178. package/src/components/Select/index.tsx +1 -0
  179. package/src/components/Skeleton/Skeleton.module.scss +21 -0
  180. package/src/components/Skeleton/Skeleton.tsx +29 -0
  181. package/src/components/Skeleton/index.tsx +1 -0
  182. package/src/components/Spacing/Spacing.module.scss +13 -0
  183. package/src/components/Spacing/Spacing.tsx +24 -0
  184. package/src/components/Spacing/index.tsx +1 -0
  185. package/src/components/StaticScroller/StaticScroller.module.scss +14 -0
  186. package/src/components/StaticScroller/StaticScroller.tsx +83 -0
  187. package/src/components/StaticScroller/index.tsx +1 -0
  188. package/src/components/Switch/Switch.module.scss +43 -0
  189. package/src/components/Switch/Switch.tsx +41 -0
  190. package/src/components/Switch/index.tsx +1 -0
  191. package/src/components/Table/Table.module.scss +76 -0
  192. package/src/components/Table/Table.tsx +152 -0
  193. package/src/components/Table/index.tsx +1 -0
  194. package/src/components/Tabs/Tabs.module.scss +40 -0
  195. package/src/components/Tabs/Tabs.tsx +104 -0
  196. package/src/components/Tabs/index.tsx +1 -0
  197. package/src/components/Text/Text.module.scss +81 -0
  198. package/src/components/Text/Text.tsx +42 -0
  199. package/src/components/Text/index.tsx +1 -0
  200. package/src/components/Transition/MasksFactory/DiagonalReveal.tsx +47 -0
  201. package/src/components/Transition/MasksFactory/DiagonalSquareToBalls.tsx +78 -0
  202. package/src/components/Transition/MasksFactory/PhysicsSquares.tsx +106 -0
  203. package/src/components/Transition/MasksFactory/SquareToBalls.tsx +66 -0
  204. package/src/components/Transition/MasksFactory/utils.ts +35 -0
  205. package/src/components/Transition/Transition.module.scss +211 -0
  206. package/src/components/Transition/Transition.tsx +495 -0
  207. package/src/components/Transition/index.tsx +1 -0
  208. package/src/components/UncontrolledTransition/UncontrolledTransition.ai.md +9 -0
  209. package/src/components/UncontrolledTransition/UncontrolledTransition.sample.tsx +34 -0
  210. package/src/components/UncontrolledTransition/UncontrolledTransition.tsx +143 -0
  211. package/src/components/UncontrolledTransition/index.tsx +2 -0
  212. package/src/components/WalletConnectionWrapper/WalletConnectionWrapper.tsx +212 -0
  213. package/src/components/WalletConnectionWrapper/index.tsx +1 -0
  214. package/src/components/utilitary/ScrollAndFocusLock/ScrollAndFocusLock.module.scss +5 -0
  215. package/src/components/utilitary/ScrollAndFocusLock/ScrollAndFocusLock.tsx +52 -0
  216. package/src/components/utilitary/ScrollAndFocusLock/index.tsx +1 -0
  217. package/src/context/AsyncProcess.tsx +107 -0
  218. package/src/context/ContextAsyncControl.tsx +89 -0
  219. package/src/context/CustomBrowserRouter.tsx +55 -0
  220. package/src/context/OneUIProvider.tsx +308 -0
  221. package/src/hooks/logs/useDependencyChangeDetection.ts +25 -0
  222. package/src/hooks/logs/useIsMounting.ts +7 -0
  223. package/src/hooks/persistence/useLocalStorage.ts +45 -0
  224. package/src/hooks/shims/ObjectWatchShim.ts +56 -0
  225. package/src/hooks/ui/useAdaptiveImage.tsx +36 -0
  226. package/src/hooks/ui/useAlternating.tsx +22 -0
  227. package/src/hooks/ui/useBreakpoint.tsx +21 -0
  228. package/src/hooks/ui/useCustomScrollbar.module.scss +20 -0
  229. package/src/hooks/ui/useCustomScrollbar.tsx +22 -0
  230. package/src/hooks/ui/useEffectIf.ts +11 -0
  231. package/src/hooks/ui/useMouseHover.tsx +26 -0
  232. package/src/hooks/ui/usePaginationControls.module.scss +16 -0
  233. package/src/hooks/ui/usePaginationControls.tsx +176 -0
  234. package/src/hooks/ui/useSnapToViewport.module.scss +6 -0
  235. package/src/hooks/ui/useSnapToViewport.ts +28 -0
  236. package/src/hooks/ui/useTilt.tsx +219 -0
  237. package/src/hooks/ui/useZoomable.module.scss +34 -0
  238. package/src/hooks/ui/useZoomable.tsx +144 -0
  239. package/src/hooks/useAsyncControl.ai.md +25 -0
  240. package/src/hooks/useAsyncControl.ts +101 -0
  241. package/src/hooks/useContainedRepositioning.ts +110 -0
  242. package/src/hooks/useCustomHistory.ts +14 -0
  243. package/src/hooks/useElementFit.ts +82 -0
  244. package/src/hooks/useFirestoreWatch.ts +54 -0
  245. package/src/hooks/useForm.ts +49 -0
  246. package/src/hooks/useFreeze.ts +12 -0
  247. package/src/hooks/useHero.module.scss +41 -0
  248. package/src/hooks/useHero.ts +512 -0
  249. package/src/hooks/useIntersection.ts +32 -0
  250. package/src/hooks/useMergeRefs.ts +29 -0
  251. package/src/hooks/useObserve.ts +24 -0
  252. package/src/hooks/usePagination.ts +228 -0
  253. package/src/hooks/usePooledOperation.ts +54 -0
  254. package/src/hooks/usePooling.ts +46 -0
  255. package/src/hooks/useRebound.ts +23 -0
  256. package/src/hooks/useShortIntl.ai.md +5 -0
  257. package/src/hooks/useShortIntl.ts +97 -0
  258. package/src/hooks/utility/useAsyncMemo.ts +43 -0
  259. package/src/hooks/utility/useDepChange.ts +11 -0
  260. package/src/hooks/utility/useEvents.ts +33 -0
  261. package/src/hooks/utility/useImmediate.ts +8 -0
  262. package/src/hooks/utility/useManualInit.ts +24 -0
  263. package/src/hooks/utility/useModule.ts +15 -0
  264. package/src/hooks/utility/useQuery.ts +15 -0
  265. package/src/hooks/utility/useUniqueEffect.ts +22 -0
  266. package/src/index.ts +3 -0
  267. package/src/models/DebugLogger.ts +7 -0
  268. package/src/models/GenericContract.ts +169 -0
  269. package/src/models/Orbs.ts +97 -0
  270. package/src/reac-app-env.d.ts +6 -0
  271. package/src/storybook/assets/video/txt-reversed.mp4 +0 -0
  272. package/src/storybookUtils/index.tsx +53 -0
  273. package/src/type-utils.ts +49 -0
  274. package/src/utility.d.ts +70 -0
  275. package/src/utils/blockchain.ts +43 -0
  276. package/src/utils/e2e.ts +52 -0
  277. package/src/utils/flatten.ts +17 -0
  278. package/src/utils/formatters.ts +36 -0
  279. package/src/utils/html.utils.ts +3 -0
  280. package/src/utils/ownEvent.ts +8 -0
  281. package/src/utils/test.ts +19 -0
@@ -0,0 +1,97 @@
1
+ import React, { PropsWithChildren, useEffect, useRef, useState } from "react";
2
+ import ReactDOM from "react-dom";
3
+ import Styles from "./AdaptiveDialog.module.scss";
4
+ import MutableHamburgerButton from "../MutableHamburgerButton";
5
+ import ScrollAndFocusLock from "../utilitary/ScrollAndFocusLock";
6
+ import { useOneUIConfig } from "../../context/OneUIProvider";
7
+
8
+ /**
9
+ * This component implements a generic drawer that displays it as a drawer on mobile and as a modal on desktop
10
+ **/
11
+ export default function AdaptiveDialog({
12
+ variant = "default",
13
+ onClose,
14
+ open = false,
15
+ className = "",
16
+ onClickOut,
17
+ children,
18
+ onClosed,
19
+ inline = false,
20
+ }: PropsWithChildren<{
21
+ variant?: OnepercentUtility.UIElements.AdaptiveDialogVariants;
22
+ className?: string;
23
+ open: boolean;
24
+ onClose?: () => void;
25
+ onClickOut?: () => void;
26
+ onClosed?: () => void;
27
+ /**
28
+ * Indicates this rendering will write the html inside the current position on dom.
29
+ * If omitted or false, it will render on the document body, to prevent style bleeding */
30
+ inline?: boolean;
31
+ }>) {
32
+ const rootDivRef = useRef<HTMLDivElement>(null);
33
+ const [isVisible, setIsVisible] = useState(open);
34
+ const [expanded, setExpanded] = useState(false);
35
+ const variantClass = useOneUIConfig(
36
+ `component.adaptiveDialog.variant.${variant}`,
37
+ ""
38
+ );
39
+
40
+ useEffect(() => {
41
+ if (open) {
42
+ setIsVisible(true);
43
+ const toggleVisbility = (e: AnimationEvent) => {
44
+ if (e.animationName === Styles.backdropDismiss) {
45
+ onClosed?.();
46
+ setIsVisible(false);
47
+ (e.target! as HTMLDivElement).removeEventListener(
48
+ "animationend",
49
+ toggleVisbility
50
+ );
51
+ }
52
+ };
53
+ rootDivRef.current!.addEventListener("animationend", toggleVisbility);
54
+ }
55
+ }, [open]);
56
+
57
+ const globalClassName = {
58
+ backdrop: useOneUIConfig("component.adaptiveDialog.backdropClassName", ""),
59
+ dialog: useOneUIConfig("component.adaptiveDialog.dialogClassName", ""),
60
+ };
61
+ const content = (
62
+ <div
63
+ ref={rootDivRef}
64
+ className={`${Styles.backdrop} ${open ? Styles.open : Styles.close} ${
65
+ expanded ? Styles.expanded : ""
66
+ } ${globalClassName.backdrop} ${variantClass}`}
67
+ onClick={onClickOut}
68
+ onAnimationEnd={({ target, currentTarget }) => {
69
+ if (target === currentTarget)
70
+ (target as HTMLDivElement).style.pointerEvents = "initial";
71
+ }}
72
+ >
73
+ <div
74
+ className={`${Styles.container} ${className} ${globalClassName.dialog}`}
75
+ onClick={(e) => e.stopPropagation()}
76
+ >
77
+ <ScrollAndFocusLock open={open}>
78
+ {onClose && (
79
+ <button className={Styles.closeBtn} onClick={onClose}>
80
+ <MutableHamburgerButton state="closed" size={24} />
81
+ </button>
82
+ )}
83
+ <div onClick={() => setExpanded((p) => !p)} />
84
+ {children}
85
+ </ScrollAndFocusLock>
86
+ </div>
87
+ </div>
88
+ );
89
+
90
+ return isVisible || open ? (
91
+ inline ? (
92
+ content
93
+ ) : (
94
+ <>{ReactDOM.createPortal(content, document.body)}</>
95
+ )
96
+ ) : null;
97
+ }
@@ -0,0 +1 @@
1
+ export { default } from './AdaptiveDialog';
@@ -0,0 +1,49 @@
1
+ @import "../../assets/styles/index.scss";
2
+
3
+ $hamburgerSize: 48;
4
+ $hamburgerOffset: 24;
5
+
6
+ @value hamburgerSize #{$hamburgerSize};
7
+
8
+ .hamburger {
9
+ position: fixed;
10
+ top: #{$hamburgerOffset}px;
11
+ left: #{$hamburgerOffset}px;
12
+ }
13
+
14
+ .hamburger {
15
+ display: initial;
16
+ }
17
+
18
+ .hamburger,
19
+ .container {
20
+ z-index: 1000;
21
+ }
22
+
23
+ .container {
24
+ box-sizing: border-box;
25
+ height: 100%;
26
+ }
27
+ .hamburger.desktop {
28
+ display: none;
29
+ }
30
+
31
+ .container.mobile {
32
+ &.defaultPadding {
33
+ padding-top: #{$hamburgerSize + $hamburgerOffset * 2}px;
34
+ }
35
+ position: fixed;
36
+ width: 100%;
37
+ overflow: auto;
38
+ z-index: 1000;
39
+ left: 0;
40
+
41
+ &.open {
42
+ transition: transform $veryFast ease-out;
43
+ transform: translateX(-0%);
44
+ }
45
+ &.closed {
46
+ transition: transform $veryFast ease-in;
47
+ transform: translateX(-100%);
48
+ }
49
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import AdaptiveSidebar from "./AdaptiveSidebar";
3
+
4
+ export default function AdaptiveSidebarSample() {
5
+ return (
6
+ <AdaptiveSidebar>
7
+ Experiment with different resolutions to see how this container behaves
8
+ </AdaptiveSidebar>
9
+ );
10
+ }
@@ -0,0 +1,123 @@
1
+ import React, {
2
+ ForwardedRef,
3
+ forwardRef,
4
+ PropsWithChildren,
5
+ useEffect,
6
+ useImperativeHandle,
7
+ useRef,
8
+ useState,
9
+ } from "react";
10
+ import { createPortal } from "react-dom";
11
+ import MutableHamburgerButton from "../MutableHamburgerButton";
12
+ import ScrollAndFocusLock from "../utilitary/ScrollAndFocusLock";
13
+ import Styles from "./AdaptiveSidebar.module.scss";
14
+ import useBreakpoint from "../../hooks/ui/useBreakpoint";
15
+ import { useOneUIConfig } from "../../context/OneUIProvider";
16
+
17
+ const DefaultVisibilityControl = ({ open }: { open: boolean }) => (
18
+ <MutableHamburgerButton size={48} state={open ? "closed" : "default"} />
19
+ );
20
+
21
+ type AdaptiveSidebarControls = {
22
+ dismiss: () => void;
23
+ };
24
+ function _AdaptiveSidebar(
25
+ {
26
+ open: externalOpen,
27
+ children,
28
+ className = "",
29
+ breakInto = 640,
30
+ visibilityControlComponent:
31
+ VisibilityControlComponent = DefaultVisibilityControl,
32
+ ...props
33
+ }: PropsWithChildren<
34
+ {
35
+ /** To control AdaptiveSidebar externally
36
+ * (created for flows that requires floating views when on mobile)
37
+ **/
38
+ open?: boolean;
39
+ /**
40
+ * The screen width to turn into responsive mode
41
+ */
42
+ breakInto?: number;
43
+ className?: string;
44
+ visibilityControlComponent?: (props: {
45
+ open: boolean;
46
+ }) => React.ReactElement;
47
+ } & Omit<React.HTMLProps<HTMLDivElement>, "ref">
48
+ >,
49
+ ref: ForwardedRef<AdaptiveSidebarControls>
50
+ ) {
51
+ const [open, setOpen] = useState(false);
52
+ const containerRef = useRef<HTMLDivElement>(null);
53
+ const _open = externalOpen === undefined ? open : externalOpen;
54
+ const isMobile = useBreakpoint(breakInto);
55
+ const globalClassName = useOneUIConfig("component.adaptiveSidebar.className");
56
+ const globalControlClassName = useOneUIConfig(
57
+ "component.adaptiveSidebar.controlClassName"
58
+ );
59
+
60
+ useImperativeHandle(
61
+ ref,
62
+ () => ({
63
+ dismiss: () => setOpen(false),
64
+ }),
65
+ []
66
+ );
67
+
68
+ useEffect(() => {
69
+ if (process.env.NODE_ENV === "test") return;
70
+ containerRef.current!.scrollTo({
71
+ left: 0,
72
+ behavior: "smooth",
73
+ top: 0,
74
+ });
75
+ }, [_open]);
76
+ const externalControl = externalOpen !== undefined;
77
+
78
+ const content = (
79
+ <div
80
+ ref={containerRef}
81
+ className={`${isMobile ? Styles.mobile : Styles.desktop} ${
82
+ Styles.container
83
+ } ${
84
+ !externalControl &&
85
+ DefaultVisibilityControl === VisibilityControlComponent
86
+ ? Styles.defaultPadding
87
+ : ""
88
+ } ${_open ? Styles.open : Styles.closed} ${className} ${globalClassName}`}
89
+ {...props}
90
+ >
91
+ <ScrollAndFocusLock open={_open}>{children}</ScrollAndFocusLock>
92
+ </div>
93
+ );
94
+
95
+ return (
96
+ <>
97
+ {isMobile
98
+ ? createPortal(
99
+ <>
100
+ {content}
101
+ {!externalControl && (
102
+ <div
103
+ className={`${isMobile ? Styles.mobile : Styles.desktop} ${
104
+ Styles.hamburger
105
+ } ${globalControlClassName}`}
106
+ onClick={() => setOpen((a) => !a)}
107
+ >
108
+ <VisibilityControlComponent open={_open} />
109
+ </div>
110
+ )}
111
+ </>,
112
+ document.body
113
+ )
114
+ : content}
115
+ </>
116
+ );
117
+ }
118
+
119
+ /**
120
+ * A component that you can put anywhere but hides when small enough and shows the control via a fixed floating button
121
+ **/
122
+ const AdaptiveSidebar = forwardRef(_AdaptiveSidebar);
123
+ export default AdaptiveSidebar;
@@ -0,0 +1 @@
1
+ export { default } from './AdaptiveSidebar';
@@ -0,0 +1,64 @@
1
+ @import "../../assets/styles/index.scss";
2
+
3
+ $arrowDim: 1em;
4
+
5
+ /**
6
+ * Some notions to take into account
7
+ */
8
+
9
+ .tooltipContainer {
10
+ & > div {
11
+ background-color: $tooltipBackgroudColor;
12
+ }
13
+ // It should not overflow the viewport (screen)
14
+ max-width: 100vw;
15
+ max-height: 100vh;
16
+ min-width: fit-content;
17
+
18
+ // It should be floating over some point into the viewport
19
+ position: fixed;
20
+
21
+ // The position will be calculated via the javascript and the context
22
+
23
+ transition: top $almostInstant, left $almostInstant, opacity $normal;
24
+ z-index: 1000;
25
+
26
+ pointer-events: none;
27
+
28
+ &.open {
29
+ pointer-events: initial;
30
+ }
31
+
32
+ &::after,
33
+ &::before {
34
+ content: " ";
35
+ width: 0px;
36
+ height: 0px;
37
+ border: $arrowDim solid $tooltipBackgroudColor;
38
+ border-top-color: transparent;
39
+ border-right-color: transparent;
40
+ transform: translateY(-$arrowDim) rotate(-45deg);
41
+ display: block;
42
+ margin: auto;
43
+ position: relative;
44
+ left: var(--anchor-indicator-offset-left, 0px);
45
+ z-index: -1;
46
+ }
47
+
48
+ &::before {
49
+ display: none;
50
+ transform: translateY($arrowDim) rotate(135deg);
51
+ }
52
+ &.anchoredTop {
53
+ transform: translateY(4px);
54
+ }
55
+ &.anchoredBottom {
56
+ transform: translateY(-4px);
57
+ &::after {
58
+ display: none;
59
+ }
60
+ &::before {
61
+ display: block;
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,250 @@
1
+ import React, {
2
+ ForwardedRef,
3
+ forwardRef,
4
+ JSX,
5
+ ReactNode,
6
+ RefObject,
7
+ useEffect,
8
+ useImperativeHandle,
9
+ useLayoutEffect,
10
+ useRef,
11
+ useState,
12
+ } from "react";
13
+ import ReactDOM from "react-dom";
14
+ import { useOneUIConfig } from "../../context/OneUIProvider";
15
+ import FadeIn from "../FadeIn";
16
+ import Styles from "./AnchoredTooltip.module.scss";
17
+
18
+ type Props = {
19
+ children: JSX.Element;
20
+ anchorRef: RefObject<HTMLElement | null>;
21
+ open: boolean;
22
+ className?: string;
23
+ /**
24
+ * Indicates the tooltip should be always visible on viewport
25
+ *
26
+ * @default true
27
+ */
28
+ containInViewport?: boolean;
29
+
30
+ style?: any;
31
+ alignment?: AnchoredTooltipAlignment;
32
+ };
33
+
34
+ function getPositionOnViewport(element: HTMLElement) {
35
+ return element.getBoundingClientRect();
36
+ }
37
+
38
+ export enum AnchoredTooltipAlignment {
39
+ LEFT,
40
+ CENTER,
41
+ RIGHT,
42
+ }
43
+
44
+ export enum AnchoredTooltipAnchor {
45
+ TOP,
46
+ BOTTOM,
47
+ }
48
+
49
+ function calculateTooltipFromAnchor(
50
+ anchorRef: HTMLElement,
51
+ tooltipRef: HTMLDivElement,
52
+ containInViewport: boolean,
53
+ alignTo: AnchoredTooltipAlignment = AnchoredTooltipAlignment.CENTER,
54
+ anchorTo: AnchoredTooltipAnchor = AnchoredTooltipAnchor.TOP
55
+ ) {
56
+ const anchorPosition = getPositionOnViewport(anchorRef);
57
+
58
+ const shouldAnchorToBottom =
59
+ anchorTo === AnchoredTooltipAnchor.BOTTOM ||
60
+ tooltipRef.clientHeight > anchorPosition.top;
61
+
62
+ let top = anchorPosition.top - tooltipRef.clientHeight;
63
+
64
+ /**
65
+ * The terms mean:
66
+ * anchorPosition.left = The left to get to the left border of the anchor (visible element)
67
+ * anchorPosition.width = The width of the anchor (visible element)
68
+ * tooltipRef.clientWidth = The width of the content
69
+ */
70
+ let left = (() => {
71
+ switch (alignTo) {
72
+ case AnchoredTooltipAlignment.CENTER:
73
+ return (
74
+ anchorPosition.left +
75
+ anchorPosition.width / 2 -
76
+ tooltipRef.clientWidth / 2
77
+ );
78
+ case AnchoredTooltipAlignment.LEFT:
79
+ return anchorPosition.left;
80
+ case AnchoredTooltipAlignment.RIGHT:
81
+ return (
82
+ anchorPosition.left + anchorPosition.width - tooltipRef.clientWidth
83
+ );
84
+ }
85
+ })();
86
+
87
+ if (shouldAnchorToBottom)
88
+ top += tooltipRef.clientHeight + anchorRef.clientHeight;
89
+
90
+ if (containInViewport && top < 0) top = 0;
91
+ const offset = top + tooltipRef.clientHeight - window.innerHeight;
92
+ if (containInViewport && offset > 0) {
93
+ top -= offset;
94
+ }
95
+ const offsetLeft = left + tooltipRef.clientWidth - window.innerWidth;
96
+ if (containInViewport && offsetLeft > 0) {
97
+ left -= offsetLeft;
98
+ }
99
+ if (containInViewport && left < 0) {
100
+ left = 0;
101
+ }
102
+
103
+ const maxLeftOffsetIndicator = tooltipRef.clientWidth / 2 - 60;
104
+ const tooltipCenter = tooltipRef.clientWidth / 2 + left;
105
+ const anchorPositionCenter = anchorPosition.left + anchorPosition.width / 2;
106
+
107
+ const offsetTooltip = anchorPositionCenter - tooltipCenter;
108
+ const minOffsetTooltip = -(tooltipRef.clientWidth / 2) + 60;
109
+
110
+ const offsetIndicatorLeft =
111
+ offsetLeft > 0
112
+ ? offsetLeft > maxLeftOffsetIndicator
113
+ ? maxLeftOffsetIndicator
114
+ : offsetLeft
115
+ : offsetTooltip < 0
116
+ ? offsetTooltip < minOffsetTooltip
117
+ ? minOffsetTooltip
118
+ : offsetTooltip
119
+ : 0;
120
+
121
+ return {
122
+ offset,
123
+ offsetIndicatorLeft,
124
+ top,
125
+ left,
126
+ shouldAnchorToBottom,
127
+ };
128
+ }
129
+
130
+ export function updateTooltipPosition(
131
+ tooltipRef: HTMLDivElement,
132
+ anchorRef: HTMLElement,
133
+ limitToViewport: boolean = true,
134
+ alignment: AnchoredTooltipAlignment = AnchoredTooltipAlignment.CENTER,
135
+ anchorTo: AnchoredTooltipAnchor = AnchoredTooltipAnchor.TOP
136
+ ) {
137
+ const { top, left, shouldAnchorToBottom, offsetIndicatorLeft } =
138
+ calculateTooltipFromAnchor(
139
+ anchorRef,
140
+ tooltipRef,
141
+ limitToViewport,
142
+ alignment,
143
+ anchorTo
144
+ );
145
+ if (limitToViewport) {
146
+ const maxHeight = window.innerHeight - top;
147
+ tooltipRef.style.maxHeight = `${maxHeight - 32}px`;
148
+ }
149
+ tooltipRef.style.top = `${top}px`;
150
+ tooltipRef.style.left = `${left}px`;
151
+ tooltipRef.style.setProperty(
152
+ "--anchor-indicator-offset-left",
153
+ `${offsetIndicatorLeft}px`
154
+ );
155
+ if (shouldAnchorToBottom) {
156
+ tooltipRef.classList.remove(Styles.anchoredTop);
157
+ tooltipRef.classList.add(Styles.anchoredBottom);
158
+ } else {
159
+ tooltipRef.classList.add(Styles.anchoredTop);
160
+ tooltipRef.classList.remove(Styles.anchoredBottom);
161
+ }
162
+
163
+ return { shouldAnchorToBottom };
164
+ }
165
+ function _AnchoredTooltip(
166
+ { containInViewport = true, alignment, ...props }: Props,
167
+ ref: ForwardedRef<{ updatePosition: () => void } | null>
168
+ ) {
169
+ const { open, children, anchorRef } = props;
170
+ const tooltipRef = useRef<HTMLDivElement>(null);
171
+ const className = useOneUIConfig("component.tooltip.className");
172
+ const [realClosed, setRealClosed] = useState(!open);
173
+
174
+ useEffect(() => {
175
+ if (open) setRealClosed(false);
176
+ }, [open]);
177
+
178
+ useImperativeHandle(
179
+ ref,
180
+ () => ({
181
+ updatePosition: () => {
182
+ updateTooltipPosition(
183
+ tooltipRef.current!,
184
+ anchorRef.current!,
185
+ containInViewport,
186
+ alignment
187
+ );
188
+ },
189
+ }),
190
+ [containInViewport]
191
+ );
192
+
193
+ useEffect(() => {
194
+ if (open && !realClosed) {
195
+ if (anchorRef.current && tooltipRef.current)
196
+ updateTooltipPosition(
197
+ tooltipRef.current,
198
+ anchorRef.current,
199
+ containInViewport,
200
+ alignment
201
+ );
202
+ const scrollHandler = () => {
203
+ if (anchorRef.current && tooltipRef.current)
204
+ updateTooltipPosition(
205
+ tooltipRef.current,
206
+ anchorRef.current,
207
+ containInViewport,
208
+ alignment
209
+ );
210
+ };
211
+ window.addEventListener("scroll", scrollHandler, {
212
+ passive: true,
213
+ });
214
+ return () => {
215
+ window.removeEventListener("scroll", scrollHandler);
216
+ };
217
+ }
218
+ }, [open, anchorRef, realClosed]);
219
+
220
+ useLayoutEffect(() => {
221
+ if (!tooltipRef.current) return;
222
+ if (open) tooltipRef.current!.classList.add(Styles.open);
223
+ else tooltipRef.current!.classList.remove(Styles.open);
224
+ }, [open]);
225
+
226
+ return !realClosed || open ? (
227
+ <>
228
+ {ReactDOM.createPortal(
229
+ <FadeIn
230
+ onClick={(e) => e.stopPropagation()}
231
+ ref={tooltipRef}
232
+ className={`${Styles.tooltipContainer} ${
233
+ props.className || ""
234
+ } ${className}`}
235
+ style={props.style}
236
+ onHidden={() => setRealClosed(true)}
237
+ >
238
+ {open && !realClosed ? <div>{children}</div> : undefined}
239
+ </FadeIn>,
240
+ document.body
241
+ )}
242
+ </>
243
+ ) : null;
244
+ }
245
+
246
+ /**
247
+ * This tooltip anchors itself to an element and handles positioning relative to the anchored element
248
+ **/
249
+ const AnchoredTooltip = forwardRef(_AnchoredTooltip);
250
+ export default AnchoredTooltip;
@@ -0,0 +1 @@
1
+ export { default } from './AnchoredTooltip';
@@ -0,0 +1,108 @@
1
+ @use 'sass:math';
2
+ @keyframes expand {
3
+ 0% {
4
+ transform: translateX(100%);
5
+ }
6
+
7
+ 35% {
8
+ transform: translateX(100%);
9
+ }
10
+
11
+ 85% {
12
+ transform: translateX(-5%);
13
+ }
14
+
15
+ 100% {
16
+ transform: translateX(0%);
17
+ }
18
+ }
19
+
20
+ @keyframes exiting {
21
+ 100% {
22
+ transform: translateX(100%);
23
+ }
24
+
25
+ 65% {
26
+ transform: translateX(100%);
27
+ }
28
+
29
+ 50% {
30
+ opacity: 0;
31
+ }
32
+
33
+ 15% {
34
+ transform: translateX(-5%);
35
+ opacity: 1;
36
+ }
37
+
38
+ 0% {
39
+ transform: translateX(0%);
40
+ }
41
+ }
42
+ $duration: 1s;
43
+
44
+ .elementExiting {
45
+ animation-duration: $duration !important;
46
+ animation-name: exiting;
47
+ position: absolute;
48
+ }
49
+
50
+ .elementEntering {
51
+ animation-duration: $duration !important;
52
+ animation-name: expand;
53
+ }
54
+ .elementExitingReverse {
55
+ animation-duration: $duration !important;
56
+ animation-name: exiting;
57
+ }
58
+
59
+ .elementEnteringReverse {
60
+ animation-duration: $duration !important;
61
+ animation-name: expand;
62
+ position: absolute;
63
+ }
64
+
65
+ .resetHeight {
66
+ transition: max-height math.div($duration, 2) $duration * 0.2;
67
+ min-height: initial;
68
+ align-items: flex-start !important;
69
+ flex-shrink: 0;
70
+ > * {
71
+ justify-content: flex-start !important;
72
+ }
73
+ }
74
+
75
+ .maxHeight {
76
+ max-height: 0px;
77
+ }
78
+
79
+ @keyframes nothing {
80
+ 100% {
81
+ transform: translateX(0%);
82
+ }
83
+
84
+ 0% {
85
+ transform: translateX(0%);
86
+ }
87
+ }
88
+
89
+ .elementShrinking {
90
+ animation-duration: $duration !important;
91
+ animation-name: nothing;
92
+ position: absolute;
93
+ }
94
+
95
+ .elementExpanding {
96
+ animation-duration: $duration !important;
97
+ animation-name: nothing;
98
+ }
99
+ .elementShrinkingReverse {
100
+ animation-duration: $duration !important;
101
+ animation-name: nothing;
102
+ }
103
+
104
+ .elementExpandingReverse {
105
+ animation-duration: $duration !important;
106
+ animation-name: nothing;
107
+ position: absolute;
108
+ }