@typed/navigation 0.18.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nvmrc +1 -0
- package/biome.json +39 -0
- package/dist/Blocking.d.ts +23 -0
- package/dist/Blocking.js +41 -0
- package/dist/Blocking.js.map +1 -0
- package/dist/Destination.d.ts +11 -0
- package/dist/Destination.js +10 -0
- package/dist/Destination.js.map +1 -0
- package/dist/Error.d.ts +33 -0
- package/dist/Error.js +22 -0
- package/dist/Error.js.map +1 -0
- package/dist/Event.d.ts +45 -0
- package/dist/Event.js +17 -0
- package/dist/Event.js.map +1 -0
- package/dist/Forms.d.ts +79 -0
- package/dist/Forms.js +111 -0
- package/dist/Forms.js.map +1 -0
- package/dist/Handler.d.ts +6 -0
- package/dist/Handler.js +2 -0
- package/dist/Handler.js.map +1 -0
- package/dist/{dts/Layer.d.ts → Layer.d.ts} +11 -8
- package/dist/{esm/Layer.js → Layer.js} +2 -2
- package/dist/Layer.js.map +1 -0
- package/dist/NavigateOptions.d.ts +7 -0
- package/dist/NavigateOptions.js +7 -0
- package/dist/NavigateOptions.js.map +1 -0
- package/dist/Navigation.d.ts +79 -0
- package/dist/Navigation.js +49 -0
- package/dist/Navigation.js.map +1 -0
- package/dist/NavigationType.d.ts +3 -0
- package/dist/NavigationType.js +3 -0
- package/dist/NavigationType.js.map +1 -0
- package/dist/ProposedDestination.d.ts +13 -0
- package/dist/ProposedDestination.js +4 -0
- package/dist/ProposedDestination.js.map +1 -0
- package/dist/Url.d.ts +13 -0
- package/dist/Url.js +72 -0
- package/dist/Url.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/fromWindow.d.ts +4 -0
- package/dist/{esm/internal → internal}/fromWindow.js +125 -136
- package/dist/internal/fromWindow.js.map +1 -0
- package/dist/internal/memory.d.ts +6 -0
- package/dist/internal/memory.js +59 -0
- package/dist/internal/memory.js.map +1 -0
- package/dist/{dts/internal → internal}/shared.d.ts +44 -46
- package/dist/{esm/internal → internal}/shared.js +121 -168
- package/dist/internal/shared.js.map +1 -0
- package/package.json +35 -53
- package/readme.md +243 -0
- package/src/Blocking.ts +65 -65
- package/src/Destination.ts +14 -0
- package/src/Error.ts +28 -0
- package/src/Event.ts +26 -0
- package/src/Forms.ts +216 -0
- package/src/Handler.ts +16 -0
- package/src/Layer.ts +20 -9
- package/src/NavigateOptions.ts +9 -0
- package/src/Navigation.test.ts +697 -0
- package/src/Navigation.ts +135 -472
- package/src/NavigationType.ts +5 -0
- package/src/ProposedDestination.ts +8 -0
- package/src/Url.ts +106 -0
- package/src/index.ts +12 -17
- package/src/internal/fromWindow.ts +163 -234
- package/src/internal/memory.ts +62 -49
- package/src/internal/shared.ts +218 -377
- package/tsconfig.json +30 -0
- package/Blocking/package.json +0 -6
- package/LICENSE +0 -21
- package/Layer/package.json +0 -6
- package/Navigation/package.json +0 -6
- package/README.md +0 -5
- package/dist/cjs/Blocking.js +0 -58
- package/dist/cjs/Blocking.js.map +0 -1
- package/dist/cjs/Layer.js +0 -27
- package/dist/cjs/Layer.js.map +0 -1
- package/dist/cjs/Navigation.js +0 -278
- package/dist/cjs/Navigation.js.map +0 -1
- package/dist/cjs/index.js +0 -39
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/internal/fromWindow.js +0 -436
- package/dist/cjs/internal/fromWindow.js.map +0 -1
- package/dist/cjs/internal/memory.js +0 -72
- package/dist/cjs/internal/memory.js.map +0 -1
- package/dist/cjs/internal/shared.js +0 -525
- package/dist/cjs/internal/shared.js.map +0 -1
- package/dist/dts/Blocking.d.ts +0 -34
- package/dist/dts/Blocking.d.ts.map +0 -1
- package/dist/dts/Layer.d.ts.map +0 -1
- package/dist/dts/Navigation.d.ts +0 -451
- package/dist/dts/Navigation.d.ts.map +0 -1
- package/dist/dts/index.d.ts +0 -17
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/dts/internal/fromWindow.d.ts +0 -12
- package/dist/dts/internal/fromWindow.d.ts.map +0 -1
- package/dist/dts/internal/memory.d.ts +0 -6
- package/dist/dts/internal/memory.d.ts.map +0 -1
- package/dist/dts/internal/shared.d.ts.map +0 -1
- package/dist/esm/Blocking.js +0 -46
- package/dist/esm/Blocking.js.map +0 -1
- package/dist/esm/Layer.js.map +0 -1
- package/dist/esm/Navigation.js +0 -238
- package/dist/esm/Navigation.js.map +0 -1
- package/dist/esm/index.js +0 -17
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/fromWindow.js.map +0 -1
- package/dist/esm/internal/memory.js +0 -56
- package/dist/esm/internal/memory.js.map +0 -1
- package/dist/esm/internal/shared.js.map +0 -1
- package/dist/esm/package.json +0 -4
package/src/Forms.ts
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { HttpBody } from '@effect/platform'
|
|
2
|
+
import type { Options } from '@effect/platform/HttpClientRequest'
|
|
3
|
+
import * as Array from 'effect/Array'
|
|
4
|
+
import * as Effect from 'effect/Effect'
|
|
5
|
+
import * as ParseResult from 'effect/ParseResult'
|
|
6
|
+
import * as Schema from 'effect/Schema'
|
|
7
|
+
import * as SchemaAST from 'effect/SchemaAST'
|
|
8
|
+
import type * as Types from 'effect/Types'
|
|
9
|
+
import type { NavigateOptions } from './NavigateOptions.js'
|
|
10
|
+
import { UrlSearchParamsFromSelf } from './Url.js'
|
|
11
|
+
|
|
12
|
+
export const BlobFromSelf = Schema.instanceOf(globalThis.Blob)
|
|
13
|
+
export type BlobFromSelf = typeof BlobFromSelf.Type
|
|
14
|
+
|
|
15
|
+
export const BlobFrom = Schema.TaggedStruct('Blob', {
|
|
16
|
+
type: Schema.String,
|
|
17
|
+
size: Schema.Number,
|
|
18
|
+
data: Schema.Uint8Array,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
export type BlobEncoded = typeof BlobFrom.Encoded
|
|
22
|
+
export type BlobFrom = typeof BlobFrom.Type
|
|
23
|
+
|
|
24
|
+
export const Blob: Schema.Schema<Blob, BlobEncoded> = BlobFrom.pipe(
|
|
25
|
+
Schema.transformOrFail(BlobFromSelf, {
|
|
26
|
+
strict: true,
|
|
27
|
+
decode: (blob) => Effect.succeed(new globalThis.Blob([blob.data], { type: blob.type })),
|
|
28
|
+
encode: (blob) =>
|
|
29
|
+
Effect.promise(() =>
|
|
30
|
+
blob
|
|
31
|
+
.arrayBuffer()
|
|
32
|
+
.then((data) =>
|
|
33
|
+
BlobFrom.make({ type: blob.type, size: blob.size, data: new Uint8Array(data) }),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
}),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
export const FileFromSelf = Schema.instanceOf(globalThis.File)
|
|
40
|
+
export type FileFromSelf = typeof FileFromSelf.Type
|
|
41
|
+
|
|
42
|
+
export const FileFrom = Schema.TaggedStruct('File', {
|
|
43
|
+
name: Schema.String,
|
|
44
|
+
size: Schema.Number,
|
|
45
|
+
type: Schema.String,
|
|
46
|
+
lastModified: Schema.DateFromNumber,
|
|
47
|
+
data: Schema.Uint8Array,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
export type FileEncoded = typeof FileFrom.Encoded
|
|
51
|
+
export type FileFrom = typeof FileFrom.Type
|
|
52
|
+
|
|
53
|
+
export const File: Schema.Schema<File, FileEncoded> = FileFrom.pipe(
|
|
54
|
+
Schema.transformOrFail(FileFromSelf, {
|
|
55
|
+
strict: true,
|
|
56
|
+
decode: (file) =>
|
|
57
|
+
Effect.succeed(
|
|
58
|
+
new globalThis.File([file.data], file.name, {
|
|
59
|
+
type: file.type,
|
|
60
|
+
lastModified: file.lastModified.getTime(),
|
|
61
|
+
}),
|
|
62
|
+
),
|
|
63
|
+
encode: (file) =>
|
|
64
|
+
Effect.promise(() =>
|
|
65
|
+
file.arrayBuffer().then((data) =>
|
|
66
|
+
FileFrom.make({
|
|
67
|
+
name: file.name,
|
|
68
|
+
size: file.size,
|
|
69
|
+
type: file.type,
|
|
70
|
+
lastModified: new Date(file.lastModified),
|
|
71
|
+
data: new Uint8Array(data),
|
|
72
|
+
}),
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
}),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
export const FormDataFromSelf = Schema.instanceOf(globalThis.FormData)
|
|
79
|
+
export type FormDataFromSelf = typeof FormDataFromSelf.Type
|
|
80
|
+
|
|
81
|
+
export const FormDataEntryValue = Schema.Union(Blob, File, Schema.String)
|
|
82
|
+
export type FormDataEntryValue = typeof FormDataEntryValue.Type
|
|
83
|
+
export type FormDataEntryValueEncoded = typeof FormDataEntryValue.Encoded
|
|
84
|
+
|
|
85
|
+
export const FormDataFrom = Schema.Record({
|
|
86
|
+
key: Schema.String,
|
|
87
|
+
value: FormDataEntryValue,
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
export type FormDataEncoded = typeof FormDataFrom.Encoded
|
|
91
|
+
export type FormDataFrom = typeof FormDataFrom.Type
|
|
92
|
+
|
|
93
|
+
export const FormData: Schema.Schema<FormData, FormDataEncoded> = FormDataFrom.pipe(
|
|
94
|
+
Schema.transform(FormDataFromSelf, {
|
|
95
|
+
strict: true,
|
|
96
|
+
decode: structToFormData,
|
|
97
|
+
encode: formDataToStruct,
|
|
98
|
+
}),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
type AnySchemaEncoded<T> = Schema.Schema<any, T, any> | Schema.Schema<any, T, never>
|
|
102
|
+
|
|
103
|
+
type AnyFormDataFieldSchema =
|
|
104
|
+
| AnySchemaEncoded<string>
|
|
105
|
+
| AnySchemaEncoded<Blob>
|
|
106
|
+
| AnySchemaEncoded<File>
|
|
107
|
+
| AnySchemaEncoded<string | null>
|
|
108
|
+
| AnySchemaEncoded<Blob | null>
|
|
109
|
+
| AnySchemaEncoded<File | null>
|
|
110
|
+
|
|
111
|
+
type FormDataFields = Record<string, AnyFormDataFieldSchema>
|
|
112
|
+
|
|
113
|
+
export function schemaFormData<const Fields extends FormDataFields>(
|
|
114
|
+
fields: Fields,
|
|
115
|
+
): Schema.Schema<
|
|
116
|
+
{ readonly [K in keyof Schema.Struct.Type<Fields>]: Schema.Struct.Type<Fields>[K] },
|
|
117
|
+
FormData,
|
|
118
|
+
Schema.Schema.Context<Fields[keyof Fields]>
|
|
119
|
+
> {
|
|
120
|
+
return Schema.transform(FormDataFromSelf, Schema.Struct(fields), {
|
|
121
|
+
strict: false,
|
|
122
|
+
decode: formDataToStruct,
|
|
123
|
+
encode: structToFormData as any,
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function formDataToStruct(formData: FormData): Record<string, FormDataEntryValue> {
|
|
128
|
+
const record: Record<string, FormDataEntryValue> = {}
|
|
129
|
+
formData.forEach((value, key) => {
|
|
130
|
+
record[key] = value
|
|
131
|
+
})
|
|
132
|
+
return record
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function structToFormData(struct: Record<string, FormDataEntryValue>): FormData {
|
|
136
|
+
const formData = new globalThis.FormData()
|
|
137
|
+
for (const [key, value] of Object.entries(struct)) {
|
|
138
|
+
formData.append(key, value)
|
|
139
|
+
}
|
|
140
|
+
return formData
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export type FormGetSubmit = Types.Simplify<
|
|
144
|
+
Options.NoBody &
|
|
145
|
+
NavigateOptions & {
|
|
146
|
+
readonly method: 'get'
|
|
147
|
+
readonly name: string
|
|
148
|
+
readonly action?: string | URL
|
|
149
|
+
}
|
|
150
|
+
>
|
|
151
|
+
|
|
152
|
+
export type FormPostSubmit = Types.Simplify<
|
|
153
|
+
Omit<FormGetSubmit, 'method'> & {
|
|
154
|
+
readonly method: 'post'
|
|
155
|
+
readonly body?: HttpBody.HttpBody
|
|
156
|
+
}
|
|
157
|
+
>
|
|
158
|
+
|
|
159
|
+
export type FormSubmit = FormGetSubmit | FormPostSubmit
|
|
160
|
+
|
|
161
|
+
export const FormDataFromUrlSearchParams: Schema.Schema<FormData, URLSearchParams> =
|
|
162
|
+
UrlSearchParamsFromSelf.pipe(
|
|
163
|
+
Schema.transformOrFail(FormDataFromSelf, {
|
|
164
|
+
strict: true,
|
|
165
|
+
decode: (searchParams) => Effect.succeed(searchParamsToFormData(searchParams)),
|
|
166
|
+
encode: (formData) =>
|
|
167
|
+
Effect.gen(function* () {
|
|
168
|
+
const searchParams = new globalThis.URLSearchParams()
|
|
169
|
+
const errors: ParseResult.ParseIssue[] = []
|
|
170
|
+
|
|
171
|
+
for (const [key, value] of Object.entries(formDataToStruct(formData))) {
|
|
172
|
+
if (typeof value === 'string') {
|
|
173
|
+
searchParams.set(key, value)
|
|
174
|
+
} else {
|
|
175
|
+
errors.push(
|
|
176
|
+
new ParseResult.Type(
|
|
177
|
+
SchemaAST.stringKeyword,
|
|
178
|
+
value,
|
|
179
|
+
`Expected string at '${key}' but found ${value instanceof globalThis.File ? 'File' : 'Blob'}`,
|
|
180
|
+
),
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (Array.isNonEmptyReadonlyArray(errors)) {
|
|
186
|
+
return yield* ParseResult.fail(
|
|
187
|
+
new ParseResult.Composite(SchemaAST.stringKeyword, formData, errors),
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return searchParams
|
|
192
|
+
}),
|
|
193
|
+
}),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
export const UrlSearchParamsToFormData: Schema.Schema<URLSearchParams, FormData> = swap(
|
|
197
|
+
FormDataFromUrlSearchParams,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
function searchParamsToFormData(searchParams: URLSearchParams): FormData {
|
|
201
|
+
const formData = new globalThis.FormData()
|
|
202
|
+
searchParams.forEach((value, key) => {
|
|
203
|
+
formData.append(key, value)
|
|
204
|
+
})
|
|
205
|
+
return formData
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function swap<A, I, R>(schema: Schema.Schema<A, I, R>): Schema.Schema<I, A, R> {
|
|
209
|
+
const encode = ParseResult.encode(schema)
|
|
210
|
+
const decode = ParseResult.decode(schema)
|
|
211
|
+
return Schema.transformOrFail(Schema.typeSchema(schema), Schema.encodedSchema(schema), {
|
|
212
|
+
strict: true,
|
|
213
|
+
decode: encode,
|
|
214
|
+
encode: decode,
|
|
215
|
+
})
|
|
216
|
+
}
|
package/src/Handler.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type * as Effect from 'effect/Effect'
|
|
2
|
+
import type * as Option from 'effect/Option'
|
|
3
|
+
import type { CancelNavigation, RedirectError } from './Error.js'
|
|
4
|
+
import type { NavigationEvent, TransitionEvent } from './Event.js'
|
|
5
|
+
|
|
6
|
+
export type BeforeNavigationHandler<R, R2> = (event: TransitionEvent) => Effect.Effect<
|
|
7
|
+
// biome-ignore lint/suspicious/noConfusingVoidType: <explanation>
|
|
8
|
+
void | Option.Option<Effect.Effect<unknown, RedirectError | CancelNavigation, R2>>,
|
|
9
|
+
RedirectError | CancelNavigation,
|
|
10
|
+
R
|
|
11
|
+
>
|
|
12
|
+
|
|
13
|
+
export type NavigationHandler<R, R2> = (
|
|
14
|
+
event: NavigationEvent,
|
|
15
|
+
// biome-ignore lint/suspicious/noConfusingVoidType: <explanation>
|
|
16
|
+
) => Effect.Effect<void | Option.Option<Effect.Effect<unknown, never, R2>>, never, R>
|
package/src/Layer.ts
CHANGED
|
@@ -2,16 +2,21 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type
|
|
6
|
-
import type * as
|
|
7
|
-
import * as
|
|
8
|
-
import
|
|
9
|
-
import type {
|
|
5
|
+
import type { GetRandomValues } from '@typed/id'
|
|
6
|
+
import type * as Effect from 'effect/Effect'
|
|
7
|
+
import type * as Layer from 'effect/Layer'
|
|
8
|
+
import type { Destination } from './Destination.js'
|
|
9
|
+
import type { NavigationError } from './Error.js'
|
|
10
|
+
import type { TransitionEvent } from './Event.js'
|
|
11
|
+
import * as internalFromWindow from './internal/fromWindow.js'
|
|
12
|
+
import * as internalMemory from './internal/memory.js'
|
|
13
|
+
import type { Navigation } from './Navigation.js'
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* @since 1.0.0
|
|
13
17
|
*/
|
|
14
|
-
export const fromWindow: Layer.Layer<Navigation, never,
|
|
18
|
+
export const fromWindow: (window: Window) => Layer.Layer<Navigation, never, GetRandomValues> =
|
|
19
|
+
internalFromWindow.fromWindow
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* @since 1.0.0
|
|
@@ -28,7 +33,8 @@ export interface MemoryOptions {
|
|
|
28
33
|
/**
|
|
29
34
|
* @since 1.0.0
|
|
30
35
|
*/
|
|
31
|
-
export const memory: (options: MemoryOptions) => Layer.Layer<Navigation> =
|
|
36
|
+
export const memory: (options: MemoryOptions) => Layer.Layer<Navigation, never, GetRandomValues> =
|
|
37
|
+
internalMemory.memory
|
|
32
38
|
|
|
33
39
|
/**
|
|
34
40
|
* @since 1.0.0
|
|
@@ -45,9 +51,14 @@ export interface InitialMemoryOptions {
|
|
|
45
51
|
/**
|
|
46
52
|
* @since 1.0.0
|
|
47
53
|
*/
|
|
48
|
-
export const initialMemory: (
|
|
54
|
+
export const initialMemory: (
|
|
55
|
+
options: InitialMemoryOptions,
|
|
56
|
+
) => Layer.Layer<Navigation, never, GetRandomValues> = internalMemory.initialMemory
|
|
49
57
|
|
|
50
58
|
/**
|
|
51
59
|
* @since 1.0.0
|
|
52
60
|
*/
|
|
53
|
-
export type Commit = (
|
|
61
|
+
export type Commit = (
|
|
62
|
+
to: Destination,
|
|
63
|
+
event: TransitionEvent,
|
|
64
|
+
) => Effect.Effect<void, NavigationError>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as Schema from 'effect/Schema'
|
|
2
|
+
|
|
3
|
+
export const NavigateOptions = Schema.Struct({
|
|
4
|
+
history: Schema.optional(Schema.Union(Schema.Literal('replace', 'push', 'auto'))),
|
|
5
|
+
state: Schema.optional(Schema.Unknown),
|
|
6
|
+
info: Schema.optional(Schema.Unknown),
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
export type NavigateOptions = Schema.Schema.Type<typeof NavigateOptions>
|