@typed/navigation 0.13.5 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Blocking.js +8 -8
- package/dist/cjs/Blocking.js.map +1 -1
- package/dist/cjs/Layer.js +1 -1
- package/dist/cjs/Layer.js.map +1 -1
- package/dist/cjs/Navigation.js +66 -57
- package/dist/cjs/Navigation.js.map +1 -1
- package/dist/cjs/internal/fromWindow.js +32 -32
- package/dist/cjs/internal/fromWindow.js.map +1 -1
- package/dist/cjs/internal/memory.js +18 -20
- package/dist/cjs/internal/memory.js.map +1 -1
- package/dist/cjs/internal/shared.js +88 -88
- package/dist/cjs/internal/shared.js.map +1 -1
- package/dist/dts/Blocking.d.ts +1 -1
- package/dist/dts/Blocking.d.ts.map +1 -1
- package/dist/dts/Layer.d.ts +2 -1
- package/dist/dts/Layer.d.ts.map +1 -1
- package/dist/dts/Navigation.d.ts +122 -199
- package/dist/dts/Navigation.d.ts.map +1 -1
- package/dist/dts/internal/fromWindow.d.ts +1 -1
- package/dist/dts/internal/fromWindow.d.ts.map +1 -1
- package/dist/dts/internal/memory.d.ts +1 -1
- package/dist/dts/internal/memory.d.ts.map +1 -1
- package/dist/dts/internal/shared.d.ts +34 -68
- package/dist/dts/internal/shared.d.ts.map +1 -1
- package/dist/esm/Blocking.js +7 -7
- package/dist/esm/Blocking.js.map +1 -1
- package/dist/esm/Layer.js.map +1 -1
- package/dist/esm/Navigation.js +55 -46
- package/dist/esm/Navigation.js.map +1 -1
- package/dist/esm/internal/fromWindow.js +25 -25
- package/dist/esm/internal/fromWindow.js.map +1 -1
- package/dist/esm/internal/memory.js +15 -17
- package/dist/esm/internal/memory.js.map +1 -1
- package/dist/esm/internal/shared.js +76 -76
- package/dist/esm/internal/shared.js.map +1 -1
- package/package.json +8 -8
- package/src/Blocking.ts +21 -23
- package/src/Layer.ts +2 -1
- package/src/Navigation.ts +81 -75
- package/src/internal/fromWindow.ts +44 -47
- package/src/internal/memory.ts +17 -23
- package/src/internal/shared.ts +82 -91
package/src/Navigation.ts
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type * as HttpClient from "@effect/platform/HttpClient"
|
|
6
|
-
import {
|
|
6
|
+
import { ParseResult } from "@effect/schema"
|
|
7
7
|
import * as Schema from "@effect/schema/Schema"
|
|
8
8
|
import { Tagged } from "@typed/context"
|
|
9
9
|
import * as RefSubject from "@typed/fx/RefSubject"
|
|
10
10
|
import type { Uuid } from "@typed/id"
|
|
11
11
|
import * as IdSchema from "@typed/id/Schema"
|
|
12
|
-
import type { Option, Scope } from "effect"
|
|
13
12
|
import * as Data from "effect/Data"
|
|
14
13
|
import * as Effect from "effect/Effect"
|
|
14
|
+
import type * as Option from "effect/Option"
|
|
15
|
+
import type * as Scope from "effect/Scope"
|
|
15
16
|
import type { Simplify } from "effect/Types"
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -83,40 +84,42 @@ export const Navigation: Tagged<Navigation> = Tagged<Navigation, Navigation>("@t
|
|
|
83
84
|
|
|
84
85
|
const urlSchema_ = Schema.instanceOf(URL).pipe(Schema.equivalence((a, b) => a.href === b.href))
|
|
85
86
|
|
|
86
|
-
const urlSchema = Schema.
|
|
87
|
+
const urlSchema = Schema.String.pipe(
|
|
87
88
|
Schema.transformOrFail(
|
|
88
89
|
urlSchema_,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
{
|
|
91
|
+
decode: (s) =>
|
|
92
|
+
Effect.suspend(() => {
|
|
93
|
+
try {
|
|
94
|
+
return Effect.succeed(new URL(s))
|
|
95
|
+
} catch {
|
|
96
|
+
return Effect.fail(new ParseResult.Type(urlSchema_.ast, s, `Expected a URL`))
|
|
97
|
+
}
|
|
98
|
+
}),
|
|
99
|
+
encode: (url) => Effect.succeed(url.toString())
|
|
100
|
+
}
|
|
98
101
|
)
|
|
99
102
|
)
|
|
100
103
|
|
|
101
104
|
/**
|
|
102
105
|
* @since 1.0.0
|
|
103
106
|
*/
|
|
104
|
-
export const Destination = Schema.
|
|
107
|
+
export const Destination = Schema.Struct({
|
|
105
108
|
id: IdSchema.uuid,
|
|
106
109
|
key: IdSchema.uuid,
|
|
107
110
|
url: urlSchema,
|
|
108
|
-
state: Schema.
|
|
109
|
-
sameDocument: Schema.
|
|
111
|
+
state: Schema.Unknown,
|
|
112
|
+
sameDocument: Schema.Boolean
|
|
110
113
|
})
|
|
111
114
|
|
|
112
115
|
/**
|
|
113
116
|
* @since 1.0.0
|
|
114
117
|
*/
|
|
115
|
-
export type DestinationJson = Schema.Schema.
|
|
118
|
+
export type DestinationJson = Schema.Schema.Encoded<typeof Destination>
|
|
116
119
|
/**
|
|
117
120
|
* @since 1.0.0
|
|
118
121
|
*/
|
|
119
|
-
export interface Destination extends Schema.Schema.
|
|
122
|
+
export interface Destination extends Schema.Schema.Type<typeof Destination> {}
|
|
120
123
|
|
|
121
124
|
/**
|
|
122
125
|
* @since 1.0.0
|
|
@@ -126,76 +129,76 @@ export const ProposedDestination = Destination.pipe(Schema.omit("id", "key"))
|
|
|
126
129
|
/**
|
|
127
130
|
* @since 1.0.0
|
|
128
131
|
*/
|
|
129
|
-
export type ProposedDestinationJson = Schema.Schema.
|
|
132
|
+
export type ProposedDestinationJson = Schema.Schema.Encoded<typeof ProposedDestination>
|
|
130
133
|
/**
|
|
131
134
|
* @since 1.0.0
|
|
132
135
|
*/
|
|
133
|
-
export interface ProposedDestination extends Schema.Schema.
|
|
136
|
+
export interface ProposedDestination extends Schema.Schema.Type<typeof ProposedDestination> {}
|
|
134
137
|
|
|
135
138
|
/**
|
|
136
139
|
* @since 1.0.0
|
|
137
140
|
*/
|
|
138
|
-
export const NavigationType = Schema.
|
|
141
|
+
export const NavigationType = Schema.Literal("push", "replace", "reload", "traverse")
|
|
139
142
|
/**
|
|
140
143
|
* @since 1.0.0
|
|
141
144
|
*/
|
|
142
|
-
export type NavigationType = Schema.Schema.
|
|
145
|
+
export type NavigationType = Schema.Schema.Type<typeof NavigationType>
|
|
143
146
|
|
|
144
147
|
/**
|
|
145
148
|
* @since 1.0.0
|
|
146
149
|
*/
|
|
147
|
-
export const Transition = Schema.
|
|
150
|
+
export const Transition = Schema.Struct({
|
|
148
151
|
type: NavigationType,
|
|
149
152
|
from: Destination,
|
|
150
|
-
to: Schema.
|
|
153
|
+
to: Schema.Union(ProposedDestination, Destination)
|
|
151
154
|
})
|
|
152
155
|
|
|
153
156
|
/**
|
|
154
157
|
* @since 1.0.0
|
|
155
158
|
*/
|
|
156
|
-
export type TransitionJson = Schema.Schema.
|
|
159
|
+
export type TransitionJson = Schema.Schema.Encoded<typeof Transition>
|
|
157
160
|
/**
|
|
158
161
|
* @since 1.0.0
|
|
159
162
|
*/
|
|
160
|
-
export interface Transition extends Schema.Schema.
|
|
163
|
+
export interface Transition extends Schema.Schema.Type<typeof Transition> {}
|
|
161
164
|
|
|
162
165
|
/**
|
|
163
166
|
* @since 1.0.0
|
|
164
167
|
*/
|
|
165
|
-
export const BeforeNavigationEvent = Schema.
|
|
168
|
+
export const BeforeNavigationEvent = Schema.Struct({
|
|
166
169
|
type: NavigationType,
|
|
167
170
|
from: Destination,
|
|
168
|
-
delta: Schema.
|
|
169
|
-
to: Schema.
|
|
170
|
-
info: Schema.
|
|
171
|
+
delta: Schema.Number,
|
|
172
|
+
to: Schema.Union(ProposedDestination, Destination),
|
|
173
|
+
info: Schema.Unknown
|
|
171
174
|
})
|
|
172
175
|
|
|
173
176
|
/**
|
|
174
177
|
* @since 1.0.0
|
|
175
178
|
*/
|
|
176
|
-
export type BeforeNavigationEventJson = Schema.Schema.
|
|
179
|
+
export type BeforeNavigationEventJson = Schema.Schema.Encoded<typeof BeforeNavigationEvent>
|
|
177
180
|
/**
|
|
178
181
|
* @since 1.0.0
|
|
179
182
|
*/
|
|
180
|
-
export interface BeforeNavigationEvent extends Schema.Schema.
|
|
183
|
+
export interface BeforeNavigationEvent extends Schema.Schema.Type<typeof BeforeNavigationEvent> {}
|
|
181
184
|
|
|
182
185
|
/**
|
|
183
186
|
* @since 1.0.0
|
|
184
187
|
*/
|
|
185
|
-
export const NavigationEvent = Schema.
|
|
188
|
+
export const NavigationEvent = Schema.Struct({
|
|
186
189
|
type: NavigationType,
|
|
187
190
|
destination: Destination,
|
|
188
|
-
info: Schema.
|
|
191
|
+
info: Schema.Unknown
|
|
189
192
|
})
|
|
190
193
|
|
|
191
194
|
/**
|
|
192
195
|
* @since 1.0.0
|
|
193
196
|
*/
|
|
194
|
-
export type NavigationEventJson = Schema.Schema.
|
|
197
|
+
export type NavigationEventJson = Schema.Schema.Encoded<typeof NavigationEvent>
|
|
195
198
|
/**
|
|
196
199
|
* @since 1.0.0
|
|
197
200
|
*/
|
|
198
|
-
export interface NavigationEvent extends Schema.Schema.
|
|
201
|
+
export interface NavigationEvent extends Schema.Schema.Type<typeof NavigationEvent> {}
|
|
199
202
|
|
|
200
203
|
/**
|
|
201
204
|
* @since 1.0.0
|
|
@@ -268,19 +271,19 @@ export interface NavigateOptions {
|
|
|
268
271
|
/**
|
|
269
272
|
* @since 1.0.0
|
|
270
273
|
*/
|
|
271
|
-
export const FileSchemaFrom = Schema.
|
|
272
|
-
_id: Schema.
|
|
273
|
-
name: Schema.
|
|
274
|
-
data: Schema.
|
|
274
|
+
export const FileSchemaFrom = Schema.Struct({
|
|
275
|
+
_id: Schema.Literal("File"),
|
|
276
|
+
name: Schema.String,
|
|
277
|
+
data: Schema.String // Base64 encoded
|
|
275
278
|
})
|
|
276
279
|
|
|
277
280
|
/**
|
|
278
281
|
* @since 1.0.0
|
|
279
282
|
*/
|
|
280
|
-
export type FileSchemaFrom = Schema.Schema.
|
|
283
|
+
export type FileSchemaFrom = Schema.Schema.Encoded<typeof FileSchemaFrom>
|
|
281
284
|
|
|
282
|
-
const decodeBase64 =
|
|
283
|
-
const encodeBase64 =
|
|
285
|
+
const decodeBase64 = ParseResult.decode(Schema.Base64)
|
|
286
|
+
const encodeBase64 = ParseResult.encode(Schema.Base64)
|
|
284
287
|
|
|
285
288
|
/**
|
|
286
289
|
* @since 1.0.0
|
|
@@ -288,35 +291,39 @@ const encodeBase64 = Parser.encode(Schema.Base64)
|
|
|
288
291
|
export const FileSchema = FileSchemaFrom.pipe(
|
|
289
292
|
Schema.transformOrFail(
|
|
290
293
|
Schema.instanceOf(File),
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
Effect.
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
{
|
|
295
|
+
decode: ({ data, name }) => Effect.map(decodeBase64(data), (buffer) => new File([buffer], name)),
|
|
296
|
+
encode: (file) =>
|
|
297
|
+
Effect.promise(() => file.arrayBuffer()).pipe(
|
|
298
|
+
Effect.flatMap((buffer) => encodeBase64(new Uint8Array(buffer))),
|
|
299
|
+
Effect.map((data): FileSchemaFrom => ({ _id: "File", name: file.name, data }))
|
|
300
|
+
)
|
|
301
|
+
}
|
|
297
302
|
)
|
|
298
303
|
)
|
|
299
304
|
|
|
300
305
|
/**
|
|
301
306
|
* @since 1.0.0
|
|
302
307
|
*/
|
|
303
|
-
export const FormDataSchema = Schema.
|
|
308
|
+
export const FormDataSchema = Schema.Record(Schema.String, Schema.Union(Schema.String, FileSchema)).pipe(
|
|
304
309
|
Schema.transform(
|
|
305
310
|
Schema.instanceOf(FormData),
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
311
|
+
{
|
|
312
|
+
decode: (formData) => {
|
|
313
|
+
const data = new FormData()
|
|
314
|
+
|
|
315
|
+
for (const [key, value] of Object.entries(formData)) {
|
|
316
|
+
if (value instanceof File) {
|
|
317
|
+
data.append(key, value, value.name)
|
|
318
|
+
} else {
|
|
319
|
+
data.append(key, value)
|
|
320
|
+
}
|
|
314
321
|
}
|
|
315
|
-
}
|
|
316
322
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
323
|
+
return data
|
|
324
|
+
},
|
|
325
|
+
encode: (formData) => Object.fromEntries(formData.entries())
|
|
326
|
+
}
|
|
320
327
|
)
|
|
321
328
|
)
|
|
322
329
|
|
|
@@ -325,38 +332,38 @@ const optionNullable = { as: "Option", nullable: true } as const
|
|
|
325
332
|
/**
|
|
326
333
|
* @since 1.0.0
|
|
327
334
|
*/
|
|
328
|
-
export const FormInputSchema = Schema.
|
|
329
|
-
name: Schema.optional(Schema.
|
|
330
|
-
action: Schema.optional(Schema.
|
|
331
|
-
method: Schema.optional(Schema.
|
|
332
|
-
encoding: Schema.optional(Schema.
|
|
335
|
+
export const FormInputSchema = Schema.Struct({
|
|
336
|
+
name: Schema.optional(Schema.String, optionNullable),
|
|
337
|
+
action: Schema.optional(Schema.String, optionNullable),
|
|
338
|
+
method: Schema.optional(Schema.String, optionNullable),
|
|
339
|
+
encoding: Schema.optional(Schema.String, optionNullable),
|
|
333
340
|
data: FormDataSchema
|
|
334
341
|
})
|
|
335
342
|
|
|
336
343
|
/**
|
|
337
344
|
* @since 1.0.0
|
|
338
345
|
*/
|
|
339
|
-
export type FormInputFrom = Schema.Schema.
|
|
346
|
+
export type FormInputFrom = Schema.Schema.Encoded<typeof FormInputSchema>
|
|
340
347
|
|
|
341
348
|
/**
|
|
342
349
|
* @since 1.0.0
|
|
343
350
|
*/
|
|
344
|
-
export interface FormInput extends Schema.Schema.
|
|
351
|
+
export interface FormInput extends Schema.Schema.Type<typeof FormInputSchema> {}
|
|
345
352
|
|
|
346
353
|
/**
|
|
347
354
|
* @since 1.0.0
|
|
348
355
|
*/
|
|
349
|
-
export const FormDataEvent = Schema.extend(Schema.
|
|
356
|
+
export const FormDataEvent = Schema.extend(Schema.Struct({ from: Destination }), FormInputSchema)
|
|
350
357
|
|
|
351
358
|
/**
|
|
352
359
|
* @since 1.0.0
|
|
353
360
|
*/
|
|
354
|
-
export type FormDataEventJson = Schema.Schema.
|
|
361
|
+
export type FormDataEventJson = Schema.Schema.Encoded<typeof FormDataEvent>
|
|
355
362
|
|
|
356
363
|
/**
|
|
357
364
|
* @since 1.0.0
|
|
358
365
|
*/
|
|
359
|
-
export interface FormDataEvent extends Schema.Schema.
|
|
366
|
+
export interface FormDataEvent extends Schema.Schema.Type<typeof FormDataEvent> {}
|
|
360
367
|
|
|
361
368
|
/**
|
|
362
369
|
* @since 1.0.0
|
|
@@ -461,11 +468,10 @@ export function getCurrentPathFromUrl(location: Pick<URL, "pathname" | "search"
|
|
|
461
468
|
/**
|
|
462
469
|
* @since 1.0.0
|
|
463
470
|
*/
|
|
464
|
-
export const CurrentPath: RefSubject.Computed<string, never, Navigation> = RefSubject.
|
|
465
|
-
|
|
466
|
-
(
|
|
471
|
+
export const CurrentPath: RefSubject.Computed<string, never, Navigation> = RefSubject.computedFromTag(
|
|
472
|
+
Navigation,
|
|
473
|
+
(nav) => RefSubject.map(nav.currentEntry, (e) => getCurrentPathFromUrl(e.url))
|
|
467
474
|
)
|
|
468
|
-
|
|
469
475
|
/**
|
|
470
476
|
* @since 1.0.0
|
|
471
477
|
*/
|
|
@@ -10,8 +10,9 @@ import * as Option from "effect/Option"
|
|
|
10
10
|
import * as Runtime from "effect/Runtime"
|
|
11
11
|
import * as Scope from "effect/Scope"
|
|
12
12
|
|
|
13
|
-
import
|
|
14
|
-
import
|
|
13
|
+
import * as Schema from "@effect/schema/Schema"
|
|
14
|
+
import * as Exit from "effect/Exit"
|
|
15
|
+
import type * as Layer from "effect/Layer"
|
|
15
16
|
import type { Commit } from "../Layer.js"
|
|
16
17
|
import type { BeforeNavigationEvent, Destination, NavigationEvent, Transition } from "../Navigation.js"
|
|
17
18
|
import { Navigation, NavigationError } from "../Navigation.js"
|
|
@@ -41,14 +42,12 @@ declare global {
|
|
|
41
42
|
export const fromWindow: Layer.Layer<Navigation, never, Window> = Navigation.scoped(
|
|
42
43
|
Window.withEffect((window) => {
|
|
43
44
|
const getRandomValues = (length: number) => Effect.sync(() => window.crypto.getRandomValues(new Uint8Array(length)))
|
|
44
|
-
return Effect.gen(function*(
|
|
45
|
-
const { run, runPromise } = yield*
|
|
45
|
+
return Effect.gen(function*() {
|
|
46
|
+
const { run, runPromise } = yield* scopedRuntime<never>()
|
|
46
47
|
const hasNativeNavigation = !!window.navigation
|
|
47
|
-
const modelAndIntent = yield*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
: setupWithHistory(window, (event) => run(handleHistoryEvent(event)))
|
|
51
|
-
)
|
|
48
|
+
const modelAndIntent = yield* hasNativeNavigation
|
|
49
|
+
? setupWithNavigation(window.navigation!, runPromise)
|
|
50
|
+
: setupWithHistory(window, (event) => run(handleHistoryEvent(event)))
|
|
52
51
|
|
|
53
52
|
const navigation = setupFromModelAndIntent(
|
|
54
53
|
modelAndIntent,
|
|
@@ -61,26 +60,28 @@ export const fromWindow: Layer.Layer<Navigation, never, Window> = Navigation.sco
|
|
|
61
60
|
return navigation
|
|
62
61
|
|
|
63
62
|
function handleHistoryEvent(event: HistoryEvent) {
|
|
64
|
-
return Effect.gen(function*(
|
|
63
|
+
return Effect.gen(function*() {
|
|
65
64
|
if (event._tag === "PushState") {
|
|
66
|
-
return yield*
|
|
65
|
+
return yield* navigation.navigate(event.url, {}, event.skipCommit)
|
|
67
66
|
} else if (event._tag === "ReplaceState") {
|
|
68
67
|
if (Option.isSome(event.url)) {
|
|
69
|
-
return yield*
|
|
70
|
-
|
|
68
|
+
return yield* navigation.navigate(
|
|
69
|
+
event.url.value,
|
|
70
|
+
{ history: "replace", state: event.state },
|
|
71
|
+
event.skipCommit
|
|
71
72
|
)
|
|
72
73
|
} else {
|
|
73
|
-
return yield*
|
|
74
|
+
return yield* navigation.updateCurrentEntry(event)
|
|
74
75
|
}
|
|
75
76
|
} else if (event._tag === "Traverse") {
|
|
76
|
-
const { entries, index } = yield*
|
|
77
|
+
const { entries, index } = yield* modelAndIntent.state
|
|
77
78
|
const toIndex = Math.min(Math.max(0, index + event.delta), entries.length - 1)
|
|
78
79
|
const to = entries[toIndex]
|
|
79
80
|
|
|
80
|
-
return yield*
|
|
81
|
+
return yield* navigation.traverseTo(to.key, {}, event.skipCommit)
|
|
81
82
|
} else {
|
|
82
|
-
yield*
|
|
83
|
-
return yield*
|
|
83
|
+
yield* navigation.traverseTo(event.key, {}, event.skipCommit)
|
|
84
|
+
return yield* navigation.updateCurrentEntry({ state: event.state })
|
|
84
85
|
}
|
|
85
86
|
})
|
|
86
87
|
}
|
|
@@ -110,16 +111,14 @@ function setupWithNavigation(
|
|
|
110
111
|
navigation: NativeNavigation,
|
|
111
112
|
runPromise: <E, A>(effect: Effect.Effect<A, E, Scope.Scope>) => Promise<A>
|
|
112
113
|
): Effect.Effect<ModelAndIntent, never, Scope.Scope | GetRandomValues> {
|
|
113
|
-
return Effect.gen(function*(
|
|
114
|
-
const state = yield*
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
{ eq: Equivalence.make(Schema.to(Schema.to(NavigationState))) }
|
|
118
|
-
)
|
|
114
|
+
return Effect.gen(function*() {
|
|
115
|
+
const state = yield* RefSubject.fromEffect(
|
|
116
|
+
Effect.sync((): NavigationState => getNavigationState(navigation)),
|
|
117
|
+
{ eq: Equivalence.make(Schema.typeSchema(Schema.typeSchema(NavigationState))) }
|
|
119
118
|
)
|
|
120
119
|
const canGoBack = RefSubject.map(state, (s) => s.index > 0)
|
|
121
120
|
const canGoForward = RefSubject.map(state, (s) => s.index < s.entries.length - 1)
|
|
122
|
-
const { beforeHandlers, formDataHandlers, handlers } = yield*
|
|
121
|
+
const { beforeHandlers, formDataHandlers, handlers } = yield* makeHandlersState()
|
|
123
122
|
const commit: Commit = (to: Destination, event: BeforeNavigationEvent) =>
|
|
124
123
|
Effect.gen(function*(_) {
|
|
125
124
|
const { key, state, url } = to
|
|
@@ -144,8 +143,8 @@ function setupWithNavigation(
|
|
|
144
143
|
})
|
|
145
144
|
|
|
146
145
|
const runHandlers = (native: NativeEvent) =>
|
|
147
|
-
Effect.gen(function*(
|
|
148
|
-
const eventHandlers = yield*
|
|
146
|
+
Effect.gen(function*() {
|
|
147
|
+
const eventHandlers = yield* handlers
|
|
149
148
|
const matches: Array<Effect.Effect<unknown>> = []
|
|
150
149
|
|
|
151
150
|
const event: NavigationEvent = {
|
|
@@ -155,14 +154,14 @@ function setupWithNavigation(
|
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
for (const [handler, ctx] of eventHandlers) {
|
|
158
|
-
const match = yield*
|
|
157
|
+
const match = yield* Effect.provide(handler(event), ctx)
|
|
159
158
|
if (Option.isSome(match)) {
|
|
160
159
|
matches.push(Effect.provide(match.value, ctx))
|
|
161
160
|
}
|
|
162
161
|
}
|
|
163
162
|
|
|
164
163
|
if (matches.length > 0) {
|
|
165
|
-
yield*
|
|
164
|
+
yield* Effect.all(matches)
|
|
166
165
|
}
|
|
167
166
|
})
|
|
168
167
|
|
|
@@ -217,30 +216,28 @@ function setupWithHistory(
|
|
|
217
216
|
window: Window,
|
|
218
217
|
onEvent: (event: HistoryEvent) => void
|
|
219
218
|
): Effect.Effect<ModelAndIntent, never, GetRandomValues | Scope.Scope> {
|
|
220
|
-
return Effect.gen(function*(
|
|
219
|
+
return Effect.gen(function*() {
|
|
221
220
|
const { location } = window
|
|
222
221
|
const { original: history, unpatch } = patchHistory(window, onEvent)
|
|
223
222
|
|
|
224
|
-
yield*
|
|
225
|
-
|
|
226
|
-
const state = yield*
|
|
227
|
-
|
|
228
|
-
Effect.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
{ eq: Equivalence.make(Schema.to(NavigationState)) }
|
|
239
|
-
)
|
|
223
|
+
yield* Effect.addFinalizer(() => unpatch)
|
|
224
|
+
|
|
225
|
+
const state = yield* RefSubject.fromEffect(
|
|
226
|
+
Effect.suspend(() =>
|
|
227
|
+
Effect.map(
|
|
228
|
+
makeDestination(
|
|
229
|
+
new URL(location.href),
|
|
230
|
+
history.state,
|
|
231
|
+
location.origin
|
|
232
|
+
),
|
|
233
|
+
(destination): NavigationState => ({ entries: [destination], index: 0, transition: Option.none() })
|
|
234
|
+
)
|
|
235
|
+
),
|
|
236
|
+
{ eq: Equivalence.make(Schema.typeSchema(NavigationState)) }
|
|
240
237
|
)
|
|
241
238
|
const canGoBack = RefSubject.map(state, (s) => s.index > 0)
|
|
242
239
|
const canGoForward = RefSubject.map(state, (s) => s.index < s.entries.length - 1)
|
|
243
|
-
const { beforeHandlers, formDataHandlers, handlers } = yield*
|
|
240
|
+
const { beforeHandlers, formDataHandlers, handlers } = yield* makeHandlersState()
|
|
244
241
|
const commit: Commit = ({ id, key, state, url }: Destination, event: BeforeNavigationEvent) =>
|
|
245
242
|
Effect.sync(() => {
|
|
246
243
|
const { type } = event
|
package/src/internal/memory.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { Schema } from "@effect/schema"
|
|
|
2
2
|
import * as Equivalence from "@effect/schema/Equivalence"
|
|
3
3
|
import * as RefSubject from "@typed/fx/RefSubject"
|
|
4
4
|
import { GetRandomValues, getRandomValues } from "@typed/id"
|
|
5
|
-
import type { Layer } from "effect"
|
|
6
5
|
import * as Effect from "effect/Effect"
|
|
6
|
+
import type * as Layer from "effect/Layer"
|
|
7
7
|
import * as Option from "effect/Option"
|
|
8
8
|
import type * as Scope from "effect/Scope"
|
|
9
9
|
import type { Commit, InitialMemoryOptions, MemoryOptions } from "../Layer.js"
|
|
@@ -20,9 +20,9 @@ import {
|
|
|
20
20
|
|
|
21
21
|
export const memory = (options: MemoryOptions): Layer.Layer<Navigation> =>
|
|
22
22
|
Navigation.scoped(
|
|
23
|
-
Effect.gen(function*(
|
|
24
|
-
const getRandomValues = yield*
|
|
25
|
-
const modelAndIntent = yield*
|
|
23
|
+
Effect.gen(function*() {
|
|
24
|
+
const getRandomValues = yield* GetRandomValues
|
|
25
|
+
const modelAndIntent = yield* setupMemory(options)
|
|
26
26
|
const current = options.entries[options.currentIndex ?? 0]
|
|
27
27
|
const origin = options.origin ?? getOriginFromUrl(current.url)
|
|
28
28
|
const base = options.base ?? "/"
|
|
@@ -35,11 +35,11 @@ export function initialMemory(
|
|
|
35
35
|
options: InitialMemoryOptions
|
|
36
36
|
): Layer.Layer<Navigation> {
|
|
37
37
|
return Navigation.scoped(
|
|
38
|
-
Effect.gen(function*(
|
|
39
|
-
const getRandomValues = yield*
|
|
38
|
+
Effect.gen(function*() {
|
|
39
|
+
const getRandomValues = yield* GetRandomValues
|
|
40
40
|
const origin = options.origin ?? getOriginFromUrl(options.url)
|
|
41
41
|
const base = options.base ?? "/"
|
|
42
|
-
const destination = yield*
|
|
42
|
+
const destination = yield* makeDestination(getUrl(origin, options.url), options.state, origin)
|
|
43
43
|
const memoryOptions: MemoryOptions = {
|
|
44
44
|
entries: [destination],
|
|
45
45
|
origin,
|
|
@@ -47,7 +47,7 @@ export function initialMemory(
|
|
|
47
47
|
currentIndex: 0,
|
|
48
48
|
maxEntries: options.maxEntries
|
|
49
49
|
}
|
|
50
|
-
const modelAndIntent = yield*
|
|
50
|
+
const modelAndIntent = yield* setupMemory(memoryOptions)
|
|
51
51
|
|
|
52
52
|
return setupFromModelAndIntent(modelAndIntent, origin, base, getRandomValues)
|
|
53
53
|
}).pipe(Effect.provide(getRandomValues))
|
|
@@ -57,23 +57,17 @@ export function initialMemory(
|
|
|
57
57
|
function setupMemory(
|
|
58
58
|
options: MemoryOptions
|
|
59
59
|
): Effect.Effect<ModelAndIntent, never, GetRandomValues | Scope.Scope> {
|
|
60
|
-
return Effect.gen(function*(
|
|
61
|
-
const state = yield*
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
transition: Option.none()
|
|
68
|
-
}
|
|
69
|
-
}),
|
|
70
|
-
{ eq: Equivalence.make(Schema.to(NavigationState)) }
|
|
71
|
-
)
|
|
72
|
-
)
|
|
60
|
+
return Effect.gen(function*() {
|
|
61
|
+
const state = yield* RefSubject.of<NavigationState>({
|
|
62
|
+
entries: options.entries,
|
|
63
|
+
index: options.currentIndex ?? options.entries.length - 1,
|
|
64
|
+
transition: Option.none()
|
|
65
|
+
}, { eq: Equivalence.make(Schema.typeSchema(NavigationState)) })
|
|
66
|
+
|
|
73
67
|
const canGoBack = RefSubject.map(state, (s) => s.index > 0)
|
|
74
68
|
const canGoForward = RefSubject.map(state, (s) => s.index < s.entries.length - 1)
|
|
75
|
-
const { beforeHandlers, formDataHandlers, handlers } = yield*
|
|
76
|
-
const commit: Commit = options.commit ?? (() => Effect.
|
|
69
|
+
const { beforeHandlers, formDataHandlers, handlers } = yield* makeHandlersState()
|
|
70
|
+
const commit: Commit = options.commit ?? (() => Effect.void)
|
|
77
71
|
|
|
78
72
|
return {
|
|
79
73
|
state,
|