@typed/navigation 0.5.3 → 0.6.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.
Files changed (186) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/dist/cjs/Blocking.js +53 -0
  4. package/dist/cjs/Blocking.js.map +1 -0
  5. package/dist/cjs/Layer.js +27 -0
  6. package/dist/cjs/Layer.js.map +1 -0
  7. package/dist/cjs/Navigation.js +184 -62
  8. package/dist/cjs/Navigation.js.map +1 -1
  9. package/dist/cjs/index.js +36 -17
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/internal/fromWindow.js +376 -0
  12. package/dist/cjs/internal/fromWindow.js.map +1 -0
  13. package/dist/cjs/internal/memory.js +67 -0
  14. package/dist/cjs/internal/memory.js.map +1 -0
  15. package/dist/cjs/internal/shared.js +403 -0
  16. package/dist/cjs/internal/shared.js.map +1 -0
  17. package/dist/dts/Blocking.d.ts +33 -0
  18. package/dist/dts/Blocking.d.ts.map +1 -0
  19. package/dist/dts/Layer.d.ts +44 -0
  20. package/dist/dts/Layer.d.ts.map +1 -0
  21. package/dist/dts/Navigation.d.ts +377 -0
  22. package/dist/dts/Navigation.d.ts.map +1 -0
  23. package/dist/dts/index.d.ts +17 -0
  24. package/dist/dts/index.d.ts.map +1 -0
  25. package/dist/dts/internal/fromWindow.d.ts +12 -0
  26. package/dist/dts/internal/fromWindow.d.ts.map +1 -0
  27. package/dist/dts/internal/memory.d.ts +6 -0
  28. package/dist/dts/internal/memory.d.ts.map +1 -0
  29. package/dist/dts/internal/shared.d.ts +139 -0
  30. package/dist/dts/internal/shared.d.ts.map +1 -0
  31. package/dist/esm/Blocking.js +39 -0
  32. package/dist/esm/Blocking.js.map +1 -0
  33. package/dist/esm/Layer.js +18 -0
  34. package/dist/esm/Layer.js.map +1 -0
  35. package/dist/esm/Navigation.js +166 -0
  36. package/dist/esm/Navigation.js.map +1 -0
  37. package/dist/esm/index.js +17 -0
  38. package/dist/esm/index.js.map +1 -0
  39. package/dist/esm/internal/fromWindow.js +273 -0
  40. package/dist/esm/internal/fromWindow.js.map +1 -0
  41. package/dist/esm/internal/memory.js +54 -0
  42. package/dist/esm/internal/memory.js.map +1 -0
  43. package/dist/esm/internal/shared.js +336 -0
  44. package/dist/esm/internal/shared.js.map +1 -0
  45. package/dist/esm/package.json +4 -0
  46. package/package.json +52 -32
  47. package/src/Blocking.ts +102 -0
  48. package/src/Layer.ts +53 -0
  49. package/src/Navigation.ts +342 -159
  50. package/src/index.ts +17 -3
  51. package/src/internal/fromWindow.ts +421 -0
  52. package/src/internal/memory.ts +79 -0
  53. package/src/internal/shared.ts +514 -0
  54. package/dist/DOM.d.ts +0 -12
  55. package/dist/DOM.d.ts.map +0 -1
  56. package/dist/DOM.js +0 -87
  57. package/dist/DOM.js.map +0 -1
  58. package/dist/Memory.d.ts +0 -10
  59. package/dist/Memory.d.ts.map +0 -1
  60. package/dist/Memory.js +0 -55
  61. package/dist/Memory.js.map +0 -1
  62. package/dist/Navigation.d.ts +0 -116
  63. package/dist/Navigation.d.ts.map +0 -1
  64. package/dist/Navigation.js +0 -36
  65. package/dist/Navigation.js.map +0 -1
  66. package/dist/_makeServerWindow.d.ts +0 -16
  67. package/dist/_makeServerWindow.d.ts.map +0 -1
  68. package/dist/_makeServerWindow.js +0 -9
  69. package/dist/_makeServerWindow.js.map +0 -1
  70. package/dist/cjs/DOM.d.ts +0 -12
  71. package/dist/cjs/DOM.d.ts.map +0 -1
  72. package/dist/cjs/DOM.js +0 -116
  73. package/dist/cjs/DOM.js.map +0 -1
  74. package/dist/cjs/Memory.d.ts +0 -10
  75. package/dist/cjs/Memory.d.ts.map +0 -1
  76. package/dist/cjs/Memory.js +0 -82
  77. package/dist/cjs/Memory.js.map +0 -1
  78. package/dist/cjs/Navigation.d.ts +0 -116
  79. package/dist/cjs/Navigation.d.ts.map +0 -1
  80. package/dist/cjs/_makeServerWindow.d.ts +0 -16
  81. package/dist/cjs/_makeServerWindow.d.ts.map +0 -1
  82. package/dist/cjs/_makeServerWindow.js +0 -36
  83. package/dist/cjs/_makeServerWindow.js.map +0 -1
  84. package/dist/cjs/constant.d.ts +0 -2
  85. package/dist/cjs/constant.d.ts.map +0 -1
  86. package/dist/cjs/constant.js +0 -30
  87. package/dist/cjs/constant.js.map +0 -1
  88. package/dist/cjs/dom-intent.d.ts +0 -28
  89. package/dist/cjs/dom-intent.d.ts.map +0 -1
  90. package/dist/cjs/dom-intent.js +0 -172
  91. package/dist/cjs/dom-intent.js.map +0 -1
  92. package/dist/cjs/history.d.ts +0 -31
  93. package/dist/cjs/history.d.ts.map +0 -1
  94. package/dist/cjs/history.js +0 -131
  95. package/dist/cjs/history.js.map +0 -1
  96. package/dist/cjs/index.d.ts +0 -4
  97. package/dist/cjs/index.d.ts.map +0 -1
  98. package/dist/cjs/json.d.ts +0 -13
  99. package/dist/cjs/json.d.ts.map +0 -1
  100. package/dist/cjs/json.js +0 -24
  101. package/dist/cjs/json.js.map +0 -1
  102. package/dist/cjs/memory-intent.d.ts +0 -27
  103. package/dist/cjs/memory-intent.d.ts.map +0 -1
  104. package/dist/cjs/memory-intent.js +0 -156
  105. package/dist/cjs/memory-intent.js.map +0 -1
  106. package/dist/cjs/model.d.ts +0 -22
  107. package/dist/cjs/model.d.ts.map +0 -1
  108. package/dist/cjs/model.js +0 -48
  109. package/dist/cjs/model.js.map +0 -1
  110. package/dist/cjs/shared-intent.d.ts +0 -14
  111. package/dist/cjs/shared-intent.d.ts.map +0 -1
  112. package/dist/cjs/shared-intent.js +0 -82
  113. package/dist/cjs/shared-intent.js.map +0 -1
  114. package/dist/cjs/storage.d.ts +0 -19
  115. package/dist/cjs/storage.d.ts.map +0 -1
  116. package/dist/cjs/storage.js +0 -101
  117. package/dist/cjs/storage.js.map +0 -1
  118. package/dist/cjs/util.d.ts +0 -5
  119. package/dist/cjs/util.d.ts.map +0 -1
  120. package/dist/cjs/util.js +0 -39
  121. package/dist/cjs/util.js.map +0 -1
  122. package/dist/constant.d.ts +0 -2
  123. package/dist/constant.d.ts.map +0 -1
  124. package/dist/constant.js +0 -4
  125. package/dist/constant.js.map +0 -1
  126. package/dist/dom-intent.d.ts +0 -28
  127. package/dist/dom-intent.d.ts.map +0 -1
  128. package/dist/dom-intent.js +0 -140
  129. package/dist/dom-intent.js.map +0 -1
  130. package/dist/history.d.ts +0 -31
  131. package/dist/history.d.ts.map +0 -1
  132. package/dist/history.js +0 -104
  133. package/dist/history.js.map +0 -1
  134. package/dist/index.d.ts +0 -4
  135. package/dist/index.d.ts.map +0 -1
  136. package/dist/index.js +0 -4
  137. package/dist/index.js.map +0 -1
  138. package/dist/intent.d.ts +0 -31
  139. package/dist/intent.d.ts.map +0 -1
  140. package/dist/intent.js +0 -157
  141. package/dist/intent.js.map +0 -1
  142. package/dist/json.d.ts +0 -13
  143. package/dist/json.d.ts.map +0 -1
  144. package/dist/json.js +0 -17
  145. package/dist/json.js.map +0 -1
  146. package/dist/memory-intent.d.ts +0 -27
  147. package/dist/memory-intent.d.ts.map +0 -1
  148. package/dist/memory-intent.js +0 -124
  149. package/dist/memory-intent.js.map +0 -1
  150. package/dist/model.d.ts +0 -22
  151. package/dist/model.d.ts.map +0 -1
  152. package/dist/model.js +0 -21
  153. package/dist/model.js.map +0 -1
  154. package/dist/shared-intent.d.ts +0 -14
  155. package/dist/shared-intent.d.ts.map +0 -1
  156. package/dist/shared-intent.js +0 -51
  157. package/dist/shared-intent.js.map +0 -1
  158. package/dist/storage.d.ts +0 -19
  159. package/dist/storage.d.ts.map +0 -1
  160. package/dist/storage.js +0 -73
  161. package/dist/storage.js.map +0 -1
  162. package/dist/tsconfig.cjs.build.tsbuildinfo +0 -1
  163. package/dist/util.d.ts +0 -5
  164. package/dist/util.d.ts.map +0 -1
  165. package/dist/util.js +0 -12
  166. package/dist/util.js.map +0 -1
  167. package/eslintrc.json +0 -3
  168. package/project.json +0 -46
  169. package/src/DOM.test.ts +0 -699
  170. package/src/DOM.ts +0 -163
  171. package/src/Memory.test.ts +0 -464
  172. package/src/Memory.ts +0 -102
  173. package/src/_makeServerWindow.ts +0 -28
  174. package/src/dom-intent.ts +0 -268
  175. package/src/history.ts +0 -165
  176. package/src/json.ts +0 -31
  177. package/src/memory-intent.ts +0 -224
  178. package/src/model.ts +0 -54
  179. package/src/shared-intent.ts +0 -117
  180. package/src/storage.ts +0 -101
  181. package/src/util.ts +0 -20
  182. package/tsconfig.build.json +0 -4
  183. package/tsconfig.build.tsbuildinfo +0 -1
  184. package/tsconfig.cjs.build.json +0 -22
  185. package/tsconfig.json +0 -27
  186. package/vite.config.mjs +0 -3
@@ -1,224 +0,0 @@
1
- import { Option } from '@effect/data/Option'
2
- import * as Effect from '@effect/io/Effect'
3
-
4
- import type { MemoryNavigationOptions } from './Memory.js'
5
- import {
6
- Destination,
7
- NavigateOptions,
8
- NavigationError,
9
- NavigationEvent,
10
- NavigationType,
11
- } from './Navigation.js'
12
- import { Model } from './model.js'
13
- import {
14
- Notify,
15
- Save,
16
- makeGoTo,
17
- makeNotify,
18
- makeOnNavigation,
19
- makeOnNavigationEnd,
20
- } from './shared-intent.js'
21
- import { createKey, getUrl } from './util.js'
22
-
23
- // Roughly the number of History entries in a browser anyways
24
- const DEFAULT_MAX_ENTRIES = 50
25
-
26
- export type MemoryIntent = {
27
- readonly back: ReturnType<ReturnType<typeof makeGo>>
28
-
29
- readonly forward: ReturnType<ReturnType<typeof makeGo>>
30
-
31
- readonly push: ReturnType<typeof makePush>
32
-
33
- readonly replace: ReturnType<typeof makeReplace>
34
-
35
- readonly navigate: (
36
- url: string,
37
- options?: NavigateOptions,
38
- ) => ReturnType<ReturnType<typeof makePush | typeof makeReplace>>
39
-
40
- readonly notify: Notify
41
-
42
- readonly go: ReturnType<typeof makeGo>
43
-
44
- readonly goTo: (key: string) => Effect.Effect<never, NavigationError, Option<Destination>>
45
-
46
- readonly reload: ReturnType<typeof makeReload>
47
-
48
- readonly onNavigation: ReturnType<typeof makeOnNavigation>
49
-
50
- readonly onNavigationEnd: ReturnType<typeof makeOnNavigationEnd>
51
- }
52
-
53
- export function makeIntent(model: Model, options: MemoryNavigationOptions): MemoryIntent {
54
- const { origin } = options.initialUrl
55
- const base = options.base ?? '/'
56
- const maxEntries = Math.abs(options.maxEntries ?? DEFAULT_MAX_ENTRIES)
57
- const notify = makeNotify(model)
58
- const save = makeSave(model)
59
- const go = makeGo(model, notify, save)
60
- const replace = makeReplace(model, notify, save, base, origin)
61
- const push = makePush(model, notify, save, base, origin, maxEntries)
62
-
63
- return {
64
- back: go(-1),
65
- forward: go(1),
66
- push,
67
- replace,
68
- navigate: (url: string, options: NavigateOptions = {}) =>
69
- options.history === 'replace' ? replace(url, options) : push(url, options),
70
- go: go,
71
- goTo: makeGoTo(model, go),
72
- reload: makeReload(model, notify, save),
73
- onNavigation: makeOnNavigation(model),
74
- onNavigationEnd: makeOnNavigationEnd(model),
75
- notify,
76
- } as const
77
- }
78
-
79
- export type Intent = ReturnType<typeof makeIntent>
80
-
81
- export const makeSave: (
82
- model: Model,
83
- ) => (event: NavigationEvent) => Effect.Effect<never, never, void> =
84
- (model: Model) => (event: NavigationEvent) =>
85
- Effect.gen(function* ($) {
86
- const events = yield* $(model.events)
87
- const index = yield* $(model.index)
88
-
89
- // Update current entry
90
- yield* $(model.currentEntry.set(event.destination))
91
-
92
- // Update canGoBack
93
- yield* $(model.canGoBack.set(index > 0))
94
-
95
- // Update canGoForward
96
- yield* $(model.canGoForward.set(index < events.length - 1))
97
- })
98
-
99
- export const makeReload = (model: Model, notify: Notify, save: Save<never>) =>
100
- Effect.gen(function* ($) {
101
- const i = yield* $(model.index.get)
102
- const e = yield* $(model.events)
103
- const event = e[i]
104
- const reloadEvent = { ...event, navigationType: NavigationType.Reload }
105
-
106
- yield* $(notify(reloadEvent))
107
- yield* $(save(reloadEvent))
108
-
109
- return event.destination
110
- })
111
-
112
- export const makeReplace =
113
- (model: Model, notify: Notify, save: Save<never>, base: string, origin: string) =>
114
- (url: string, options: NavigateOptions = {}) =>
115
- Effect.gen(function* ($) {
116
- const entry = yield* $(model.currentEntry.get)
117
- const destination: Destination = {
118
- key: entry.key,
119
- url: getUrl(url, base, origin),
120
- state: options.state,
121
- }
122
- const event: NavigationEvent = {
123
- destination,
124
- hashChange: entry.url.hash !== destination.url.hash,
125
- navigationType: NavigationType.Replace,
126
- }
127
-
128
- yield* $(notify(event))
129
-
130
- const currentIndex = yield* $(model.index)
131
-
132
- yield* $(
133
- model.events.update((entries) => {
134
- const updated = entries.slice(0)
135
- updated[currentIndex] = event
136
- return updated
137
- }),
138
- )
139
-
140
- yield* $(save(event))
141
-
142
- return destination
143
- })
144
-
145
- export const makePush =
146
- (
147
- model: Model,
148
- notify: Notify,
149
- save: Save<never>,
150
- base: string,
151
- origin: string,
152
- maxEntries: number,
153
- ) =>
154
- (url: string, options: NavigateOptions = {}) =>
155
- Effect.gen(function* ($) {
156
- const entry = yield* $(model.currentEntry.get)
157
- const destination: Destination = {
158
- key: yield* $(createKey),
159
- url: getUrl(url, base, origin),
160
- state: options.state,
161
- }
162
- const event: NavigationEvent = {
163
- destination,
164
- hashChange: entry.url.hash !== destination.url.hash,
165
- navigationType: NavigationType.Push,
166
- }
167
-
168
- // Notify event handlers
169
- yield* $(notify(event))
170
-
171
- const currentIndex = yield* $(model.index)
172
-
173
- // Remove all entries after the current index
174
- // and add the new destination to the end
175
- yield* $(
176
- model.events.update((entries) => {
177
- const updated = entries.slice(0, currentIndex + 1)
178
- updated.push(event)
179
- return updated.slice(-maxEntries)
180
- }),
181
- )
182
-
183
- // Update the index to the new destination
184
- yield* $(model.index.update((i) => i + 1))
185
-
186
- yield* $(save(event))
187
-
188
- return destination
189
- })
190
-
191
- export const makeGo = (model: Model, notify: Notify, save: Save<never>) => (delta: number) =>
192
- Effect.gen(function* ($) {
193
- const currentEntries = yield* $(model.events)
194
- const totalEntries = currentEntries.length
195
- const currentIndex = yield* $(model.index)
196
-
197
- // Nothing to do here
198
- if (delta === 0) return currentEntries[currentIndex].destination
199
-
200
- const nextIndex =
201
- delta > 0
202
- ? Math.min(currentIndex + delta, totalEntries - 1)
203
- : Math.max(currentIndex + delta, 0)
204
- const nextEntry = currentEntries[nextIndex]
205
-
206
- yield* $(
207
- notify({
208
- ...nextEntry,
209
- navigationType: getNavigationType(currentIndex, nextIndex),
210
- }),
211
- )
212
-
213
- yield* $(model.index.set(nextIndex))
214
-
215
- yield* $(save(nextEntry))
216
-
217
- return nextEntry.destination
218
- })
219
-
220
- function getNavigationType(currentIndex: number, nextIndex: number): NavigationType {
221
- if (nextIndex > currentIndex) return NavigationType.Forward
222
- if (nextIndex < currentIndex) return NavigationType.Back
223
- return NavigationType.Reload
224
- }
package/src/model.ts DELETED
@@ -1,54 +0,0 @@
1
- import * as Effect from '@effect/io/Effect'
2
- import * as Scope from '@effect/io/Scope'
3
- import * as Fx from '@typed/fx'
4
-
5
- import { Destination, NavigationError, NavigationEvent, OnNavigationOptions } from './Navigation.js'
6
-
7
- export interface Model {
8
- readonly onNavigationHandlers: Set<
9
- readonly [
10
- (event: NavigationEvent) => Effect.Effect<never, NavigationError, unknown>,
11
- OnNavigationOptions?,
12
- ]
13
- >
14
- readonly onNavigationEndHandlers: Set<
15
- readonly [
16
- (event: NavigationEvent) => Effect.Effect<never, never, unknown>,
17
- OnNavigationOptions?,
18
- ]
19
- >
20
- readonly events: Fx.RefSubject<never, readonly NavigationEvent[]>
21
- readonly index: Fx.RefSubject<never, number>
22
- readonly entries: Fx.Computed<never, never, Destination[]>
23
- readonly currentEntry: Fx.RefSubject<never, Destination>
24
- readonly canGoBack: Fx.RefSubject<never, boolean>
25
- readonly canGoForward: Fx.RefSubject<never, boolean>
26
- }
27
-
28
- export const makeModel = (
29
- initialEntries: readonly NavigationEvent[],
30
- initialIndex: number,
31
- ): Effect.Effect<Scope.Scope, never, Model> =>
32
- Effect.gen(function* ($) {
33
- const events = yield* $(Fx.makeRef(Effect.succeed(initialEntries)))
34
- const index = yield* $(Fx.makeRef(Effect.succeed(initialIndex)))
35
- const entries = events.map((es) => es.map((e) => e.destination))
36
- const currentEntry = yield* $(
37
- Fx.makeRef(Effect.succeed(initialEntries[initialIndex].destination)),
38
- )
39
- const canGoBack = yield* $(Fx.makeRef(Effect.succeed(initialIndex > 0)))
40
- const canGoForward = yield* $(
41
- Fx.makeRef(Effect.succeed(initialIndex < initialEntries.length - 1)),
42
- )
43
-
44
- return {
45
- onNavigationHandlers: new Set(),
46
- onNavigationEndHandlers: new Set(),
47
- events,
48
- index,
49
- entries,
50
- currentEntry,
51
- canGoBack,
52
- canGoForward,
53
- }
54
- })
@@ -1,117 +0,0 @@
1
- import * as Option from '@effect/data/Option'
2
- import * as Effect from '@effect/io/Effect'
3
- import * as Scope from '@effect/io/Scope'
4
-
5
- import { Destination, NavigationError, NavigationEvent, OnNavigationOptions } from './Navigation.js'
6
- import { Model } from './model.js'
7
-
8
- export type Notify = (event: NavigationEvent) => Effect.Effect<never, NavigationError, void>
9
- export type NotifyEnd = (event: NavigationEvent) => Effect.Effect<never, never, void>
10
-
11
- export type Save<R> = (event: NavigationEvent) => Effect.Effect<R, never, void>
12
-
13
- // Anytime there are changes to the model, we need to notify all event handlers
14
- export const makeNotify = (model: Model) => (event: NavigationEvent) =>
15
- Effect.gen(function* ($) {
16
- // Notify event handlers
17
- if (model.onNavigationHandlers.size > 0)
18
- yield* $(
19
- Effect.forEach(
20
- model.onNavigationHandlers,
21
- ([handler, options]) => (options?.passive ? Effect.fork(handler(event)) : handler(event)),
22
- { discard: true },
23
- ),
24
- )
25
- })
26
-
27
- export const makeOnNavigation =
28
- (model: Model) =>
29
- <R>(
30
- handler: (event: NavigationEvent) => Effect.Effect<R, NavigationError, unknown>,
31
- options?: OnNavigationOptions,
32
- ): Effect.Effect<R | Scope.Scope, NavigationError, void> =>
33
- Effect.uninterruptibleMask((restore) =>
34
- Effect.gen(function* ($) {
35
- const context = yield* $(Effect.context<R>())
36
- const handler_ = (event: NavigationEvent) =>
37
- restore(Effect.provideContext(handler(event), context))
38
- const entry = [handler_, options] as const
39
-
40
- model.onNavigationHandlers.add(entry)
41
-
42
- yield* $(
43
- Effect.addFinalizer(() => Effect.sync(() => model.onNavigationHandlers.delete(entry))),
44
- )
45
-
46
- // Send the latest navigation event on subscription
47
- const events = yield* $(model.events)
48
- const index = yield* $(model.index)
49
- const event = events[index]
50
-
51
- yield* $(restore(handler(event)))
52
- }),
53
- )
54
-
55
- // Anytime there are changes to the model, we need to notify all event handlers
56
- export const makeNotifyEnd = (model: Model) => (event: NavigationEvent) =>
57
- Effect.gen(function* ($) {
58
- // Notify event handlers
59
- if (model.onNavigationEndHandlers.size > 0)
60
- yield* $(
61
- Effect.forEach(
62
- model.onNavigationEndHandlers,
63
- ([handler, options]) => (options?.passive ? Effect.fork(handler(event)) : handler(event)),
64
- { discard: true },
65
- ),
66
- )
67
- })
68
-
69
- export const makeOnNavigationEnd =
70
- (model: Model) =>
71
- <R>(
72
- handler: (event: NavigationEvent) => Effect.Effect<R, never, unknown>,
73
- options?: OnNavigationOptions,
74
- ): Effect.Effect<R | Scope.Scope, never, void> =>
75
- Effect.uninterruptibleMask((restore) =>
76
- Effect.gen(function* ($) {
77
- const context = yield* $(Effect.context<R>())
78
- const handler_ = (event: NavigationEvent) =>
79
- restore(Effect.provideContext(handler(event), context))
80
- const entry = [handler_, options] as const
81
-
82
- model.onNavigationEndHandlers.add(entry)
83
-
84
- yield* $(
85
- Effect.addFinalizer(() => Effect.sync(() => model.onNavigationEndHandlers.delete(entry))),
86
- )
87
-
88
- // Send the latest navigation event on subscription
89
- const events = yield* $(model.events)
90
- const index = yield* $(model.index)
91
- const event = events[index]
92
-
93
- yield* $(restore(handler(event)))
94
- }),
95
- )
96
-
97
- export const makeGoTo =
98
- <R, E>(
99
- model: Model,
100
- go: (delta: number, skipHistory?: boolean) => Effect.Effect<R, E, Destination>,
101
- ) =>
102
- (key: string): Effect.Effect<R, E, Option.Option<Destination>> =>
103
- Effect.gen(function* ($) {
104
- const entries = yield* $(model.entries)
105
- const currentIndex = yield* $(model.index)
106
- const nextIndex = entries.findIndex((destination) => destination.key === key)
107
-
108
- if (nextIndex === -1) return Option.none()
109
-
110
- const delta = nextIndex - currentIndex
111
-
112
- if (delta !== 0) {
113
- return Option.some(yield* $(go(delta)))
114
- }
115
-
116
- return Option.some(entries[nextIndex])
117
- })
package/src/storage.ts DELETED
@@ -1,101 +0,0 @@
1
- import * as Option from '@effect/data/Option'
2
- import * as Effect from '@effect/io/Effect'
3
- import { History, Location, getItem, setItem } from '@typed/dom'
4
-
5
- import type { DomNavigationOptions } from './DOM.js'
6
- import { NavigationEvent, Destination, NavigationType } from './Navigation.js'
7
- import { NavigationEventJson, decodeNavigationEvent } from './json.js'
8
- import { createKey, getUrl } from './util.js'
9
-
10
- const TYPED_NAVIGATION_ENTRIES_KEY = '@typed/navigation/entries'
11
- const TYPED_NAVIGATION_INDEX_KEY = '@typed/navigation/index'
12
-
13
- /**
14
- * @internal
15
- */
16
- export const getStoredEvents: Effect.Effect<Storage, never, readonly NavigationEvent[]> =
17
- Effect.gen(function* ($) {
18
- const option = yield* $(getItem(TYPED_NAVIGATION_ENTRIES_KEY))
19
-
20
- if (Option.isNone(option)) {
21
- return []
22
- }
23
-
24
- return (JSON.parse(option.value) as readonly NavigationEventJson[]).map(decodeNavigationEvent)
25
- })
26
-
27
- /**
28
- * @internal
29
- */
30
- export const getStoredIndex = Effect.gen(function* ($) {
31
- const option = yield* $(getItem(TYPED_NAVIGATION_INDEX_KEY))
32
-
33
- if (Option.isNone(option)) {
34
- return Option.none()
35
- }
36
-
37
- const n = JSON.parse(option.value) as number
38
-
39
- if (Number.isNaN(n)) {
40
- return Option.none()
41
- }
42
-
43
- return Option.some(n)
44
- })
45
-
46
- /**
47
- * @internal
48
- */
49
- export const getInitialValues = (
50
- base: string,
51
- options: DomNavigationOptions,
52
- ): Effect.Effect<
53
- Storage | History | Location,
54
- never,
55
- readonly [readonly NavigationEvent[], number]
56
- > =>
57
- Effect.gen(function* ($) {
58
- // Get Resources
59
- const history = yield* $(History)
60
- const location = yield* $(Location)
61
-
62
- // Read the stored entries and index
63
- const storedEntries = yield* $(getStoredEvents)
64
- const storedIndex = Option.getOrElse(yield* $(getStoredIndex), () => storedEntries.length - 1)
65
- const storedEntry = storedEntries[storedIndex]
66
-
67
- // Read the initial url from the location
68
- const initialUrl = getUrl(location.href, base, location.origin)
69
- const initial: Destination = {
70
- key: options.initialKey ?? (yield* $(createKey)),
71
- url: initialUrl,
72
- state: history.state,
73
- }
74
- const initialEvent: NavigationEvent = {
75
- destination: initial,
76
- hashChange: false,
77
- navigationType: NavigationType.Push,
78
- }
79
-
80
- // If there are no stored entries then we can just use the initial entry
81
- if (!storedEntry) {
82
- return [[initialEvent], 0] as const
83
- }
84
-
85
- // If we're starting on the same page as the initial entry
86
- // then we can just use the initial entries
87
- if (storedEntry.destination.url.href === initialUrl.href) {
88
- return [storedEntries, storedIndex] as const
89
- }
90
-
91
- // Otherwise, we need to push the initial entry with the current page
92
- const entries = [...storedEntries.slice(0, storedIndex + 1), initialEvent]
93
-
94
- return [entries, entries.length - 1] as const
95
- })
96
-
97
- export const saveToStorage = (entries: readonly NavigationEvent[], index: number) =>
98
- Effect.gen(function* ($) {
99
- yield* $(setItem(TYPED_NAVIGATION_ENTRIES_KEY, JSON.stringify(entries)))
100
- yield* $(setItem(TYPED_NAVIGATION_INDEX_KEY, JSON.stringify(index)))
101
- })
package/src/util.ts DELETED
@@ -1,20 +0,0 @@
1
- import * as Effect from '@effect/io/Effect'
2
- import { pathJoin } from '@typed/path'
3
-
4
- import { DestinationKey } from './Navigation.js'
5
-
6
- export function getUrl(href: string, base: string, origin: string) {
7
- const url = new URL(href, origin)
8
-
9
- if (!url.pathname.startsWith(base)) {
10
- url.pathname = pathJoin(base, url.pathname)
11
- }
12
-
13
- return url
14
- }
15
-
16
- export const createKey = Effect.randomWith((random) =>
17
- Effect.map(random.nextIntBetween(0, Number.MAX_SAFE_INTEGER), (n) =>
18
- DestinationKey(n.toString(36).slice(2, 10)),
19
- ),
20
- )
@@ -1,4 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "exclude": ["src/**/*.test.ts"]
4
- }