unwrapped 0.1.5 → 0.1.7
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/CHANGELOG.md +13 -0
- package/dist/core/index.d.mts +118 -1
- package/dist/core/index.d.ts +118 -1
- package/dist/core/index.js +209 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +206 -2
- package/dist/core/index.mjs.map +1 -1
- package/dist/vue/index.d.mts +257 -44
- package/dist/vue/index.d.ts +257 -44
- package/dist/vue/index.js +42 -50
- package/dist/vue/index.js.map +1 -1
- package/dist/vue/index.mjs +43 -51
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/vue/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import * as unwrapped_core from 'unwrapped/core';
|
|
2
|
+
import { ErrorBase, AsyncResult, Result, FlatChainStep, Action, AsyncResultGenerator, AsyncResultList } from 'unwrapped/core';
|
|
1
3
|
import * as vue from 'vue';
|
|
2
|
-
import { Ref, WatchSource, VNode } from 'vue';
|
|
3
|
-
import { ErrorBase, AsyncResult, Result, FlatChainStep, Action, AsyncResultGenerator } from 'unwrapped/core';
|
|
4
|
+
import { Ref, WatchSource, VNode, SlotsType } from 'vue';
|
|
4
5
|
|
|
5
6
|
interface ReactiveProcessOptions {
|
|
6
7
|
immediate: boolean;
|
|
@@ -12,7 +13,7 @@ interface ReactiveProcessOptions {
|
|
|
12
13
|
* @param asyncResult the result to make reactive
|
|
13
14
|
* @returns the ref to the result
|
|
14
15
|
*/
|
|
15
|
-
declare function useAsyncResultRef<T, E extends ErrorBase = ErrorBase>(asyncResult
|
|
16
|
+
declare function useAsyncResultRef<T, E extends ErrorBase = ErrorBase>(asyncResult?: AsyncResult<T, E>): Ref<AsyncResult<T, E>, AsyncResult<T, E>>;
|
|
16
17
|
/**
|
|
17
18
|
* Creates an AsyncResult ref from a promise returning a Result.
|
|
18
19
|
* @param promise the promise returning a Result
|
|
@@ -78,68 +79,280 @@ declare function useLazyGenerator<T>(generatorFunc: () => AsyncResultGenerator<T
|
|
|
78
79
|
* @returns ref to the result
|
|
79
80
|
*/
|
|
80
81
|
declare function useReactiveGenerator<Inputs, T, E extends ErrorBase = ErrorBase>(source: WatchSource<Inputs>, generatorFunc: (args: Inputs) => AsyncResultGenerator<T>, options?: ReactiveProcessOptions): Ref<AsyncResult<T, E>>;
|
|
81
|
-
|
|
82
82
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
83
|
+
* Creates a reactive AsyncResultList wrapped in a Vue ref.
|
|
84
|
+
* The AsyncResultList notifies Vue's reactivity system whenever its state changes.
|
|
85
85
|
*
|
|
86
|
-
* @
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* <div>Loading data...</div>
|
|
90
|
-
* </template>
|
|
91
|
-
* <template #error="{ error }">
|
|
92
|
-
* <div>Error occurred: {{ error.message }}</div>
|
|
93
|
-
* </template>
|
|
94
|
-
* <template #default="{ value }">
|
|
95
|
-
* <div>Data loaded: {{ value }}</div>
|
|
96
|
-
* </template>
|
|
97
|
-
* <template #idle>
|
|
98
|
-
* <div>Waiting to start...</div>
|
|
99
|
-
* </template>
|
|
100
|
-
* </AsyncResultLoader>
|
|
86
|
+
* @template T - The type of the values in the AsyncResultList.
|
|
87
|
+
* @template E - The type of the error, extending ErrorBase (default is ErrorBase).
|
|
88
|
+
* @returns a ref to the AsyncResultList
|
|
101
89
|
*/
|
|
102
|
-
declare
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
90
|
+
declare function useAsyncResultList<T = any, E extends ErrorBase = ErrorBase>(): Ref<{
|
|
91
|
+
readonly tasks: Map<string, {
|
|
92
|
+
key: string;
|
|
93
|
+
result: {
|
|
94
|
+
state: {
|
|
95
|
+
status: "idle";
|
|
96
|
+
} | {
|
|
97
|
+
status: "loading";
|
|
98
|
+
promise: {
|
|
99
|
+
then: <TResult1 = Result<T, E>, TResult2 = never>(onfulfilled?: ((value: Result<T, E>) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>;
|
|
100
|
+
catch: <TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null | undefined) => Promise<Result<T, E> | TResult>;
|
|
101
|
+
finally: (onfinally?: (() => void) | null | undefined) => Promise<Result<T, E>>;
|
|
102
|
+
readonly [Symbol.toStringTag]: string;
|
|
103
|
+
};
|
|
104
|
+
} | {
|
|
105
|
+
status: "success";
|
|
106
|
+
value: vue.UnwrapRef<T>;
|
|
107
|
+
} | {
|
|
108
|
+
status: "error";
|
|
109
|
+
error: vue.UnwrapRef<E>;
|
|
110
|
+
};
|
|
111
|
+
isSuccess: () => boolean;
|
|
112
|
+
isError: () => boolean;
|
|
113
|
+
isIdle: () => boolean;
|
|
114
|
+
isLoading: () => boolean;
|
|
115
|
+
unwrapOrNull: () => T | null;
|
|
116
|
+
unwrapOrThrow: () => T;
|
|
117
|
+
unwrapErrorOrNull: () => E | null;
|
|
118
|
+
updateFromValue: (value: T) => AsyncResult<T, E>;
|
|
119
|
+
updateFromError: (error: E) => AsyncResult<T, E>;
|
|
120
|
+
updateFromValuePromise: (promise: Promise<T>) => AsyncResult<T, E>;
|
|
121
|
+
waitForSettled: () => Promise<AsyncResult<T, E>>;
|
|
122
|
+
toResultPromise: () => Promise<Result<T, E>>;
|
|
123
|
+
toValueOrThrowPromise: () => Promise<T>;
|
|
124
|
+
toValueOrNullPromise: () => Promise<T | null>;
|
|
125
|
+
updateFromResultPromise: (promise: Promise<Result<T, E>>) => AsyncResult<T, E>;
|
|
126
|
+
listen: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
127
|
+
listenUntilSettled: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
128
|
+
mirror: (other: AsyncResult<T, E>) => () => void;
|
|
129
|
+
mirrorUntilSettled: (other: AsyncResult<T, E>) => () => void;
|
|
130
|
+
chain: <O, E2 extends ErrorBase = ErrorBase>(fn: unwrapped_core.ChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
131
|
+
flatChain: <O, E2 extends ErrorBase = ErrorBase>(fn: FlatChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
132
|
+
runInPlace: (generatorFunc: () => AsyncResultGenerator<T>) => AsyncResult<T, E>;
|
|
133
|
+
log: (name?: string) => void;
|
|
134
|
+
debug: (name?: string) => () => void;
|
|
135
|
+
[Symbol.iterator]: () => Generator<AsyncResult<T, E>, T, any>;
|
|
136
|
+
};
|
|
137
|
+
unsub: () => void;
|
|
138
|
+
}> & Omit<Map<string, unwrapped_core.AsyncResultListItem<T, E>>, keyof Map<any, any>>;
|
|
139
|
+
readonly length: number;
|
|
140
|
+
readonly items: {
|
|
141
|
+
state: {
|
|
142
|
+
status: "idle";
|
|
143
|
+
} | {
|
|
144
|
+
status: "loading";
|
|
145
|
+
promise: {
|
|
146
|
+
then: <TResult1 = Result<T, E>, TResult2 = never>(onfulfilled?: ((value: Result<T, E>) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>;
|
|
147
|
+
catch: <TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null | undefined) => Promise<Result<T, E> | TResult>;
|
|
148
|
+
finally: (onfinally?: (() => void) | null | undefined) => Promise<Result<T, E>>;
|
|
149
|
+
readonly [Symbol.toStringTag]: string;
|
|
150
|
+
};
|
|
151
|
+
} | {
|
|
152
|
+
status: "success";
|
|
153
|
+
value: vue.UnwrapRef<T>;
|
|
154
|
+
} | {
|
|
155
|
+
status: "error";
|
|
156
|
+
error: vue.UnwrapRef<E>;
|
|
157
|
+
};
|
|
158
|
+
isSuccess: () => boolean;
|
|
159
|
+
isError: () => boolean;
|
|
160
|
+
isIdle: () => boolean;
|
|
161
|
+
isLoading: () => boolean;
|
|
162
|
+
unwrapOrNull: () => T | null;
|
|
163
|
+
unwrapOrThrow: () => T;
|
|
164
|
+
unwrapErrorOrNull: () => E | null;
|
|
165
|
+
updateFromValue: (value: T) => AsyncResult<T, E>;
|
|
166
|
+
updateFromError: (error: E) => AsyncResult<T, E>;
|
|
167
|
+
updateFromValuePromise: (promise: Promise<T>) => AsyncResult<T, E>;
|
|
168
|
+
waitForSettled: () => Promise<AsyncResult<T, E>>;
|
|
169
|
+
toResultPromise: () => Promise<Result<T, E>>;
|
|
170
|
+
toValueOrThrowPromise: () => Promise<T>;
|
|
171
|
+
toValueOrNullPromise: () => Promise<T | null>;
|
|
172
|
+
updateFromResultPromise: (promise: Promise<Result<T, E>>) => AsyncResult<T, E>;
|
|
173
|
+
listen: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
174
|
+
listenUntilSettled: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
175
|
+
mirror: (other: AsyncResult<T, E>) => () => void;
|
|
176
|
+
mirrorUntilSettled: (other: AsyncResult<T, E>) => () => void;
|
|
177
|
+
chain: <O, E2 extends ErrorBase = ErrorBase>(fn: unwrapped_core.ChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
178
|
+
flatChain: <O, E2 extends ErrorBase = ErrorBase>(fn: FlatChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
179
|
+
runInPlace: (generatorFunc: () => AsyncResultGenerator<T>) => AsyncResult<T, E>;
|
|
180
|
+
log: (name?: string) => void;
|
|
181
|
+
debug: (name?: string) => () => void;
|
|
182
|
+
[Symbol.iterator]: () => Generator<AsyncResult<T, E>, T, any>;
|
|
183
|
+
}[];
|
|
184
|
+
state: unwrapped_core.AsyncResultListState;
|
|
185
|
+
listen: (listener: (taskQueue: AsyncResultList<T, E>) => void) => () => void;
|
|
186
|
+
add: (key: string, task: AsyncResult<T, E>, removeOnSettle?: boolean) => AsyncResult<T, E>;
|
|
187
|
+
clear: () => void;
|
|
188
|
+
anyLoading: () => boolean;
|
|
189
|
+
getAllFiltered: (predicate: (task: AsyncResult<T, E>) => boolean) => AsyncResult<T, E>[];
|
|
190
|
+
getAllFilteredAndMap: <U>(filterPredicate: (task: AsyncResult<T, E>) => boolean, mapFunc: (task: AsyncResult<T, E>) => U) => U[];
|
|
191
|
+
getAllSuccess: () => AsyncResult<T, E>[];
|
|
192
|
+
getAllSuccessValues: () => T[];
|
|
193
|
+
getAllErrors: () => AsyncResult<T, E>[];
|
|
194
|
+
getAllErrorValues: () => E[];
|
|
195
|
+
getAllLoading: () => AsyncResult<T, E>[];
|
|
196
|
+
getAllLoadingPromises: () => Promise<Result<T, E>>[];
|
|
197
|
+
log: (name?: string) => void;
|
|
198
|
+
debug: (name?: string) => () => void;
|
|
199
|
+
}, AsyncResultList<T, E> | {
|
|
200
|
+
readonly tasks: Map<string, {
|
|
201
|
+
key: string;
|
|
202
|
+
result: {
|
|
203
|
+
state: {
|
|
204
|
+
status: "idle";
|
|
205
|
+
} | {
|
|
206
|
+
status: "loading";
|
|
207
|
+
promise: {
|
|
208
|
+
then: <TResult1 = Result<T, E>, TResult2 = never>(onfulfilled?: ((value: Result<T, E>) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>;
|
|
209
|
+
catch: <TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null | undefined) => Promise<Result<T, E> | TResult>;
|
|
210
|
+
finally: (onfinally?: (() => void) | null | undefined) => Promise<Result<T, E>>;
|
|
211
|
+
readonly [Symbol.toStringTag]: string;
|
|
212
|
+
};
|
|
213
|
+
} | {
|
|
214
|
+
status: "success";
|
|
215
|
+
value: vue.UnwrapRef<T>;
|
|
216
|
+
} | {
|
|
217
|
+
status: "error";
|
|
218
|
+
error: vue.UnwrapRef<E>;
|
|
219
|
+
};
|
|
220
|
+
isSuccess: () => boolean;
|
|
221
|
+
isError: () => boolean;
|
|
222
|
+
isIdle: () => boolean;
|
|
223
|
+
isLoading: () => boolean;
|
|
224
|
+
unwrapOrNull: () => T | null;
|
|
225
|
+
unwrapOrThrow: () => T;
|
|
226
|
+
unwrapErrorOrNull: () => E | null;
|
|
227
|
+
updateFromValue: (value: T) => AsyncResult<T, E>;
|
|
228
|
+
updateFromError: (error: E) => AsyncResult<T, E>;
|
|
229
|
+
updateFromValuePromise: (promise: Promise<T>) => AsyncResult<T, E>;
|
|
230
|
+
waitForSettled: () => Promise<AsyncResult<T, E>>;
|
|
231
|
+
toResultPromise: () => Promise<Result<T, E>>;
|
|
232
|
+
toValueOrThrowPromise: () => Promise<T>;
|
|
233
|
+
toValueOrNullPromise: () => Promise<T | null>;
|
|
234
|
+
updateFromResultPromise: (promise: Promise<Result<T, E>>) => AsyncResult<T, E>;
|
|
235
|
+
listen: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
236
|
+
listenUntilSettled: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
237
|
+
mirror: (other: AsyncResult<T, E>) => () => void;
|
|
238
|
+
mirrorUntilSettled: (other: AsyncResult<T, E>) => () => void;
|
|
239
|
+
chain: <O, E2 extends ErrorBase = ErrorBase>(fn: unwrapped_core.ChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
240
|
+
flatChain: <O, E2 extends ErrorBase = ErrorBase>(fn: FlatChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
241
|
+
runInPlace: (generatorFunc: () => AsyncResultGenerator<T>) => AsyncResult<T, E>;
|
|
242
|
+
log: (name?: string) => void;
|
|
243
|
+
debug: (name?: string) => () => void;
|
|
244
|
+
[Symbol.iterator]: () => Generator<AsyncResult<T, E>, T, any>;
|
|
245
|
+
};
|
|
246
|
+
unsub: () => void;
|
|
247
|
+
}> & Omit<Map<string, unwrapped_core.AsyncResultListItem<T, E>>, keyof Map<any, any>>;
|
|
248
|
+
readonly length: number;
|
|
249
|
+
readonly items: {
|
|
250
|
+
state: {
|
|
251
|
+
status: "idle";
|
|
252
|
+
} | {
|
|
253
|
+
status: "loading";
|
|
254
|
+
promise: {
|
|
255
|
+
then: <TResult1 = Result<T, E>, TResult2 = never>(onfulfilled?: ((value: Result<T, E>) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>;
|
|
256
|
+
catch: <TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null | undefined) => Promise<Result<T, E> | TResult>;
|
|
257
|
+
finally: (onfinally?: (() => void) | null | undefined) => Promise<Result<T, E>>;
|
|
258
|
+
readonly [Symbol.toStringTag]: string;
|
|
259
|
+
};
|
|
260
|
+
} | {
|
|
261
|
+
status: "success";
|
|
262
|
+
value: vue.UnwrapRef<T>;
|
|
263
|
+
} | {
|
|
264
|
+
status: "error";
|
|
265
|
+
error: vue.UnwrapRef<E>;
|
|
266
|
+
};
|
|
267
|
+
isSuccess: () => boolean;
|
|
268
|
+
isError: () => boolean;
|
|
269
|
+
isIdle: () => boolean;
|
|
270
|
+
isLoading: () => boolean;
|
|
271
|
+
unwrapOrNull: () => T | null;
|
|
272
|
+
unwrapOrThrow: () => T;
|
|
273
|
+
unwrapErrorOrNull: () => E | null;
|
|
274
|
+
updateFromValue: (value: T) => AsyncResult<T, E>;
|
|
275
|
+
updateFromError: (error: E) => AsyncResult<T, E>;
|
|
276
|
+
updateFromValuePromise: (promise: Promise<T>) => AsyncResult<T, E>;
|
|
277
|
+
waitForSettled: () => Promise<AsyncResult<T, E>>;
|
|
278
|
+
toResultPromise: () => Promise<Result<T, E>>;
|
|
279
|
+
toValueOrThrowPromise: () => Promise<T>;
|
|
280
|
+
toValueOrNullPromise: () => Promise<T | null>;
|
|
281
|
+
updateFromResultPromise: (promise: Promise<Result<T, E>>) => AsyncResult<T, E>;
|
|
282
|
+
listen: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
283
|
+
listenUntilSettled: (listener: unwrapped_core.AsyncResultListener<T, E>, immediate?: boolean) => () => void;
|
|
284
|
+
mirror: (other: AsyncResult<T, E>) => () => void;
|
|
285
|
+
mirrorUntilSettled: (other: AsyncResult<T, E>) => () => void;
|
|
286
|
+
chain: <O, E2 extends ErrorBase = ErrorBase>(fn: unwrapped_core.ChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
287
|
+
flatChain: <O, E2 extends ErrorBase = ErrorBase>(fn: FlatChainStep<T, O, E | E2>) => AsyncResult<O, E | E2>;
|
|
288
|
+
runInPlace: (generatorFunc: () => AsyncResultGenerator<T>) => AsyncResult<T, E>;
|
|
289
|
+
log: (name?: string) => void;
|
|
290
|
+
debug: (name?: string) => () => void;
|
|
291
|
+
[Symbol.iterator]: () => Generator<AsyncResult<T, E>, T, any>;
|
|
292
|
+
}[];
|
|
293
|
+
state: unwrapped_core.AsyncResultListState;
|
|
294
|
+
listen: (listener: (taskQueue: AsyncResultList<T, E>) => void) => () => void;
|
|
295
|
+
add: (key: string, task: AsyncResult<T, E>, removeOnSettle?: boolean) => AsyncResult<T, E>;
|
|
296
|
+
clear: () => void;
|
|
297
|
+
anyLoading: () => boolean;
|
|
298
|
+
getAllFiltered: (predicate: (task: AsyncResult<T, E>) => boolean) => AsyncResult<T, E>[];
|
|
299
|
+
getAllFilteredAndMap: <U>(filterPredicate: (task: AsyncResult<T, E>) => boolean, mapFunc: (task: AsyncResult<T, E>) => U) => U[];
|
|
300
|
+
getAllSuccess: () => AsyncResult<T, E>[];
|
|
301
|
+
getAllSuccessValues: () => T[];
|
|
302
|
+
getAllErrors: () => AsyncResult<T, E>[];
|
|
303
|
+
getAllErrorValues: () => E[];
|
|
304
|
+
getAllLoading: () => AsyncResult<T, E>[];
|
|
305
|
+
getAllLoadingPromises: () => Promise<Result<T, E>>[];
|
|
306
|
+
log: (name?: string) => void;
|
|
307
|
+
debug: (name?: string) => () => void;
|
|
308
|
+
}>;
|
|
309
|
+
|
|
117
310
|
interface CustomSlots<E extends ErrorBase = ErrorBase> {
|
|
118
311
|
loading?: () => VNode;
|
|
119
312
|
error?: (props: {
|
|
120
313
|
error: E;
|
|
121
314
|
}) => VNode;
|
|
315
|
+
idle?: () => VNode;
|
|
122
316
|
}
|
|
123
317
|
/**
|
|
124
|
-
*
|
|
318
|
+
* Factory function to create a component that displays different content based on an AsyncResult's state. Provides slots for loading, error, idle, and success states and passes the relevant data to each slot, and are typed appropriately.
|
|
319
|
+
* @param slots predefined slots for loading, error, and idle states. Useful for not having to repeat the same template for displaying a framework-specific spinner while in loading state, or a custom error message.
|
|
320
|
+
* @param name Optional internal name for the component
|
|
321
|
+
* @returns An instantiable component that accepts an AsyncResult prop and a default slot for the success state.
|
|
125
322
|
*
|
|
126
|
-
*
|
|
323
|
+
* @example
|
|
324
|
+
* // loaders.ts - Create reusable loader with default loading/error UI
|
|
325
|
+
* const MyLoader = makeAsyncResultLoader({
|
|
326
|
+
* loading: () => h(Spinner),
|
|
327
|
+
* error: ({ error }) => h(ErrorDisplay, { error }),
|
|
328
|
+
* idle: () => h('div', 'Ready')
|
|
329
|
+
* });
|
|
127
330
|
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
331
|
+
* // MyPage.vue - Use the loader with custom success content
|
|
332
|
+
* <MyLoader :result="myAsyncResult">
|
|
333
|
+
* <template #default="{ value }">
|
|
334
|
+
* <UserProfile :user="value" />
|
|
335
|
+
* </template>
|
|
336
|
+
* </MyLoader>
|
|
130
337
|
*/
|
|
131
|
-
declare function
|
|
338
|
+
declare function makeAsyncResultLoader<T, E extends ErrorBase = ErrorBase>(slots: CustomSlots<E>, name?: string): vue.DefineComponent<vue.ExtractPropTypes<{
|
|
132
339
|
result: {
|
|
133
340
|
type: () => AsyncResult<T, E>;
|
|
134
341
|
required: true;
|
|
135
342
|
};
|
|
136
343
|
}>, () => VNode<vue.RendererNode, vue.RendererElement, {
|
|
137
344
|
[key: string]: any;
|
|
138
|
-
}
|
|
345
|
+
}> | VNode<vue.RendererNode, vue.RendererElement, {
|
|
346
|
+
[key: string]: any;
|
|
347
|
+
}>[], {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
139
348
|
result: {
|
|
140
349
|
type: () => AsyncResult<T, E>;
|
|
141
350
|
required: true;
|
|
142
351
|
};
|
|
143
|
-
}>> & Readonly<{}>, {},
|
|
352
|
+
}>> & Readonly<{}>, {}, SlotsType<CustomSlots<E> & {
|
|
353
|
+
default: {
|
|
354
|
+
value: T;
|
|
355
|
+
};
|
|
356
|
+
}>, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
144
357
|
|
|
145
|
-
export {
|
|
358
|
+
export { type LazyActionRef, makeAsyncResultLoader, useAction, useAsyncResultList, useAsyncResultRef, useAsyncResultRefFromPromise, useGenerator, useLazyAction, useLazyGenerator, useReactiveChain, useReactiveGenerator };
|
package/dist/vue/index.js
CHANGED
|
@@ -20,9 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/vue/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
24
|
-
buildCustomAsyncResultLoader: () => buildCustomAsyncResultLoader,
|
|
23
|
+
makeAsyncResultLoader: () => makeAsyncResultLoader,
|
|
25
24
|
useAction: () => useAction,
|
|
25
|
+
useAsyncResultList: () => useAsyncResultList,
|
|
26
26
|
useAsyncResultRef: () => useAsyncResultRef,
|
|
27
27
|
useAsyncResultRefFromPromise: () => useAsyncResultRefFromPromise,
|
|
28
28
|
useGenerator: () => useGenerator,
|
|
@@ -37,6 +37,9 @@ module.exports = __toCommonJS(index_exports);
|
|
|
37
37
|
var import_vue = require("vue");
|
|
38
38
|
var import_core = require("unwrapped/core");
|
|
39
39
|
function useAsyncResultRef(asyncResult) {
|
|
40
|
+
if (!asyncResult) {
|
|
41
|
+
asyncResult = new import_core.AsyncResult();
|
|
42
|
+
}
|
|
40
43
|
const state = (0, import_vue.ref)(asyncResult);
|
|
41
44
|
const unsub = asyncResult.listen(() => {
|
|
42
45
|
(0, import_vue.triggerRef)(state);
|
|
@@ -89,67 +92,56 @@ function useReactiveGenerator(source, generatorFunc, options = { immediate: true
|
|
|
89
92
|
}, { immediate: options.immediate });
|
|
90
93
|
return resultRef;
|
|
91
94
|
}
|
|
95
|
+
function useAsyncResultList() {
|
|
96
|
+
const list = new import_core.AsyncResultList();
|
|
97
|
+
const listRef = (0, import_vue.ref)(list);
|
|
98
|
+
list.listen(() => {
|
|
99
|
+
(0, import_vue.triggerRef)(listRef);
|
|
100
|
+
});
|
|
101
|
+
return listRef;
|
|
102
|
+
}
|
|
92
103
|
|
|
93
104
|
// src/vue/components/asyncResultLoader.ts
|
|
94
105
|
var import_vue2 = require("vue");
|
|
95
|
-
var
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
type: Object,
|
|
100
|
-
required: true
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
setup(props, { slots }) {
|
|
104
|
-
let resultRef = useAsyncResultRef(props.result);
|
|
105
|
-
(0, import_vue2.watch)(
|
|
106
|
-
() => props.result,
|
|
107
|
-
(newResult, oldResult) => {
|
|
108
|
-
if (newResult === oldResult) return;
|
|
109
|
-
resultRef = useAsyncResultRef(newResult);
|
|
110
|
-
},
|
|
111
|
-
{ immediate: true }
|
|
112
|
-
);
|
|
113
|
-
return () => {
|
|
114
|
-
const s = resultRef.value.state;
|
|
115
|
-
switch (s.status) {
|
|
116
|
-
case "loading":
|
|
117
|
-
return slots.loading ? slots.loading() : (0, import_vue2.h)("div", { class: "loading" }, "Loading\u2026");
|
|
118
|
-
case "error":
|
|
119
|
-
return slots.error ? slots.error({ error: s.error }) : (0, import_vue2.h)("div", { class: "error" }, `Error: ${s.error}`);
|
|
120
|
-
case "success":
|
|
121
|
-
return slots.default ? slots.default({ value: s.value }) : null;
|
|
122
|
-
default:
|
|
123
|
-
return slots.idle ? slots.idle() : (0, import_vue2.h)("div", { class: "idle" }, "Idle");
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
function buildCustomAsyncResultLoader(slots) {
|
|
129
|
-
const comp = (0, import_vue2.defineComponent)({
|
|
130
|
-
name: "CustomAsyncResultLoader",
|
|
106
|
+
var import_core2 = require("unwrapped/core");
|
|
107
|
+
function makeAsyncResultLoader(slots, name = "AsyncResultLoader") {
|
|
108
|
+
return (0, import_vue2.defineComponent)({
|
|
109
|
+
name,
|
|
131
110
|
props: {
|
|
132
111
|
result: {
|
|
133
112
|
type: Object,
|
|
134
113
|
required: true
|
|
135
114
|
}
|
|
136
115
|
},
|
|
116
|
+
slots: Object,
|
|
137
117
|
setup(props, context) {
|
|
118
|
+
let resultRef = useAsyncResultRef(props.result);
|
|
119
|
+
(0, import_vue2.watch)(
|
|
120
|
+
() => props.result,
|
|
121
|
+
(newResult, oldResult) => {
|
|
122
|
+
if (newResult === oldResult) return;
|
|
123
|
+
resultRef = useAsyncResultRef(newResult);
|
|
124
|
+
},
|
|
125
|
+
{ immediate: true }
|
|
126
|
+
);
|
|
138
127
|
return () => {
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
128
|
+
const s = resultRef.value.state;
|
|
129
|
+
const renderDefault = context.slots.default ?? (() => (0, import_vue2.h)("div", { class: "success" }, "Success"));
|
|
130
|
+
const renderError = context.slots.error ?? slots.error ?? (() => (0, import_vue2.h)("div", { class: "error" }, "Error"));
|
|
131
|
+
const renderLoading = context.slots.loading ?? slots.loading ?? (() => (0, import_vue2.h)("div", { class: "loading" }, "Loading\u2026"));
|
|
132
|
+
const renderIdle = context.slots.idle ?? slots.idle ?? (() => (0, import_vue2.h)("div", { class: "idle" }, "Idle"));
|
|
133
|
+
switch (s.status) {
|
|
134
|
+
case "loading":
|
|
135
|
+
return renderLoading();
|
|
136
|
+
case "error":
|
|
137
|
+
return renderError({ error: s.error });
|
|
138
|
+
case "success":
|
|
139
|
+
return renderDefault({ value: s.value });
|
|
140
|
+
default:
|
|
141
|
+
return renderIdle();
|
|
142
|
+
}
|
|
150
143
|
};
|
|
151
144
|
}
|
|
152
145
|
});
|
|
153
|
-
return comp;
|
|
154
146
|
}
|
|
155
147
|
//# sourceMappingURL=index.js.map
|
package/dist/vue/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/vue/index.ts","../../src/vue/composables.ts","../../src/vue/components/asyncResultLoader.ts"],"sourcesContent":["export * from \"./composables\"\nexport * from \"./components/asyncResultLoader\"","import { onUnmounted, ref, triggerRef, watch, type Ref, type WatchSource } from \"vue\";\nimport { AsyncResult, ErrorBase, type Action, type AsyncResultGenerator, type FlatChainStep, type Result } from \"unwrapped/core\";\n\n\n// === Vue specific types ===\n\ninterface ReactiveProcessOptions {\n immediate: boolean;\n}\n\n\n\n// === Vue Composables for AsyncResult ===\n\n/**\n * Makes a ref to the given AsyncResult. Whenever the state of the AsyncResult changes,\n * the ref gets retriggered, making those changes visible to Vue's reactivity system.\n * \n * @param asyncResult the result to make reactive\n * @returns the ref to the result\n */\nexport function useAsyncResultRef<T, E extends ErrorBase = ErrorBase>(asyncResult: AsyncResult<T, E>) {\n const state = ref<AsyncResult<T, E>>(asyncResult) as Ref<AsyncResult<T, E>>;\n\n const unsub = asyncResult.listen(() => {\n triggerRef(state);\n });\n\n onUnmounted(() => {\n unsub();\n });\n\n return state;\n}\n\n/**\n * Creates an AsyncResult ref from a promise returning a Result.\n * @param promise the promise returning a Result\n * @returns the ref to the AsyncResult\n */\nexport function useAsyncResultRefFromPromise<T, E extends ErrorBase = ErrorBase>(promise: Promise<Result<T, E>>) {\n return useAsyncResultRef(AsyncResult.fromResultPromise(promise));\n}\n\n\n\n// === Vue Composables for Chains ===\n\n/**\n * Watches a source, gives it as inputs to the function provided, and updates the result contained in the ref accordingly.\n * \n * @param source the inputs to react to\n * @param pipe the function to run when the inputs change\n * @param options optional settings\n * @returns ref to the result\n */\nexport function useReactiveChain<Inputs, T, E extends ErrorBase = ErrorBase>(source: WatchSource<Inputs>, pipe: FlatChainStep<Inputs, T, E>, options: ReactiveProcessOptions = { immediate: true }): Ref<AsyncResult<T, E>> {\n const result = new AsyncResult<T, E>();\n const resultRef = useAsyncResultRef(result);\n\n let unsub: (() => void) | null = null;\n\n watch(source, (newInputs) => {\n unsub?.();\n unsub = result.mirror(pipe(newInputs));\n }, { immediate: options.immediate });\n\n onUnmounted(() => {\n unsub?.();\n });\n\n return resultRef;\n}\n\n\n// === Vue Composables for Actions ===\n\n/**\n * The return type of useLazyAction.\n */\nexport interface LazyActionRef<T, E extends ErrorBase = ErrorBase> {\n resultRef: Ref<AsyncResult<T, E>>;\n trigger: () => void;\n}\n\n/**\n * Executes an action immediately and returns a ref to the AsyncResult representing the action's state.\n * \n * Same as useAsyncResultRefFromPromise(action()).\n * \n * @param action the action to execute immediately\n * @returns a ref to the AsyncResult representing the action's state\n */\nexport function useAction<T, E extends ErrorBase = ErrorBase>(action: Action<T, E>): Ref<AsyncResult<T, E>> {\n return useAsyncResultRefFromPromise(action());\n}\n\n/**\n * Creates a lazy action that can be triggered manually.\n * \n * Same as AsyncResult.makeLazyAction(action), but the AsyncResult is wrapped in a ref for Vue reactivity.\n * \n * @param action the action to execute when triggered\n * @returns an object containing a ref to the AsyncResult and a trigger function\n */\nexport function useLazyAction<T, E extends ErrorBase = ErrorBase>(action: Action<T, E>): LazyActionRef<T, E> {\n const lazyAction = AsyncResult.makeLazyAction<T, E>(action);\n const resultRef = useAsyncResultRef(lazyAction.result);\n\n return { resultRef, trigger: lazyAction.trigger };\n}\n\n\n// === Vue Composables for Generators ===\n\n/**\n * Runs a generator function immediately and returns a ref to the AsyncResult representing the generator's state.\n * @param generatorFunc the generator function to run immediately\n * @returns a ref to the AsyncResult representing the generator's state\n */\nexport function useGenerator<T>(generatorFunc: () => AsyncResultGenerator<T>): Ref<AsyncResult<T, any>> {\n const resultRef = useAsyncResultRef(AsyncResult.run(generatorFunc));\n return resultRef;\n}\n\n/**\n * Creates a lazy generator that can be triggered manually.\n * \n * @param generatorFunc the generator function to run when triggered\n * @returns an object containing a ref to the AsyncResult and a trigger function\n */\nexport function useLazyGenerator<T>(generatorFunc: () => AsyncResultGenerator<T>): { resultRef: Ref<AsyncResult<T, any>>, trigger: () => void } {\n const result = new AsyncResult<T, any>();\n const resultRef = useAsyncResultRef(result);\n\n const trigger = () => {\n result.runInPlace(generatorFunc);\n }\n\n return { resultRef, trigger };\n}\n\n/**\n * Watches a source, gives it as inputs to the generator function provided, and updates the result contained in the ref accordingly.\n * \n * @param source the inputs to react to\n * @param generatorFunc the generator function to run when the inputs change\n * @param options optional settings\n * @returns ref to the result\n */\nexport function useReactiveGenerator<Inputs, T, E extends ErrorBase = ErrorBase>(source: WatchSource<Inputs>, generatorFunc: (args: Inputs) => AsyncResultGenerator<T>, options: ReactiveProcessOptions = { immediate: true }): Ref<AsyncResult<T, E>> {\n const resultRef = useAsyncResultRef(new AsyncResult<T, E>());\n\n watch(source, (newInputs) => {\n resultRef.value.runInPlace(() => generatorFunc(newInputs));\n }, { immediate: options.immediate });\n\n return resultRef;\n}","import { defineComponent, watch, h, type VNode } from \"vue\"\nimport type { AsyncResult, ErrorBase } from \"unwrapped/core\"\nimport { useAsyncResultRef } from \"../composables\"\n\n/**\n * A Vue component that displays different content based on the state of an AsyncResult.\n * It supports slots for 'loading', 'error', 'success' (default), and 'idle' states.\n * \n * @example\n * <AsyncResultLoader :result=\"myAsyncResult\">\n * <template #loading>\n * <div>Loading data...</div>\n * </template>\n * <template #error=\"{ error }\">\n * <div>Error occurred: {{ error.message }}</div>\n * </template>\n * <template #default=\"{ value }\">\n * <div>Data loaded: {{ value }}</div>\n * </template>\n * <template #idle>\n * <div>Waiting to start...</div>\n * </template>\n * </AsyncResultLoader>\n */\nexport const AsyncResultLoader = defineComponent({\n name: \"AsyncResultLoader\",\n\n props: {\n result: {\n type: Object as () => AsyncResult<unknown>,\n required: true\n }\n },\n\n setup(props, { slots }) {\n let resultRef = useAsyncResultRef(props.result);\n\n // Watch for prop changes & update listener\n watch(\n () => props.result,\n (newResult, oldResult) => {\n if (newResult === oldResult) return;\n resultRef = useAsyncResultRef(newResult);\n },\n { immediate: true }\n )\n\n return () => {\n const s = resultRef.value.state;\n\n // Choose what to render based on status\n switch (s.status) {\n case \"loading\":\n return slots.loading\n ? slots.loading()\n : h(\"div\", { class: \"loading\" }, \"Loading…\");\n\n case \"error\":\n return slots.error\n ? slots.error({ error: s.error })\n : h(\"div\", { class: \"error\" }, `Error: ${s.error}`);\n\n case \"success\":\n return slots.default\n ? slots.default({ value: s.value })\n : null;\n\n default:\n // \"idle\"\n return slots.idle\n ? slots.idle()\n : h(\"div\", { class: \"idle\" }, \"Idle\");\n }\n }\n }\n})\n\n\n\ninterface CustomSlots<E extends ErrorBase = ErrorBase> {\n loading?: () => VNode;\n error?: (props: { error: E }) => VNode;\n}\n\n/**\n * Builds a custom AsyncResultLoader component with predefined slots for loading and error states.\n * \n * Useful for creating reusable components with consistent loading and error handling UI (eg. framework-specific spinners, etc...).\n * \n * @param slots the custom slots for loading and error states\n * @returns a Vue component that uses the provided slots\n */\nexport function buildCustomAsyncResultLoader<T, E extends ErrorBase = ErrorBase>(slots: CustomSlots<E>) {\n const comp = defineComponent({\n name: \"CustomAsyncResultLoader\",\n props: {\n result: {\n type: Object as () => AsyncResult<T, E>,\n required: true\n }\n },\n setup(props, context) {\n return () => {\n const renderLoading = context.slots.loading ?? slots.loading ?? (() => undefined);\n const renderError = context.slots.error ?? slots.error ?? (() => undefined);\n return h(\n AsyncResultLoader,\n { result: props.result },\n {\n default: context.slots.default ? (propsDefault: { value: T }) => context.slots.default!(propsDefault) : undefined,\n\n loading: () => renderLoading(),\n error: ((propsError: { error: E }) => renderError(propsError))\n }\n )\n }\n }\n });\n\n return comp;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,iBAAgF;AAChF,kBAAgH;AAoBzG,SAAS,kBAAsD,aAAgC;AAClG,QAAM,YAAQ,gBAAuB,WAAW;AAEhD,QAAM,QAAQ,YAAY,OAAO,MAAM;AACnC,+BAAW,KAAK;AAAA,EACpB,CAAC;AAED,8BAAY,MAAM;AACd,UAAM;AAAA,EACV,CAAC;AAED,SAAO;AACX;AAOO,SAAS,6BAAiE,SAAgC;AAC7G,SAAO,kBAAkB,wBAAY,kBAAkB,OAAO,CAAC;AACnE;AAcO,SAAS,iBAA6D,QAA6B,MAAmC,UAAkC,EAAE,WAAW,KAAK,GAA2B;AACxN,QAAM,SAAS,IAAI,wBAAkB;AACrC,QAAM,YAAY,kBAAkB,MAAM;AAE1C,MAAI,QAA6B;AAEjC,wBAAM,QAAQ,CAAC,cAAc;AACzB,YAAQ;AACR,YAAQ,OAAO,OAAO,KAAK,SAAS,CAAC;AAAA,EACzC,GAAG,EAAE,WAAW,QAAQ,UAAU,CAAC;AAEnC,8BAAY,MAAM;AACd,YAAQ;AAAA,EACZ,CAAC;AAED,SAAO;AACX;AAqBO,SAAS,UAA8C,QAA8C;AACxG,SAAO,6BAA6B,OAAO,CAAC;AAChD;AAUO,SAAS,cAAkD,QAA2C;AACzG,QAAM,aAAa,wBAAY,eAAqB,MAAM;AAC1D,QAAM,YAAY,kBAAkB,WAAW,MAAM;AAErD,SAAO,EAAE,WAAW,SAAS,WAAW,QAAQ;AACpD;AAUO,SAAS,aAAgB,eAAwE;AACpG,QAAM,YAAY,kBAAkB,wBAAY,IAAI,aAAa,CAAC;AAClE,SAAO;AACX;AAQO,SAAS,iBAAoB,eAA4G;AAC5I,QAAM,SAAS,IAAI,wBAAoB;AACvC,QAAM,YAAY,kBAAkB,MAAM;AAE1C,QAAM,UAAU,MAAM;AAClB,WAAO,WAAW,aAAa;AAAA,EACnC;AAEA,SAAO,EAAE,WAAW,QAAQ;AAChC;AAUO,SAAS,qBAAiE,QAA6B,eAA0D,UAAkC,EAAE,WAAW,KAAK,GAA2B;AACnP,QAAM,YAAY,kBAAkB,IAAI,wBAAkB,CAAC;AAE3D,wBAAM,QAAQ,CAAC,cAAc;AACzB,cAAU,MAAM,WAAW,MAAM,cAAc,SAAS,CAAC;AAAA,EAC7D,GAAG,EAAE,WAAW,QAAQ,UAAU,CAAC;AAEnC,SAAO;AACX;;;AC9JA,IAAAA,cAAsD;AAwB/C,IAAM,wBAAoB,6BAAgB;AAAA,EAC7C,MAAM;AAAA,EAEN,OAAO;AAAA,IACH,QAAQ;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,IACd;AAAA,EACJ;AAAA,EAEA,MAAM,OAAO,EAAE,MAAM,GAAG;AACpB,QAAI,YAAY,kBAAkB,MAAM,MAAM;AAG9C;AAAA,MACI,MAAM,MAAM;AAAA,MACZ,CAAC,WAAW,cAAc;AACtB,YAAI,cAAc,UAAW;AAC7B,oBAAY,kBAAkB,SAAS;AAAA,MAC3C;AAAA,MACA,EAAE,WAAW,KAAK;AAAA,IACtB;AAEA,WAAO,MAAM;AACT,YAAM,IAAI,UAAU,MAAM;AAG1B,cAAQ,EAAE,QAAQ;AAAA,QACd,KAAK;AACD,iBAAO,MAAM,UACP,MAAM,QAAQ,QACd,eAAE,OAAO,EAAE,OAAO,UAAU,GAAG,eAAU;AAAA,QAEnD,KAAK;AACD,iBAAO,MAAM,QACP,MAAM,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,QAC9B,eAAE,OAAO,EAAE,OAAO,QAAQ,GAAG,UAAU,EAAE,KAAK,EAAE;AAAA,QAE1D,KAAK;AACD,iBAAO,MAAM,UACP,MAAM,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,IAChC;AAAA,QAEV;AAEI,iBAAO,MAAM,OACP,MAAM,KAAK,QACX,eAAE,OAAO,EAAE,OAAO,OAAO,GAAG,MAAM;AAAA,MAChD;AAAA,IACJ;AAAA,EACJ;AACJ,CAAC;AAiBM,SAAS,6BAAiE,OAAuB;AACpG,QAAM,WAAO,6BAAgB;AAAA,IACzB,MAAM;AAAA,IACN,OAAO;AAAA,MACH,QAAQ;AAAA,QACJ,MAAM;AAAA,QACN,UAAU;AAAA,MACd;AAAA,IACJ;AAAA,IACA,MAAM,OAAO,SAAS;AAClB,aAAO,MAAM;AACT,cAAM,gBAAgB,QAAQ,MAAM,WAAW,MAAM,YAAY,MAAM;AACvE,cAAM,cAAc,QAAQ,MAAM,SAAS,MAAM,UAAU,MAAM;AACjE,mBAAO;AAAA,UACH;AAAA,UACA,EAAE,QAAQ,MAAM,OAAO;AAAA,UACvB;AAAA,YACI,SAAS,QAAQ,MAAM,UAAU,CAAC,iBAA+B,QAAQ,MAAM,QAAS,YAAY,IAAI;AAAA,YAExG,SAAS,MAAM,cAAc;AAAA,YAC7B,QAAQ,CAAC,eAA6B,YAAY,UAAU;AAAA,UAChE;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ,CAAC;AAED,SAAO;AACX;","names":["import_vue"]}
|
|
1
|
+
{"version":3,"sources":["../../src/vue/index.ts","../../src/vue/composables.ts","../../src/vue/components/asyncResultLoader.ts"],"sourcesContent":["export * from \"./composables\"\nexport * from \"./components/asyncResultLoader\"","import { onUnmounted, ref, triggerRef, watch, type Ref, type WatchSource } from \"vue\";\nimport { AsyncResult, AsyncResultList, ErrorBase, type Action, type AsyncResultGenerator, type FlatChainStep, type Result } from \"unwrapped/core\";\n\n\n// === Vue specific types ===\n\ninterface ReactiveProcessOptions {\n immediate: boolean;\n}\n\n\n\n// === Vue Composables for AsyncResult ===\n\n/**\n * Makes a ref to the given AsyncResult. Whenever the state of the AsyncResult changes,\n * the ref gets retriggered, making those changes visible to Vue's reactivity system.\n * \n * @param asyncResult the result to make reactive\n * @returns the ref to the result\n */\nexport function useAsyncResultRef<T, E extends ErrorBase = ErrorBase>(asyncResult?: AsyncResult<T, E>) {\n if (!asyncResult) {\n asyncResult = new AsyncResult<T, E>();\n }\n const state = ref<AsyncResult<T, E>>(asyncResult) as Ref<AsyncResult<T, E>>;\n\n const unsub = asyncResult.listen(() => {\n triggerRef(state);\n });\n\n onUnmounted(() => {\n unsub();\n });\n\n return state;\n}\n\n/**\n * Creates an AsyncResult ref from a promise returning a Result.\n * @param promise the promise returning a Result\n * @returns the ref to the AsyncResult\n */\nexport function useAsyncResultRefFromPromise<T, E extends ErrorBase = ErrorBase>(promise: Promise<Result<T, E>>) {\n return useAsyncResultRef(AsyncResult.fromResultPromise(promise));\n}\n\n\n\n// === Vue Composables for Chains ===\n\n/**\n * Watches a source, gives it as inputs to the function provided, and updates the result contained in the ref accordingly.\n * \n * @param source the inputs to react to\n * @param pipe the function to run when the inputs change\n * @param options optional settings\n * @returns ref to the result\n */\nexport function useReactiveChain<Inputs, T, E extends ErrorBase = ErrorBase>(source: WatchSource<Inputs>, pipe: FlatChainStep<Inputs, T, E>, options: ReactiveProcessOptions = { immediate: true }): Ref<AsyncResult<T, E>> {\n const result = new AsyncResult<T, E>();\n const resultRef = useAsyncResultRef(result);\n\n let unsub: (() => void) | null = null;\n\n watch(source, (newInputs) => {\n unsub?.();\n unsub = result.mirror(pipe(newInputs));\n }, { immediate: options.immediate });\n\n onUnmounted(() => {\n unsub?.();\n });\n\n return resultRef;\n}\n\n\n// === Vue Composables for Actions ===\n\n/**\n * The return type of useLazyAction.\n */\nexport interface LazyActionRef<T, E extends ErrorBase = ErrorBase> {\n resultRef: Ref<AsyncResult<T, E>>;\n trigger: () => void;\n}\n\n/**\n * Executes an action immediately and returns a ref to the AsyncResult representing the action's state.\n * \n * Same as useAsyncResultRefFromPromise(action()).\n * \n * @param action the action to execute immediately\n * @returns a ref to the AsyncResult representing the action's state\n */\nexport function useAction<T, E extends ErrorBase = ErrorBase>(action: Action<T, E>): Ref<AsyncResult<T, E>> {\n return useAsyncResultRefFromPromise(action());\n}\n\n/**\n * Creates a lazy action that can be triggered manually.\n * \n * Same as AsyncResult.makeLazyAction(action), but the AsyncResult is wrapped in a ref for Vue reactivity.\n * \n * @param action the action to execute when triggered\n * @returns an object containing a ref to the AsyncResult and a trigger function\n */\nexport function useLazyAction<T, E extends ErrorBase = ErrorBase>(action: Action<T, E>): LazyActionRef<T, E> {\n const lazyAction = AsyncResult.makeLazyAction<T, E>(action);\n const resultRef = useAsyncResultRef(lazyAction.result);\n\n return { resultRef, trigger: lazyAction.trigger };\n}\n\n\n// === Vue Composables for Generators ===\n\n/**\n * Runs a generator function immediately and returns a ref to the AsyncResult representing the generator's state.\n * @param generatorFunc the generator function to run immediately\n * @returns a ref to the AsyncResult representing the generator's state\n */\nexport function useGenerator<T>(generatorFunc: () => AsyncResultGenerator<T>): Ref<AsyncResult<T, any>> {\n const resultRef = useAsyncResultRef(AsyncResult.run(generatorFunc));\n return resultRef;\n}\n\n/**\n * Creates a lazy generator that can be triggered manually.\n * \n * @param generatorFunc the generator function to run when triggered\n * @returns an object containing a ref to the AsyncResult and a trigger function\n */\nexport function useLazyGenerator<T>(generatorFunc: () => AsyncResultGenerator<T>): { resultRef: Ref<AsyncResult<T, any>>, trigger: () => void } {\n const result = new AsyncResult<T, any>();\n const resultRef = useAsyncResultRef(result);\n\n const trigger = () => {\n result.runInPlace(generatorFunc);\n }\n\n return { resultRef, trigger };\n}\n\n/**\n * Watches a source, gives it as inputs to the generator function provided, and updates the result contained in the ref accordingly.\n * \n * @param source the inputs to react to\n * @param generatorFunc the generator function to run when the inputs change\n * @param options optional settings\n * @returns ref to the result\n */\nexport function useReactiveGenerator<Inputs, T, E extends ErrorBase = ErrorBase>(source: WatchSource<Inputs>, generatorFunc: (args: Inputs) => AsyncResultGenerator<T>, options: ReactiveProcessOptions = { immediate: true }): Ref<AsyncResult<T, E>> {\n const resultRef = useAsyncResultRef(new AsyncResult<T, E>());\n\n watch(source, (newInputs) => {\n resultRef.value.runInPlace(() => generatorFunc(newInputs));\n }, { immediate: options.immediate });\n\n return resultRef;\n}\n\n\n// === Vue Composables for AsyncResultList ===\n\n/**\n * Creates a reactive AsyncResultList wrapped in a Vue ref.\n * The AsyncResultList notifies Vue's reactivity system whenever its state changes.\n * \n * @template T - The type of the values in the AsyncResultList.\n * @template E - The type of the error, extending ErrorBase (default is ErrorBase).\n * @returns a ref to the AsyncResultList\n */\nexport function useAsyncResultList<T = any, E extends ErrorBase = ErrorBase>() {\n const list = new AsyncResultList<T, E>();\n const listRef = ref(list);\n\n list.listen(() => {\n triggerRef(listRef);\n });\n\n return listRef;\n}","import { defineComponent, watch, h, type VNode, type SlotsType } from \"vue\"\nimport { ErrorBase, type AsyncResult } from \"unwrapped/core\"\nimport { useAsyncResultRef } from \"../composables\"\n\ninterface CustomSlots<E extends ErrorBase = ErrorBase> {\n loading?: () => VNode;\n error?: (props: { error: E }) => VNode;\n idle?: () => VNode;\n}\n\n/**\n * Factory function to create a component that displays different content based on an AsyncResult's state. Provides slots for loading, error, idle, and success states and passes the relevant data to each slot, and are typed appropriately.\n * @param slots predefined slots for loading, error, and idle states. Useful for not having to repeat the same template for displaying a framework-specific spinner while in loading state, or a custom error message.\n * @param name Optional internal name for the component\n * @returns An instantiable component that accepts an AsyncResult prop and a default slot for the success state.\n * \n * @example\n * // loaders.ts - Create reusable loader with default loading/error UI\n * const MyLoader = makeAsyncResultLoader({\n * loading: () => h(Spinner),\n * error: ({ error }) => h(ErrorDisplay, { error }),\n * idle: () => h('div', 'Ready')\n * });\n * \n * // MyPage.vue - Use the loader with custom success content\n * <MyLoader :result=\"myAsyncResult\">\n * <template #default=\"{ value }\">\n * <UserProfile :user=\"value\" />\n * </template>\n * </MyLoader>\n */\nexport function makeAsyncResultLoader<T, E extends ErrorBase = ErrorBase>(slots: CustomSlots<E>, name = \"AsyncResultLoader\") {\n return defineComponent({\n name,\n props: {\n result: {\n type: Object as () => AsyncResult<T, E>,\n required: true\n }\n },\n slots: Object as SlotsType<CustomSlots<E> & { default: { value: T } }>,\n setup(props, context) {\n let resultRef = useAsyncResultRef(props.result);\n\n // Watch for prop changes & update listener\n watch(\n () => props.result,\n (newResult, oldResult) => {\n if (newResult === oldResult) return;\n resultRef = useAsyncResultRef(newResult);\n },\n { immediate: true }\n )\n\n return () => {\n const s = resultRef.value.state;\n\n const renderDefault = context.slots.default ?? (() => h(\"div\", { class: \"success\" }, \"Success\"));\n const renderError = context.slots.error ?? slots.error ?? (() => h(\"div\", { class: \"error\" }, \"Error\"));\n const renderLoading = context.slots.loading ?? slots.loading ?? (() => h(\"div\", { class: \"loading\" }, \"Loading…\"));\n const renderIdle = context.slots.idle ?? slots.idle ?? (() => h(\"div\", { class: \"idle\" }, \"Idle\"));\n\n // Choose what to render based on status\n switch (s.status) {\n case \"loading\":\n return renderLoading();\n\n case \"error\":\n return renderError({ error: s.error });\n\n case \"success\":\n return renderDefault({ value: s.value });\n\n default:\n return renderIdle();\n }\n }\n }\n })\n}"],"mappings":"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","names":["import_vue","import_core"]}
|