@indietabletop/appkit 3.2.0-2 → 3.2.0-3
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.
- package/lib/ExternalLink.tsx +10 -0
- package/lib/FormSubmitButton.tsx +48 -0
- package/lib/FullscreenDismissBlocker.tsx +23 -0
- package/lib/IndieTabletopClubLogo.tsx +44 -0
- package/lib/IndieTabletopClubSymbol.tsx +37 -0
- package/lib/Letterhead.tsx +33 -0
- package/lib/LetterheadFooter.tsx +36 -0
- package/lib/LoadingIndicator.tsx +39 -0
- package/lib/ServiceWorkerHandler.tsx +53 -0
- package/lib/animations.css.ts +17 -0
- package/lib/append-copy-to-text.ts +35 -0
- package/lib/async-op.ts +246 -0
- package/{dist/caught-value.js → lib/caught-value.ts} +10 -8
- package/lib/class-names.ts +8 -0
- package/lib/client.ts +288 -0
- package/lib/common.css.ts +46 -0
- package/lib/globals.css.ts +42 -0
- package/{dist/index.d.ts → lib/index.ts} +5 -0
- package/lib/internal.css.ts +26 -0
- package/lib/media.ts +50 -0
- package/lib/structs.ts +17 -0
- package/{dist/types.d.ts → lib/types.ts} +11 -6
- package/lib/use-async-op.ts +16 -0
- package/lib/use-document-background-color.ts +16 -0
- package/lib/use-form.ts +73 -0
- package/{dist/use-is-installed.js → lib/use-is-installed.ts} +7 -3
- package/lib/use-media-query.ts +21 -0
- package/lib/use-reverting-state.ts +32 -0
- package/lib/use-scroll-restoration.ts +99 -0
- package/package.json +3 -4
- package/dist/ExternalLink.d.ts +0 -3
- package/dist/ExternalLink.js +0 -4
- package/dist/FormSubmitButton.d.ts +0 -7
- package/dist/FormSubmitButton.js +0 -16
- package/dist/FullscreenDismissBlocker.d.ts +0 -5
- package/dist/FullscreenDismissBlocker.js +0 -19
- package/dist/IndieTabletopClubLogo.d.ts +0 -7
- package/dist/IndieTabletopClubLogo.js +0 -6
- package/dist/IndieTabletopClubSymbol.d.ts +0 -7
- package/dist/IndieTabletopClubSymbol.js +0 -5
- package/dist/Letterhead.d.ts +0 -6
- package/dist/Letterhead.js +0 -14
- package/dist/LetterheadFooter.d.ts +0 -1
- package/dist/LetterheadFooter.js +0 -17
- package/dist/LoadingIndicator.d.ts +0 -3
- package/dist/LoadingIndicator.js +0 -17
- package/dist/ServiceWorkerHandler.d.ts +0 -11
- package/dist/ServiceWorkerHandler.js +0 -42
- package/dist/animations.css.d.ts +0 -3
- package/dist/animations.css.js +0 -14
- package/dist/append-copy-to-text.d.ts +0 -10
- package/dist/append-copy-to-text.js +0 -29
- package/dist/async-op.d.ts +0 -87
- package/dist/async-op.js +0 -223
- package/dist/caught-value.d.ts +0 -15
- package/dist/class-names.d.ts +0 -4
- package/dist/class-names.js +0 -6
- package/dist/client.d.ts +0 -117
- package/dist/client.js +0 -201
- package/dist/common.css.d.ts +0 -5
- package/dist/common.css.js +0 -38
- package/dist/globals.css.d.ts +0 -1
- package/dist/globals.css.js +0 -35
- package/dist/index.js +0 -26
- package/dist/internal.css.d.ts +0 -4
- package/dist/internal.css.js +0 -21
- package/dist/media.d.ts +0 -39
- package/dist/media.js +0 -49
- package/dist/structs.d.ts +0 -20
- package/dist/structs.js +0 -15
- package/dist/types.js +0 -1
- package/dist/use-async-op.d.ts +0 -6
- package/dist/use-async-op.js +0 -12
- package/dist/use-document-background-color.d.ts +0 -4
- package/dist/use-document-background-color.js +0 -14
- package/dist/use-form.d.ts +0 -29
- package/dist/use-form.js +0 -33
- package/dist/use-is-installed.d.ts +0 -8
- package/dist/use-media-query.d.ts +0 -1
- package/dist/use-media-query.js +0 -15
- package/dist/use-reverting-state.d.ts +0 -5
- package/dist/use-reverting-state.js +0 -26
- package/dist/use-scroll-restoration.d.ts +0 -25
- package/dist/use-scroll-restoration.js +0 -67
package/dist/internal.css.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { createVar, style } from "@vanilla-extract/css";
|
|
2
|
-
import { bounce } from "./animations.css.js";
|
|
3
|
-
import { minion } from "./common.css.js";
|
|
4
|
-
export const animationDelay = createVar();
|
|
5
|
-
export const dot = style({
|
|
6
|
-
fill: "currentcolor",
|
|
7
|
-
opacity: 0.8,
|
|
8
|
-
animation: `${bounce} 2s ${animationDelay} infinite`,
|
|
9
|
-
});
|
|
10
|
-
export const padding = createVar();
|
|
11
|
-
export const letterhead = style([
|
|
12
|
-
minion,
|
|
13
|
-
{
|
|
14
|
-
vars: { [padding]: "clamp(1rem, 8vw, 4rem)" },
|
|
15
|
-
backgroundColor: "white",
|
|
16
|
-
padding: `max(1rem, calc(${padding} - .5rem)) ${padding} ${padding}`,
|
|
17
|
-
borderRadius: "1rem",
|
|
18
|
-
marginInline: "auto",
|
|
19
|
-
maxInlineSize: "36rem",
|
|
20
|
-
},
|
|
21
|
-
]);
|
package/dist/media.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
|
|
3
|
-
*/
|
|
4
|
-
export declare enum PrefersColorScheme {
|
|
5
|
-
LIGHT = "(prefers-color-scheme: light)",
|
|
6
|
-
DARK = "(prefers-color-scheme: dark)"
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
|
|
10
|
-
*/
|
|
11
|
-
export declare enum PrefersReducedMotion {
|
|
12
|
-
NO_PREFERENCE = "(prefers-reduced-motion: no-preference)",
|
|
13
|
-
REDUCE = "(prefers-reduced-motion: reduce)"
|
|
14
|
-
}
|
|
15
|
-
export declare enum Hover {
|
|
16
|
-
NONE = "(hover: none)",
|
|
17
|
-
HOVER = "(hover: hover) and (pointer: fine)"
|
|
18
|
-
}
|
|
19
|
-
export declare enum MediaType {
|
|
20
|
-
PRINT = "print",
|
|
21
|
-
SCREEN = "screen"
|
|
22
|
-
}
|
|
23
|
-
export declare enum MinHeight {
|
|
24
|
-
TALL = "(min-height: 40em)"
|
|
25
|
-
}
|
|
26
|
-
export declare enum MinWidth {
|
|
27
|
-
SMALL = "(min-width: 28em)",
|
|
28
|
-
MEDIUM = "(min-width: 50em)",
|
|
29
|
-
WIDE = "(min-width: 66em)",
|
|
30
|
-
X_WIDE = "(min-width: 80em)",
|
|
31
|
-
XX_WIDE = "(min-width: 140em)"
|
|
32
|
-
}
|
|
33
|
-
export declare enum DisplayMode {
|
|
34
|
-
STANDALONE = "(display-mode: standalone)"
|
|
35
|
-
}
|
|
36
|
-
export declare enum Pointer {
|
|
37
|
-
COARSE = "(pointer: coarse)",
|
|
38
|
-
FINE = "(pointer: fine)"
|
|
39
|
-
}
|
package/dist/media.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
|
|
3
|
-
*/
|
|
4
|
-
export var PrefersColorScheme;
|
|
5
|
-
(function (PrefersColorScheme) {
|
|
6
|
-
PrefersColorScheme["LIGHT"] = "(prefers-color-scheme: light)";
|
|
7
|
-
PrefersColorScheme["DARK"] = "(prefers-color-scheme: dark)";
|
|
8
|
-
})(PrefersColorScheme || (PrefersColorScheme = {}));
|
|
9
|
-
/**
|
|
10
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
|
|
11
|
-
*/
|
|
12
|
-
export var PrefersReducedMotion;
|
|
13
|
-
(function (PrefersReducedMotion) {
|
|
14
|
-
PrefersReducedMotion["NO_PREFERENCE"] = "(prefers-reduced-motion: no-preference)";
|
|
15
|
-
PrefersReducedMotion["REDUCE"] = "(prefers-reduced-motion: reduce)";
|
|
16
|
-
})(PrefersReducedMotion || (PrefersReducedMotion = {}));
|
|
17
|
-
export var Hover;
|
|
18
|
-
(function (Hover) {
|
|
19
|
-
Hover["NONE"] = "(hover: none)";
|
|
20
|
-
// Some Samsung phones incorrectly report that they have "hover" even though they
|
|
21
|
-
// do not. Adding the pointer query correctly filters these phones out.
|
|
22
|
-
Hover["HOVER"] = "(hover: hover) and (pointer: fine)";
|
|
23
|
-
})(Hover || (Hover = {}));
|
|
24
|
-
export var MediaType;
|
|
25
|
-
(function (MediaType) {
|
|
26
|
-
MediaType["PRINT"] = "print";
|
|
27
|
-
MediaType["SCREEN"] = "screen";
|
|
28
|
-
})(MediaType || (MediaType = {}));
|
|
29
|
-
export var MinHeight;
|
|
30
|
-
(function (MinHeight) {
|
|
31
|
-
MinHeight["TALL"] = "(min-height: 40em)";
|
|
32
|
-
})(MinHeight || (MinHeight = {}));
|
|
33
|
-
export var MinWidth;
|
|
34
|
-
(function (MinWidth) {
|
|
35
|
-
MinWidth["SMALL"] = "(min-width: 28em)";
|
|
36
|
-
MinWidth["MEDIUM"] = "(min-width: 50em)";
|
|
37
|
-
MinWidth["WIDE"] = "(min-width: 66em)";
|
|
38
|
-
MinWidth["X_WIDE"] = "(min-width: 80em)";
|
|
39
|
-
MinWidth["XX_WIDE"] = "(min-width: 140em)";
|
|
40
|
-
})(MinWidth || (MinWidth = {}));
|
|
41
|
-
export var DisplayMode;
|
|
42
|
-
(function (DisplayMode) {
|
|
43
|
-
DisplayMode["STANDALONE"] = "(display-mode: standalone)";
|
|
44
|
-
})(DisplayMode || (DisplayMode = {}));
|
|
45
|
-
export var Pointer;
|
|
46
|
-
(function (Pointer) {
|
|
47
|
-
Pointer["COARSE"] = "(pointer: coarse)";
|
|
48
|
-
Pointer["FINE"] = "(pointer: fine)";
|
|
49
|
-
})(Pointer || (Pointer = {}));
|
package/dist/structs.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export declare function currentUser(): import("superstruct").Struct<{
|
|
2
|
-
id: string;
|
|
3
|
-
email: string;
|
|
4
|
-
isVerified: boolean;
|
|
5
|
-
prefersScrollbarVisibility?: "ALWAYS" | undefined;
|
|
6
|
-
}, {
|
|
7
|
-
id: import("superstruct").Struct<string, null>;
|
|
8
|
-
email: import("superstruct").Struct<string, null>;
|
|
9
|
-
isVerified: import("superstruct").Struct<boolean, null>;
|
|
10
|
-
prefersScrollbarVisibility: import("superstruct").Struct<"ALWAYS" | undefined, {
|
|
11
|
-
ALWAYS: "ALWAYS";
|
|
12
|
-
}>;
|
|
13
|
-
}>;
|
|
14
|
-
export declare function sessionInfo(): import("superstruct").Struct<{
|
|
15
|
-
expiresTs: number;
|
|
16
|
-
createdTs: number;
|
|
17
|
-
}, {
|
|
18
|
-
expiresTs: import("superstruct").Struct<number, null>;
|
|
19
|
-
createdTs: import("superstruct").Struct<number, null>;
|
|
20
|
-
}>;
|
package/dist/structs.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { boolean, enums, number, object, optional, string } from "superstruct";
|
|
2
|
-
export function currentUser() {
|
|
3
|
-
return object({
|
|
4
|
-
id: string(),
|
|
5
|
-
email: string(),
|
|
6
|
-
isVerified: boolean(),
|
|
7
|
-
prefersScrollbarVisibility: optional(enums(["ALWAYS"])),
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
export function sessionInfo() {
|
|
11
|
-
return object({
|
|
12
|
-
expiresTs: number(),
|
|
13
|
-
createdTs: number(),
|
|
14
|
-
});
|
|
15
|
-
}
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import { currentUser, sessionInfo } from "./structs.js";
|
package/dist/use-async-op.d.ts
DELETED
package/dist/use-async-op.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useCallback, useState } from "react";
|
|
2
|
-
import { Failure, Pending, Success } from "./async-op.js";
|
|
3
|
-
export function useAsyncOp() {
|
|
4
|
-
const [op, setOp] = useState(new Pending());
|
|
5
|
-
const setSuccess = useCallback((value) => {
|
|
6
|
-
setOp(new Success(value));
|
|
7
|
-
}, []);
|
|
8
|
-
const setFailure = useCallback((failure) => {
|
|
9
|
-
setOp(new Failure(failure));
|
|
10
|
-
}, []);
|
|
11
|
-
return { op, setSuccess, setFailure };
|
|
12
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
/**
|
|
3
|
-
* Sets document background color, reverting it to previous color on unmount.
|
|
4
|
-
*/
|
|
5
|
-
export function useDocumentBackgroundColor(bodyColor) {
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
const style = window.document.documentElement.style;
|
|
8
|
-
const originalColor = style.backgroundColor;
|
|
9
|
-
style.backgroundColor = bodyColor;
|
|
10
|
-
return () => {
|
|
11
|
-
style.backgroundColor = originalColor;
|
|
12
|
-
};
|
|
13
|
-
});
|
|
14
|
-
}
|
package/dist/use-form.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { type FormStoreState } from "@ariakit/react";
|
|
2
|
-
import { Failure, Success } from "./async-op.ts";
|
|
3
|
-
type Validator<T> = (value: T) => string | null;
|
|
4
|
-
type MaybePromise<T> = T | Promise<T>;
|
|
5
|
-
export declare function useForm<T extends object, R>(props: {
|
|
6
|
-
defaultValues: T;
|
|
7
|
-
validate?: {
|
|
8
|
-
[K in keyof T]?: Validator<T[K]>;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Handles form submission login.
|
|
12
|
-
*
|
|
13
|
-
* This function should return a Success or Failure. Failures should always contain a string
|
|
14
|
-
* which will be used as the form error message.
|
|
15
|
-
*/
|
|
16
|
-
onSubmit: (state: FormStoreState<T>) => MaybePromise<Success<R> | Failure<string>>;
|
|
17
|
-
/**
|
|
18
|
-
* If submission was successful (i.e. onSubmit returned a Success), will be run to perform any
|
|
19
|
-
* side-effect necessary.
|
|
20
|
-
*
|
|
21
|
-
* Typically this is used for navigation on mutating some local state.
|
|
22
|
-
*/
|
|
23
|
-
onSuccess?: (value: R, state: FormStoreState<T>) => MaybePromise<void>;
|
|
24
|
-
}): {
|
|
25
|
-
form: import("@ariakit/react").FormStore<T>;
|
|
26
|
-
submitName: string;
|
|
27
|
-
op: Success<R> | Failure<string> | null;
|
|
28
|
-
};
|
|
29
|
-
export {};
|
package/dist/use-form.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { useFormStore } from "@ariakit/react";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { Failure, Success } from "./async-op.js";
|
|
4
|
-
export function useForm(props) {
|
|
5
|
-
const submitName = "submit";
|
|
6
|
-
const [op, setOp] = useState(null);
|
|
7
|
-
const form = useFormStore({
|
|
8
|
-
defaultValues: props.defaultValues,
|
|
9
|
-
});
|
|
10
|
-
form.useSubmit(async (state) => {
|
|
11
|
-
const submitOp = await props.onSubmit(state);
|
|
12
|
-
if (submitOp.isFailure) {
|
|
13
|
-
form.setError(submitName, submitOp.failure);
|
|
14
|
-
}
|
|
15
|
-
if (submitOp.isSuccess) {
|
|
16
|
-
await props.onSuccess?.(submitOp.value, state);
|
|
17
|
-
}
|
|
18
|
-
setOp(submitOp);
|
|
19
|
-
});
|
|
20
|
-
form.useValidate((state) => {
|
|
21
|
-
if (props.validate) {
|
|
22
|
-
const entries = Object.entries(props.validate);
|
|
23
|
-
for (const [key, validate] of entries) {
|
|
24
|
-
const value = state.values[key];
|
|
25
|
-
const message = validate(value);
|
|
26
|
-
if (message) {
|
|
27
|
-
form.setError(key, message);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
return { form, submitName, op };
|
|
33
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checks whether the app is installed.
|
|
3
|
-
*
|
|
4
|
-
* Note that this doesn't check whether the app is installed on the device at
|
|
5
|
-
* all, only whether the currently running process is within an installed window
|
|
6
|
-
* or running within a browser.
|
|
7
|
-
*/
|
|
8
|
-
export declare function useIsInstalled(): boolean;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function useMediaQuery(query: string): boolean;
|
package/dist/use-media-query.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from "react";
|
|
2
|
-
export function useMediaQuery(query) {
|
|
3
|
-
const [isMatch, setMatch] = useState(window.matchMedia(query).matches);
|
|
4
|
-
useEffect(() => {
|
|
5
|
-
const mql = window.matchMedia(query);
|
|
6
|
-
const handleChange = ({ matches }) => {
|
|
7
|
-
setMatch(matches);
|
|
8
|
-
};
|
|
9
|
-
mql.addEventListener("change", handleChange);
|
|
10
|
-
return () => {
|
|
11
|
-
mql.removeEventListener("change", handleChange);
|
|
12
|
-
};
|
|
13
|
-
}, [query]);
|
|
14
|
-
return isMatch;
|
|
15
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sets a state that will automatically revert to null after specified number
|
|
3
|
-
* of milliseconds.
|
|
4
|
-
*/
|
|
5
|
-
export declare function useRevertingState<T>(initialState: T, revertAfterMs: number): readonly [T | null, import("react").Dispatch<import("react").SetStateAction<T | null>>];
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from "react";
|
|
2
|
-
/**
|
|
3
|
-
* Sets a state that will automatically revert to null after specified number
|
|
4
|
-
* of milliseconds.
|
|
5
|
-
*/
|
|
6
|
-
export function useRevertingState(initialState, revertAfterMs) {
|
|
7
|
-
const [state, setState] = useState(initialState);
|
|
8
|
-
const timeoutRef = useRef(null);
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
const timeoutId = timeoutRef.current;
|
|
11
|
-
if (timeoutId) {
|
|
12
|
-
clearInterval(timeoutId);
|
|
13
|
-
}
|
|
14
|
-
if (state) {
|
|
15
|
-
timeoutRef.current = setTimeout(() => {
|
|
16
|
-
setState(null);
|
|
17
|
-
}, revertAfterMs);
|
|
18
|
-
}
|
|
19
|
-
return () => {
|
|
20
|
-
if (timeoutId) {
|
|
21
|
-
clearTimeout(timeoutId);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
}, [revertAfterMs, state]);
|
|
25
|
-
return [state, setState];
|
|
26
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handles scroll restoration on window.
|
|
3
|
-
*
|
|
4
|
-
* This hook behaves a little differently than the default browser scroll
|
|
5
|
-
* restoration. This is due to limitations of Wouter (our router of choice)
|
|
6
|
-
* as well the need to make the app feel more app-like.
|
|
7
|
-
*
|
|
8
|
-
* Every scroll position is remembered however the user has got to it (we
|
|
9
|
-
* don't differentiate between new entries in browser history and back
|
|
10
|
-
* navigation), but they are only restored if the user last visited the
|
|
11
|
-
* location less than 60 minutes ago.
|
|
12
|
-
*/
|
|
13
|
-
export declare function useScrollRestoration(
|
|
14
|
-
/**
|
|
15
|
-
* The current path, provided by your router of choice.
|
|
16
|
-
*/
|
|
17
|
-
pathname: string, options?: {
|
|
18
|
-
/**
|
|
19
|
-
* A list of paths where scroll restoration should never be performed.
|
|
20
|
-
*
|
|
21
|
-
* This list should have stable identity for optimal performance. Make
|
|
22
|
-
* sure to use `useMemo` or define the list in module scope.
|
|
23
|
-
*/
|
|
24
|
-
neverRestore?: string[];
|
|
25
|
-
}): void;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { useEffect, useLayoutEffect, useMemo } from "react";
|
|
2
|
-
const scrollPositions = new Map();
|
|
3
|
-
/**
|
|
4
|
-
* Handles scroll restoration on window.
|
|
5
|
-
*
|
|
6
|
-
* This hook behaves a little differently than the default browser scroll
|
|
7
|
-
* restoration. This is due to limitations of Wouter (our router of choice)
|
|
8
|
-
* as well the need to make the app feel more app-like.
|
|
9
|
-
*
|
|
10
|
-
* Every scroll position is remembered however the user has got to it (we
|
|
11
|
-
* don't differentiate between new entries in browser history and back
|
|
12
|
-
* navigation), but they are only restored if the user last visited the
|
|
13
|
-
* location less than 60 minutes ago.
|
|
14
|
-
*/
|
|
15
|
-
export function useScrollRestoration(
|
|
16
|
-
/**
|
|
17
|
-
* The current path, provided by your router of choice.
|
|
18
|
-
*/
|
|
19
|
-
pathname, options) {
|
|
20
|
-
// Standardise pathname, making sure that paths ending with and without
|
|
21
|
-
// a slash are treated equally
|
|
22
|
-
const normalizedPathname = pathname.replace(/\/$/, "") || "/";
|
|
23
|
-
const neverRestore = useMemo(() => new Set(options?.neverRestore), [options?.neverRestore]);
|
|
24
|
-
// Record scroll position for given pathname on pushState/replaceState.
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
const handleEvent = () => {
|
|
27
|
-
const x = window.scrollX;
|
|
28
|
-
const y = window.scrollY;
|
|
29
|
-
scrollPositions.set(normalizedPathname, [Date.now(), x, y]);
|
|
30
|
-
console.info(`Set scroll position for '${normalizedPathname}' (x: ${x}, y: ${y}).`);
|
|
31
|
-
};
|
|
32
|
-
// These events are provided by Wouter. They are not native browser events!
|
|
33
|
-
window.addEventListener("pushState", handleEvent);
|
|
34
|
-
window.addEventListener("replaceState", handleEvent);
|
|
35
|
-
return () => {
|
|
36
|
-
window.removeEventListener("pushState", handleEvent);
|
|
37
|
-
window.removeEventListener("replaceState", handleEvent);
|
|
38
|
-
};
|
|
39
|
-
}, [normalizedPathname]);
|
|
40
|
-
// Restore scroll position if last visit was less than 60 minutes ago.
|
|
41
|
-
useLayoutEffect(() => {
|
|
42
|
-
const maxDiff = 60000 * 60; // 60 minutes
|
|
43
|
-
const coordinates = scrollPositions.get(normalizedPathname);
|
|
44
|
-
if (coordinates) {
|
|
45
|
-
if (!neverRestore.has(normalizedPathname)) {
|
|
46
|
-
const now = Date.now();
|
|
47
|
-
const [ts, x, y] = coordinates;
|
|
48
|
-
if (now - ts < maxDiff) {
|
|
49
|
-
window.scrollTo(x, y);
|
|
50
|
-
console.info(`Restoring scroll position for '${normalizedPathname}' (x: ${x}, y: ${y}).`);
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
window.scrollTo(0, 0);
|
|
54
|
-
console.info(`Not restoring scroll position for '${normalizedPathname}'. Last visit >60 min ago.`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
window.scrollTo(0, 0);
|
|
59
|
-
console.info(`Not restoring scroll position for '${normalizedPathname}'. Page is set never to restore.`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
window.scrollTo(0, 0);
|
|
64
|
-
console.info(`Not restoring scroll position for '${normalizedPathname}'. Page not visited yet.`);
|
|
65
|
-
}
|
|
66
|
-
}, [normalizedPathname]);
|
|
67
|
-
}
|