@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.
Files changed (115) hide show
  1. package/.nvmrc +1 -0
  2. package/biome.json +39 -0
  3. package/dist/Blocking.d.ts +23 -0
  4. package/dist/Blocking.js +41 -0
  5. package/dist/Blocking.js.map +1 -0
  6. package/dist/Destination.d.ts +11 -0
  7. package/dist/Destination.js +10 -0
  8. package/dist/Destination.js.map +1 -0
  9. package/dist/Error.d.ts +33 -0
  10. package/dist/Error.js +22 -0
  11. package/dist/Error.js.map +1 -0
  12. package/dist/Event.d.ts +45 -0
  13. package/dist/Event.js +17 -0
  14. package/dist/Event.js.map +1 -0
  15. package/dist/Forms.d.ts +79 -0
  16. package/dist/Forms.js +111 -0
  17. package/dist/Forms.js.map +1 -0
  18. package/dist/Handler.d.ts +6 -0
  19. package/dist/Handler.js +2 -0
  20. package/dist/Handler.js.map +1 -0
  21. package/dist/{dts/Layer.d.ts → Layer.d.ts} +11 -8
  22. package/dist/{esm/Layer.js → Layer.js} +2 -2
  23. package/dist/Layer.js.map +1 -0
  24. package/dist/NavigateOptions.d.ts +7 -0
  25. package/dist/NavigateOptions.js +7 -0
  26. package/dist/NavigateOptions.js.map +1 -0
  27. package/dist/Navigation.d.ts +79 -0
  28. package/dist/Navigation.js +49 -0
  29. package/dist/Navigation.js.map +1 -0
  30. package/dist/NavigationType.d.ts +3 -0
  31. package/dist/NavigationType.js +3 -0
  32. package/dist/NavigationType.js.map +1 -0
  33. package/dist/ProposedDestination.d.ts +13 -0
  34. package/dist/ProposedDestination.js +4 -0
  35. package/dist/ProposedDestination.js.map +1 -0
  36. package/dist/Url.d.ts +13 -0
  37. package/dist/Url.js +72 -0
  38. package/dist/Url.js.map +1 -0
  39. package/dist/index.d.ts +12 -0
  40. package/dist/index.js +13 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/internal/fromWindow.d.ts +4 -0
  43. package/dist/internal/fromWindow.js +358 -0
  44. package/dist/internal/fromWindow.js.map +1 -0
  45. package/dist/internal/memory.d.ts +6 -0
  46. package/dist/internal/memory.js +59 -0
  47. package/dist/internal/memory.js.map +1 -0
  48. package/dist/internal/shared.d.ts +109 -0
  49. package/dist/{esm/internal → internal}/shared.js +134 -165
  50. package/dist/internal/shared.js.map +1 -0
  51. package/package.json +35 -52
  52. package/readme.md +243 -0
  53. package/src/Blocking.ts +65 -65
  54. package/src/Destination.ts +14 -0
  55. package/src/Error.ts +28 -0
  56. package/src/Event.ts +26 -0
  57. package/src/Forms.ts +216 -0
  58. package/src/Handler.ts +16 -0
  59. package/src/Layer.ts +20 -9
  60. package/src/NavigateOptions.ts +9 -0
  61. package/src/Navigation.test.ts +697 -0
  62. package/src/Navigation.ts +133 -468
  63. package/src/NavigationType.ts +5 -0
  64. package/src/ProposedDestination.ts +8 -0
  65. package/src/Url.ts +106 -0
  66. package/src/index.ts +12 -17
  67. package/src/internal/fromWindow.ts +250 -180
  68. package/src/internal/memory.ts +62 -49
  69. package/src/internal/shared.ts +238 -305
  70. package/tsconfig.json +30 -0
  71. package/Blocking/package.json +0 -6
  72. package/LICENSE +0 -21
  73. package/Layer/package.json +0 -6
  74. package/Navigation/package.json +0 -6
  75. package/README.md +0 -5
  76. package/dist/cjs/Blocking.js +0 -58
  77. package/dist/cjs/Blocking.js.map +0 -1
  78. package/dist/cjs/Layer.js +0 -27
  79. package/dist/cjs/Layer.js.map +0 -1
  80. package/dist/cjs/Navigation.js +0 -275
  81. package/dist/cjs/Navigation.js.map +0 -1
  82. package/dist/cjs/index.js +0 -39
  83. package/dist/cjs/index.js.map +0 -1
  84. package/dist/cjs/internal/fromWindow.js +0 -421
  85. package/dist/cjs/internal/fromWindow.js.map +0 -1
  86. package/dist/cjs/internal/memory.js +0 -72
  87. package/dist/cjs/internal/memory.js.map +0 -1
  88. package/dist/cjs/internal/shared.js +0 -522
  89. package/dist/cjs/internal/shared.js.map +0 -1
  90. package/dist/dts/Blocking.d.ts +0 -34
  91. package/dist/dts/Blocking.d.ts.map +0 -1
  92. package/dist/dts/Layer.d.ts.map +0 -1
  93. package/dist/dts/Navigation.d.ts +0 -462
  94. package/dist/dts/Navigation.d.ts.map +0 -1
  95. package/dist/dts/index.d.ts +0 -17
  96. package/dist/dts/index.d.ts.map +0 -1
  97. package/dist/dts/internal/fromWindow.d.ts +0 -12
  98. package/dist/dts/internal/fromWindow.d.ts.map +0 -1
  99. package/dist/dts/internal/memory.d.ts +0 -6
  100. package/dist/dts/internal/memory.d.ts.map +0 -1
  101. package/dist/dts/internal/shared.d.ts +0 -114
  102. package/dist/dts/internal/shared.d.ts.map +0 -1
  103. package/dist/esm/Blocking.js +0 -46
  104. package/dist/esm/Blocking.js.map +0 -1
  105. package/dist/esm/Layer.js.map +0 -1
  106. package/dist/esm/Navigation.js +0 -237
  107. package/dist/esm/Navigation.js.map +0 -1
  108. package/dist/esm/index.js +0 -17
  109. package/dist/esm/index.js.map +0 -1
  110. package/dist/esm/internal/fromWindow.js +0 -310
  111. package/dist/esm/internal/fromWindow.js.map +0 -1
  112. package/dist/esm/internal/memory.js +0 -56
  113. package/dist/esm/internal/memory.js.map +0 -1
  114. package/dist/esm/internal/shared.js.map +0 -1
  115. 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":"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"}
@@ -0,0 +1,3 @@
1
+ import * as Schema from 'effect/Schema';
2
+ export declare const NavigationType: Schema.Literal<["push", "replace", "reload", "traverse"]>;
3
+ export type NavigationType = typeof NavigationType.Type;
@@ -0,0 +1,3 @@
1
+ import * as Schema from 'effect/Schema';
2
+ export const NavigationType = Schema.Literal('push', 'replace', 'reload', 'traverse');
3
+ //# sourceMappingURL=NavigationType.js.map
@@ -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,4 @@
1
+ import * as Schema from 'effect/Schema';
2
+ import { Destination } from './Destination.js';
3
+ export const ProposedDestination = Destination.pipe(Schema.omit('id', 'key'));
4
+ //# sourceMappingURL=ProposedDestination.js.map
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Url.js","sourceRoot":"","sources":["../src/Url.ts"],"names":[],"mappings":"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"}
@@ -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,4 @@
1
+ import { GetRandomValues } from '@typed/id';
2
+ import * as Layer from 'effect/Layer';
3
+ import { Navigation } from '../Navigation.js';
4
+ export declare const fromWindow: (window: Window) => Layer.Layer<Navigation, never, GetRandomValues>;
@@ -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