@onepercentio/one-ui 0.28.8 → 0.28.9

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 (278) hide show
  1. package/package.json +4 -1
  2. package/src/assets/img/svg/checkbox.svg +3 -0
  3. package/src/assets/styles/index.scss +2 -0
  4. package/src/assets/styles/mixins.scss +12 -0
  5. package/src/assets/styles/variables.scss +49 -0
  6. package/src/components/AdaptiveButton/AdaptiveButton.module.scss +7 -0
  7. package/src/components/AdaptiveButton/AdaptiveButton.tsx +26 -0
  8. package/src/components/AdaptiveButton/index.tsx +1 -0
  9. package/src/components/AdaptiveContainer/AdaptiveContainer.module.scss +53 -0
  10. package/src/components/AdaptiveContainer/AdaptiveContainer.tsx +200 -0
  11. package/src/components/AdaptiveContainer/index.tsx +1 -0
  12. package/src/components/AdaptiveDialog/AdaptiveDialog.module.scss +147 -0
  13. package/src/components/AdaptiveDialog/AdaptiveDialog.tsx +97 -0
  14. package/src/components/AdaptiveDialog/index.tsx +1 -0
  15. package/src/components/AdaptiveSidebar/AdaptiveSidebar.module.scss +49 -0
  16. package/src/components/AdaptiveSidebar/AdaptiveSidebar.sample.tsx +10 -0
  17. package/src/components/AdaptiveSidebar/AdaptiveSidebar.tsx +123 -0
  18. package/src/components/AdaptiveSidebar/index.tsx +1 -0
  19. package/src/components/AnchoredTooltip/AnchoredTooltip.module.scss +64 -0
  20. package/src/components/AnchoredTooltip/AnchoredTooltip.tsx +250 -0
  21. package/src/components/AnchoredTooltip/index.tsx +1 -0
  22. package/src/components/AnimatedEntrance/AnimatedEntrance.module.scss +108 -0
  23. package/src/components/AnimatedEntrance/AnimatedEntrance.tsx +227 -0
  24. package/src/components/AnimatedEntrance/index.tsx +5 -0
  25. package/src/components/AsyncWrapper/AsyncWrapper.tsx +38 -0
  26. package/src/components/AsyncWrapper/index.tsx +1 -0
  27. package/src/components/Avatar/Avatar.module.scss +22 -0
  28. package/src/components/Avatar/Avatar.tsx +31 -0
  29. package/src/components/Avatar/index.tsx +1 -0
  30. package/src/components/BucketFill/BucketFill.module.scss +36 -0
  31. package/src/components/BucketFill/BucketFill.tsx +65 -0
  32. package/src/components/BucketFill/index.tsx +1 -0
  33. package/src/components/Button/Button.module.scss +45 -0
  34. package/src/components/Button/Button.tsx +40 -0
  35. package/src/components/Button/index.tsx +1 -0
  36. package/src/components/Card/Card.module.scss +12 -0
  37. package/src/components/Card/Card.tsx +9 -0
  38. package/src/components/Card/index.tsx +1 -0
  39. package/src/components/Chart/Chart.e2e.ts +4 -0
  40. package/src/components/Chart/Chart.logic.tsx +8 -0
  41. package/src/components/Chart/Chart.module.scss +58 -0
  42. package/src/components/Chart/Chart.types.ts +35 -0
  43. package/src/components/Chart/Chart.view.tsx +240 -0
  44. package/src/components/Chart/index.tsx +1 -0
  45. package/src/components/CheckBox/CheckBox.module.scss +36 -0
  46. package/src/components/CheckBox/CheckBox.tsx +63 -0
  47. package/src/components/CheckBox/index.tsx +1 -0
  48. package/src/components/CodeInput/CodeInput.module.scss +5 -0
  49. package/src/components/CodeInput/CodeInput.tsx +84 -0
  50. package/src/components/CodeInput/index.tsx +1 -0
  51. package/src/components/Collapsable/Collapsable.module.scss +42 -0
  52. package/src/components/Collapsable/Collapsable.tsx +253 -0
  53. package/src/components/Collapsable/index.tsx +1 -0
  54. package/src/components/Countdown/Countdown.tsx +130 -0
  55. package/src/components/Countdown/index.tsx +1 -0
  56. package/src/components/CurrencyInput/CurrencyInput.hook.ts +37 -0
  57. package/src/components/CurrencyInput/CurrencyInput.tsx +25 -0
  58. package/src/components/CurrencyInput/index.tsx +1 -0
  59. package/src/components/Divider/Divider.module.scss +7 -0
  60. package/src/components/Divider/Divider.tsx +13 -0
  61. package/src/components/Divider/index.tsx +1 -0
  62. package/src/components/EmailInput/EmailInput.module.scss +0 -0
  63. package/src/components/EmailInput/EmailInput.tsx +51 -0
  64. package/src/components/EmailInput/index.tsx +1 -0
  65. package/src/components/FadeIn/FadeIn.module.scss +9 -0
  66. package/src/components/FadeIn/FadeIn.tsx +77 -0
  67. package/src/components/FadeIn/index.tsx +1 -0
  68. package/src/components/FileInput/FileInput.module.scss +6 -0
  69. package/src/components/FileInput/FileInput.tsx +75 -0
  70. package/src/components/FileInput/View/BigFactory/BigFactory.module.scss +20 -0
  71. package/src/components/FileInput/View/BigFactory/BigFactory.tsx +48 -0
  72. package/src/components/FileInput/View/BigFactory/index.tsx +1 -0
  73. package/src/components/FileInput/View/Compact/Compact.module.scss +68 -0
  74. package/src/components/FileInput/View/Compact/Compact.tsx +151 -0
  75. package/src/components/FileInput/View/Compact/index.tsx +1 -0
  76. package/src/components/FileInput/View/View.types.ts +12 -0
  77. package/src/components/FileInput/index.tsx +1 -0
  78. package/src/components/FlowController/FlowController.module.scss +47 -0
  79. package/src/components/FlowController/FlowController.tsx +93 -0
  80. package/src/components/FlowController/index.tsx +1 -0
  81. package/src/components/Form/Form.tsx +243 -0
  82. package/src/components/Form/index.ts +1 -0
  83. package/src/components/Form/v2/Form.hook.ts +341 -0
  84. package/src/components/Form/v2/Form.module.scss +0 -0
  85. package/src/components/Form/v2/Form.tsx +78 -0
  86. package/src/components/Form/v2/Form.types.ts +118 -0
  87. package/src/components/Form/v2/FormField/Extensions/DateField/DateField.module.scss +0 -0
  88. package/src/components/Form/v2/FormField/Extensions/DateField/DateField.tsx +73 -0
  89. package/src/components/Form/v2/FormField/Extensions/DateField/index.tsx +1 -0
  90. package/src/components/Form/v2/FormField/Extensions/PhoneField/PhoneField.module.scss +0 -0
  91. package/src/components/Form/v2/FormField/Extensions/PhoneField/PhoneField.tsx +91 -0
  92. package/src/components/Form/v2/FormField/Extensions/PhoneField/index.tsx +1 -0
  93. package/src/components/Form/v2/FormField/FormField.module.scss +0 -0
  94. package/src/components/Form/v2/FormField/FormField.tsx +378 -0
  95. package/src/components/Form/v2/FormField/FormField.types.ts +129 -0
  96. package/src/components/Form/v2/FormField/index.tsx +1 -0
  97. package/src/components/Form/v2/index.tsx +1 -0
  98. package/src/components/Freeze/Freeze.tsx +9 -0
  99. package/src/components/Freeze/index.tsx +1 -0
  100. package/src/components/HSForms/HSForms.tsx +57 -0
  101. package/src/components/HSForms/index.tsx +1 -0
  102. package/src/components/Header/Header.module.scss +119 -0
  103. package/src/components/Header/Header.tsx +138 -0
  104. package/src/components/Header/index.tsx +1 -0
  105. package/src/components/HeaderCloseBtn/HeaderCloseBtn.module.scss +44 -0
  106. package/src/components/HeaderCloseBtn/HeaderCloseBtn.tsx +28 -0
  107. package/src/components/HeaderCloseBtn/index.tsx +1 -0
  108. package/src/components/InfinityScroll/InfinityScroll.module.scss +30 -0
  109. package/src/components/InfinityScroll/InfinityScroll.tsx +187 -0
  110. package/src/components/InfinityScroll/index.tsx +1 -0
  111. package/src/components/Input/Input.module.scss +71 -0
  112. package/src/components/Input/Input.tsx +134 -0
  113. package/src/components/Input/index.tsx +1 -0
  114. package/src/components/InstantCounter/InstantCounter.tsx +77 -0
  115. package/src/components/InstantCounter/index.tsx +1 -0
  116. package/src/components/LavaLamp/LavaLamp.data.tsx +114 -0
  117. package/src/components/LavaLamp/LavaLamp.module.scss +26 -0
  118. package/src/components/LavaLamp/LavaLamp.tsx +131 -0
  119. package/src/components/LavaLamp/index.tsx +1 -0
  120. package/src/components/LavaLamp/v2/LavaLamp.module.scss +23 -0
  121. package/src/components/LavaLamp/v2/LavaLamp.tsx +197 -0
  122. package/src/components/LinkToId/LinkToId.module.scss +4 -0
  123. package/src/components/LinkToId/LinkToId.tsx +51 -0
  124. package/src/components/LinkToId/index.tsx +1 -0
  125. package/src/components/Loader/Loader.module.scss +40 -0
  126. package/src/components/Loader/Loader.tsx +18 -0
  127. package/src/components/Loader/index.tsx +1 -0
  128. package/src/components/LoaderDotsIndicator/LoaderDotsIndicator.tsx +34 -0
  129. package/src/components/LoaderDotsIndicator/index.tsx +1 -0
  130. package/src/components/LoopableVideo/LoopableVideo.tsx +37 -0
  131. package/src/components/LoopableVideo/index.tsx +1 -0
  132. package/src/components/MainGrid/MainGrid.module.scss +28 -0
  133. package/src/components/MainGrid/MainGrid.tsx +68 -0
  134. package/src/components/MainGrid/index.tsx +1 -0
  135. package/src/components/MutableHamburgerButton/MutableHamburgerButton.module.scss +220 -0
  136. package/src/components/MutableHamburgerButton/MutableHamburgerButton.tsx +38 -0
  137. package/src/components/MutableHamburgerButton/index.tsx +1 -0
  138. package/src/components/Notification/Notification.module.scss +25 -0
  139. package/src/components/Notification/Notification.tsx +13 -0
  140. package/src/components/Notification/index.tsx +1 -0
  141. package/src/components/OrderableList/OrderableList.module.scss +98 -0
  142. package/src/components/OrderableList/OrderableList.tsx +564 -0
  143. package/src/components/OrderableList/index.tsx +1 -0
  144. package/src/components/PaginationIndicator/PaginationIndicator.tsx +365 -0
  145. package/src/components/PaginationIndicator/index.tsx +1 -0
  146. package/src/components/Parallax/Parallax.module.scss +28 -0
  147. package/src/components/Parallax/Parallax.tsx +248 -0
  148. package/src/components/Parallax/index.tsx +1 -0
  149. package/src/components/Parallax/math/helpers.ts +289 -0
  150. package/src/components/PasswordInput/PasswordInput.module.scss +17 -0
  151. package/src/components/PasswordInput/PasswordInput.tsx +154 -0
  152. package/src/components/PasswordInput/index.tsx +1 -0
  153. package/src/components/PingPongText/PingPongText.module.scss +4 -0
  154. package/src/components/PingPongText/PingPongText.tsx +83 -0
  155. package/src/components/PingPongText/index.tsx +1 -0
  156. package/src/components/PixelatedScan/PixelatedScan.module.scss +86 -0
  157. package/src/components/PixelatedScan/PixelatedScan.tsx +175 -0
  158. package/src/components/PixelatedScan/index.tsx +1 -0
  159. package/src/components/Portal/Portal.module.scss +3 -0
  160. package/src/components/Portal/Portal.tsx +68 -0
  161. package/src/components/Portal/index.tsx +1 -0
  162. package/src/components/ProgressBar/ProgressBar.module.scss +44 -0
  163. package/src/components/ProgressBar/ProgressBar.tsx +124 -0
  164. package/src/components/ProgressBar/index.tsx +1 -0
  165. package/src/components/ProgressTexts/ProgressTexts.module.scss +37 -0
  166. package/src/components/ProgressTexts/ProgressTexts.tsx +85 -0
  167. package/src/components/ProgressTexts/index.tsx +1 -0
  168. package/src/components/Radio/Radio.module.scss +36 -0
  169. package/src/components/Radio/Radio.tsx +53 -0
  170. package/src/components/Radio/index.tsx +1 -0
  171. package/src/components/SectionContainer/SectionContainer.module.scss +30 -0
  172. package/src/components/SectionContainer/SectionContainer.tsx +49 -0
  173. package/src/components/SectionContainer/index.tsx +1 -0
  174. package/src/components/Select/Select.module.scss +58 -0
  175. package/src/components/Select/Select.tsx +192 -0
  176. package/src/components/Select/index.tsx +1 -0
  177. package/src/components/Skeleton/Skeleton.module.scss +21 -0
  178. package/src/components/Skeleton/Skeleton.tsx +29 -0
  179. package/src/components/Skeleton/index.tsx +1 -0
  180. package/src/components/Spacing/Spacing.module.scss +13 -0
  181. package/src/components/Spacing/Spacing.tsx +24 -0
  182. package/src/components/Spacing/index.tsx +1 -0
  183. package/src/components/StaticScroller/StaticScroller.module.scss +14 -0
  184. package/src/components/StaticScroller/StaticScroller.tsx +83 -0
  185. package/src/components/StaticScroller/index.tsx +1 -0
  186. package/src/components/Switch/Switch.module.scss +43 -0
  187. package/src/components/Switch/Switch.tsx +41 -0
  188. package/src/components/Switch/index.tsx +1 -0
  189. package/src/components/Table/Table.module.scss +76 -0
  190. package/src/components/Table/Table.tsx +152 -0
  191. package/src/components/Table/index.tsx +1 -0
  192. package/src/components/Tabs/Tabs.module.scss +40 -0
  193. package/src/components/Tabs/Tabs.tsx +104 -0
  194. package/src/components/Tabs/index.tsx +1 -0
  195. package/src/components/Text/Text.module.scss +81 -0
  196. package/src/components/Text/Text.tsx +42 -0
  197. package/src/components/Text/index.tsx +1 -0
  198. package/src/components/Transition/MasksFactory/DiagonalReveal.tsx +47 -0
  199. package/src/components/Transition/MasksFactory/DiagonalSquareToBalls.tsx +78 -0
  200. package/src/components/Transition/MasksFactory/PhysicsSquares.tsx +106 -0
  201. package/src/components/Transition/MasksFactory/SquareToBalls.tsx +66 -0
  202. package/src/components/Transition/MasksFactory/utils.ts +35 -0
  203. package/src/components/Transition/Transition.module.scss +211 -0
  204. package/src/components/Transition/Transition.tsx +495 -0
  205. package/src/components/Transition/index.tsx +1 -0
  206. package/src/components/UncontrolledTransition/UncontrolledTransition.ai.md +9 -0
  207. package/src/components/UncontrolledTransition/UncontrolledTransition.sample.tsx +34 -0
  208. package/src/components/UncontrolledTransition/UncontrolledTransition.tsx +143 -0
  209. package/src/components/UncontrolledTransition/index.tsx +2 -0
  210. package/src/components/WalletConnectionWrapper/WalletConnectionWrapper.tsx +212 -0
  211. package/src/components/WalletConnectionWrapper/index.tsx +1 -0
  212. package/src/components/utilitary/ScrollAndFocusLock/ScrollAndFocusLock.module.scss +5 -0
  213. package/src/components/utilitary/ScrollAndFocusLock/ScrollAndFocusLock.tsx +52 -0
  214. package/src/components/utilitary/ScrollAndFocusLock/index.tsx +1 -0
  215. package/src/context/AsyncProcess.tsx +107 -0
  216. package/src/context/ContextAsyncControl.tsx +89 -0
  217. package/src/context/CustomBrowserRouter.tsx +55 -0
  218. package/src/context/OneUIProvider.tsx +308 -0
  219. package/src/hooks/logs/useDependencyChangeDetection.ts +25 -0
  220. package/src/hooks/logs/useIsMounting.ts +7 -0
  221. package/src/hooks/persistence/useLocalStorage.ts +45 -0
  222. package/src/hooks/shims/ObjectWatchShim.ts +56 -0
  223. package/src/hooks/ui/useAdaptiveImage.tsx +36 -0
  224. package/src/hooks/ui/useAlternating.tsx +22 -0
  225. package/src/hooks/ui/useBreakpoint.tsx +21 -0
  226. package/src/hooks/ui/useCustomScrollbar.module.scss +20 -0
  227. package/src/hooks/ui/useCustomScrollbar.tsx +22 -0
  228. package/src/hooks/ui/useEffectIf.ts +11 -0
  229. package/src/hooks/ui/useMouseHover.tsx +26 -0
  230. package/src/hooks/ui/usePaginationControls.module.scss +16 -0
  231. package/src/hooks/ui/usePaginationControls.tsx +176 -0
  232. package/src/hooks/ui/useSnapToViewport.module.scss +6 -0
  233. package/src/hooks/ui/useSnapToViewport.ts +28 -0
  234. package/src/hooks/ui/useTilt.tsx +219 -0
  235. package/src/hooks/ui/useZoomable.module.scss +34 -0
  236. package/src/hooks/ui/useZoomable.tsx +144 -0
  237. package/src/hooks/useAsyncControl.ai.md +25 -0
  238. package/src/hooks/useAsyncControl.ts +101 -0
  239. package/src/hooks/useContainedRepositioning.ts +110 -0
  240. package/src/hooks/useCustomHistory.ts +14 -0
  241. package/src/hooks/useElementFit.ts +82 -0
  242. package/src/hooks/useFirestoreWatch.ts +54 -0
  243. package/src/hooks/useForm.ts +49 -0
  244. package/src/hooks/useFreeze.ts +12 -0
  245. package/src/hooks/useHero.module.scss +41 -0
  246. package/src/hooks/useHero.ts +512 -0
  247. package/src/hooks/useIntersection.ts +32 -0
  248. package/src/hooks/useMergeRefs.ts +29 -0
  249. package/src/hooks/useObserve.ts +24 -0
  250. package/src/hooks/usePagination.ts +228 -0
  251. package/src/hooks/usePooledOperation.ts +54 -0
  252. package/src/hooks/usePooling.ts +46 -0
  253. package/src/hooks/useRebound.ts +23 -0
  254. package/src/hooks/useShortIntl.ai.md +5 -0
  255. package/src/hooks/useShortIntl.ts +97 -0
  256. package/src/hooks/utility/useAsyncMemo.ts +43 -0
  257. package/src/hooks/utility/useDepChange.ts +11 -0
  258. package/src/hooks/utility/useEvents.ts +33 -0
  259. package/src/hooks/utility/useImmediate.ts +8 -0
  260. package/src/hooks/utility/useManualInit.ts +24 -0
  261. package/src/hooks/utility/useModule.ts +15 -0
  262. package/src/hooks/utility/useQuery.ts +15 -0
  263. package/src/hooks/utility/useUniqueEffect.ts +22 -0
  264. package/src/index.ts +3 -0
  265. package/src/models/DebugLogger.ts +7 -0
  266. package/src/models/GenericContract.ts +169 -0
  267. package/src/models/Orbs.ts +97 -0
  268. package/src/reac-app-env.d.ts +6 -0
  269. package/src/storybook/assets/video/txt-reversed.mp4 +0 -0
  270. package/src/storybookUtils/index.tsx +53 -0
  271. package/src/type-utils.ts +49 -0
  272. package/src/utility.d.ts +70 -0
  273. package/src/utils/blockchain.ts +43 -0
  274. package/src/utils/flatten.ts +17 -0
  275. package/src/utils/formatters.ts +36 -0
  276. package/src/utils/html.utils.ts +3 -0
  277. package/src/utils/ownEvent.ts +8 -0
  278. package/src/utils/test.ts +19 -0
@@ -0,0 +1,176 @@
1
+ import throttle from "lodash/throttle";
2
+ import React, { RefObject, useEffect, useState } from "react";
3
+ import Fade from "../../components/FadeIn";
4
+ import { useOneUIConfig } from "../../context/OneUIProvider";
5
+ import Styles from "./usePaginationControls.module.scss";
6
+ import { isSameTarget } from "../../utils/html.utils";
7
+
8
+ /**
9
+ * This hook handles the display of pagination controls for the user to move to another page
10
+ */
11
+ export default function usePaginationControls(
12
+ containerRef: RefObject<HTMLDivElement>,
13
+ {
14
+ snapToPage,
15
+ baseWidth,
16
+ snapToCutElement: _snapToCutElement,
17
+ ...props
18
+ }: {
19
+ snapToPage?: boolean;
20
+ baseWidth?: number;
21
+ /** This will scroll only until the partially visible element is at the border, instead of scrolling all the container */
22
+ snapToCutElement?: boolean;
23
+ "data-testid"?: [left: string, right: string];
24
+ } = {}
25
+ ) {
26
+ const [controlsState, setControls] = useState<
27
+ [leftControl: boolean, rightControl: boolean]
28
+ >([false, false]);
29
+ const [leftControl, rightControl] = controlsState;
30
+ const LeftControl = useOneUIConfig(
31
+ "hook.ui.usePaginationControls.LeftControl"
32
+ );
33
+ const RightControl = useOneUIConfig(
34
+ "hook.ui.usePaginationControls.RightControl"
35
+ );
36
+ const className = useOneUIConfig(
37
+ "hook.ui.usePaginationControls.className",
38
+ ""
39
+ );
40
+ function move(direction: "l" | "r", snapToCutElement = _snapToCutElement) {
41
+ return () => {
42
+ if (snapToCutElement ?? false) {
43
+ const childBaseWidth =
44
+ baseWidth! || containerRef.current!.firstElementChild!.clientWidth;
45
+ const howMuchDoesTheScrollAddsUpTo =
46
+ containerRef.current!.scrollLeft / childBaseWidth -
47
+ Math.floor(
48
+ (containerRef.current!.scrollLeft + (direction === "l" ? -1 : 0)) /
49
+ childBaseWidth
50
+ );
51
+ const howMuchElementsFitOnAPage =
52
+ containerRef.current!.clientWidth / childBaseWidth;
53
+
54
+ const howMuchElementsFullyFitOnAPage =
55
+ Math.floor(howMuchElementsFitOnAPage) || 1;
56
+
57
+ const directionScale =
58
+ direction === "l"
59
+ ? 1 - howMuchDoesTheScrollAddsUpTo
60
+ : howMuchDoesTheScrollAddsUpTo;
61
+
62
+ const howMuchOfTheRemainingElementIsShown =
63
+ howMuchElementsFitOnAPage +
64
+ directionScale -
65
+ howMuchElementsFullyFitOnAPage;
66
+
67
+ const howMuchToScroll =
68
+ (containerRef.current!.clientWidth -
69
+ childBaseWidth * howMuchOfTheRemainingElementIsShown) *
70
+ (direction === "l" ? -1 : 1);
71
+
72
+ containerRef.current!.scrollBy({
73
+ left: howMuchToScroll,
74
+ behavior: "smooth",
75
+ });
76
+ } else {
77
+ const rest =
78
+ Math.round(containerRef.current!.scrollLeft) %
79
+ containerRef.current!.clientWidth;
80
+ const snapOffset = snapToPage
81
+ ? direction === "l"
82
+ ? rest
83
+ ? containerRef.current!.clientWidth - rest
84
+ : 0
85
+ : rest
86
+ : 0;
87
+ containerRef.current!.scrollBy({
88
+ left:
89
+ (containerRef.current!.clientWidth - snapOffset) *
90
+ (direction === "l" ? -1 : 1),
91
+ behavior: "smooth",
92
+ });
93
+ }
94
+ };
95
+ }
96
+
97
+ function checkControlsRequirement() {
98
+ const updateFunc =
99
+ (next: typeof controlsState) => (prev: typeof controlsState) => {
100
+ if (prev[0] !== next[0] || prev[1] !== next[1]) return next;
101
+ return prev;
102
+ };
103
+ const el = containerRef.current;
104
+ if (!el) return;
105
+ const shouldHaveAnyControl = el.scrollWidth > el.clientWidth;
106
+ if (!shouldHaveAnyControl) setControls(updateFunc([false, false]));
107
+ else {
108
+ const shouldHaveRightControl =
109
+ el.scrollLeft < el.scrollWidth - el.clientWidth;
110
+ const shouldHaveLeftControl = el.scrollLeft > 0;
111
+
112
+ setControls(updateFunc([shouldHaveLeftControl, shouldHaveRightControl]));
113
+ }
114
+ }
115
+ useEffect(() => {
116
+ const el = containerRef.current!;
117
+ const throttledCheck = throttle(checkControlsRequirement, 1000 / 4);
118
+ checkControlsRequirement();
119
+ let startingX: number | undefined;
120
+ let lastX: number | undefined;
121
+
122
+ const onTouchStart = ({ touches, ...e }: TouchEvent) => {
123
+ if (!isSameTarget(e)) return;
124
+ const { pageX } = touches.item(0)!;
125
+ startingX = pageX;
126
+ };
127
+ const onTouchMove = ({ touches, ...e }: TouchEvent) => {
128
+ if (!isSameTarget(e)) return;
129
+ const touch = touches.item(0);
130
+
131
+ lastX = touch!.pageX;
132
+ };
133
+ const onTouchEnd = (e: Event) => {
134
+ if (!lastX) return;
135
+ const dir = lastX > startingX! ? "l" : "r";
136
+ move(dir, true)();
137
+ startingX = undefined;
138
+ };
139
+ el.addEventListener("scroll", throttledCheck, {
140
+ passive: true,
141
+ });
142
+ el.addEventListener("touchstart", onTouchStart);
143
+ el.addEventListener("touchend", onTouchEnd);
144
+ el.addEventListener("touchmove", onTouchMove);
145
+ return () => {
146
+ el.removeEventListener("scroll", throttledCheck);
147
+ el.removeEventListener("touchstart", onTouchStart);
148
+ el.removeEventListener("touchend", onTouchEnd);
149
+ el.removeEventListener("touchend", onTouchEnd);
150
+ };
151
+ }, []);
152
+
153
+ return {
154
+ controls: [
155
+ <Fade
156
+ key={"l"}
157
+ active={leftControl}
158
+ className={`${Styles.left} ${Styles.control} ${className}`}
159
+ data-testid={props["data-testid"]?.[0]}
160
+ onClick={move("l")}
161
+ >
162
+ {leftControl && <LeftControl />}
163
+ </Fade>,
164
+ <Fade
165
+ key={"r"}
166
+ active={rightControl}
167
+ className={`${Styles.right} ${Styles.control} ${className}`}
168
+ data-testid={props["data-testid"]?.[1]}
169
+ onClick={move("r")}
170
+ >
171
+ {rightControl && <RightControl />}
172
+ </Fade>,
173
+ ],
174
+ checkControlsRequirement,
175
+ };
176
+ }
@@ -0,0 +1,6 @@
1
+ .applySpacings {
2
+ padding-left: var(--overflow-padding, var(--default-padding));
3
+ padding-right: var(--overflow-padding, var(--default-padding));
4
+ margin-left: var(--overflow-margin, var(--default-margin));
5
+ margin-right: var(--overflow-margin, var(--default-margin));
6
+ }
@@ -0,0 +1,28 @@
1
+ import { useLayoutEffect, useRef } from "react";
2
+ import Styles from "./useSnapToViewport.module.scss";
3
+ /**
4
+ * This takes a container and applies padding and margin so the content overflow container and goes until it hits the viewport border
5
+ */
6
+ export default function useSnapToViewport(defaultPadding: number) {
7
+ const elRef = useRef<HTMLDivElement>(null);
8
+
9
+ useLayoutEffect(() => {
10
+ const diff = window.visualViewport!.width - elRef.current!.clientWidth;
11
+
12
+ const margin = diff / 2;
13
+
14
+ elRef.current!.style.setProperty("--overflow-padding", `${margin}px`);
15
+ elRef.current!.style.setProperty("--overflow-margin", `${-margin}px`);
16
+ elRef.current!.style.setProperty(
17
+ "--default-padding",
18
+ `${defaultPadding}px`
19
+ );
20
+ elRef.current!.style.setProperty(
21
+ "--default-margin",
22
+ `${-defaultPadding}px`
23
+ );
24
+ elRef.current!.classList.add(Styles.applySpacings);
25
+ }, []);
26
+
27
+ return elRef;
28
+ }
@@ -0,0 +1,219 @@
1
+ import throttle from "lodash/throttle";
2
+ import { RefObject, useEffect, useRef, useState } from "react";
3
+ import {
4
+ flattenMatrix,
5
+ generateMatrixFromOperations,
6
+ IDENTITY_MATRIX,
7
+ invertMatrix,
8
+ } from "../../components/Parallax/math/helpers";
9
+
10
+ const MAX_TILT = {
11
+ x: 100,
12
+ y: 100,
13
+ };
14
+
15
+ type Options = {
16
+ round?: boolean;
17
+ gyroEnabled?: boolean;
18
+ };
19
+
20
+ export function useTiltUpdates(
21
+ active: boolean,
22
+ relativeToEl: RefObject<HTMLDivElement | null>,
23
+ onTilt: (p: { x: number; y: number }) => void,
24
+ onInverseMatrix?: (updateFunc: (matrix: number[]) => number[]) => void,
25
+ sensorScale: number = 1,
26
+ tiltLimit: { x: number; y: number } = MAX_TILT,
27
+ options?: Options
28
+ ) {
29
+ useEffect(() => {
30
+ if (active) {
31
+ const updatePositions = (relativeToX: number, relativeToY: number) => {
32
+ const el = relativeToEl.current!;
33
+ const rect = el.getBoundingClientRect();
34
+ const {
35
+ width: [x0, xW],
36
+ height: [y0, yH],
37
+ } = {
38
+ width: [rect.left, el.clientWidth],
39
+ height: [rect.top, el.clientHeight],
40
+ };
41
+ const distanceOffRight = calculateDistanceRelativeToBounds(
42
+ relativeToX,
43
+ x0,
44
+ xW,
45
+ options?.round ?? true
46
+ );
47
+ const distanceOffBottom = calculateDistanceRelativeToBounds(
48
+ relativeToY,
49
+ y0,
50
+ yH,
51
+ options?.round ?? true
52
+ );
53
+ const howMuchToRotateY = givenTheRelativePositionHowMuchToRotate(
54
+ distanceOffRight,
55
+ tiltLimit.y
56
+ );
57
+ const howMuchToRotateX = givenTheRelativePositionHowMuchToRotate(
58
+ distanceOffBottom,
59
+ tiltLimit.x
60
+ );
61
+
62
+ onTilt({
63
+ y: howMuchToRotateX * 2,
64
+ x: howMuchToRotateY * 2,
65
+ });
66
+ };
67
+ const handler = throttle(({ x, y }: MouseEvent) => {
68
+ updatePositions(x, y);
69
+ }, 1000 / 30);
70
+ const touchHandler = throttle(({ touches }: TouchEvent) => {
71
+ const { pageX, pageY } = touches[0];
72
+ updatePositions(pageX, pageY);
73
+ }, 1000 / 30);
74
+ window.addEventListener("mousemove", handler);
75
+ window.addEventListener("touchmove", touchHandler);
76
+ let _inverseMatrix: number[] | undefined;
77
+ const _limits: {
78
+ [k in "beta" | "gamma"]?: [number, number];
79
+ } = {
80
+ beta: undefined,
81
+ gamma: undefined,
82
+ };
83
+ const orientationListener: (e: DeviceOrientationEvent) => void = ({
84
+ beta,
85
+ gamma,
86
+ }) => {
87
+ beta = beta! * 0.5;
88
+ gamma = gamma! * 0.5;
89
+ if (!_inverseMatrix) {
90
+ window.removeEventListener("mousemove", handler);
91
+ window.removeEventListener("touchmove", touchHandler);
92
+ const offset = 12.5;
93
+ _limits.beta = [beta! - offset, beta! + offset];
94
+ _limits.gamma = [gamma! - offset, gamma! + offset];
95
+ }
96
+ const _beta = Math.min(
97
+ _limits.beta![1],
98
+ Math.max(_limits.beta![0], beta!)
99
+ );
100
+ const _gamma = Math.min(
101
+ _limits.gamma![1],
102
+ Math.max(_limits.gamma![0], gamma!)
103
+ );
104
+ if (!_inverseMatrix && onInverseMatrix) {
105
+ onInverseMatrix(() => {
106
+ return (_inverseMatrix = flattenMatrix(
107
+ invertMatrix(
108
+ generateMatrixFromOperations(
109
+ {
110
+ type: "rotateY",
111
+ angle: _gamma!,
112
+ },
113
+ {
114
+ type: "rotateX",
115
+ angle: -_beta!,
116
+ }
117
+ )
118
+ )
119
+ ));
120
+ });
121
+ }
122
+ onTilt({
123
+ y: -_beta * sensorScale,
124
+ x: _gamma * sensorScale,
125
+ });
126
+ };
127
+ function removeListeners() {
128
+ window.removeEventListener("mousemove", handler);
129
+ window.removeEventListener("touchmove", touchHandler);
130
+ }
131
+ if (options?.gyroEnabled ?? true) {
132
+ window.addEventListener("deviceorientation", orientationListener);
133
+ return () => {
134
+ window.removeEventListener("deviceorientation", orientationListener);
135
+ removeListeners();
136
+ };
137
+ } else {
138
+ return () => removeListeners();
139
+ }
140
+ }
141
+ }, [active, onInverseMatrix, onTilt]);
142
+ }
143
+
144
+ /**
145
+ * This hook binds to two methods for calculating tilt
146
+ *
147
+ * When available: The device sensors
148
+ * When on desktop: The mouse position relative to a ref
149
+ */
150
+ export default function useTilt(
151
+ active: boolean,
152
+ /**
153
+ * A scale to increase the values from the sensors
154
+ *
155
+ * @hack You can set this value to 0 as a way to disable the tilt calc on mobile
156
+ */
157
+ sensorScale: number = 1,
158
+ maxTilt: { x: number; y: number } = MAX_TILT,
159
+ options?: Options
160
+ ) {
161
+ const [tilt, setTilt] = useState<{ x: number; y: number }>({
162
+ x: 0,
163
+ y: 0,
164
+ });
165
+ const [tiltResetMatrix, setTiltResetMatrix] = useState<number[]>(() =>
166
+ flattenMatrix(IDENTITY_MATRIX())
167
+ );
168
+ const relativeTo = useRef<HTMLDivElement>(null);
169
+
170
+ useTiltUpdates(
171
+ active,
172
+ relativeTo,
173
+ setTilt,
174
+ setTiltResetMatrix,
175
+ sensorScale,
176
+ maxTilt,
177
+ options
178
+ );
179
+
180
+ return {
181
+ /** The element to monitor mouse hover relative to */
182
+ relativeTo,
183
+ /**
184
+ * The matrix that represents the original tilt, so it can be used with the tilt prop to tilt relative to the user
185
+ * Use it on css like so transform: matrix3d(tiltResetMatrix.join(",")) rotateX(tilt.x) rotateY(tilt.y)
186
+ */
187
+ tiltResetMatrix,
188
+
189
+ /**
190
+ * How much tilt should be applied based
191
+ */
192
+ tilt,
193
+ };
194
+ }
195
+
196
+ export function calculateDistanceRelativeToBounds(
197
+ mousePosition: number,
198
+ elementInitialPosition: number,
199
+ elementSizeDimension: number,
200
+ shouldRound: boolean
201
+ ) {
202
+ const normalizeInitialPosition = mousePosition - elementInitialPosition;
203
+ const doNotAllowGoingBeyondLowerLimit = Math.max(normalizeInitialPosition, 0);
204
+ const doNotAllowHoingBeyondHigherLimit = Math.min(
205
+ doNotAllowGoingBeyondLowerLimit,
206
+ elementSizeDimension
207
+ );
208
+ const threeRule =
209
+ (doNotAllowHoingBeyondHigherLimit * 100) / elementSizeDimension;
210
+ const result = (shouldRound ? Math.round(threeRule) : threeRule) / 100;
211
+ return result;
212
+ }
213
+
214
+ export function givenTheRelativePositionHowMuchToRotate(
215
+ relativePosition: number,
216
+ maxRotation: number
217
+ ) {
218
+ return relativePosition * maxRotation - maxRotation / 2;
219
+ }
@@ -0,0 +1,34 @@
1
+ @import "../../assets/styles/variables.scss";
2
+
3
+ .zoomableIndicator {
4
+ cursor: zoom-in;
5
+ }
6
+
7
+ $stubZIndex: 1000000;
8
+
9
+ .backdrop {
10
+ position: fixed;
11
+ width: 100vw;
12
+ height: 100vh;
13
+ top: 0;
14
+ left: 0;
15
+ z-index: $stubZIndex;
16
+ background: var(--zoomable--backdrop-bg, #0009);
17
+ transition: opacity $fast linear;
18
+ opacity: 0;
19
+ > * {
20
+ height: 100%;
21
+ width: 100%;
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ > * {
26
+ cursor: zoom-out;
27
+ }
28
+ }
29
+ }
30
+
31
+ .backdrop + * {
32
+ z-index: $stubZIndex + 1;
33
+ max-width: initial;
34
+ }
@@ -0,0 +1,144 @@
1
+ import React, { useEffect, useMemo, useRef } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import ReactDOM from "react-dom";
4
+ import Styles from "./useZoomable.module.scss";
5
+ import useHero from "../useHero";
6
+ import { useMergeRefsFunc } from "../useMergeRefs";
7
+ import ownEvent from "../../utils/ownEvent";
8
+ /**
9
+ * Allows an element to be zoomable for fullscreen
10
+ */
11
+ export default function useZoomable(id: string) {
12
+ const zoomableID = useMemo(() => `zoomable-${id}`, []);
13
+ const getBackdrop = () => {
14
+ return document.querySelector(
15
+ `[data-zoomable="${zoomableID}"]`
16
+ )! as HTMLDivElement;
17
+ };
18
+ const { heroRef, trigger } = useHero(
19
+ zoomableID,
20
+ {
21
+ "data-preffix": "zoomable",
22
+ repeatable: true,
23
+ },
24
+ {
25
+ onHeroStart: (clone, ...args) => {
26
+ const bd = getBackdrop();
27
+ const removeCb = ({ currentTarget, target }: TransitionEvent) => {
28
+ if (target === currentTarget) {
29
+ if (("unmountComponentAtNode" in ReactDOM) as any)
30
+ (ReactDOM as any).unmountComponentAtNode(bd);
31
+ else
32
+ console.error("This component doesn't work with the new versions of react yet...")
33
+ bd.remove();
34
+ }
35
+ };
36
+ bd.style.opacity = "0";
37
+ const middlewayClick = () => {
38
+ bd.removeEventListener("transitionend", removeCb);
39
+ clone.removeEventListener("click", middlewayClick);
40
+ _zoom();
41
+ };
42
+ clone.addEventListener("click", middlewayClick);
43
+ bd.addEventListener("transitionend", removeCb);
44
+ bd.addEventListener("transitionstart", () => {
45
+ bd.addEventListener(
46
+ "transitioncancel",
47
+ ownEvent(() => bd.removeEventListener("transitionend", removeCb))
48
+ );
49
+ });
50
+ },
51
+ }
52
+ );
53
+ const zoomableEl = useRef<HTMLDivElement>(null);
54
+ function _unzoom() {
55
+ trigger();
56
+ }
57
+
58
+ function _zoom() {
59
+ const el = zoomableEl.current!;
60
+ const elClone = el.cloneNode(true) as HTMLDivElement;
61
+ elClone.style.visibility = "hidden";
62
+
63
+ function HeroMount() {
64
+ const { heroRef } = useHero(
65
+ zoomableID,
66
+ {
67
+ "data-preffix": "zoomable",
68
+ repeatable: true,
69
+ },
70
+ {
71
+ onHeroStart: (clone, ...args) => {
72
+ getBackdrop().style.opacity = "1";
73
+ const unzoomCb = () => {
74
+ _unzoom();
75
+ clone.removeEventListener("click", unzoomCb);
76
+ };
77
+ clone.addEventListener("click", unzoomCb);
78
+ },
79
+ onHeroEnd: () => {
80
+ heroRef.current!.classList.remove(Styles.zoomableIndicator);
81
+ },
82
+ }
83
+ );
84
+
85
+ return (
86
+ <div
87
+ ref={(ref) => {
88
+ if (ref) {
89
+ ref.appendChild(elClone);
90
+ (heroRef as any).current = elClone;
91
+ const verticalProportion = el.clientWidth / el.clientHeight;
92
+ const targetWidth = ref.clientHeight * verticalProportion;
93
+
94
+ if (targetWidth > ref.clientWidth) {
95
+ const horizontalProportion = el.clientHeight / el.clientWidth;
96
+ elClone.style.width = ref.clientWidth + "px";
97
+ elClone.style.height =
98
+ ref.clientWidth * horizontalProportion + "px";
99
+ } else {
100
+ elClone.style.height = ref.clientHeight + "px";
101
+ elClone.style.width = targetWidth + "px";
102
+ }
103
+ }
104
+ }}
105
+ />
106
+ );
107
+ }
108
+
109
+ const existingBackdrop = getBackdrop();
110
+ if (!existingBackdrop) {
111
+ const backdrop = document.createElement("div");
112
+
113
+ backdrop.classList.add(Styles.backdrop);
114
+ backdrop.addEventListener("click", _unzoom);
115
+ backdrop.setAttribute("data-zoomable", zoomableID);
116
+
117
+ document.body.appendChild(backdrop);
118
+ createRoot(backdrop).render(<HeroMount />);
119
+ } else {
120
+ createRoot(existingBackdrop).render(<HeroMount />);
121
+ }
122
+ }
123
+ useEffect(() => {
124
+ const el = zoomableEl.current!;
125
+ el.classList.add(Styles.zoomableIndicator);
126
+ el.addEventListener("click", _zoom);
127
+ return () => {
128
+ el.classList.remove(Styles.zoomableIndicator);
129
+ const bd = getBackdrop();
130
+ if (bd) {
131
+ bd.style.opacity = "0";
132
+ bd.addEventListener("transitionend", () => {
133
+ bd.remove();
134
+ });
135
+ }
136
+ };
137
+ }, []);
138
+
139
+ const mergedRefs = useMergeRefsFunc(heroRef, zoomableEl);
140
+
141
+ return {
142
+ zoomableEl: mergedRefs,
143
+ };
144
+ }
@@ -0,0 +1,25 @@
1
+ # Protecting an async function
2
+ ```tsx
3
+ const control = useAsyncControl()
4
+
5
+ control.process(() => anAsyncFunction());
6
+ ```
7
+
8
+ # Using multiple async functions
9
+ ```tsx
10
+ const control = useAsyncControl({
11
+ asyncFunctionOne,
12
+ asyncFunctionTwo,
13
+ })
14
+
15
+ control.asyncFunctionOne();
16
+ control.asyncFunctionTwo();
17
+ ```
18
+
19
+ # Storing data
20
+ ```tsx
21
+ const [result, setResult] = useState()
22
+ const control = useAsyncControl({anAsyncFunctionThatReturnsData})
23
+
24
+ control.anAsyncFunctionThatReturnsData().then(setResult);
25
+ ```