@typed/navigation 0.17.0 → 0.18.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 +5 -5
- package/dist/cjs/Blocking.js.map +1 -1
- package/dist/cjs/Layer.js +2 -2
- package/dist/cjs/Layer.js.map +1 -1
- package/dist/cjs/Navigation.js +21 -18
- package/dist/cjs/Navigation.js.map +1 -1
- package/dist/cjs/internal/fromWindow.js +60 -45
- package/dist/cjs/internal/fromWindow.js.map +1 -1
- package/dist/cjs/internal/memory.js +4 -4
- package/dist/cjs/internal/memory.js.map +1 -1
- package/dist/cjs/internal/shared.js +20 -17
- package/dist/cjs/internal/shared.js.map +1 -1
- package/dist/dts/Blocking.d.ts.map +1 -1
- package/dist/dts/Navigation.d.ts +21 -32
- package/dist/dts/Navigation.d.ts.map +1 -1
- package/dist/dts/internal/fromWindow.d.ts.map +1 -1
- package/dist/dts/internal/memory.d.ts.map +1 -1
- package/dist/dts/internal/shared.d.ts +11 -14
- package/dist/dts/internal/shared.d.ts.map +1 -1
- package/dist/esm/Navigation.js +8 -7
- package/dist/esm/Navigation.js.map +1 -1
- package/dist/esm/internal/fromWindow.js +99 -40
- package/dist/esm/internal/fromWindow.js.map +1 -1
- package/dist/esm/internal/shared.js +34 -18
- package/dist/esm/internal/shared.js.map +1 -1
- package/package.json +9 -8
- package/src/Navigation.ts +33 -31
- package/src/internal/fromWindow.ts +205 -64
- package/src/internal/shared.ts +150 -58
package/src/Navigation.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { HttpClientError, HttpClientResponse } from "@effect/platform"
|
|
5
6
|
import type * as HttpClient from "@effect/platform/HttpClient"
|
|
6
7
|
import { ParseResult } from "@effect/schema"
|
|
7
8
|
import * as Equivalence from "@effect/schema/Equivalence"
|
|
@@ -68,9 +69,9 @@ export interface Navigation {
|
|
|
68
69
|
data: FormData,
|
|
69
70
|
formInput?: Simplify<Omit<FormInputFrom, "data">>
|
|
70
71
|
) => Effect.Effect<
|
|
71
|
-
Option.Option<
|
|
72
|
-
NavigationError |
|
|
73
|
-
Scope.Scope | HttpClient.
|
|
72
|
+
Option.Option<HttpClientResponse.HttpClientResponse>,
|
|
73
|
+
NavigationError | HttpClientError.HttpClientError,
|
|
74
|
+
Scope.Scope | HttpClient.HttpClient.Service
|
|
74
75
|
>
|
|
75
76
|
|
|
76
77
|
readonly onFormData: <R = never, R2 = never>(
|
|
@@ -234,7 +235,7 @@ export type FormDataHandler<R, R2> = (
|
|
|
234
235
|
event: FormDataEvent
|
|
235
236
|
) => Effect.Effect<
|
|
236
237
|
Option.Option<
|
|
237
|
-
Effect.Effect<Option.Option<
|
|
238
|
+
Effect.Effect<Option.Option<HttpClientResponse.HttpClientResponse>, RedirectError | CancelNavigation, R2>
|
|
238
239
|
>,
|
|
239
240
|
RedirectError | CancelNavigation,
|
|
240
241
|
R
|
|
@@ -283,8 +284,8 @@ export const FileSchemaFrom = Schema.Struct({
|
|
|
283
284
|
*/
|
|
284
285
|
export type FileSchemaFrom = Schema.Schema.Encoded<typeof FileSchemaFrom>
|
|
285
286
|
|
|
286
|
-
const decodeBase64 = ParseResult.decode(Schema.
|
|
287
|
-
const encodeBase64 = ParseResult.encode(Schema.
|
|
287
|
+
const decodeBase64 = ParseResult.decode(Schema.Uint8ArrayFromBase64Url)
|
|
288
|
+
const encodeBase64 = ParseResult.encode(Schema.Uint8ArrayFromBase64Url)
|
|
288
289
|
|
|
289
290
|
/**
|
|
290
291
|
* @since 1.0.0
|
|
@@ -306,27 +307,28 @@ export const FileSchema = FileSchemaFrom.pipe(
|
|
|
306
307
|
/**
|
|
307
308
|
* @since 1.0.0
|
|
308
309
|
*/
|
|
309
|
-
export const FormDataSchema = Schema.Record(Schema.String, Schema.Union(Schema.String, FileSchema))
|
|
310
|
-
|
|
311
|
-
Schema.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
310
|
+
export const FormDataSchema = Schema.Record({ key: Schema.String, value: Schema.Union(Schema.String, FileSchema) })
|
|
311
|
+
.pipe(
|
|
312
|
+
Schema.transform(
|
|
313
|
+
Schema.instanceOf(FormData),
|
|
314
|
+
{
|
|
315
|
+
decode: (formData) => {
|
|
316
|
+
const data = new FormData()
|
|
317
|
+
|
|
318
|
+
for (const [key, value] of Object.entries(formData)) {
|
|
319
|
+
if (value instanceof File) {
|
|
320
|
+
data.append(key, value, value.name)
|
|
321
|
+
} else {
|
|
322
|
+
data.append(key, value)
|
|
323
|
+
}
|
|
321
324
|
}
|
|
322
|
-
}
|
|
323
325
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
return data
|
|
327
|
+
},
|
|
328
|
+
encode: (formData) => Object.fromEntries(formData.entries())
|
|
329
|
+
}
|
|
330
|
+
)
|
|
328
331
|
)
|
|
329
|
-
)
|
|
330
332
|
|
|
331
333
|
const optionNullable = { as: "Option", nullable: true } as const
|
|
332
334
|
|
|
@@ -334,10 +336,10 @@ const optionNullable = { as: "Option", nullable: true } as const
|
|
|
334
336
|
* @since 1.0.0
|
|
335
337
|
*/
|
|
336
338
|
export const FormInputSchema = Schema.Struct({
|
|
337
|
-
name: Schema.
|
|
338
|
-
action: Schema.
|
|
339
|
-
method: Schema.
|
|
340
|
-
encoding: Schema.
|
|
339
|
+
name: Schema.optionalWith(Schema.String, optionNullable),
|
|
340
|
+
action: Schema.optionalWith(Schema.String, optionNullable),
|
|
341
|
+
method: Schema.optionalWith(Schema.String, optionNullable),
|
|
342
|
+
encoding: Schema.optionalWith(Schema.String, optionNullable),
|
|
341
343
|
data: FormDataSchema
|
|
342
344
|
})
|
|
343
345
|
|
|
@@ -515,9 +517,9 @@ export function submit(
|
|
|
515
517
|
data: FormData,
|
|
516
518
|
formInput?: Simplify<Omit<FormInputFrom, "data">>
|
|
517
519
|
): Effect.Effect<
|
|
518
|
-
Option.Option<
|
|
519
|
-
NavigationError |
|
|
520
|
-
Navigation | HttpClient.
|
|
520
|
+
Option.Option<HttpClientResponse.HttpClientResponse>,
|
|
521
|
+
NavigationError | HttpClientError.HttpClientError,
|
|
522
|
+
Navigation | HttpClient.HttpClient.Service | Scope.Scope
|
|
521
523
|
> {
|
|
522
524
|
return Navigation.withEffect((n) => n.submit(data, formInput))
|
|
523
525
|
}
|
|
@@ -16,7 +16,7 @@ import type * as Layer from "effect/Layer"
|
|
|
16
16
|
import type { Commit } from "../Layer.js"
|
|
17
17
|
import type { BeforeNavigationEvent, Destination, NavigationEvent, Transition } from "../Navigation.js"
|
|
18
18
|
import { Navigation, NavigationError } from "../Navigation.js"
|
|
19
|
-
import type { ModelAndIntent } from "./shared.js"
|
|
19
|
+
import type { ModelAndIntent, PatchedState } from "./shared.js"
|
|
20
20
|
import {
|
|
21
21
|
getOriginalState,
|
|
22
22
|
getUrl,
|
|
@@ -54,7 +54,9 @@ export const fromWindow: Layer.Layer<Navigation, never, Window> = Navigation.sco
|
|
|
54
54
|
window.location.origin,
|
|
55
55
|
getBaseHref(window),
|
|
56
56
|
getRandomValues,
|
|
57
|
-
hasNativeNavigation
|
|
57
|
+
hasNativeNavigation
|
|
58
|
+
? () => getNavigationState(window.navigation!)
|
|
59
|
+
: undefined
|
|
58
60
|
)
|
|
59
61
|
|
|
60
62
|
return navigation
|
|
@@ -62,7 +64,11 @@ export const fromWindow: Layer.Layer<Navigation, never, Window> = Navigation.sco
|
|
|
62
64
|
function handleHistoryEvent(event: HistoryEvent) {
|
|
63
65
|
return Effect.gen(function*() {
|
|
64
66
|
if (event._tag === "PushState") {
|
|
65
|
-
return yield* navigation.navigate(
|
|
67
|
+
return yield* navigation.navigate(
|
|
68
|
+
event.url,
|
|
69
|
+
{},
|
|
70
|
+
event.skipCommit
|
|
71
|
+
)
|
|
66
72
|
} else if (event._tag === "ReplaceState") {
|
|
67
73
|
if (Option.isSome(event.url)) {
|
|
68
74
|
return yield* navigation.navigate(
|
|
@@ -75,19 +81,28 @@ export const fromWindow: Layer.Layer<Navigation, never, Window> = Navigation.sco
|
|
|
75
81
|
}
|
|
76
82
|
} else if (event._tag === "Traverse") {
|
|
77
83
|
const { entries, index } = yield* modelAndIntent.state
|
|
78
|
-
const toIndex = Math.min(
|
|
84
|
+
const toIndex = Math.min(
|
|
85
|
+
Math.max(0, index + event.delta),
|
|
86
|
+
entries.length - 1
|
|
87
|
+
)
|
|
79
88
|
const to = entries[toIndex]
|
|
80
89
|
|
|
81
|
-
|
|
90
|
+
const result = yield* navigation.traverseTo(
|
|
91
|
+
to.key,
|
|
92
|
+
{},
|
|
93
|
+
event.skipCommit
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return result
|
|
82
97
|
} else {
|
|
83
98
|
yield* navigation.traverseTo(event.key, {}, event.skipCommit)
|
|
84
|
-
return yield* navigation.updateCurrentEntry({
|
|
99
|
+
return yield* navigation.updateCurrentEntry({
|
|
100
|
+
state: event.state
|
|
101
|
+
})
|
|
85
102
|
}
|
|
86
103
|
})
|
|
87
104
|
}
|
|
88
|
-
}).pipe(
|
|
89
|
-
GetRandomValues.provide(getRandomValues)
|
|
90
|
-
)
|
|
105
|
+
}).pipe(GetRandomValues.provide(getRandomValues))
|
|
91
106
|
})
|
|
92
107
|
)
|
|
93
108
|
|
|
@@ -114,10 +129,17 @@ function setupWithNavigation(
|
|
|
114
129
|
return Effect.gen(function*() {
|
|
115
130
|
const state = yield* RefSubject.fromEffect(
|
|
116
131
|
Effect.sync((): NavigationState => getNavigationState(navigation)),
|
|
117
|
-
{
|
|
132
|
+
{
|
|
133
|
+
eq: Equivalence.make(
|
|
134
|
+
Schema.typeSchema(Schema.typeSchema(NavigationState))
|
|
135
|
+
)
|
|
136
|
+
}
|
|
118
137
|
)
|
|
119
138
|
const canGoBack = RefSubject.map(state, (s) => s.index > 0)
|
|
120
|
-
const canGoForward = RefSubject.map(
|
|
139
|
+
const canGoForward = RefSubject.map(
|
|
140
|
+
state,
|
|
141
|
+
(s) => s.index < s.entries.length - 1
|
|
142
|
+
)
|
|
121
143
|
const { beforeHandlers, formDataHandlers, handlers } = yield* makeHandlersState()
|
|
122
144
|
const commit: Commit = (to: Destination, event: BeforeNavigationEvent) =>
|
|
123
145
|
Effect.gen(function*(_) {
|
|
@@ -126,7 +148,14 @@ function setupWithNavigation(
|
|
|
126
148
|
|
|
127
149
|
if (type === "push" || type === "replace") {
|
|
128
150
|
yield* _(
|
|
129
|
-
Effect.promise(
|
|
151
|
+
Effect.promise(
|
|
152
|
+
() =>
|
|
153
|
+
navigation.navigate(url.toString(), {
|
|
154
|
+
history: type,
|
|
155
|
+
state,
|
|
156
|
+
info
|
|
157
|
+
}).committed
|
|
158
|
+
),
|
|
130
159
|
Effect.catchAllDefect((error) => Effect.fail(new NavigationError({ error })))
|
|
131
160
|
)
|
|
132
161
|
} else if (event.type === "reload") {
|
|
@@ -136,7 +165,9 @@ function setupWithNavigation(
|
|
|
136
165
|
)
|
|
137
166
|
} else {
|
|
138
167
|
yield* _(
|
|
139
|
-
Effect.promise(
|
|
168
|
+
Effect.promise(
|
|
169
|
+
() => navigation.traverseTo(key, { info }).committed
|
|
170
|
+
),
|
|
140
171
|
Effect.catchAllDefect((error) => Effect.fail(new NavigationError({ error })))
|
|
141
172
|
)
|
|
142
173
|
}
|
|
@@ -218,7 +249,11 @@ function setupWithHistory(
|
|
|
218
249
|
): Effect.Effect<ModelAndIntent, never, GetRandomValues | Scope.Scope> {
|
|
219
250
|
return Effect.gen(function*() {
|
|
220
251
|
const { location } = window
|
|
221
|
-
const {
|
|
252
|
+
const {
|
|
253
|
+
getHistoryState,
|
|
254
|
+
original: history,
|
|
255
|
+
unpatch
|
|
256
|
+
} = patchHistory(window, onEvent)
|
|
222
257
|
|
|
223
258
|
yield* Effect.addFinalizer(() => unpatch)
|
|
224
259
|
|
|
@@ -227,29 +262,65 @@ function setupWithHistory(
|
|
|
227
262
|
Effect.map(
|
|
228
263
|
makeDestination(
|
|
229
264
|
new URL(location.href),
|
|
230
|
-
|
|
265
|
+
getHistoryState(),
|
|
231
266
|
location.origin
|
|
232
267
|
),
|
|
233
|
-
(destination): NavigationState => ({
|
|
268
|
+
(destination): NavigationState => ({
|
|
269
|
+
entries: [destination],
|
|
270
|
+
index: 0,
|
|
271
|
+
transition: Option.none()
|
|
272
|
+
})
|
|
234
273
|
)
|
|
235
274
|
),
|
|
236
275
|
{ eq: Equivalence.make(Schema.typeSchema(NavigationState)) }
|
|
237
276
|
)
|
|
238
277
|
const canGoBack = RefSubject.map(state, (s) => s.index > 0)
|
|
239
|
-
const canGoForward = RefSubject.map(
|
|
278
|
+
const canGoForward = RefSubject.map(
|
|
279
|
+
state,
|
|
280
|
+
(s) => s.index < s.entries.length - 1
|
|
281
|
+
)
|
|
240
282
|
const { beforeHandlers, formDataHandlers, handlers } = yield* makeHandlersState()
|
|
241
|
-
const commit: Commit = (
|
|
283
|
+
const commit: Commit = (
|
|
284
|
+
{ id, key, state, url }: Destination,
|
|
285
|
+
event: BeforeNavigationEvent
|
|
286
|
+
) =>
|
|
242
287
|
Effect.sync(() => {
|
|
243
288
|
const { type } = event
|
|
244
289
|
|
|
245
290
|
if (type === "push") {
|
|
246
|
-
history.pushState(
|
|
291
|
+
history.pushState(
|
|
292
|
+
{
|
|
293
|
+
__typed__navigation__id__: id,
|
|
294
|
+
__typed__navigation__key__: key,
|
|
295
|
+
__typed__navigation__state__: state
|
|
296
|
+
},
|
|
297
|
+
"",
|
|
298
|
+
url
|
|
299
|
+
)
|
|
247
300
|
} else if (type === "replace") {
|
|
248
|
-
history.replaceState(
|
|
301
|
+
history.replaceState(
|
|
302
|
+
{
|
|
303
|
+
__typed__navigation__id__: id,
|
|
304
|
+
__typed__navigation__key__: key,
|
|
305
|
+
__typed__navigation__state__: state
|
|
306
|
+
},
|
|
307
|
+
"",
|
|
308
|
+
url
|
|
309
|
+
)
|
|
249
310
|
} else if (event.type === "reload") {
|
|
250
311
|
location.reload()
|
|
251
312
|
} else {
|
|
252
313
|
history.go(event.delta)
|
|
314
|
+
|
|
315
|
+
history.replaceState(
|
|
316
|
+
{
|
|
317
|
+
__typed__navigation__id__: id,
|
|
318
|
+
__typed__navigation__key__: key,
|
|
319
|
+
__typed__navigation__state__: state
|
|
320
|
+
},
|
|
321
|
+
"",
|
|
322
|
+
window.location.href
|
|
323
|
+
)
|
|
253
324
|
}
|
|
254
325
|
})
|
|
255
326
|
|
|
@@ -265,16 +336,36 @@ function setupWithHistory(
|
|
|
265
336
|
})
|
|
266
337
|
}
|
|
267
338
|
|
|
268
|
-
type HistoryEvent =
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
339
|
+
type HistoryEvent =
|
|
340
|
+
| PushStateEvent
|
|
341
|
+
| ReplaceStateEvent
|
|
342
|
+
| TraverseEvent
|
|
343
|
+
| TraverseToEvent
|
|
344
|
+
|
|
345
|
+
type PushStateEvent = {
|
|
346
|
+
_tag: "PushState"
|
|
347
|
+
state: unknown
|
|
348
|
+
url: URL
|
|
349
|
+
skipCommit: boolean
|
|
350
|
+
}
|
|
351
|
+
type ReplaceStateEvent = {
|
|
352
|
+
_tag: "ReplaceState"
|
|
353
|
+
state: unknown
|
|
354
|
+
url: Option.Option<URL>
|
|
355
|
+
skipCommit: boolean
|
|
356
|
+
}
|
|
272
357
|
type TraverseEvent = { _tag: "Traverse"; delta: number; skipCommit: boolean }
|
|
273
|
-
type TraverseToEvent = {
|
|
358
|
+
type TraverseToEvent = {
|
|
359
|
+
_tag: "TraverseTo"
|
|
360
|
+
key: Uuid
|
|
361
|
+
state: unknown
|
|
362
|
+
skipCommit: boolean
|
|
363
|
+
}
|
|
274
364
|
|
|
275
365
|
function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
|
|
276
366
|
const { history, location } = window
|
|
277
|
-
const stateDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(history), "state")
|
|
367
|
+
const stateDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(history), "state") ||
|
|
368
|
+
Object.getOwnPropertyDescriptor(history, "state")
|
|
278
369
|
|
|
279
370
|
const methods = {
|
|
280
371
|
pushState: history.pushState.bind(history),
|
|
@@ -283,7 +374,9 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
|
|
|
283
374
|
back: history.back.bind(history),
|
|
284
375
|
forward: history.forward.bind(history)
|
|
285
376
|
}
|
|
286
|
-
const
|
|
377
|
+
const getStateDescriptor = stateDescriptor?.get?.bind(history)
|
|
378
|
+
|
|
379
|
+
const getHistoryState = () => getStateDescriptor?.()
|
|
287
380
|
|
|
288
381
|
const original: History = {
|
|
289
382
|
get length() {
|
|
@@ -296,30 +389,32 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
|
|
|
296
389
|
history.scrollRestoration = mode
|
|
297
390
|
},
|
|
298
391
|
get state() {
|
|
299
|
-
return
|
|
392
|
+
return getHistoryState()
|
|
300
393
|
},
|
|
301
394
|
...methods,
|
|
302
395
|
pushState(data, _, url) {
|
|
303
|
-
|
|
304
|
-
;(history as any).state = data
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return methods.pushState(data, _, url)
|
|
396
|
+
return methods.pushState(data, _, url?.toString())
|
|
308
397
|
},
|
|
309
398
|
replaceState(data, _, url) {
|
|
310
|
-
|
|
311
|
-
;(history as any).state = data
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
return methods.replaceState(data, _, url)
|
|
399
|
+
return methods.replaceState(data, _, url?.toString())
|
|
315
400
|
}
|
|
316
401
|
}
|
|
317
402
|
|
|
318
403
|
history.pushState = (state, _, url) => {
|
|
319
404
|
if (url) {
|
|
320
|
-
onEvent({
|
|
405
|
+
onEvent({
|
|
406
|
+
_tag: "PushState",
|
|
407
|
+
state,
|
|
408
|
+
url: getUrl(location.origin, url),
|
|
409
|
+
skipCommit: false
|
|
410
|
+
})
|
|
321
411
|
} else {
|
|
322
|
-
onEvent({
|
|
412
|
+
onEvent({
|
|
413
|
+
_tag: "ReplaceState",
|
|
414
|
+
state,
|
|
415
|
+
url: Option.none(),
|
|
416
|
+
skipCommit: false
|
|
417
|
+
})
|
|
323
418
|
}
|
|
324
419
|
}
|
|
325
420
|
history.replaceState = (state, _, url) => {
|
|
@@ -342,30 +437,32 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
|
|
|
342
437
|
onEvent({ _tag: "Traverse", delta: 1, skipCommit: false })
|
|
343
438
|
}
|
|
344
439
|
|
|
345
|
-
// In a proper browser this will allow patching to hide the id/key's associated with the state
|
|
346
|
-
if (stateDescriptor) {
|
|
347
|
-
try {
|
|
348
|
-
Object.defineProperty(history, "state", {
|
|
349
|
-
get() {
|
|
350
|
-
return getOriginalState(stateDescriptor.get!.call(history))
|
|
351
|
-
}
|
|
352
|
-
})
|
|
353
|
-
} catch {
|
|
354
|
-
// We tried, but it didn't work
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
440
|
const onHashChange = (ev: HashChangeEvent) => {
|
|
359
|
-
onEvent({
|
|
441
|
+
onEvent({
|
|
442
|
+
_tag: "ReplaceState",
|
|
443
|
+
state: history.state,
|
|
444
|
+
url: Option.some(new URL(ev.newURL)),
|
|
445
|
+
skipCommit: false
|
|
446
|
+
})
|
|
360
447
|
}
|
|
361
448
|
|
|
362
449
|
window.addEventListener("hashchange", onHashChange, { capture: true })
|
|
363
450
|
|
|
364
451
|
const onPopState = (ev: PopStateEvent) => {
|
|
365
452
|
if (isPatchedState(ev.state)) {
|
|
366
|
-
onEvent({
|
|
453
|
+
onEvent({
|
|
454
|
+
_tag: "TraverseTo",
|
|
455
|
+
key: ev.state.__typed__navigation__key__,
|
|
456
|
+
state: ev.state.__typed__navigation__state__,
|
|
457
|
+
skipCommit: true
|
|
458
|
+
})
|
|
367
459
|
} else {
|
|
368
|
-
onEvent({
|
|
460
|
+
onEvent({
|
|
461
|
+
_tag: "ReplaceState",
|
|
462
|
+
state: ev.state,
|
|
463
|
+
url: Option.some(new URL(location.href)),
|
|
464
|
+
skipCommit: true
|
|
465
|
+
})
|
|
369
466
|
}
|
|
370
467
|
}
|
|
371
468
|
|
|
@@ -390,7 +487,39 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
|
|
|
390
487
|
window.removeEventListener("popstate", onPopState)
|
|
391
488
|
})
|
|
392
489
|
|
|
490
|
+
Object.defineProperty(history, "state", {
|
|
491
|
+
get() {
|
|
492
|
+
console.log("here")
|
|
493
|
+
return getOriginalState(getStateDescriptor?.() ?? history.state)
|
|
494
|
+
},
|
|
495
|
+
set(value) {
|
|
496
|
+
const { __typed__navigation__id__, __typed__navigation__key__ } = getStateDescriptor?.() ?? original.state
|
|
497
|
+
|
|
498
|
+
if (isPatchedState(value)) {
|
|
499
|
+
// The setter is not actually modifying the history.state
|
|
500
|
+
// We need to call the original replaceState to update the actual state
|
|
501
|
+
original.replaceState.call(history, value, "", location.href)
|
|
502
|
+
} else {
|
|
503
|
+
// The setter is not actually modifying the history.state
|
|
504
|
+
// We need to call the original replaceState to update the actual state
|
|
505
|
+
original.replaceState.call(
|
|
506
|
+
history,
|
|
507
|
+
{
|
|
508
|
+
__typed__navigation__id__,
|
|
509
|
+
__typed__navigation__key__,
|
|
510
|
+
__typed__navigation__state__: value
|
|
511
|
+
} satisfies PatchedState,
|
|
512
|
+
"",
|
|
513
|
+
location.href
|
|
514
|
+
)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return value
|
|
518
|
+
}
|
|
519
|
+
})
|
|
520
|
+
|
|
393
521
|
return {
|
|
522
|
+
getHistoryState,
|
|
394
523
|
original,
|
|
395
524
|
patched: history,
|
|
396
525
|
unpatch
|
|
@@ -400,21 +529,33 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
|
|
|
400
529
|
type ScopedRuntime<R> = {
|
|
401
530
|
readonly runtime: Runtime.Runtime<R | Scope.Scope>
|
|
402
531
|
readonly scope: Scope.Scope
|
|
403
|
-
readonly run: <E, A>(
|
|
404
|
-
|
|
532
|
+
readonly run: <E, A>(
|
|
533
|
+
effect: Effect.Effect<A, E, R | Scope.Scope>
|
|
534
|
+
) => Fiber.RuntimeFiber<A, E>
|
|
535
|
+
readonly runPromise: <E, A>(
|
|
536
|
+
effect: Effect.Effect<A, E, R | Scope.Scope>
|
|
537
|
+
) => Promise<A>
|
|
405
538
|
}
|
|
406
539
|
|
|
407
|
-
function scopedRuntime<R>(): Effect.Effect<
|
|
540
|
+
function scopedRuntime<R>(): Effect.Effect<
|
|
541
|
+
ScopedRuntime<R>,
|
|
542
|
+
never,
|
|
543
|
+
R | Scope.Scope
|
|
544
|
+
> {
|
|
408
545
|
return Effect.map(Effect.runtime<R | Scope.Scope>(), (runtime) => {
|
|
409
546
|
const scope = Context.get(runtime.context, Scope.Scope)
|
|
410
547
|
const runFork = Runtime.runFork(runtime)
|
|
411
|
-
const runPromise = <E, A>(
|
|
548
|
+
const runPromise = <E, A>(
|
|
549
|
+
effect: Effect.Effect<A, E, R | Scope.Scope>
|
|
550
|
+
): Promise<A> =>
|
|
412
551
|
new Promise((resolve, reject) => {
|
|
413
552
|
const fiber = runFork(effect, { scope })
|
|
414
|
-
fiber.addObserver(
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
553
|
+
fiber.addObserver(
|
|
554
|
+
Exit.match({
|
|
555
|
+
onFailure: (cause) => reject(Runtime.makeFiberFailure(cause)),
|
|
556
|
+
onSuccess: resolve
|
|
557
|
+
})
|
|
558
|
+
)
|
|
418
559
|
})
|
|
419
560
|
|
|
420
561
|
return {
|