@indietabletop/appkit 7.0.0-0 → 7.0.0-rc.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 (279) hide show
  1. package/lib/AppConfig/AppConfig.tsx +80 -0
  2. package/lib/AppConfig/formatters.tsx +43 -0
  3. package/lib/AuthCard/AuthCard.stories.ts +34 -0
  4. package/lib/AuthCard/AuthCard.tsx +64 -0
  5. package/lib/AuthCard/style.css.ts +49 -0
  6. package/lib/CacheProvider.tsx +20 -0
  7. package/lib/DialogTrigger/index.tsx +36 -0
  8. package/lib/DocumentTitle/DocumentTitle.tsx +10 -0
  9. package/lib/EnumMapper.ts +50 -0
  10. package/lib/ExternalLink.tsx +10 -0
  11. package/lib/FullscreenDismissBlocker.tsx +23 -0
  12. package/{dist/HistoryState.d.ts → lib/HistoryState.ts} +5 -2
  13. package/lib/IndieTabletopClubLogo.tsx +44 -0
  14. package/lib/IndieTabletopClubSymbol.tsx +37 -0
  15. package/lib/InfoPage/index.tsx +46 -0
  16. package/lib/InfoPage/pages.tsx +36 -0
  17. package/lib/InfoPage/style.css.ts +36 -0
  18. package/lib/Letterhead/index.tsx +85 -0
  19. package/lib/Letterhead/stories.tsx +41 -0
  20. package/lib/Letterhead/style.css.ts +152 -0
  21. package/lib/LetterheadForm/LetterheadReadonlyTextField.stories.tsx +17 -0
  22. package/lib/LetterheadForm/LetterheadSubmitError.stories.tsx +19 -0
  23. package/lib/LetterheadForm/LetterheadTextField.stories.tsx +19 -0
  24. package/lib/LetterheadForm/index.tsx +137 -0
  25. package/lib/LetterheadForm/style.css.ts +89 -0
  26. package/lib/LoadingIndicator.tsx +40 -0
  27. package/lib/MiddotSeparated/MiddotSeparated.stories.ts +26 -0
  28. package/lib/MiddotSeparated/MiddotSeparated.tsx +26 -0
  29. package/lib/MiddotSeparated/style.css.ts +10 -0
  30. package/lib/ModalDialog/index.tsx +28 -0
  31. package/lib/ModalDialog/style.css.ts +88 -0
  32. package/lib/ModernIDB/Cursor.ts +91 -0
  33. package/lib/ModernIDB/ModernIDB.ts +337 -0
  34. package/lib/ModernIDB/ModernIDBError.ts +9 -0
  35. package/lib/ModernIDB/ObjectStore.ts +195 -0
  36. package/lib/ModernIDB/ObjectStoreIndex.ts +102 -0
  37. package/lib/ModernIDB/README.md +9 -0
  38. package/lib/ModernIDB/Transaction.ts +40 -0
  39. package/lib/ModernIDB/VersionChangeManager.ts +57 -0
  40. package/lib/ModernIDB/bindings/factory.tsx +165 -0
  41. package/lib/ModernIDB/bindings/index.ts +2 -0
  42. package/{dist/ModernIDB/bindings/types.d.ts → lib/ModernIDB/bindings/types.ts} +32 -13
  43. package/lib/ModernIDB/bindings/utils.tsx +32 -0
  44. package/lib/ModernIDB/index.ts +10 -0
  45. package/lib/ModernIDB/types.ts +120 -0
  46. package/lib/ModernIDB/utils.ts +51 -0
  47. package/lib/QRCode/QRCode.stories.tsx +41 -0
  48. package/lib/QRCode/QRCode.tsx +54 -0
  49. package/lib/QRCode/style.css.ts +23 -0
  50. package/lib/ReleaseInfo/index.tsx +29 -0
  51. package/lib/RulesetResolver.ts +214 -0
  52. package/lib/SafariCheck/SafariCheck.stories.tsx +99 -0
  53. package/lib/SafariCheck/SafariCheck.tsx +273 -0
  54. package/lib/SafariCheck/addToDock.svg +13 -0
  55. package/lib/SafariCheck/addToHomeScreen.svg +12 -0
  56. package/lib/SafariCheck/safari.svg +32 -0
  57. package/lib/SafariCheck/shareIcon.svg +11 -0
  58. package/lib/SafariCheck/style.css.ts +106 -0
  59. package/lib/ServiceWorkerHandler.tsx +53 -0
  60. package/lib/ShareButton/ShareButton.stories.tsx +58 -0
  61. package/lib/ShareButton/ShareButton.tsx +153 -0
  62. package/lib/ShareButton/test.css.ts +3 -0
  63. package/lib/SubscribeCard/LetterheadInfoCard.tsx +23 -0
  64. package/lib/SubscribeCard/SubscribeByEmailCard.stories.tsx +69 -0
  65. package/lib/SubscribeCard/SubscribeByEmailCard.tsx +183 -0
  66. package/lib/SubscribeCard/SubscribeByPledgeCard.stories.tsx +133 -0
  67. package/lib/SubscribeCard/SubscribeByPledgeCard.tsx +127 -0
  68. package/lib/SubscribeCard/style.css.ts +14 -0
  69. package/lib/Sync/SyncIcon.stories.tsx +67 -0
  70. package/lib/Sync/SyncIcon.tsx +102 -0
  71. package/lib/Sync/SyncLog.tsx +222 -0
  72. package/lib/Sync/SyncLogList.stories.tsx +219 -0
  73. package/lib/Sync/style.css.ts +126 -0
  74. package/lib/account/AccountIcon.tsx +15 -0
  75. package/lib/account/AccountIssueView.tsx +44 -0
  76. package/lib/account/AlreadyLoggedInView.tsx +47 -0
  77. package/lib/account/CurrentUserFetcher.stories.tsx +292 -0
  78. package/lib/account/CurrentUserFetcher.tsx +118 -0
  79. package/lib/account/FailureFallbackView.tsx +36 -0
  80. package/lib/account/JoinCard.stories.tsx +257 -0
  81. package/lib/account/JoinCard.tsx +301 -0
  82. package/lib/account/LoadingView.tsx +14 -0
  83. package/lib/account/LoginCard.stories.tsx +288 -0
  84. package/lib/account/LoginCard.tsx +100 -0
  85. package/lib/account/LoginView.tsx +151 -0
  86. package/lib/account/NoConnectionView.tsx +34 -0
  87. package/lib/account/PasswordResetCard.stories.tsx +242 -0
  88. package/lib/account/PasswordResetCard.tsx +296 -0
  89. package/lib/account/UserMismatchView.tsx +62 -0
  90. package/lib/account/VerifyPage.tsx +195 -0
  91. package/lib/account/iconMask.svg +3 -0
  92. package/lib/account/style.css.ts +81 -0
  93. package/{dist/account/types.d.ts → lib/account/types.ts} +6 -3
  94. package/lib/account/useFetchCurrentUser.tsx +63 -0
  95. package/lib/account/useRedirectPath.ts +21 -0
  96. package/lib/animations.css.ts +17 -0
  97. package/lib/append-copy-to-text.ts +35 -0
  98. package/lib/async-op.ts +286 -0
  99. package/lib/atomic.css.ts +11 -0
  100. package/{dist/caught-value.d.ts → lib/caught-value.ts} +11 -1
  101. package/{dist/class-names.d.ts → lib/class-names.ts} +17 -6
  102. package/lib/client.ts +662 -0
  103. package/lib/common.css.ts +48 -0
  104. package/lib/copyrightRange.ts +10 -0
  105. package/lib/createSafeStorage.ts +91 -0
  106. package/lib/createStrictContext.ts +15 -0
  107. package/lib/failureMessages.ts +108 -0
  108. package/lib/form/FormSubmitButton.tsx +58 -0
  109. package/lib/form/SubmitErrorAlert.tsx +21 -0
  110. package/lib/form/style.css.ts +9 -0
  111. package/lib/globals.css.ts +62 -0
  112. package/lib/groupBy.ts +25 -0
  113. package/lib/hrefs.ts +48 -0
  114. package/lib/idToDate.ts +8 -0
  115. package/lib/ids.ts +6 -0
  116. package/lib/index.ts +75 -0
  117. package/lib/internal.css.ts +10 -0
  118. package/lib/mailto.ts +40 -0
  119. package/lib/media.ts +50 -0
  120. package/lib/random.ts +19 -0
  121. package/lib/result/swr.ts +18 -0
  122. package/{dist/sleep.d.ts → lib/sleep.ts} +3 -1
  123. package/lib/store/index.tsx +294 -0
  124. package/lib/store/store.ts +482 -0
  125. package/lib/store/types.ts +45 -0
  126. package/lib/store/utils.ts +54 -0
  127. package/lib/storybook/decorators.tsx +10 -0
  128. package/lib/structs.ts +3 -0
  129. package/{dist/typeguards.d.ts → lib/typeguards.ts} +3 -1
  130. package/{dist/types.d.ts → lib/types.ts} +23 -12
  131. package/lib/unique.ts +24 -0
  132. package/lib/use-async-op.ts +16 -0
  133. package/lib/use-document-background-color.ts +16 -0
  134. package/lib/use-form.ts +78 -0
  135. package/lib/use-is-installed.ts +17 -0
  136. package/lib/use-media-query.ts +21 -0
  137. package/lib/use-reverting-state.ts +32 -0
  138. package/lib/use-scroll-restoration.ts +99 -0
  139. package/lib/useEnsureValue.ts +31 -0
  140. package/lib/useInvokeClient.ts +54 -0
  141. package/lib/useIsVisible.ts +27 -0
  142. package/lib/utm.ts +92 -0
  143. package/lib/validations.ts +25 -0
  144. package/lib/vars.css.ts +13 -0
  145. package/package.json +23 -29
  146. package/dist/AppConfig/AppConfig.d.ts +0 -29
  147. package/dist/AuthCard/AuthCard.d.ts +0 -10
  148. package/dist/AuthCard/AuthCard.stories.d.ts +0 -34
  149. package/dist/AuthCard/style.css.d.ts +0 -23
  150. package/dist/DialogTrigger/index.d.ts +0 -13
  151. package/dist/DocumentTitle/DocumentTitle.d.ts +0 -3
  152. package/dist/EnumMapper.d.ts +0 -25
  153. package/dist/ExternalLink.d.ts +0 -3
  154. package/dist/FullscreenDismissBlocker.d.ts +0 -5
  155. package/dist/IndieTabletopClubLogo.d.ts +0 -7
  156. package/dist/IndieTabletopClubSymbol.d.ts +0 -7
  157. package/dist/InfoPage/index.d.ts +0 -8
  158. package/dist/InfoPage/pages.d.ts +0 -2
  159. package/dist/InfoPage/style.css.d.ts +0 -5
  160. package/dist/Letterhead/index.d.ts +0 -19
  161. package/dist/Letterhead/stories.d.ts +0 -13
  162. package/dist/Letterhead/style.css.d.ts +0 -46
  163. package/dist/LetterheadForm/LetterheadReadonlyTextField.stories.d.ts +0 -17
  164. package/dist/LetterheadForm/LetterheadSubmitError.stories.d.ts +0 -11
  165. package/dist/LetterheadForm/LetterheadTextField.stories.d.ts +0 -336
  166. package/dist/LetterheadForm/index.d.ts +0 -44
  167. package/dist/LetterheadForm/style.css.d.ts +0 -8
  168. package/dist/LoadingIndicator.d.ts +0 -3
  169. package/dist/MiddotSeparated/MiddotSeparated.d.ts +0 -8
  170. package/dist/MiddotSeparated/MiddotSeparated.stories.d.ts +0 -586
  171. package/dist/MiddotSeparated/style.css.d.ts +0 -1
  172. package/dist/ModalDialog/index.d.ts +0 -12
  173. package/dist/ModalDialog/style.css.d.ts +0 -58
  174. package/dist/ModernIDB/Cursor.d.ts +0 -56
  175. package/dist/ModernIDB/ModernIDB.d.ts +0 -66
  176. package/dist/ModernIDB/ModernIDBError.d.ts +0 -3
  177. package/dist/ModernIDB/ObjectStore.d.ts +0 -112
  178. package/dist/ModernIDB/ObjectStoreIndex.d.ts +0 -53
  179. package/dist/ModernIDB/Transaction.d.ts +0 -16
  180. package/dist/ModernIDB/VersionChangeManager.d.ts +0 -30
  181. package/dist/ModernIDB/bindings/factory.d.ts +0 -12
  182. package/dist/ModernIDB/bindings/index.d.ts +0 -2
  183. package/dist/ModernIDB/bindings/utils.d.ts +0 -2
  184. package/dist/ModernIDB/index.d.ts +0 -10
  185. package/dist/ModernIDB/types.d.ts +0 -88
  186. package/dist/ModernIDB/utils.d.ts +0 -4
  187. package/dist/QRCode/QRCode.d.ts +0 -7
  188. package/dist/QRCode/QRCode.stories.d.ts +0 -33
  189. package/dist/QRCode/style.css.d.ts +0 -4
  190. package/dist/ReleaseInfo/index.d.ts +0 -5
  191. package/dist/RulesetResolver.d.ts +0 -87
  192. package/dist/SafariCheck/SafariCheck.d.ts +0 -23
  193. package/dist/SafariCheck/SafariCheck.stories.d.ts +0 -73
  194. package/dist/SafariCheck/style.css.d.ts +0 -17
  195. package/dist/ServiceWorkerHandler.d.ts +0 -11
  196. package/dist/ShareButton/ShareButton.d.ts +0 -57
  197. package/dist/ShareButton/ShareButton.stories.d.ts +0 -1577
  198. package/dist/ShareButton/test.css.d.ts +0 -1
  199. package/dist/SubscribeCard/LetterheadInfoCard.d.ts +0 -2
  200. package/dist/SubscribeCard/SubscribeByEmailCard.d.ts +0 -24
  201. package/dist/SubscribeCard/SubscribeByEmailCard.stories.d.ts +0 -10
  202. package/dist/SubscribeCard/SubscribeByPledgeCard.d.ts +0 -36
  203. package/dist/SubscribeCard/SubscribeByPledgeCard.stories.d.ts +0 -65
  204. package/dist/SubscribeCard/style.css.d.ts +0 -4
  205. package/dist/account/AccountIssueView.d.ts +0 -3
  206. package/dist/account/AlreadyLoggedInView.d.ts +0 -5
  207. package/dist/account/CurrentUserFetcher.d.ts +0 -20
  208. package/dist/account/CurrentUserFetcher.stories.d.ts +0 -136
  209. package/dist/account/FailureFallbackView.d.ts +0 -1
  210. package/dist/account/JoinCard.d.ts +0 -14
  211. package/dist/account/JoinCard.stories.d.ts +0 -143
  212. package/dist/account/LoadingView.d.ts +0 -1
  213. package/dist/account/LoginCard.d.ts +0 -39
  214. package/dist/account/LoginCard.stories.d.ts +0 -217
  215. package/dist/account/LoginView.d.ts +0 -10
  216. package/dist/account/NoConnectionView.d.ts +0 -4
  217. package/dist/account/PasswordResetCard.d.ts +0 -15
  218. package/dist/account/PasswordResetCard.stories.d.ts +0 -128
  219. package/dist/account/UserMismatchView.d.ts +0 -6
  220. package/dist/account/VerifyPage.d.ts +0 -13
  221. package/dist/account/style.css.d.ts +0 -10
  222. package/dist/account/useFetchCurrentUser.d.ts +0 -28
  223. package/dist/account/useRedirectPath.d.ts +0 -6
  224. package/dist/animations.css.d.ts +0 -3
  225. package/dist/append-copy-to-text.d.ts +0 -10
  226. package/dist/append-copy-to-text.test.d.ts +0 -1
  227. package/dist/appkit.css +0 -1
  228. package/dist/appkit.js +0 -10692
  229. package/dist/async-op.d.ts +0 -101
  230. package/dist/atomic.css.d.ts +0 -6
  231. package/dist/client.d.ts +0 -424
  232. package/dist/common.css.d.ts +0 -5
  233. package/dist/copyrightRange.d.ts +0 -1
  234. package/dist/copyrightRange.test.d.ts +0 -1
  235. package/dist/createSafeStorage.d.ts +0 -34
  236. package/dist/failureMessages.d.ts +0 -20
  237. package/dist/failureMessages.test.d.ts +0 -1
  238. package/dist/form/FormSubmitButton.d.ts +0 -17
  239. package/dist/form/SubmitErrorAlert.d.ts +0 -5
  240. package/dist/form/style.css.d.ts +0 -3
  241. package/dist/globals.css.d.ts +0 -0
  242. package/dist/groupBy.d.ts +0 -1
  243. package/dist/groupBy.test.d.ts +0 -1
  244. package/dist/hrefs.d.ts +0 -32
  245. package/dist/hrefs.test.d.ts +0 -1
  246. package/dist/idToDate.d.ts +0 -5
  247. package/dist/idToDate.test.d.ts +0 -1
  248. package/dist/ids.d.ts +0 -1
  249. package/dist/ids.test.d.ts +0 -1
  250. package/dist/index.d.ts +0 -64
  251. package/dist/internal.css.d.ts +0 -2
  252. package/dist/mailto.d.ts +0 -8
  253. package/dist/mailto.test.d.ts +0 -1
  254. package/dist/media.d.ts +0 -39
  255. package/dist/random.d.ts +0 -3
  256. package/dist/result/swr.d.ts +0 -4
  257. package/dist/store/index.d.ts +0 -237
  258. package/dist/store/store.d.ts +0 -144
  259. package/dist/store/types.d.ts +0 -49
  260. package/dist/store/utils.d.ts +0 -10
  261. package/dist/storybook/decorators.d.ts +0 -3
  262. package/dist/structs.d.ts +0 -1
  263. package/dist/typeguards.test.d.ts +0 -1
  264. package/dist/unique.d.ts +0 -10
  265. package/dist/unique.test.d.ts +0 -1
  266. package/dist/use-async-op.d.ts +0 -6
  267. package/dist/use-document-background-color.d.ts +0 -4
  268. package/dist/use-form.d.ts +0 -29
  269. package/dist/use-is-installed.d.ts +0 -8
  270. package/dist/use-media-query.d.ts +0 -1
  271. package/dist/use-reverting-state.d.ts +0 -5
  272. package/dist/use-scroll-restoration.d.ts +0 -25
  273. package/dist/useEnsureValue.d.ts +0 -6
  274. package/dist/useInvokeClient.d.ts +0 -25
  275. package/dist/useIsVisible.d.ts +0 -4
  276. package/dist/utm.d.ts +0 -58
  277. package/dist/utm.test.d.ts +0 -1
  278. package/dist/validations.d.ts +0 -3
  279. package/dist/vars.css.d.ts +0 -10
@@ -0,0 +1,195 @@
1
+ import { Button, Form } from "@ariakit/react";
2
+ import { useState, type Dispatch, type SetStateAction } from "react";
3
+ import { Link } from "wouter";
4
+ import { useAppConfig, useClient } from "../AppConfig/AppConfig.tsx";
5
+ import { interactiveText } from "../common.css.ts";
6
+ import { getSubmitFailureMessage } from "../failureMessages.ts";
7
+ import {
8
+ Letterhead,
9
+ LetterheadHeading,
10
+ LetterheadParagraph,
11
+ LetterheadSubmitButton,
12
+ } from "../Letterhead/index.tsx";
13
+ import { button } from "../Letterhead/style.css.ts";
14
+ import {
15
+ LetterheadFormActions,
16
+ LetterheadHeader,
17
+ LetterheadSubmitError,
18
+ LetterheadTextField,
19
+ } from "../LetterheadForm/index.tsx";
20
+ import { useAppActions } from "../store/index.tsx";
21
+ import type { CurrentUser } from "../types.ts";
22
+ import { useForm } from "../use-form.ts";
23
+ import type { AuthEventHandler } from "./types.ts";
24
+
25
+ type SetStep = Dispatch<SetStateAction<VerifyStep>>;
26
+
27
+ function InitialStep(props: {
28
+ setStep: SetStep;
29
+ currentUser: CurrentUser;
30
+ reload: () => void;
31
+ }) {
32
+ const { setStep, currentUser, reload } = props;
33
+ const { email } = currentUser;
34
+ const { logout } = useAppActions();
35
+
36
+ const client = useClient();
37
+ const { form, submitName } = useForm({
38
+ defaultValues: {},
39
+ async onSubmit() {
40
+ const op = await client.requestUserVerification();
41
+ return op.mapFailure(getSubmitFailureMessage);
42
+ },
43
+ onSuccess(value) {
44
+ setStep({ type: "SUBMIT_CODE", tokenId: value.tokenId });
45
+ },
46
+ });
47
+
48
+ return (
49
+ <Form store={form}>
50
+ <Letterhead>
51
+ <LetterheadHeader>
52
+ <LetterheadHeading>Verify account</LetterheadHeading>
53
+ <LetterheadParagraph>
54
+ Your account is currently not verified. We will send a one-time code
55
+ to your email ({email}) to complete the verification.
56
+ </LetterheadParagraph>
57
+ </LetterheadHeader>
58
+
59
+ <LetterheadFormActions>
60
+ <LetterheadSubmitError name={submitName} />
61
+ <LetterheadSubmitButton>Send code</LetterheadSubmitButton>
62
+ <LetterheadParagraph>
63
+ Cannot complete verification?{" "}
64
+ <Button
65
+ className={interactiveText}
66
+ onClick={async () => {
67
+ await logout();
68
+ reload();
69
+ }}
70
+ >
71
+ Log out
72
+ </Button>
73
+ .
74
+ </LetterheadParagraph>
75
+ </LetterheadFormActions>
76
+ </Letterhead>
77
+ </Form>
78
+ );
79
+ }
80
+
81
+ function SubmitCodeStep(props: {
82
+ tokenId: string;
83
+ setStep: SetStep;
84
+ currentUser: CurrentUser;
85
+ }) {
86
+ const client = useClient();
87
+ const { email } = props.currentUser;
88
+ const { form, submitName } = useForm({
89
+ defaultValues: {
90
+ code: "",
91
+ },
92
+ async onSubmit({ values }) {
93
+ const op = await client.verifyUser({
94
+ ...values,
95
+ tokenId: props.tokenId,
96
+ });
97
+
98
+ return op.mapFailure((failure) => {
99
+ return getSubmitFailureMessage(failure, {
100
+ 404: "🚫 This code is incorrect or expired. Please try again.",
101
+ });
102
+ });
103
+ },
104
+ onSuccess() {
105
+ props.setStep({ type: "SUCCESS" });
106
+ },
107
+ });
108
+
109
+ return (
110
+ <Form store={form}>
111
+ <Letterhead>
112
+ <LetterheadHeader>
113
+ <LetterheadHeading>Verify Account</LetterheadHeading>
114
+ <LetterheadParagraph>
115
+ We've sent a one-time code to {email}. Please, enter the code in the
116
+ field below to complete verification.
117
+ </LetterheadParagraph>
118
+ </LetterheadHeader>
119
+
120
+ <LetterheadTextField
121
+ name={form.names.code}
122
+ label="Code"
123
+ placeholder="E.g. 123123"
124
+ autoComplete="one-time-code"
125
+ required
126
+ />
127
+
128
+ <LetterheadFormActions>
129
+ <LetterheadSubmitError name={submitName} />
130
+ <LetterheadSubmitButton>Verify</LetterheadSubmitButton>
131
+ </LetterheadFormActions>
132
+ </Letterhead>
133
+ </Form>
134
+ );
135
+ }
136
+
137
+ function SuccessStep(props: { onClose?: AuthEventHandler }) {
138
+ const { onClose } = props;
139
+ const { hrefs } = useAppConfig();
140
+
141
+ return (
142
+ <Letterhead>
143
+ <LetterheadHeader>
144
+ <LetterheadHeading>Success!</LetterheadHeading>
145
+ <LetterheadParagraph>
146
+ Your Indie Tabletop Club account has been verified. Yay!
147
+ </LetterheadParagraph>
148
+ </LetterheadHeader>
149
+
150
+ {onClose ? (
151
+ <Button onClick={() => onClose()} className={button()}>
152
+ Done
153
+ </Button>
154
+ ) : (
155
+ <Link href={hrefs.dashboard()} className={button()}>
156
+ Go to dashboard
157
+ </Link>
158
+ )}
159
+ </Letterhead>
160
+ );
161
+ }
162
+
163
+ type VerifyStep =
164
+ | { type: "INITIAL" }
165
+ | { type: "SUBMIT_CODE"; tokenId: string }
166
+ | { type: "SUCCESS" };
167
+
168
+ export function VerifyAccountView(props: {
169
+ currentUser: CurrentUser;
170
+ reload: () => void;
171
+
172
+ /**
173
+ * If provided, will cause the success step to render a close dialog button
174
+ * instead of "Go to Dashboard" button.
175
+ *
176
+ * This is useful if this view is used within a modal dialog context.
177
+ */
178
+ onClose?: AuthEventHandler;
179
+ }) {
180
+ const [step, setStep] = useState<VerifyStep>({ type: "INITIAL" });
181
+
182
+ switch (step.type) {
183
+ case "INITIAL": {
184
+ return <InitialStep {...props} setStep={setStep} />;
185
+ }
186
+
187
+ case "SUBMIT_CODE": {
188
+ return <SubmitCodeStep {...props} {...step} setStep={setStep} />;
189
+ }
190
+
191
+ case "SUCCESS": {
192
+ return <SuccessStep {...props} />;
193
+ }
194
+ }
195
+ }
@@ -0,0 +1,3 @@
1
+ <svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M28 0C43.464 0 56 12.536 56 28C56 31.3019 55.4265 34.4697 54.377 37.4111C52.2143 35.3015 49.2598 34 46 34C39.3726 34 34 39.3726 34 46C34 49.2598 35.3015 52.2143 37.4111 54.377C34.4697 55.4265 31.3019 56 28 56C12.536 56 0 43.464 0 28C0 12.536 12.536 0 28 0Z" fill="white"/>
3
+ </svg>
@@ -0,0 +1,81 @@
1
+ import { style } from "@vanilla-extract/css";
2
+ import { Hover, MinWidth } from "../media.ts";
3
+ import iconMask from "./iconMask.svg";
4
+
5
+ export const accountIcon = {
6
+ container: style({
7
+ position: "relative",
8
+ marginInline: "auto",
9
+
10
+ inlineSize: "56px",
11
+ blockSize: "56px",
12
+ }),
13
+
14
+ syncIcon: style({
15
+ position: "absolute",
16
+ right: "0",
17
+ bottom: "0",
18
+ }),
19
+
20
+ image: style({
21
+ mask: `url("${iconMask}") no-repeat`,
22
+ inlineSize: "100%",
23
+ blockSize: "100%",
24
+ borderRadius: "50%",
25
+ }),
26
+ };
27
+
28
+ export const page = style({
29
+ backgroundColor: "white",
30
+
31
+ "@media": {
32
+ [MinWidth.SMALL]: {
33
+ backgroundColor: "transparent",
34
+ padding: "clamp(1rem, 5vw, 5rem)",
35
+ },
36
+ },
37
+ });
38
+
39
+ export const accountPicker = {
40
+ container: style({
41
+ backgroundColor: "#fafafa",
42
+ borderRadius: "0.5rem",
43
+ }),
44
+
45
+ button: style({
46
+ padding: "1rem 1.5rem",
47
+ textAlign: "start",
48
+ inlineSize: "100%",
49
+ borderRadius: "inherit",
50
+
51
+ "@media": {
52
+ [Hover.HOVER]: {
53
+ transition: "200ms background-color",
54
+
55
+ ":hover": {
56
+ backgroundColor: "hsl(from #fafafa h s calc(l - 3))",
57
+ },
58
+ },
59
+ },
60
+ }),
61
+
62
+ buttonLabel: style({
63
+ fontWeight: 600,
64
+ fontSize: "1.125rem",
65
+ }),
66
+
67
+ divider: style({
68
+ marginInline: "1.5rem",
69
+ backgroundColor: "#e2e2e2",
70
+ blockSize: "1px",
71
+ }),
72
+ };
73
+
74
+ export const loadingView = {
75
+ container: style({
76
+ display: "flex",
77
+ justifyContent: "center",
78
+ alignItems: "center",
79
+ height: "12rem",
80
+ }),
81
+ };
@@ -1,8 +1,11 @@
1
- import { CurrentUser } from '../types.ts';
1
+ import type { CurrentUser } from "../types.ts";
2
+
2
3
  export type AuthEventHandler = () => Promise<void> | void;
4
+
3
5
  export type ClientLogoutHandler = (options: {
4
- serverUser: CurrentUser;
6
+ serverUser: CurrentUser;
5
7
  }) => Promise<void> | void;
8
+
6
9
  export type DefaultFormValues = {
7
- email?: string;
10
+ email?: string;
8
11
  };
@@ -0,0 +1,63 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useClient } from "../AppConfig/AppConfig.tsx";
3
+ import { type Failure, Pending, type Success } from "../async-op.ts";
4
+ import type { CurrentUser, FailurePayload } from "../types.ts";
5
+
6
+ export function useFetchCurrentUser(options?: {
7
+ /**
8
+ * Optionally disable immediate fetch action.
9
+ *
10
+ * @default true
11
+ */
12
+ performFetch?: boolean;
13
+
14
+ /**
15
+ * Fetch new data every time the window is focused.
16
+ *
17
+ * Note that `performFetch` has to be enabled for this option to have an
18
+ * effect — we are not revalidating when there is no fetch to do!
19
+ *
20
+ * @default false
21
+ */
22
+ revalidateOnFocus?: boolean;
23
+ }) {
24
+ const { performFetch = true, revalidateOnFocus = false } = options ?? {};
25
+ const client = useClient();
26
+ const [latestAttemptTs, setLatestAttemptTs] = useState(Date.now());
27
+
28
+ const [result, setResult] = useState<
29
+ Success<CurrentUser> | Failure<FailurePayload> | Pending
30
+ >(new Pending());
31
+
32
+ // We are intentionally not using SWR in this case, as we don't want to deal
33
+ // with caching or any of that business.
34
+ useEffect(() => {
35
+ if (performFetch) {
36
+ const fetchUserAndStoreResult = async () => {
37
+ const result = await client.getCurrentUser();
38
+ setResult(result);
39
+ };
40
+
41
+ // Invoke the fetch action
42
+ fetchUserAndStoreResult();
43
+
44
+ if (revalidateOnFocus) {
45
+ const controller = new AbortController();
46
+ window.addEventListener("focus", fetchUserAndStoreResult, controller);
47
+
48
+ return () => {
49
+ controller.abort();
50
+ };
51
+ }
52
+ }
53
+ }, [client, latestAttemptTs, performFetch]);
54
+
55
+ return {
56
+ result,
57
+ latestAttemptTs,
58
+ reload: () => {
59
+ setResult(new Pending());
60
+ setLatestAttemptTs(Date.now());
61
+ },
62
+ };
63
+ }
@@ -0,0 +1,21 @@
1
+ import { useSearchParams } from "wouter";
2
+
3
+ function isValidRedirect(value: string | null | undefined): value is string {
4
+ return !!(value && /^[~/]/.test(value));
5
+ }
6
+
7
+ /**
8
+ * Gets redirect path from query params and validates it.
9
+ *
10
+ * Returns `null` if no path is found, or it is invalid.
11
+ */
12
+ export function useRedirectPath() {
13
+ const [params] = useSearchParams();
14
+ const redirectTo = params.get("redirectTo");
15
+
16
+ if (isValidRedirect(redirectTo)) {
17
+ return redirectTo;
18
+ }
19
+
20
+ return null;
21
+ }
@@ -0,0 +1,17 @@
1
+ import { keyframes } from "@vanilla-extract/css";
2
+
3
+ export const fadeIn = keyframes({
4
+ from: { opacity: 0 },
5
+ to: { opacity: 1 },
6
+ });
7
+
8
+ export const slideUp = keyframes({
9
+ from: { transform: `translateY(100%)` },
10
+ to: { transform: `translateY(0)` },
11
+ });
12
+
13
+ export const bounce = keyframes({
14
+ "0%": { transform: "translateY(0)" },
15
+ "20%": { transform: "translateY(-20%)" },
16
+ "50%": { transform: "translateY(0)" },
17
+ });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Appends " (Copy)" to the end of the input string if it doesn't already end
3
+ * with " (Copy)", otherwise it appends a number after "Copy", incrementing it
4
+ * if necessary.
5
+ */
6
+ export function appendCopyToText(input: string): string {
7
+ const regex = /^(?<value>.*) \(Copy(?: (?<count>\d+))?\)$/;
8
+ const match = input.match(regex);
9
+
10
+ // If there isn't a match, we directly append to the input.
11
+ if (!match) {
12
+ return `${input.trim()} (Copy)`;
13
+ }
14
+
15
+ const { value, count } = match.groups ?? {};
16
+
17
+ // If `count` capturing group is not present, it means that the input ends
18
+ // with the copy suffix, but it doesn't contain count.
19
+ const nextCount = !count ? 2 : parseInt(count, 10) + 1;
20
+
21
+ return `${value?.trim()} (Copy ${nextCount})`;
22
+ }
23
+
24
+ /**
25
+ * Works like {@link appendCopyToText}, but ignores empty strings.
26
+ */
27
+ export function maybeAppendCopyToText(input: string) {
28
+ // If input is falsy (i.e. empty string) then we don't want to append
29
+ // anything to it.
30
+ if (!input) {
31
+ return "";
32
+ }
33
+
34
+ return appendCopyToText(input);
35
+ }