@swan-io/lake 1.0.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 (288) hide show
  1. package/HISTORY.md +3 -0
  2. package/LICENSE +21 -0
  3. package/README.md +49 -0
  4. package/package.json +60 -0
  5. package/src/components/Alert.d.ts +10 -0
  6. package/src/components/Alert.js +36 -0
  7. package/src/components/AppOpeningAnimation.d.ts +10 -0
  8. package/src/components/AppOpeningAnimation.js +50 -0
  9. package/src/components/AutoWidthImage.d.ts +8 -0
  10. package/src/components/AutoWidthImage.js +26 -0
  11. package/src/components/Avatar.d.ts +7 -0
  12. package/src/components/Avatar.js +42 -0
  13. package/src/components/BorderedButton.d.ts +16 -0
  14. package/src/components/BorderedButton.js +98 -0
  15. package/src/components/BorderedIcon.d.ts +12 -0
  16. package/src/components/BorderedIcon.js +25 -0
  17. package/src/components/BottomPanel.d.ts +9 -0
  18. package/src/components/BottomPanel.js +94 -0
  19. package/src/components/Box.d.ts +65 -0
  20. package/src/components/Box.js +31 -0
  21. package/src/components/Breadcrumbs.d.ts +18 -0
  22. package/src/components/Breadcrumbs.js +362 -0
  23. package/src/components/Button.d.ts +15 -0
  24. package/src/components/Button.js +83 -0
  25. package/src/components/Caption.d.ts +6 -0
  26. package/src/components/Caption.js +11 -0
  27. package/src/components/Checkbox.d.ts +12 -0
  28. package/src/components/Checkbox.js +83 -0
  29. package/src/components/ChoicePicker.d.ts +11 -0
  30. package/src/components/ChoicePicker.js +99 -0
  31. package/src/components/Combobox.d.ts +29 -0
  32. package/src/components/Combobox.js +182 -0
  33. package/src/components/FailureIcon.d.ts +8 -0
  34. package/src/components/FailureIcon.js +4 -0
  35. package/src/components/FileTile.d.ts +11 -0
  36. package/src/components/FileTile.js +37 -0
  37. package/src/components/Fill.d.ts +8 -0
  38. package/src/components/Fill.js +24 -0
  39. package/src/components/FilterChooser.d.ts +15 -0
  40. package/src/components/FilterChooser.js +52 -0
  41. package/src/components/Filters.d.ts +57 -0
  42. package/src/components/Filters.js +229 -0
  43. package/src/components/FixedListView.d.ts +104 -0
  44. package/src/components/FixedListView.js +821 -0
  45. package/src/components/FixedListViewCells.d.ts +55 -0
  46. package/src/components/FixedListViewCells.js +157 -0
  47. package/src/components/Flag.d.ts +8 -0
  48. package/src/components/Flag.js +36 -0
  49. package/src/components/FlowPresentation.d.ts +12 -0
  50. package/src/components/FlowPresentation.js +70 -0
  51. package/src/components/FocusTrap.d.ts +16 -0
  52. package/src/components/FocusTrap.js +90 -0
  53. package/src/components/Form.d.ts +8 -0
  54. package/src/components/Form.js +17 -0
  55. package/src/components/FullViewportLayer.d.ts +7 -0
  56. package/src/components/FullViewportLayer.js +91 -0
  57. package/src/components/Grid.d.ts +13 -0
  58. package/src/components/Grid.js +33 -0
  59. package/src/components/Heading.d.ts +61 -0
  60. package/src/components/Heading.js +27 -0
  61. package/src/components/Icon.d.ts +191 -0
  62. package/src/components/Icon.js +11 -0
  63. package/src/components/Input.d.ts +34 -0
  64. package/src/components/Input.js +115 -0
  65. package/src/components/InputError.d.ts +8 -0
  66. package/src/components/InputError.js +16 -0
  67. package/src/components/Label.d.ts +10 -0
  68. package/src/components/Label.js +19 -0
  69. package/src/components/LakeAlert.d.ts +14 -0
  70. package/src/components/LakeAlert.js +75 -0
  71. package/src/components/LakeButton.d.ts +36 -0
  72. package/src/components/LakeButton.js +171 -0
  73. package/src/components/LakeCheckbox.d.ts +16 -0
  74. package/src/components/LakeCheckbox.js +54 -0
  75. package/src/components/LakeCombobox.d.ts +28 -0
  76. package/src/components/LakeCombobox.js +166 -0
  77. package/src/components/LakeCopyButton.d.ts +10 -0
  78. package/src/components/LakeCopyButton.js +16 -0
  79. package/src/components/LakeDownloadButton.d.ts +8 -0
  80. package/src/components/LakeDownloadButton.js +6 -0
  81. package/src/components/LakeHeading.d.ts +10 -0
  82. package/src/components/LakeHeading.js +19 -0
  83. package/src/components/LakeLabel.d.ts +19 -0
  84. package/src/components/LakeLabel.js +43 -0
  85. package/src/components/LakeModal.d.ts +14 -0
  86. package/src/components/LakeModal.js +132 -0
  87. package/src/components/LakeRadio.d.ts +9 -0
  88. package/src/components/LakeRadio.js +44 -0
  89. package/src/components/LakeScrollView.d.ts +10 -0
  90. package/src/components/LakeScrollView.js +35 -0
  91. package/src/components/LakeSearchField.d.ts +10 -0
  92. package/src/components/LakeSearchField.js +111 -0
  93. package/src/components/LakeSelect.d.ts +30 -0
  94. package/src/components/LakeSelect.js +183 -0
  95. package/src/components/LakeSlider.d.ts +12 -0
  96. package/src/components/LakeSlider.js +31 -0
  97. package/src/components/LakeStepper.d.ts +21 -0
  98. package/src/components/LakeStepper.js +134 -0
  99. package/src/components/LakeText.d.ts +19 -0
  100. package/src/components/LakeText.js +20 -0
  101. package/src/components/LakeTextInput.d.ts +36 -0
  102. package/src/components/LakeTextInput.js +154 -0
  103. package/src/components/LakeTooltip.d.ts +24 -0
  104. package/src/components/LakeTooltip.js +188 -0
  105. package/src/components/Link.d.ts +138 -0
  106. package/src/components/Link.js +23 -0
  107. package/src/components/ListRightPanel.d.ts +17 -0
  108. package/src/components/ListRightPanel.js +79 -0
  109. package/src/components/LoadingView.d.ts +9 -0
  110. package/src/components/LoadingView.js +24 -0
  111. package/src/components/Modal.d.ts +12 -0
  112. package/src/components/Modal.js +80 -0
  113. package/src/components/MultiSelect.d.ts +27 -0
  114. package/src/components/MultiSelect.js +223 -0
  115. package/src/components/MultilineInput.d.ts +15 -0
  116. package/src/components/MultilineInput.js +55 -0
  117. package/src/components/Picker.d.ts +26 -0
  118. package/src/components/Picker.js +116 -0
  119. package/src/components/PlainListView.d.ts +36 -0
  120. package/src/components/PlainListView.js +208 -0
  121. package/src/components/Popover.d.ts +23 -0
  122. package/src/components/Popover.js +147 -0
  123. package/src/components/PopoverContent.d.ts +8 -0
  124. package/src/components/PopoverContent.js +9 -0
  125. package/src/components/Portal.d.ts +7 -0
  126. package/src/components/Portal.js +9 -0
  127. package/src/components/Pressable.d.ts +348 -0
  128. package/src/components/Pressable.js +91 -0
  129. package/src/components/ProgressBar.d.ts +11 -0
  130. package/src/components/ProgressBar.js +46 -0
  131. package/src/components/ProjectEnvTag.d.ts +7 -0
  132. package/src/components/ProjectEnvTag.js +12 -0
  133. package/src/components/QuickActions.d.ts +15 -0
  134. package/src/components/QuickActions.js +38 -0
  135. package/src/components/RadioGroup.d.ts +16 -0
  136. package/src/components/RadioGroup.js +34 -0
  137. package/src/components/ReadOnlyFieldList.d.ts +6 -0
  138. package/src/components/ReadOnlyFieldList.js +8 -0
  139. package/src/components/ResponsiveContainer.d.ts +13 -0
  140. package/src/components/ResponsiveContainer.js +23 -0
  141. package/src/components/RightPanel.d.ts +10 -0
  142. package/src/components/RightPanel.js +102 -0
  143. package/src/components/SegmentedControl.d.ts +19 -0
  144. package/src/components/SegmentedControl.js +74 -0
  145. package/src/components/Separator.d.ts +10 -0
  146. package/src/components/Separator.js +19 -0
  147. package/src/components/SidebarNavigationTracker.d.ts +13 -0
  148. package/src/components/SidebarNavigationTracker.js +93 -0
  149. package/src/components/Slider.d.ts +11 -0
  150. package/src/components/Slider.js +119 -0
  151. package/src/components/SmsOpeningAnimation.d.ts +8 -0
  152. package/src/components/SmsOpeningAnimation.js +52 -0
  153. package/src/components/Space.d.ts +10 -0
  154. package/src/components/Space.js +23 -0
  155. package/src/components/Stack.d.ts +12 -0
  156. package/src/components/Stack.js +23 -0
  157. package/src/components/StepDots.d.ts +7 -0
  158. package/src/components/StepDots.js +24 -0
  159. package/src/components/Stepper.d.ts +9 -0
  160. package/src/components/Stepper.js +67 -0
  161. package/src/components/SuccessIcon.d.ts +8 -0
  162. package/src/components/SuccessIcon.js +4 -0
  163. package/src/components/Svg.d.ts +145 -0
  164. package/src/components/Svg.js +24 -0
  165. package/src/components/SwanLogo.d.ts +8 -0
  166. package/src/components/SwanLogo.js +11 -0
  167. package/src/components/Switch.d.ts +9 -0
  168. package/src/components/Switch.js +74 -0
  169. package/src/components/TabView.d.ts +16 -0
  170. package/src/components/TabView.js +398 -0
  171. package/src/components/Table.d.ts +34 -0
  172. package/src/components/Table.js +79 -0
  173. package/src/components/Tag.d.ts +17 -0
  174. package/src/components/Tag.js +76 -0
  175. package/src/components/Tile.d.ts +34 -0
  176. package/src/components/Tile.js +130 -0
  177. package/src/components/TilePlaceholder.d.ts +6 -0
  178. package/src/components/TilePlaceholder.js +51 -0
  179. package/src/components/ToastStack.d.ts +2 -0
  180. package/src/components/ToastStack.js +96 -0
  181. package/src/components/Tooltip.d.ts +18 -0
  182. package/src/components/Tooltip.js +162 -0
  183. package/src/components/TransitionGroupView.d.ts +12 -0
  184. package/src/components/TransitionGroupView.js +43 -0
  185. package/src/components/TransitionView.d.ts +12 -0
  186. package/src/components/TransitionView.js +43 -0
  187. package/src/components/WithCurrentColor.d.ts +12 -0
  188. package/src/components/WithCurrentColor.js +65 -0
  189. package/src/components/WithPartnerAccentColor.d.ts +7 -0
  190. package/src/components/WithPartnerAccentColor.js +91 -0
  191. package/src/constants/colors.d.ts +42 -0
  192. package/src/constants/colors.js +42 -0
  193. package/src/constants/commonStyles.d.ts +66 -0
  194. package/src/constants/commonStyles.js +45 -0
  195. package/src/constants/design.d.ts +168 -0
  196. package/src/constants/design.js +564 -0
  197. package/src/constants/insets.d.ts +10 -0
  198. package/src/constants/insets.js +22 -0
  199. package/src/constants/typography.d.ts +26 -0
  200. package/src/constants/typography.js +54 -0
  201. package/src/hooks/useAnimatedValue.d.ts +2 -0
  202. package/src/hooks/useAnimatedValue.js +3 -0
  203. package/src/hooks/useBodyClassName.d.ts +3 -0
  204. package/src/hooks/useBodyClassName.js +14 -0
  205. package/src/hooks/useBoolean.d.ts +8 -0
  206. package/src/hooks/useBoolean.js +12 -0
  207. package/src/hooks/useComputedColors.d.ts +10 -0
  208. package/src/hooks/useComputedColors.js +42 -0
  209. package/src/hooks/useDebounce.d.ts +1 -0
  210. package/src/hooks/useDebounce.js +12 -0
  211. package/src/hooks/useDisclosure.d.ts +8 -0
  212. package/src/hooks/useDisclosure.js +12 -0
  213. package/src/hooks/useFirstMountState.d.ts +1 -0
  214. package/src/hooks/useFirstMountState.js +9 -0
  215. package/src/hooks/useForceableState.d.ts +1 -0
  216. package/src/hooks/useForceableState.js +6 -0
  217. package/src/hooks/useHover.d.ts +11 -0
  218. package/src/hooks/useHover.js +4 -0
  219. package/src/hooks/useInterval.d.ts +1 -0
  220. package/src/hooks/useInterval.js +11 -0
  221. package/src/hooks/useLazyRef.d.ts +2 -0
  222. package/src/hooks/useLazyRef.js +9 -0
  223. package/src/hooks/useMergeRefs.d.ts +2 -0
  224. package/src/hooks/useMergeRefs.js +5 -0
  225. package/src/hooks/useNativeProp.d.ts +2 -0
  226. package/src/hooks/useNativeProp.js +9 -0
  227. package/src/hooks/useOutsideClick.d.ts +8 -0
  228. package/src/hooks/useOutsideClick.js +54 -0
  229. package/src/hooks/usePersistedState.d.ts +1 -0
  230. package/src/hooks/usePersistedState.js +21 -0
  231. package/src/hooks/usePressEvents.d.ts +31 -0
  232. package/src/hooks/usePressEvents.js +4 -0
  233. package/src/hooks/usePreviousValue.d.ts +1 -0
  234. package/src/hooks/usePreviousValue.js +8 -0
  235. package/src/hooks/useResponsive.d.ts +7 -0
  236. package/src/hooks/useResponsive.js +20 -0
  237. package/src/hooks/useUpdateEffect.d.ts +2 -0
  238. package/src/hooks/useUpdateEffect.js +10 -0
  239. package/src/hooks/useUrqlMutation.d.ts +4 -0
  240. package/src/hooks/useUrqlMutation.js +30 -0
  241. package/src/hooks/useUrqlQuery.d.ts +19 -0
  242. package/src/hooks/useUrqlQuery.js +73 -0
  243. package/src/state/toasts.d.ts +21 -0
  244. package/src/state/toasts.js +61 -0
  245. package/src/utils/__tests__/array.test.d.ts +1 -0
  246. package/src/utils/__tests__/array.test.js +127 -0
  247. package/src/utils/__tests__/base64.test.d.ts +1 -0
  248. package/src/utils/__tests__/base64.test.js +27 -0
  249. package/src/utils/__tests__/function.test.d.ts +1 -0
  250. package/src/utils/__tests__/function.test.js +36 -0
  251. package/src/utils/__tests__/object.test.d.ts +1 -0
  252. package/src/utils/__tests__/object.test.js +17 -0
  253. package/src/utils/__tests__/rifm.test.d.ts +1 -0
  254. package/src/utils/__tests__/rifm.test.js +124 -0
  255. package/src/utils/__tests__/string.test.d.ts +1 -0
  256. package/src/utils/__tests__/string.test.js +16 -0
  257. package/src/utils/a11y.d.ts +1 -0
  258. package/src/utils/a11y.js +18 -0
  259. package/src/utils/array.d.ts +6 -0
  260. package/src/utils/array.js +71 -0
  261. package/src/utils/base64.d.ts +2 -0
  262. package/src/utils/base64.js +20 -0
  263. package/src/utils/file.d.ts +2 -0
  264. package/src/utils/file.js +10 -0
  265. package/src/utils/flagCountry.d.ts +1 -0
  266. package/src/utils/flagCountry.js +1 -0
  267. package/src/utils/function.d.ts +4 -0
  268. package/src/utils/function.js +19 -0
  269. package/src/utils/math.d.ts +16 -0
  270. package/src/utils/math.js +47 -0
  271. package/src/utils/nullish.d.ts +10 -0
  272. package/src/utils/nullish.js +8 -0
  273. package/src/utils/object.d.ts +2 -0
  274. package/src/utils/object.js +7 -0
  275. package/src/utils/popper.d.ts +3 -0
  276. package/src/utils/popper.js +30 -0
  277. package/src/utils/rifm.d.ts +14 -0
  278. package/src/utils/rifm.js +53 -0
  279. package/src/utils/string.d.ts +4 -0
  280. package/src/utils/string.js +233 -0
  281. package/src/utils/timer.d.ts +11 -0
  282. package/src/utils/timer.js +46 -0
  283. package/src/utils/types.d.ts +8 -0
  284. package/src/utils/types.js +1 -0
  285. package/src/utils/userAgent.d.ts +4 -0
  286. package/src/utils/userAgent.js +9 -0
  287. package/src/utils/viewport.d.ts +1 -0
  288. package/src/utils/viewport.js +12 -0
@@ -0,0 +1,14 @@
1
+ import { useEffect } from "react";
2
+ export const useBodyClassName = (className, { enabled = true } = {}) => {
3
+ useEffect(() => {
4
+ if (enabled) {
5
+ document.body.classList.add(className);
6
+ }
7
+ else {
8
+ document.body.classList.remove(className);
9
+ }
10
+ return () => {
11
+ document.body.classList.remove(className);
12
+ };
13
+ }, [className, enabled]);
14
+ };
@@ -0,0 +1,8 @@
1
+ export declare const useBoolean: (initialValue: boolean | (() => boolean)) => [
2
+ boolean,
3
+ {
4
+ on: () => void;
5
+ off: () => void;
6
+ toggle: () => void;
7
+ }
8
+ ];
@@ -0,0 +1,12 @@
1
+ import { useMemo, useState } from "react";
2
+ export const useBoolean = (initialValue) => {
3
+ const [value, setValue] = useState(initialValue);
4
+ return [
5
+ value,
6
+ useMemo(() => ({
7
+ on: () => setValue(true),
8
+ off: () => setValue(false),
9
+ toggle: () => setValue(prevValue => !prevValue),
10
+ }), []),
11
+ ];
12
+ };
@@ -0,0 +1,10 @@
1
+ type ComputedColors = {
2
+ original: string;
3
+ progress: string;
4
+ text: string;
5
+ hovered: string;
6
+ pressed: string;
7
+ disabled: string;
8
+ };
9
+ export declare const useComputedColors: (color: string) => ComputedColors;
10
+ export {};
@@ -0,0 +1,42 @@
1
+ import { darken, getLuminance, meetsContrastGuidelines, tint } from "polished";
2
+ import { invariantColors } from "../constants/design";
3
+ import { identity, memoize } from "../utils/function";
4
+ const isValidColor = (color) => {
5
+ try {
6
+ getLuminance(color);
7
+ return true;
8
+ }
9
+ catch (error) {
10
+ return false;
11
+ }
12
+ };
13
+ const getComputedColors = (color) => {
14
+ const safeColor = isValidColor(color) ? color : invariantColors.gray; // fallback
15
+ const luminance = getLuminance(safeColor);
16
+ if (luminance <= 0.75) {
17
+ return {
18
+ original: safeColor,
19
+ progress: safeColor,
20
+ text: invariantColors.white,
21
+ hovered: tint(0.2, safeColor),
22
+ pressed: darken(0.05, safeColor),
23
+ disabled: tint(0.5, safeColor),
24
+ };
25
+ }
26
+ const delta = 0.5 + (1 - luminance);
27
+ let text = darken(delta / 1.5, safeColor);
28
+ if (!meetsContrastGuidelines(safeColor, text).AALarge) {
29
+ text = darken(delta, safeColor);
30
+ }
31
+ return {
32
+ original: safeColor,
33
+ progress: text,
34
+ text,
35
+ hovered: darken(delta / 12, safeColor),
36
+ pressed: darken(delta / 6, safeColor),
37
+ disabled: safeColor, // update this with Clement's values
38
+ };
39
+ };
40
+ const memoizedGetComputedColors = memoize(getComputedColors, identity);
41
+ // Not really a hook: we rely on lodash to perform cross-components memoization
42
+ export const useComputedColors = (color) => memoizedGetComputedColors(color);
@@ -0,0 +1 @@
1
+ export declare const useDebounce: <T>(func: (arg: T) => void, duration: number) => (arg: T) => () => void;
@@ -0,0 +1,12 @@
1
+ import { useCallback, useRef } from "react";
2
+ import { isNotNullish } from "../utils/nullish";
3
+ export const useDebounce = (func, duration) => {
4
+ const timeoutRef = useRef(undefined);
5
+ return useCallback((arg) => {
6
+ if (isNotNullish(timeoutRef.current)) {
7
+ clearTimeout(timeoutRef.current);
8
+ }
9
+ timeoutRef.current = window.setTimeout(func, duration, arg);
10
+ return () => clearTimeout(timeoutRef.current);
11
+ }, [func, duration]);
12
+ };
@@ -0,0 +1,8 @@
1
+ export declare const useDisclosure: (initialValue: boolean) => [
2
+ visible: boolean,
3
+ fns: {
4
+ open: () => void;
5
+ close: () => void;
6
+ toggle: () => void;
7
+ }
8
+ ];
@@ -0,0 +1,12 @@
1
+ import { useMemo, useState } from "react";
2
+ export const useDisclosure = (initialValue) => {
3
+ const [value, setValue] = useState(initialValue);
4
+ return [
5
+ value,
6
+ useMemo(() => ({
7
+ open: () => setValue(true),
8
+ close: () => setValue(false),
9
+ toggle: () => setValue(prevValue => !prevValue),
10
+ }), []),
11
+ ];
12
+ };
@@ -0,0 +1 @@
1
+ export declare const useFirstMountState: () => boolean;
@@ -0,0 +1,9 @@
1
+ import { useRef } from "react";
2
+ export const useFirstMountState = () => {
3
+ const isFirstMount = useRef(true);
4
+ if (isFirstMount.current) {
5
+ isFirstMount.current = false;
6
+ return true;
7
+ }
8
+ return isFirstMount.current;
9
+ };
@@ -0,0 +1 @@
1
+ export declare const useForceableState: (forced: boolean) => [boolean, (value: boolean) => void];
@@ -0,0 +1,6 @@
1
+ // https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/exports/Pressable/index.js#L220
2
+ import { useState } from "react";
3
+ export const useForceableState = (forced) => {
4
+ const [value, setValue] = useState(false);
5
+ return [value || forced, setValue];
6
+ };
@@ -0,0 +1,11 @@
1
+ import { MutableRefObject } from "react";
2
+ type HoverEventsConfig = {
3
+ contain?: boolean;
4
+ disabled?: boolean;
5
+ onHoverChange?: (bool: boolean) => void;
6
+ onHoverEnd?: (event: unknown) => void;
7
+ onHoverStart?: (event: unknown) => void;
8
+ onHoverUpdate?: (event: unknown) => void;
9
+ };
10
+ export declare const useHover: <T>(ref: MutableRefObject<T | null>, config: HoverEventsConfig) => void;
11
+ export {};
@@ -0,0 +1,4 @@
1
+ // https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/useHover/index.js
2
+ // @ts-expect-error
3
+ import originaUseHover from "react-native-web/dist/cjs/modules/useHover";
4
+ export const useHover = originaUseHover;
@@ -0,0 +1 @@
1
+ export declare const useInterval: (handler: (id: number) => void, timeout: number) => void;
@@ -0,0 +1,11 @@
1
+ import { useEffect, useRef } from "react";
2
+ export const useInterval = (handler, timeout) => {
3
+ const handlerRef = useRef(handler);
4
+ useEffect(() => {
5
+ handlerRef.current = handler;
6
+ }, [handler]);
7
+ useEffect(() => {
8
+ const id = window.setInterval(() => handlerRef.current(id), timeout);
9
+ return () => window.clearInterval(id);
10
+ }, [timeout]);
11
+ };
@@ -0,0 +1,2 @@
1
+ import { MutableRefObject } from "react";
2
+ export declare const useLazyRef: <T>(getInitialValue: () => T) => MutableRefObject<T>;
@@ -0,0 +1,9 @@
1
+ import { useRef } from "react";
2
+ const UNSET = Symbol("unset");
3
+ export const useLazyRef = (getInitialValue) => {
4
+ const ref = useRef(UNSET);
5
+ if (ref.current === UNSET) {
6
+ ref.current = getInitialValue();
7
+ }
8
+ return ref;
9
+ };
@@ -0,0 +1,2 @@
1
+ import { MutableRefObject, Ref } from "react";
2
+ export declare const useMergeRefs: <T>(...refs: Ref<T>[]) => MutableRefObject<T | null>;
@@ -0,0 +1,5 @@
1
+ // https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/useMergeRefs/index.js
2
+ // https://github.com/theKashey/use-callback-ref (for typing)
3
+ // @ts-expect-error
4
+ import originalUseMergeRefs from "react-native-web/dist/cjs/modules/useMergeRefs";
5
+ export const useMergeRefs = originalUseMergeRefs;
@@ -0,0 +1,2 @@
1
+ import { MutableRefObject } from "react";
2
+ export declare const useNativeProp: <T>(ref: MutableRefObject<T | null>, name: string, value: number | string | undefined) => void;
@@ -0,0 +1,9 @@
1
+ import { useLayoutEffect } from "react";
2
+ import { isNotNullish } from "../utils/nullish";
3
+ export const useNativeProp = (ref, name, value) => {
4
+ useLayoutEffect(() => {
5
+ if (isNotNullish(value) && ref.current instanceof Element) {
6
+ ref.current.setAttribute(name, String(value));
7
+ }
8
+ }, [ref, name, value]);
9
+ };
@@ -0,0 +1,8 @@
1
+ import { RefObject } from "react";
2
+ type Params = {
3
+ containerRef: RefObject<unknown>;
4
+ onClickOutside?: (event: MouseEvent | TouchEvent) => void;
5
+ onFocusOutside?: (event: FocusEvent) => void;
6
+ };
7
+ export declare const useOutsideClick: ({ containerRef, onClickOutside, onFocusOutside }: Params) => void;
8
+ export {};
@@ -0,0 +1,54 @@
1
+ import { useCallback, useEffect, useRef } from "react";
2
+ import { isNotNullish, isNullish } from "../utils/nullish";
3
+ export const useOutsideClick = ({ containerRef, onClickOutside, onFocusOutside }) => {
4
+ const hasTouchStartedRef = useRef(false);
5
+ const isTargetInside = useCallback((event) => {
6
+ const target = event.target;
7
+ // NOTE: Let's be careful with the `instanceof` check if we're ever to render a portal to another window
8
+ return (isNotNullish(containerRef.current) &&
9
+ containerRef.current instanceof HTMLElement &&
10
+ containerRef.current.contains(target));
11
+ }, [containerRef]);
12
+ useEffect(() => {
13
+ if (isNullish(onClickOutside)) {
14
+ return;
15
+ }
16
+ const onTouchStart = (event) => {
17
+ if (!isTargetInside(event)) {
18
+ hasTouchStartedRef.current = true;
19
+ }
20
+ };
21
+ const onTouchEnd = (event) => {
22
+ if (!isTargetInside(event) && hasTouchStartedRef.current) {
23
+ onClickOutside?.(event);
24
+ }
25
+ hasTouchStartedRef.current = false;
26
+ };
27
+ document.addEventListener("mousedown", onTouchStart, true);
28
+ document.addEventListener("mouseup", onTouchEnd, true);
29
+ document.addEventListener("touchstart", onTouchStart, true);
30
+ document.addEventListener("touchend", onTouchEnd, true);
31
+ return () => {
32
+ document.removeEventListener("mousedown", onTouchStart, true);
33
+ document.removeEventListener("mouseup", onTouchEnd, true);
34
+ document.removeEventListener("touchstart", onTouchStart, true);
35
+ document.removeEventListener("touchend", onTouchEnd, true);
36
+ };
37
+ }, [isTargetInside, onClickOutside]);
38
+ useEffect(() => {
39
+ if (isNullish(onFocusOutside)) {
40
+ return;
41
+ }
42
+ const onFocusIn = (event) => {
43
+ if (!isTargetInside(event)) {
44
+ onFocusOutside?.(event);
45
+ }
46
+ };
47
+ // We use the `focusin` event so that we can intercept during the capturing phase
48
+ // see: https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event
49
+ document.addEventListener("focusin", onFocusIn, true);
50
+ return () => {
51
+ document.removeEventListener("focusin", onFocusIn, true);
52
+ };
53
+ }, [isTargetInside, onFocusOutside]);
54
+ };
@@ -0,0 +1 @@
1
+ export declare const usePersistedState: <T>(key: string, defaultValue: T) => readonly [T, (state: T) => void];
@@ -0,0 +1,21 @@
1
+ import { Option, Result } from "@swan-io/boxed";
2
+ import { useCallback, useState } from "react";
3
+ export const usePersistedState = (key, defaultValue) => {
4
+ const [state, setState] = useState(() => {
5
+ return Result.fromExecution(() => localStorage.getItem(key))
6
+ .toOption()
7
+ .flatMap(Option.fromNullable)
8
+ .map(value => JSON.parse(value))
9
+ .getWithDefault(defaultValue);
10
+ });
11
+ const setPersistedState = useCallback((state) => {
12
+ setState(state);
13
+ try {
14
+ localStorage.setItem(key, JSON.stringify(state));
15
+ }
16
+ catch (err) {
17
+ // ignore
18
+ }
19
+ }, [key]);
20
+ return [state, setPersistedState];
21
+ };
@@ -0,0 +1,31 @@
1
+ import { MutableRefObject } from "react";
2
+ import { GestureResponderEvent } from "react-native";
3
+ type ClickEvent = unknown;
4
+ type KeyboardEvent = unknown;
5
+ type ResponderEvent = unknown;
6
+ export type PressResponderConfig = {
7
+ cancelable?: boolean;
8
+ delayLongPress?: number;
9
+ delayPressEnd?: number;
10
+ delayPressStart?: number;
11
+ disabled?: boolean;
12
+ onLongPress?: (event: ResponderEvent) => void;
13
+ onPress?: (event: GestureResponderEvent) => void;
14
+ onPressChange?: (event: ResponderEvent) => void;
15
+ onPressEnd?: (event: ResponderEvent) => void;
16
+ onPressMove?: (event: ResponderEvent) => void;
17
+ onPressStart?: (event: ResponderEvent) => void;
18
+ };
19
+ type EventHandlers = {
20
+ onClick?: (event: ClickEvent) => void;
21
+ onContextMenu?: (event: ClickEvent) => void;
22
+ onKeyDown?: (event: KeyboardEvent) => void;
23
+ onResponderGrant?: (event: ResponderEvent) => void;
24
+ onResponderMove?: (event: ResponderEvent) => void;
25
+ onResponderRelease?: (event: ResponderEvent) => void;
26
+ onResponderTerminate?: (event: ResponderEvent) => void;
27
+ onResponderTerminationRequest?: (event: ResponderEvent) => boolean;
28
+ onStartShouldSetResponder?: (event: ResponderEvent) => boolean;
29
+ };
30
+ export declare const usePressEvents: <T>(ref: MutableRefObject<T | null>, config: PressResponderConfig) => EventHandlers;
31
+ export {};
@@ -0,0 +1,4 @@
1
+ // https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/usePressEvents/index.js
2
+ // @ts-expect-error
3
+ import originalUsePressEvents from "react-native-web/dist/cjs/modules/usePressEvents";
4
+ export const usePressEvents = originalUsePressEvents;
@@ -0,0 +1 @@
1
+ export declare const usePreviousValue: <T>(value: T) => T;
@@ -0,0 +1,8 @@
1
+ import { useEffect, useRef } from "react";
2
+ export const usePreviousValue = (value) => {
3
+ const previousRef = useRef(value);
4
+ useEffect(() => {
5
+ previousRef.current = value;
6
+ }, [value]);
7
+ return previousRef.current;
8
+ };
@@ -0,0 +1,7 @@
1
+ export declare const useResponsive: (breakpoint?: number | undefined) => {
2
+ desktop: boolean;
3
+ media: <T>(values: {
4
+ mobile: T;
5
+ desktop?: T | undefined;
6
+ }) => T;
7
+ };
@@ -0,0 +1,20 @@
1
+ // Based on https://github.com/necolas/react-native-web/blob/0.17.7/packages/react-native-web/src/exports/useWindowDimensions/index.js
2
+ import { useCallback, useSyncExternalStore } from "react";
3
+ import { Dimensions } from "react-native";
4
+ import { isNotNullish } from "../utils/nullish";
5
+ const BREAKPOINT = 992;
6
+ const isDesktop = ({ width }, breakpoint) => width >= breakpoint;
7
+ export const useResponsive = (breakpoint = BREAKPOINT) => {
8
+ const desktop = useSyncExternalStore(onStoreChange => {
9
+ const subscription = Dimensions.addEventListener("change", ({ window }) => {
10
+ if (isNotNullish(window)) {
11
+ onStoreChange();
12
+ }
13
+ });
14
+ return () => {
15
+ subscription.remove();
16
+ };
17
+ }, () => isDesktop(Dimensions.get("window"), breakpoint));
18
+ const media = useCallback((values) => desktop ? values.desktop ?? values.mobile : values.mobile, [desktop]);
19
+ return { desktop, media };
20
+ };
@@ -0,0 +1,2 @@
1
+ import { useEffect } from "react";
2
+ export declare const useUpdateEffect: typeof useEffect;
@@ -0,0 +1,10 @@
1
+ import { useEffect } from "react";
2
+ import { useFirstMountState } from "./useFirstMountState";
3
+ export const useUpdateEffect = (effect, deps) => {
4
+ const isFirstMount = useFirstMountState();
5
+ useEffect(() => {
6
+ if (!isFirstMount) {
7
+ return effect();
8
+ }
9
+ }, deps); // eslint-disable-line react-hooks/exhaustive-deps
10
+ };
@@ -0,0 +1,4 @@
1
+ import { AsyncData, Future, Result } from "@swan-io/boxed";
2
+ import { DocumentNode } from "graphql";
3
+ import { AnyVariables, CombinedError, TypedDocumentNode } from "urql";
4
+ export declare const useUrqlMutation: <Data, Variables extends AnyVariables>(query: string | DocumentNode | TypedDocumentNode<Data, Variables>) => readonly [AsyncData<Result<Data, Error>>, (input: Variables) => Future<Result<Data, Error | CombinedError>>];
@@ -0,0 +1,30 @@
1
+ import { AsyncData, Future, Result } from "@swan-io/boxed";
2
+ import { useCallback, useMemo } from "react";
3
+ import { CombinedError, useMutation } from "urql";
4
+ import { isNotNullish, isNullish } from "../utils/nullish";
5
+ const toResult = ({ data, error, }) => {
6
+ if (isNotNullish(error)) {
7
+ return Result.Error(error);
8
+ }
9
+ if (isNullish(data)) {
10
+ return Result.Error(new CombinedError({ networkError: new Error("No Content") }));
11
+ }
12
+ return Result.Ok(data);
13
+ };
14
+ export const useUrqlMutation = (query) => {
15
+ const [{ fetching, data, error }, execute] = useMutation(query);
16
+ return [
17
+ useMemo(() => {
18
+ if (fetching) {
19
+ return AsyncData.Loading();
20
+ }
21
+ if (isNullish(data) && isNullish(error)) {
22
+ return AsyncData.NotAsked();
23
+ }
24
+ return AsyncData.Done(toResult({ data, error }));
25
+ }, [fetching, data, error]),
26
+ useCallback((input) => Future.fromPromise(execute(input))
27
+ .mapError(error => error) // Only used to cast error
28
+ .mapResult(toResult), [execute]),
29
+ ];
30
+ };
@@ -0,0 +1,19 @@
1
+ import { AsyncData, Result } from "@swan-io/boxed";
2
+ import { DependencyList } from "react";
3
+ import { AnyVariables, UseQueryArgs } from "urql";
4
+ type Query<Data> = {
5
+ data: AsyncData<Result<Data, Error>>;
6
+ nextData: AsyncData<Result<Data, Error>>;
7
+ isForceReloading: boolean;
8
+ reload: () => void;
9
+ };
10
+ export declare const useUrqlQuery: <Data, Variables extends AnyVariables>(args: UseQueryArgs<Variables, Data>, dependencyList: DependencyList) => Query<Data>;
11
+ type PaginatedQuery<Data> = {
12
+ data: AsyncData<Result<Data, Error>>;
13
+ nextData: AsyncData<Result<Data, Error>>;
14
+ isForceReloading: boolean;
15
+ reload: () => void;
16
+ setAfter: (cursor: string | undefined) => void;
17
+ };
18
+ export declare const useUrqlPaginatedQuery: <Data, Variables extends AnyVariables>(args: UseQueryArgs<Variables, Data>, dependencyList: DependencyList) => PaginatedQuery<Data>;
19
+ export {};
@@ -0,0 +1,73 @@
1
+ import { AsyncData, Result } from "@swan-io/boxed";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { useQuery } from "urql";
4
+ import { isNotNullish, isNullish } from "../utils/nullish";
5
+ const NO_SUSPENSE_CONTEXT = { suspense: false };
6
+ export const useUrqlQuery = (args, dependencyList) => {
7
+ const [haveParamsChanged, setHaveParamsChanged] = useState(false);
8
+ const [isForceReloading, setIsForceReloading] = useState(false);
9
+ const [{ data, fetching, error }, reexecute] = useQuery({
10
+ ...args,
11
+ context: NO_SUSPENSE_CONTEXT,
12
+ });
13
+ const reload = useCallback(() => {
14
+ setIsForceReloading(true);
15
+ reexecute();
16
+ }, [reexecute]);
17
+ useEffect(() => {
18
+ setHaveParamsChanged(true);
19
+ // eslint-disable-next-line react-hooks/exhaustive-deps
20
+ }, dependencyList);
21
+ useEffect(() => {
22
+ if (!fetching) {
23
+ setHaveParamsChanged(false);
24
+ setIsForceReloading(false);
25
+ }
26
+ }, [fetching]);
27
+ const okResult = useMemo(() => AsyncData.Done(Result.Ok(data)), [data]);
28
+ const errorResult = useMemo(() => AsyncData.Done(Result.Error(error)), [error]);
29
+ const shouldResetState = isForceReloading || haveParamsChanged;
30
+ if (((isNullish(data) && isNullish(error)) || shouldResetState) && fetching) {
31
+ return {
32
+ data: AsyncData.Loading(),
33
+ nextData: AsyncData.Loading(),
34
+ isForceReloading,
35
+ reload,
36
+ };
37
+ }
38
+ if (isNotNullish(error)) {
39
+ return {
40
+ data: errorResult,
41
+ nextData: errorResult,
42
+ isForceReloading,
43
+ reload,
44
+ };
45
+ }
46
+ if (isNotNullish(data)) {
47
+ return {
48
+ data: okResult,
49
+ nextData: fetching ? AsyncData.Loading() : okResult,
50
+ isForceReloading,
51
+ reload,
52
+ };
53
+ }
54
+ return {
55
+ data: AsyncData.NotAsked(),
56
+ nextData: AsyncData.NotAsked(),
57
+ isForceReloading,
58
+ reload,
59
+ };
60
+ };
61
+ export const useUrqlPaginatedQuery = (args, dependencyList) => {
62
+ const [after, setAfter] = useState(undefined);
63
+ const { data, nextData, isForceReloading, reload: originalReload, } = useUrqlQuery({ ...args, variables: { ...args.variables, after } }, dependencyList);
64
+ useEffect(() => {
65
+ setAfter(undefined);
66
+ // eslint-disable-next-line react-hooks/exhaustive-deps
67
+ }, dependencyList);
68
+ const reload = useCallback(() => {
69
+ setAfter(undefined);
70
+ originalReload();
71
+ }, [originalReload]);
72
+ return { data, nextData, isForceReloading, reload, setAfter };
73
+ };
@@ -0,0 +1,21 @@
1
+ import { Animated } from "react-native";
2
+ import { ControllableTimeout } from "../utils/timer";
3
+ export type ToastVariant = "success" | "info" | "warning" | "error";
4
+ type ToastContent = {
5
+ variant: ToastVariant;
6
+ title: string;
7
+ description?: string;
8
+ autoClose?: boolean;
9
+ };
10
+ type Toast = {
11
+ uid: string;
12
+ variant: ToastVariant;
13
+ title: string;
14
+ description?: string;
15
+ progress?: Animated.Value;
16
+ timeout?: ControllableTimeout;
17
+ };
18
+ export declare const useToasts: () => Toast[];
19
+ export declare const hideToast: (uid: string) => void;
20
+ export declare const showToast: ({ variant, title, description, autoClose }: ToastContent) => string;
21
+ export {};
@@ -0,0 +1,61 @@
1
+ import { atom, useAtom } from "react-atomic-state";
2
+ import { Animated, Easing } from "react-native";
3
+ import { createControllableTimeout } from "../utils/timer";
4
+ const toasts = atom([]);
5
+ export const useToasts = () => useAtom(toasts);
6
+ export const hideToast = (uid) => {
7
+ const toast = toasts.get().find(toast => toast.uid === uid);
8
+ if (!toast) {
9
+ return;
10
+ }
11
+ toast.timeout?.clear();
12
+ toast.progress?.stopAnimation();
13
+ toasts.set(toasts => toasts.filter(toast => toast.uid !== uid));
14
+ };
15
+ export const showToast = ({ variant, title, description, autoClose }) => {
16
+ const uid = `${variant} - ${title} - ${description ?? ""}`;
17
+ const toast = toasts.get().find(toast => toast.uid === uid);
18
+ if (toast != null) {
19
+ if (toast.timeout && toast.progress) {
20
+ toast.timeout.clear();
21
+ Animated.timing(toast.progress, {
22
+ duration: 100,
23
+ easing: Easing.linear,
24
+ toValue: 1,
25
+ useNativeDriver: false,
26
+ }).start(() => {
27
+ toast.timeout?.reset();
28
+ });
29
+ }
30
+ return uid;
31
+ }
32
+ // by default, only info and success toasts are auto-closing
33
+ const isAutoClosingToast = autoClose != null ? autoClose : variant === "info" || variant === "success";
34
+ const progress = isAutoClosingToast ? new Animated.Value(1) : undefined;
35
+ const timeout = progress
36
+ ? createControllableTimeout({
37
+ duration: 10000,
38
+ onStart: duration => {
39
+ Animated.timing(progress, {
40
+ duration,
41
+ easing: Easing.linear,
42
+ toValue: 0,
43
+ useNativeDriver: false,
44
+ }).start();
45
+ },
46
+ onReset: duration => {
47
+ Animated.timing(progress, {
48
+ duration,
49
+ easing: Easing.linear,
50
+ toValue: 0,
51
+ useNativeDriver: false,
52
+ }).start();
53
+ },
54
+ onEnd: () => {
55
+ hideToast(uid);
56
+ },
57
+ })
58
+ : undefined;
59
+ toasts.set(toasts => [{ uid, variant, title, description, progress, timeout }, ...toasts]);
60
+ return uid;
61
+ };
@@ -0,0 +1 @@
1
+ export {};