@typed/navigation 0.17.0 → 0.18.1
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/.nvmrc +1 -0
- package/biome.json +39 -0
- package/dist/Blocking.d.ts +23 -0
- package/dist/Blocking.js +41 -0
- package/dist/Blocking.js.map +1 -0
- package/dist/Destination.d.ts +11 -0
- package/dist/Destination.js +10 -0
- package/dist/Destination.js.map +1 -0
- package/dist/Error.d.ts +33 -0
- package/dist/Error.js +22 -0
- package/dist/Error.js.map +1 -0
- package/dist/Event.d.ts +45 -0
- package/dist/Event.js +17 -0
- package/dist/Event.js.map +1 -0
- package/dist/Forms.d.ts +79 -0
- package/dist/Forms.js +111 -0
- package/dist/Forms.js.map +1 -0
- package/dist/Handler.d.ts +6 -0
- package/dist/Handler.js +2 -0
- package/dist/Handler.js.map +1 -0
- package/dist/{dts/Layer.d.ts → Layer.d.ts} +11 -8
- package/dist/{esm/Layer.js → Layer.js} +2 -2
- package/dist/Layer.js.map +1 -0
- package/dist/NavigateOptions.d.ts +7 -0
- package/dist/NavigateOptions.js +7 -0
- package/dist/NavigateOptions.js.map +1 -0
- package/dist/Navigation.d.ts +79 -0
- package/dist/Navigation.js +49 -0
- package/dist/Navigation.js.map +1 -0
- package/dist/NavigationType.d.ts +3 -0
- package/dist/NavigationType.js +3 -0
- package/dist/NavigationType.js.map +1 -0
- package/dist/ProposedDestination.d.ts +13 -0
- package/dist/ProposedDestination.js +4 -0
- package/dist/ProposedDestination.js.map +1 -0
- package/dist/Url.d.ts +13 -0
- package/dist/Url.js +72 -0
- package/dist/Url.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/fromWindow.d.ts +4 -0
- package/dist/internal/fromWindow.js +358 -0
- package/dist/internal/fromWindow.js.map +1 -0
- package/dist/internal/memory.d.ts +6 -0
- package/dist/internal/memory.js +59 -0
- package/dist/internal/memory.js.map +1 -0
- package/dist/internal/shared.d.ts +109 -0
- package/dist/{esm/internal → internal}/shared.js +134 -165
- package/dist/internal/shared.js.map +1 -0
- package/package.json +35 -52
- package/readme.md +243 -0
- package/src/Blocking.ts +65 -65
- package/src/Destination.ts +14 -0
- package/src/Error.ts +28 -0
- package/src/Event.ts +26 -0
- package/src/Forms.ts +216 -0
- package/src/Handler.ts +16 -0
- package/src/Layer.ts +20 -9
- package/src/NavigateOptions.ts +9 -0
- package/src/Navigation.test.ts +697 -0
- package/src/Navigation.ts +133 -468
- package/src/NavigationType.ts +5 -0
- package/src/ProposedDestination.ts +8 -0
- package/src/Url.ts +106 -0
- package/src/index.ts +12 -17
- package/src/internal/fromWindow.ts +250 -180
- package/src/internal/memory.ts +62 -49
- package/src/internal/shared.ts +238 -305
- package/tsconfig.json +30 -0
- package/Blocking/package.json +0 -6
- package/LICENSE +0 -21
- package/Layer/package.json +0 -6
- package/Navigation/package.json +0 -6
- package/README.md +0 -5
- package/dist/cjs/Blocking.js +0 -58
- package/dist/cjs/Blocking.js.map +0 -1
- package/dist/cjs/Layer.js +0 -27
- package/dist/cjs/Layer.js.map +0 -1
- package/dist/cjs/Navigation.js +0 -275
- package/dist/cjs/Navigation.js.map +0 -1
- package/dist/cjs/index.js +0 -39
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/internal/fromWindow.js +0 -421
- package/dist/cjs/internal/fromWindow.js.map +0 -1
- package/dist/cjs/internal/memory.js +0 -72
- package/dist/cjs/internal/memory.js.map +0 -1
- package/dist/cjs/internal/shared.js +0 -522
- package/dist/cjs/internal/shared.js.map +0 -1
- package/dist/dts/Blocking.d.ts +0 -34
- package/dist/dts/Blocking.d.ts.map +0 -1
- package/dist/dts/Layer.d.ts.map +0 -1
- package/dist/dts/Navigation.d.ts +0 -462
- package/dist/dts/Navigation.d.ts.map +0 -1
- package/dist/dts/index.d.ts +0 -17
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/dts/internal/fromWindow.d.ts +0 -12
- package/dist/dts/internal/fromWindow.d.ts.map +0 -1
- package/dist/dts/internal/memory.d.ts +0 -6
- package/dist/dts/internal/memory.d.ts.map +0 -1
- package/dist/dts/internal/shared.d.ts +0 -114
- package/dist/dts/internal/shared.d.ts.map +0 -1
- package/dist/esm/Blocking.js +0 -46
- package/dist/esm/Blocking.js.map +0 -1
- package/dist/esm/Layer.js.map +0 -1
- package/dist/esm/Navigation.js +0 -237
- package/dist/esm/Navigation.js.map +0 -1
- package/dist/esm/index.js +0 -17
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/fromWindow.js +0 -310
- package/dist/esm/internal/fromWindow.js.map +0 -1
- package/dist/esm/internal/memory.js +0 -56
- package/dist/esm/internal/memory.js.map +0 -1
- package/dist/esm/internal/shared.js.map +0 -1
- package/dist/esm/package.json +0 -4
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { HttpClientResponse } from '@effect/platform';
|
|
2
|
+
import type { HttpClient } from '@effect/platform/HttpClient';
|
|
3
|
+
import * as LazyRef from '@typed/lazy-ref';
|
|
4
|
+
import * as Context from 'effect/Context';
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import type * as Option from 'effect/Option';
|
|
7
|
+
import type * as Scope from 'effect/Scope';
|
|
8
|
+
import type { Destination } from './Destination.js';
|
|
9
|
+
import { CancelNavigation, type FormSubmitError, NavigationError, RedirectError } from './Error.js';
|
|
10
|
+
import type { TransitionEvent } from './Event.js';
|
|
11
|
+
import type { FormSubmit } from './Forms.js';
|
|
12
|
+
import type { BeforeNavigationHandler, NavigationHandler } from './Handler.js';
|
|
13
|
+
import type { NavigateOptions } from './NavigateOptions.js';
|
|
14
|
+
export interface Navigation {
|
|
15
|
+
readonly origin: string;
|
|
16
|
+
readonly base: string;
|
|
17
|
+
readonly currentEntry: LazyRef.Computed<Destination>;
|
|
18
|
+
readonly entries: LazyRef.Computed<ReadonlyArray<Destination>>;
|
|
19
|
+
readonly transition: LazyRef.Computed<Option.Option<TransitionEvent>>;
|
|
20
|
+
readonly canGoBack: LazyRef.Computed<boolean>;
|
|
21
|
+
readonly canGoForward: LazyRef.Computed<boolean>;
|
|
22
|
+
readonly navigate: (url: string | URL, options?: NavigateOptions) => Effect.Effect<Destination, NavigationError>;
|
|
23
|
+
readonly back: (options?: {
|
|
24
|
+
readonly info?: unknown;
|
|
25
|
+
}) => Effect.Effect<Destination, NavigationError>;
|
|
26
|
+
readonly forward: (options?: {
|
|
27
|
+
readonly info?: unknown;
|
|
28
|
+
}) => Effect.Effect<Destination, NavigationError>;
|
|
29
|
+
readonly traverseTo: (key: Destination['key'], options?: {
|
|
30
|
+
readonly info?: unknown;
|
|
31
|
+
}) => Effect.Effect<Destination, NavigationError>;
|
|
32
|
+
readonly updateCurrentEntry: (options: {
|
|
33
|
+
readonly state: unknown;
|
|
34
|
+
}) => Effect.Effect<Destination, NavigationError>;
|
|
35
|
+
readonly reload: (options?: {
|
|
36
|
+
readonly info?: unknown;
|
|
37
|
+
readonly state?: unknown;
|
|
38
|
+
}) => Effect.Effect<Destination, NavigationError>;
|
|
39
|
+
readonly beforeNavigation: <R = never, R2 = never>(handler: BeforeNavigationHandler<R, R2>) => Effect.Effect<void, never, R | R2 | Scope.Scope>;
|
|
40
|
+
readonly onNavigation: <R = never, R2 = never>(handler: NavigationHandler<R, R2>) => Effect.Effect<void, never, R | R2 | Scope.Scope>;
|
|
41
|
+
readonly submit: (form: FormSubmit) => Effect.Effect<readonly [Destination, HttpClientResponse.HttpClientResponse], NavigationError | FormSubmitError, Navigation | HttpClient | Scope.Scope>;
|
|
42
|
+
}
|
|
43
|
+
export declare const Navigation: Context.Tag<Navigation, Navigation>;
|
|
44
|
+
export declare const CurrentEntry: LazyRef.Computed<Destination, never, Navigation>;
|
|
45
|
+
export declare const Entries: LazyRef.Computed<ReadonlyArray<Destination>, never, Navigation>;
|
|
46
|
+
export declare function getCurrentPathFromUrl(location: Pick<URL, 'pathname' | 'search' | 'hash'>): string;
|
|
47
|
+
export declare const CurrentPath: LazyRef.Computed<string, never, Navigation>;
|
|
48
|
+
export declare const CanGoForward: LazyRef.Computed<boolean, never, Navigation>;
|
|
49
|
+
export declare const CanGoBack: LazyRef.Computed<boolean, never, Navigation>;
|
|
50
|
+
export declare const navigate: (url: string | URL, options?: NavigateOptions) => Effect.Effect<Destination, NavigationError, Navigation>;
|
|
51
|
+
export declare const back: (options?: {
|
|
52
|
+
readonly info?: unknown;
|
|
53
|
+
}) => Effect.Effect<Destination, NavigationError, Navigation>;
|
|
54
|
+
export declare const forward: (options?: {
|
|
55
|
+
readonly info?: unknown;
|
|
56
|
+
}) => Effect.Effect<Destination, NavigationError, Navigation>;
|
|
57
|
+
export declare const traverseTo: (key: string, options?: {
|
|
58
|
+
readonly info?: unknown;
|
|
59
|
+
}) => Effect.Effect<Destination, NavigationError, Navigation>;
|
|
60
|
+
export declare const updateCurrentEntry: (options: {
|
|
61
|
+
readonly state: unknown;
|
|
62
|
+
}) => Effect.Effect<Destination, NavigationError, Navigation>;
|
|
63
|
+
export declare const reload: (options?: {
|
|
64
|
+
readonly info?: unknown;
|
|
65
|
+
readonly state?: unknown;
|
|
66
|
+
}) => Effect.Effect<Destination, NavigationError, Navigation>;
|
|
67
|
+
export declare const Transition: LazyRef.Computed<Option.Option<TransitionEvent>, never, Navigation>;
|
|
68
|
+
export declare function handleRedirect(error: RedirectError): Effect.Effect<Destination, NavigationError, Navigation>;
|
|
69
|
+
export declare function redirectToPath(path: string | URL, options?: {
|
|
70
|
+
readonly state?: unknown;
|
|
71
|
+
readonly info?: unknown;
|
|
72
|
+
}): RedirectError;
|
|
73
|
+
export declare function isNavigationError(e: unknown): e is NavigationError;
|
|
74
|
+
export declare function isRedirectError(e: unknown): e is RedirectError;
|
|
75
|
+
export declare function isCancelNavigation(e: unknown): e is CancelNavigation;
|
|
76
|
+
export declare const cancelNavigation: Effect.Effect<never, CancelNavigation, never>;
|
|
77
|
+
export declare function beforeNavigation<R = never, R2 = never>(handler: BeforeNavigationHandler<R, R2>): Effect.Effect<void, never, Navigation | R | R2 | Scope.Scope>;
|
|
78
|
+
export declare function onNavigation<R = never, R2 = never>(handler: NavigationHandler<R, R2>): Effect.Effect<void, never, Navigation | R | R2 | Scope.Scope>;
|
|
79
|
+
export declare function submit(form: FormSubmit): Effect.Effect<readonly [Destination, HttpClientResponse.HttpClientResponse], NavigationError | FormSubmitError, Navigation | HttpClient | Scope.Scope>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as LazyRef from '@typed/lazy-ref';
|
|
2
|
+
import * as Context from 'effect/Context';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import { CancelNavigation, NavigationError, RedirectError } from './Error.js';
|
|
5
|
+
export const Navigation = Context.GenericTag('@typed/Navigation');
|
|
6
|
+
export const CurrentEntry = LazyRef.computedFromTag(Navigation, (nav) => nav.currentEntry);
|
|
7
|
+
export const Entries = LazyRef.computedFromTag(Navigation, (nav) => nav.entries);
|
|
8
|
+
export function getCurrentPathFromUrl(location) {
|
|
9
|
+
return location.pathname + location.search + location.hash;
|
|
10
|
+
}
|
|
11
|
+
export const CurrentPath = LazyRef.computedFromTag(Navigation, (nav) => LazyRef.map(nav.currentEntry, (e) => getCurrentPathFromUrl(e.url)));
|
|
12
|
+
export const CanGoForward = LazyRef.computedFromTag(Navigation, (nav) => nav.canGoForward);
|
|
13
|
+
export const CanGoBack = LazyRef.computedFromTag(Navigation, (nav) => nav.canGoBack);
|
|
14
|
+
export const navigate = (url, options) => Effect.flatMap(Navigation, (nav) => nav.navigate(url, options));
|
|
15
|
+
export const back = (opts) => Effect.flatMap(Navigation, (nav) => nav.back(opts));
|
|
16
|
+
export const forward = (opts) => Effect.flatMap(Navigation, (nav) => nav.forward(opts));
|
|
17
|
+
export const traverseTo = (key, opts) => Effect.flatMap(Navigation, (nav) => nav.traverseTo(key, opts));
|
|
18
|
+
export const updateCurrentEntry = (opts) => Effect.flatMap(Navigation, (nav) => nav.updateCurrentEntry(opts));
|
|
19
|
+
export const reload = (opts) => Effect.flatMap(Navigation, (nav) => nav.reload(opts));
|
|
20
|
+
export const Transition = LazyRef.computedFromTag(Navigation, (nav) => nav.transition);
|
|
21
|
+
export function handleRedirect(error) {
|
|
22
|
+
return navigate(error.path, {
|
|
23
|
+
history: 'replace',
|
|
24
|
+
...error.options,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function redirectToPath(path, options) {
|
|
28
|
+
return new RedirectError({ path, options });
|
|
29
|
+
}
|
|
30
|
+
export function isNavigationError(e) {
|
|
31
|
+
return NavigationError.is(e);
|
|
32
|
+
}
|
|
33
|
+
export function isRedirectError(e) {
|
|
34
|
+
return RedirectError.is(e);
|
|
35
|
+
}
|
|
36
|
+
export function isCancelNavigation(e) {
|
|
37
|
+
return CancelNavigation.is(e);
|
|
38
|
+
}
|
|
39
|
+
export const cancelNavigation = Effect.suspend(() => new CancelNavigation());
|
|
40
|
+
export function beforeNavigation(handler) {
|
|
41
|
+
return Effect.flatMap(Navigation, (nav) => nav.beforeNavigation(handler));
|
|
42
|
+
}
|
|
43
|
+
export function onNavigation(handler) {
|
|
44
|
+
return Effect.flatMap(Navigation, (nav) => nav.onNavigation(handler));
|
|
45
|
+
}
|
|
46
|
+
export function submit(form) {
|
|
47
|
+
return Effect.flatMap(Navigation, (nav) => nav.submit(form));
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=Navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Navigation.js","sourceRoot":"","sources":["../src/Navigation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAA;AAC1C,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAIvC,OAAO,EAAE,gBAAgB,EAAwB,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAoEnG,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAa,mBAAmB,CAAC,CAAA;AAE7E,MAAM,CAAC,MAAM,YAAY,GACvB,OAAO,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;AAEhE,MAAM,CAAC,MAAM,OAAO,GAIhB,OAAO,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AAE7D,MAAM,UAAU,qBAAqB,CAAC,QAAmD;IACvF,OAAO,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAA;AAC5D,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAgD,OAAO,CAAC,eAAe,CAC7F,UAAU,EACV,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAC5E,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAiD,OAAO,CAAC,eAAe,CAC/F,UAAU,EACV,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAC1B,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAiD,OAAO,CAAC,eAAe,CAC5F,UAAU,EACV,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CACvB,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,GAAiB,EACjB,OAAyB,EACgC,EAAE,CAC3D,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;AAEjE,MAAM,CAAC,MAAM,IAAI,GAIb,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;AAEjE,MAAM,CAAC,MAAM,OAAO,GAIhB,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;AAEpE,MAAM,CAAC,MAAM,UAAU,GAGwC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAC3E,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;AAEhE,MAAM,CAAC,MAAM,kBAAkB,GAI3B,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAA;AAE/E,MAAM,CAAC,MAAM,MAAM,GAG6C,CAAC,IAAI,EAAE,EAAE,CACvE,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;AAEvD,MAAM,CAAC,MAAM,UAAU,GAInB,OAAO,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;AAEhE,MAAM,UAAU,cAAc,CAAC,KAAoB;IACjD,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;QAC1B,OAAO,EAAE,SAAS;QAClB,GAAG,KAAK,CAAC,OAAO;KACjB,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,IAAkB,EAClB,OAA+D;IAE/D,OAAO,IAAI,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAU;IAC1C,OAAO,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,CAAU;IACxC,OAAO,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,CAAU;IAC3C,OAAO,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAA;AAE5E,MAAM,UAAU,gBAAgB,CAC9B,OAAuC;IAEvC,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,OAAiC;IAEjC,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAA;AACvE,CAAC;AAED,MAAM,UAAU,MAAM,CACpB,IAAgB;IAMhB,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;AAC9D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavigationType.js","sourceRoot":"","sources":["../src/NavigationType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Schema from 'effect/Schema';
|
|
2
|
+
export declare const ProposedDestination: Schema.SchemaClass<{
|
|
3
|
+
readonly url: URL;
|
|
4
|
+
readonly state: unknown;
|
|
5
|
+
readonly sameDocument: boolean;
|
|
6
|
+
}, {
|
|
7
|
+
readonly url: string;
|
|
8
|
+
readonly state: unknown;
|
|
9
|
+
readonly sameDocument: boolean;
|
|
10
|
+
}, never>;
|
|
11
|
+
export type ProposedDestinationEncoded = Schema.Schema.Encoded<typeof ProposedDestination>;
|
|
12
|
+
export interface ProposedDestination extends Schema.Schema.Type<typeof ProposedDestination> {
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProposedDestination.js","sourceRoot":"","sources":["../src/ProposedDestination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA"}
|
package/dist/Url.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Schema from 'effect/Schema';
|
|
2
|
+
export declare const UrlFromSelf: Schema.instanceOf<URL>;
|
|
3
|
+
export declare const Url: Schema.transformOrFail<typeof Schema.String, Schema.instanceOf<URL>, never>;
|
|
4
|
+
export declare const UrlSearchParamsFromSelf: Schema.instanceOf<URLSearchParams>;
|
|
5
|
+
export declare const UrlSearchParamsFromString: Schema.transform<typeof Schema.String, Schema.instanceOf<URLSearchParams>>;
|
|
6
|
+
export declare const UrlSearchParams: Schema.transform<Schema.Record$<typeof Schema.String, Schema.Union<[typeof Schema.String, Schema.Array$<typeof Schema.String>]>>, Schema.instanceOf<URLSearchParams>>;
|
|
7
|
+
type AnySchemaEncoded<T> = Schema.Schema<any, T, any> | Schema.Schema<any, T, never>;
|
|
8
|
+
type AnyFormDataFieldSchema = AnySchemaEncoded<string> | AnySchemaEncoded<readonly string[]> | AnySchemaEncoded<string | readonly string[]>;
|
|
9
|
+
type UrlSearchParamsFields = Record<string, AnyFormDataFieldSchema>;
|
|
10
|
+
export declare function schemaUrlSearchParams<const Fields extends UrlSearchParamsFields>(fields: Fields): Schema.Schema<{
|
|
11
|
+
readonly [K in keyof Schema.Struct.Type<Fields>]: Schema.Struct.Type<Fields>[K];
|
|
12
|
+
}, URLSearchParams, Schema.Schema.Context<Fields[keyof Fields]>>;
|
|
13
|
+
export {};
|
package/dist/Url.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import * as ParseResult from 'effect/ParseResult';
|
|
3
|
+
import * as Schema from 'effect/Schema';
|
|
4
|
+
export const UrlFromSelf = Schema.instanceOf(URL).annotations({
|
|
5
|
+
equivalence: () => (a, b) => a.href === b.href,
|
|
6
|
+
jsonSchema: {
|
|
7
|
+
title: 'URL',
|
|
8
|
+
identifier: 'URL',
|
|
9
|
+
type: 'string',
|
|
10
|
+
format: 'uri',
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
export const Url = Schema.String.pipe(Schema.transformOrFail(UrlFromSelf, {
|
|
14
|
+
decode: (s) => Effect.try({
|
|
15
|
+
try: () => new URL(s),
|
|
16
|
+
catch: () => new ParseResult.Type(UrlFromSelf.ast, s, 'Expected a URL'),
|
|
17
|
+
}),
|
|
18
|
+
encode: (url) => Effect.succeed(url.href),
|
|
19
|
+
}));
|
|
20
|
+
export const UrlSearchParamsFromSelf = Schema.instanceOf(URLSearchParams).annotations({
|
|
21
|
+
equivalence: () => (a, b) => a.toString() === b.toString(),
|
|
22
|
+
});
|
|
23
|
+
export const UrlSearchParamsFromString = Schema.String.pipe(Schema.transform(UrlSearchParamsFromSelf, {
|
|
24
|
+
decode: (s) => new URLSearchParams(s),
|
|
25
|
+
encode: (searchParams) => `?${searchParams.toString()}`,
|
|
26
|
+
}));
|
|
27
|
+
export const UrlSearchParams = Schema.Record({
|
|
28
|
+
key: Schema.String,
|
|
29
|
+
value: Schema.Union(Schema.String, Schema.Array(Schema.String)),
|
|
30
|
+
}).pipe(Schema.transform(UrlSearchParamsFromSelf, {
|
|
31
|
+
strict: true,
|
|
32
|
+
decode: structToUrlSearchParams,
|
|
33
|
+
encode: urlSearchParamsToStruct,
|
|
34
|
+
}));
|
|
35
|
+
export function schemaUrlSearchParams(fields) {
|
|
36
|
+
const struct = Schema.Struct(fields);
|
|
37
|
+
const encode = ParseResult.encode(struct);
|
|
38
|
+
const decode = ParseResult.decodeUnknown(struct);
|
|
39
|
+
return Schema.transformOrFail(UrlSearchParamsFromSelf, Schema.typeSchema(struct), {
|
|
40
|
+
strict: true,
|
|
41
|
+
decode: (searchParams) => decode(urlSearchParamsToStruct(searchParams)),
|
|
42
|
+
encode: (struct) => Effect.map(encode(struct), (_) => structToUrlSearchParams(_)),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function structToUrlSearchParams(struct) {
|
|
46
|
+
const searchParams = new URLSearchParams();
|
|
47
|
+
for (const [key, value] of Object.entries(struct)) {
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
for (const v of value) {
|
|
50
|
+
searchParams.append(key, v);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
searchParams.set(key, value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return searchParams;
|
|
58
|
+
}
|
|
59
|
+
function urlSearchParamsToStruct(searchParams) {
|
|
60
|
+
const struct = {};
|
|
61
|
+
searchParams.forEach((_, key) => {
|
|
62
|
+
const values = searchParams.getAll(key);
|
|
63
|
+
if (values.length === 1) {
|
|
64
|
+
struct[key] = values[0];
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
struct[key] = values;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return struct;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=Url.js.map
|
package/dist/Url.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Url.js","sourceRoot":"","sources":["../src/Url.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './Blocking.js';
|
|
2
|
+
export * from './Destination.js';
|
|
3
|
+
export * from './Error.js';
|
|
4
|
+
export * from './Event.js';
|
|
5
|
+
export * from './Forms.js';
|
|
6
|
+
export * from './Handler.js';
|
|
7
|
+
export * from './Layer.js';
|
|
8
|
+
export * from './NavigateOptions.js';
|
|
9
|
+
export * from './Navigation.js';
|
|
10
|
+
export * from './NavigationType.js';
|
|
11
|
+
export * from './ProposedDestination.js';
|
|
12
|
+
export * from './Url.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './Blocking.js';
|
|
2
|
+
export * from './Destination.js';
|
|
3
|
+
export * from './Error.js';
|
|
4
|
+
export * from './Event.js';
|
|
5
|
+
export * from './Forms.js';
|
|
6
|
+
export * from './Handler.js';
|
|
7
|
+
export * from './Layer.js';
|
|
8
|
+
export * from './NavigateOptions.js';
|
|
9
|
+
export * from './Navigation.js';
|
|
10
|
+
export * from './NavigationType.js';
|
|
11
|
+
export * from './ProposedDestination.js';
|
|
12
|
+
export * from './Url.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,UAAU,CAAA"}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { GetRandomValues, Uuid4 } from '@typed/id';
|
|
2
|
+
import * as LazyRef from '@typed/lazy-ref';
|
|
3
|
+
import { Schema } from 'effect';
|
|
4
|
+
import * as Context from 'effect/Context';
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Exit from 'effect/Exit';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as Option from 'effect/Option';
|
|
9
|
+
import * as Runtime from 'effect/Runtime';
|
|
10
|
+
import * as Scope from 'effect/Scope';
|
|
11
|
+
import { NavigationError } from '../Error.js';
|
|
12
|
+
import { Navigation } from '../Navigation.js';
|
|
13
|
+
import { getOriginalState, getUrl, isPatchedState, makeDestination, makeHandlersState, NavigationState, setupFromModelAndIntent, } from './shared.js';
|
|
14
|
+
export const fromWindow = (window) => Layer.scoped(Navigation, Effect.gen(function* () {
|
|
15
|
+
const getRandomValues = yield* GetRandomValues;
|
|
16
|
+
const { run, runPromise } = yield* scopedRuntime();
|
|
17
|
+
const hasNativeNavigation = !!window.navigation;
|
|
18
|
+
const base = getBaseHref(window);
|
|
19
|
+
const modelAndIntent = yield* hasNativeNavigation
|
|
20
|
+
? setupWithNavigation(window.navigation, runPromise)
|
|
21
|
+
: setupWithHistory(window, base, (event) => run(handleHistoryEvent(event)));
|
|
22
|
+
const navigation = setupFromModelAndIntent(modelAndIntent, window.location.origin, base, getRandomValues, hasNativeNavigation ? () => getNavigationState(window.navigation) : undefined);
|
|
23
|
+
return navigation;
|
|
24
|
+
function handleHistoryEvent(event) {
|
|
25
|
+
return Effect.gen(function* () {
|
|
26
|
+
if (event._tag === 'PushState') {
|
|
27
|
+
return yield* navigation.navigate(event.url, {}, event.skipCommit);
|
|
28
|
+
}
|
|
29
|
+
else if (event._tag === 'ReplaceState') {
|
|
30
|
+
if (Option.isSome(event.url)) {
|
|
31
|
+
return yield* navigation.navigate(event.url.value, { history: 'replace', state: event.state }, event.skipCommit);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return yield* navigation.updateCurrentEntry(event);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (event._tag === 'Traverse') {
|
|
38
|
+
const { entries, index } = yield* modelAndIntent.state;
|
|
39
|
+
const toIndex = Math.min(Math.max(0, index + event.delta), entries.length - 1);
|
|
40
|
+
const to = entries[toIndex];
|
|
41
|
+
const result = yield* navigation.traverseTo(to.key, {}, event.skipCommit);
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
yield* navigation.traverseTo(event.key, {}, event.skipCommit);
|
|
46
|
+
return yield* navigation.updateCurrentEntry({
|
|
47
|
+
state: event.state,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}));
|
|
53
|
+
function getBaseHref(window) {
|
|
54
|
+
const base = window.document.querySelector('base');
|
|
55
|
+
return base ? base.href : '/';
|
|
56
|
+
}
|
|
57
|
+
const getNavigationState = (navigation) => {
|
|
58
|
+
const entries = navigation.entries().map(nativeEntryToDestination);
|
|
59
|
+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
60
|
+
const { index } = navigation.currentEntry;
|
|
61
|
+
return {
|
|
62
|
+
entries,
|
|
63
|
+
index,
|
|
64
|
+
transition: Option.none(),
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
function setupWithNavigation(navigation, runPromise) {
|
|
68
|
+
return Effect.gen(function* () {
|
|
69
|
+
const state = yield* LazyRef.fromEffect(Effect.sync(() => getNavigationState(navigation)), {
|
|
70
|
+
eq: Schema.equivalence(Schema.typeSchema(NavigationState)),
|
|
71
|
+
});
|
|
72
|
+
const { beforeHandlers, handlers } = yield* makeHandlersState;
|
|
73
|
+
const commit = (to, event) => Effect.gen(function* () {
|
|
74
|
+
const { key, state, url } = to;
|
|
75
|
+
const { info, type } = event;
|
|
76
|
+
if (type === 'push' || type === 'replace') {
|
|
77
|
+
yield* Effect.promise(() => navigation.navigate(url.toString(), {
|
|
78
|
+
history: type,
|
|
79
|
+
state,
|
|
80
|
+
info,
|
|
81
|
+
}).committed);
|
|
82
|
+
}
|
|
83
|
+
else if (event.type === 'reload') {
|
|
84
|
+
yield* Effect.promise(() => navigation.reload({ state, info }).committed);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
yield* Effect.promise(() => navigation.traverseTo(key, { info }).committed);
|
|
88
|
+
}
|
|
89
|
+
}).pipe(Effect.catchAllDefect((cause) => new NavigationError({ cause })));
|
|
90
|
+
const runHandlers = (native) => Effect.gen(function* () {
|
|
91
|
+
const eventHandlers = yield* handlers;
|
|
92
|
+
const matches = [];
|
|
93
|
+
const event = {
|
|
94
|
+
type: native.navigationType,
|
|
95
|
+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
96
|
+
destination: nativeEntryToDestination(navigation.currentEntry),
|
|
97
|
+
info: native.info,
|
|
98
|
+
};
|
|
99
|
+
for (const [handler, ctx] of eventHandlers) {
|
|
100
|
+
const match = yield* Effect.provide(handler(event), ctx);
|
|
101
|
+
if (match !== undefined && Option.isSome(match)) {
|
|
102
|
+
matches.push(Effect.provide(match.value, ctx));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (matches.length > 0) {
|
|
106
|
+
yield* Effect.all(matches);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
navigation.addEventListener('navigate', (ev) => {
|
|
110
|
+
if (shouldNotIntercept(ev))
|
|
111
|
+
return;
|
|
112
|
+
ev.intercept({
|
|
113
|
+
handler: () => runPromise(runHandlers(ev)),
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
state,
|
|
118
|
+
beforeHandlers,
|
|
119
|
+
handlers,
|
|
120
|
+
commit,
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function nativeEntryToDestination(entry) {
|
|
125
|
+
return {
|
|
126
|
+
id: Uuid4.make(entry.id),
|
|
127
|
+
key: Uuid4.make(entry.key),
|
|
128
|
+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
129
|
+
url: new URL(entry.url),
|
|
130
|
+
state: entry.getState(),
|
|
131
|
+
sameDocument: entry.sameDocument,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function shouldNotIntercept(navigationEvent) {
|
|
135
|
+
return (!navigationEvent.canIntercept ||
|
|
136
|
+
// If this is just a hashChange,
|
|
137
|
+
// just let the browser handle scrolling to the content.
|
|
138
|
+
navigationEvent.hashChange ||
|
|
139
|
+
// If this is a download,
|
|
140
|
+
// let the browser perform the download.
|
|
141
|
+
!!navigationEvent.downloadRequest ||
|
|
142
|
+
// If this is a form submission,
|
|
143
|
+
// let that go to the server.
|
|
144
|
+
!!navigationEvent.formData);
|
|
145
|
+
}
|
|
146
|
+
function setupWithHistory(window, base, onEvent) {
|
|
147
|
+
return Effect.gen(function* () {
|
|
148
|
+
const { location } = window;
|
|
149
|
+
const { getHistoryState, original: history, unpatch } = patchHistory(window, onEvent, base);
|
|
150
|
+
yield* Effect.addFinalizer(() => unpatch);
|
|
151
|
+
const state = yield* LazyRef.fromEffect(Effect.suspend(() => Effect.map(makeDestination(new URL(location.href), getHistoryState(), location.origin), (destination) => ({
|
|
152
|
+
entries: [destination],
|
|
153
|
+
index: 0,
|
|
154
|
+
transition: Option.none(),
|
|
155
|
+
}))), { eq: Schema.equivalence(Schema.typeSchema(NavigationState)) });
|
|
156
|
+
const { beforeHandlers, handlers } = yield* makeHandlersState;
|
|
157
|
+
const commit = ({ id, key, state, url }, event) => Effect.sync(() => {
|
|
158
|
+
const { type } = event;
|
|
159
|
+
if (type === 'push') {
|
|
160
|
+
history.pushState({
|
|
161
|
+
__typed__navigation__id__: id,
|
|
162
|
+
__typed__navigation__key__: key,
|
|
163
|
+
__typed__navigation__state__: state,
|
|
164
|
+
}, '', url);
|
|
165
|
+
}
|
|
166
|
+
else if (type === 'replace') {
|
|
167
|
+
history.replaceState({
|
|
168
|
+
__typed__navigation__id__: id,
|
|
169
|
+
__typed__navigation__key__: key,
|
|
170
|
+
__typed__navigation__state__: state,
|
|
171
|
+
}, '', url);
|
|
172
|
+
}
|
|
173
|
+
else if (event.type === 'reload') {
|
|
174
|
+
location.reload();
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
history.go(event.delta);
|
|
178
|
+
history.replaceState({
|
|
179
|
+
__typed__navigation__id__: id,
|
|
180
|
+
__typed__navigation__key__: key,
|
|
181
|
+
__typed__navigation__state__: state,
|
|
182
|
+
}, '', window.location.href);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
state,
|
|
187
|
+
beforeHandlers,
|
|
188
|
+
handlers,
|
|
189
|
+
commit,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function patchHistory(window, onEvent, base) {
|
|
194
|
+
const { history, location } = window;
|
|
195
|
+
const stateDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(history), 'state') ||
|
|
196
|
+
Object.getOwnPropertyDescriptor(history, 'state');
|
|
197
|
+
const methods = {
|
|
198
|
+
pushState: history.pushState.bind(history),
|
|
199
|
+
replaceState: history.replaceState.bind(history),
|
|
200
|
+
go: history.go.bind(history),
|
|
201
|
+
back: history.back.bind(history),
|
|
202
|
+
forward: history.forward.bind(history),
|
|
203
|
+
};
|
|
204
|
+
const getStateDescriptor = stateDescriptor?.get?.bind(history);
|
|
205
|
+
const getHistoryState = () => getStateDescriptor?.();
|
|
206
|
+
const original = {
|
|
207
|
+
get length() {
|
|
208
|
+
return history.length;
|
|
209
|
+
},
|
|
210
|
+
get scrollRestoration() {
|
|
211
|
+
return history.scrollRestoration;
|
|
212
|
+
},
|
|
213
|
+
set scrollRestoration(mode) {
|
|
214
|
+
history.scrollRestoration = mode;
|
|
215
|
+
},
|
|
216
|
+
get state() {
|
|
217
|
+
return getHistoryState();
|
|
218
|
+
},
|
|
219
|
+
...methods,
|
|
220
|
+
pushState(data, _, url) {
|
|
221
|
+
return methods.pushState(data, _, url?.toString());
|
|
222
|
+
},
|
|
223
|
+
replaceState(data, _, url) {
|
|
224
|
+
return methods.replaceState(data, _, url?.toString());
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
history.pushState = (state, _, url) => {
|
|
228
|
+
if (url) {
|
|
229
|
+
onEvent({
|
|
230
|
+
_tag: 'PushState',
|
|
231
|
+
state,
|
|
232
|
+
url: getUrl(location.origin, url, base),
|
|
233
|
+
skipCommit: false,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
onEvent({
|
|
238
|
+
_tag: 'ReplaceState',
|
|
239
|
+
state,
|
|
240
|
+
url: Option.none(),
|
|
241
|
+
skipCommit: false,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
history.replaceState = (state, _, url) => {
|
|
246
|
+
onEvent({
|
|
247
|
+
_tag: 'ReplaceState',
|
|
248
|
+
state,
|
|
249
|
+
url: url ? Option.some(getUrl(location.origin, url, base)) : Option.none(),
|
|
250
|
+
skipCommit: false,
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
history.go = (delta) => {
|
|
254
|
+
if (delta && delta !== 0) {
|
|
255
|
+
onEvent({ _tag: 'Traverse', delta, skipCommit: false });
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
history.back = () => {
|
|
259
|
+
onEvent({ _tag: 'Traverse', delta: -1, skipCommit: false });
|
|
260
|
+
};
|
|
261
|
+
history.forward = () => {
|
|
262
|
+
onEvent({ _tag: 'Traverse', delta: 1, skipCommit: false });
|
|
263
|
+
};
|
|
264
|
+
const onHashChange = (ev) => {
|
|
265
|
+
onEvent({
|
|
266
|
+
_tag: 'ReplaceState',
|
|
267
|
+
state: history.state,
|
|
268
|
+
url: Option.some(new URL(ev.newURL)),
|
|
269
|
+
skipCommit: false,
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
window.addEventListener('hashchange', onHashChange, { capture: true });
|
|
273
|
+
const onPopState = (ev) => {
|
|
274
|
+
if (isPatchedState(ev.state)) {
|
|
275
|
+
onEvent({
|
|
276
|
+
_tag: 'TraverseTo',
|
|
277
|
+
key: ev.state.__typed__navigation__key__,
|
|
278
|
+
state: ev.state.__typed__navigation__state__,
|
|
279
|
+
skipCommit: true,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
onEvent({
|
|
284
|
+
_tag: 'ReplaceState',
|
|
285
|
+
state: ev.state,
|
|
286
|
+
url: Option.some(new URL(location.href)),
|
|
287
|
+
skipCommit: true,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
window.addEventListener('popstate', onPopState, { capture: true });
|
|
292
|
+
const unpatch = Effect.sync(() => {
|
|
293
|
+
history.pushState = original.pushState;
|
|
294
|
+
history.replaceState = original.replaceState;
|
|
295
|
+
history.go = original.go;
|
|
296
|
+
history.back = original.back;
|
|
297
|
+
history.forward = original.forward;
|
|
298
|
+
if (stateDescriptor) {
|
|
299
|
+
try {
|
|
300
|
+
Object.defineProperty(history, 'state', stateDescriptor);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
// We tried, but it didn't work
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
window.removeEventListener('hashchange', onHashChange);
|
|
307
|
+
window.removeEventListener('popstate', onPopState);
|
|
308
|
+
});
|
|
309
|
+
Object.defineProperty(history, 'state', {
|
|
310
|
+
get() {
|
|
311
|
+
return getOriginalState(getStateDescriptor?.() ?? history.state);
|
|
312
|
+
},
|
|
313
|
+
set(value) {
|
|
314
|
+
const { __typed__navigation__id__, __typed__navigation__key__ } = getStateDescriptor?.() ?? original.state;
|
|
315
|
+
if (isPatchedState(value)) {
|
|
316
|
+
// The setter is not actually modifying the history.state
|
|
317
|
+
// We need to call the original replaceState to update the actual state
|
|
318
|
+
original.replaceState.call(history, value, '', location.href);
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
// The setter is not actually modifying the history.state
|
|
322
|
+
// We need to call the original replaceState to update the actual state
|
|
323
|
+
original.replaceState.call(history, {
|
|
324
|
+
__typed__navigation__id__,
|
|
325
|
+
__typed__navigation__key__,
|
|
326
|
+
__typed__navigation__state__: value,
|
|
327
|
+
}, '', location.href);
|
|
328
|
+
}
|
|
329
|
+
return value;
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
return {
|
|
333
|
+
getHistoryState,
|
|
334
|
+
original,
|
|
335
|
+
patched: history,
|
|
336
|
+
unpatch,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function scopedRuntime() {
|
|
340
|
+
return Effect.map(Effect.runtime(), (runtime) => {
|
|
341
|
+
const scope = Context.get(runtime.context, Scope.Scope);
|
|
342
|
+
const runFork = Runtime.runFork(runtime);
|
|
343
|
+
const runPromise = (effect) => new Promise((resolve, reject) => {
|
|
344
|
+
const fiber = runFork(effect, { scope });
|
|
345
|
+
fiber.addObserver(Exit.match({
|
|
346
|
+
onFailure: (cause) => reject(Runtime.makeFiberFailure(cause)),
|
|
347
|
+
onSuccess: resolve,
|
|
348
|
+
}));
|
|
349
|
+
});
|
|
350
|
+
return {
|
|
351
|
+
runtime,
|
|
352
|
+
scope: Context.unsafeGet(runtime.context, Scope.Scope),
|
|
353
|
+
run: (eff) => runFork(eff, { scope }),
|
|
354
|
+
runPromise,
|
|
355
|
+
};
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
//# sourceMappingURL=fromWindow.js.map
|