@tempots/ui 7.0.2 → 8.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tempots/ui",
3
- "version": "7.0.2",
3
+ "version": "8.0.0",
4
4
  "type": "module",
5
5
  "main": "./index.cjs",
6
6
  "module": "./index.js",
@@ -40,7 +40,7 @@
40
40
  "@floating-ui/dom": "^1.6.7"
41
41
  },
42
42
  "peerDependencies": {
43
- "@tempots/std": "0.22.1",
44
- "@tempots/dom": "29.0.2"
43
+ "@tempots/std": "0.23.0",
44
+ "@tempots/dom": "30.0.0"
45
45
  }
46
46
  }
@@ -0,0 +1,69 @@
1
+ import { Renderable, Signal, TNode } from '@tempots/dom';
2
+ import { AsyncResult, NonLoading } from '@tempots/std';
3
+ import { MutationResource, MutationResourceExecuteOptions } from '../utils/mutation-resource';
4
+ /**
5
+ * Options for displaying the different states of an asynchronous resource.
6
+ *
7
+ * @template Res - The type of the value when the resource is successfully loaded.
8
+ * @template E - The type of the error when the resource fails to load.
9
+ * @public
10
+ */
11
+ export interface MutationDisplayOptions<Req, Res, E> {
12
+ /** Function to render when the query is loading. */
13
+ pending?: (options: {
14
+ previous: Signal<Res | undefined>;
15
+ retry: () => void;
16
+ execute: (request: Req) => void;
17
+ cancel: (newState?: NonLoading<Res, E>) => void;
18
+ }) => TNode;
19
+ /** Function to render when the query has failed to load. */
20
+ failure?: (options: {
21
+ error: Signal<E>;
22
+ retry: () => void;
23
+ execute: (request: Req) => void;
24
+ }) => TNode;
25
+ /** Function to render when the query has successfully loaded. */
26
+ success: (options: {
27
+ value: Signal<Res>;
28
+ execute: (request: Req) => void;
29
+ }) => TNode;
30
+ notAsked: (options: {
31
+ execute: (request: Req) => void;
32
+ }) => TNode;
33
+ }
34
+ /**
35
+ * Component to display an asynchronous mutation based on its current status.
36
+ *
37
+ * @template Req - The type of the request.
38
+ * @template Res - The type of the value when the resource is successfully loaded.
39
+ * @template E - The type of the error when the resource fails to load.
40
+ *
41
+ * @param {MutationResource<Req, Res, E>} resource - The asynchronous resource to display.
42
+ * @param {MutationDisplayOptions<Req, Res, E>} options - The display options for the resource.
43
+ * @returns {Renderable} A node representing the current state of the resource.
44
+ * @public
45
+ */
46
+ export declare const MutationDisplay: <Req, Res, E>(resource: MutationResource<Req, Res, E>, options: MutationDisplayOptions<Req, Res, E>) => Renderable;
47
+ /**
48
+ * Creates a reactive mutation component for handling asynchronous data loading.
49
+ *
50
+ * This component provides a declarative way to handle async operations with proper
51
+ * loading, success, and error states. It automatically manages the lifecycle of
52
+ * async requests and provides reload functionality.
53
+ *
54
+ * @template Req - The type of the request.
55
+ * @template Res - The type of the value when the resource is successfully loaded.
56
+ * @template E - The type of the error when the resource fails to load.
57
+ *
58
+ * @param {MutationResource<Req, Res, E>} resource - The asynchronous resource to display.
59
+ * @param {MutationDisplayOptions<Req, Res, E>} options - The display options for the resource.
60
+ * @returns {Renderable} A node representing the current state of the resource.
61
+ * @public
62
+ */
63
+ export declare const Mutation: <Req, Res, E = unknown>({ mutate, convertError, onSuccess, onError, onSettled, pending, failure, success, notAsked, }: {
64
+ mutate: (options: MutationResourceExecuteOptions<Req, Res, E>) => Promise<Res>;
65
+ convertError?: (error: unknown) => E;
66
+ onSuccess?: (value: Res, req: Req) => void;
67
+ onError?: (error: E, req: Req) => void;
68
+ onSettled?: (result: AsyncResult<Res, E>, req: Req) => void;
69
+ } & MutationDisplayOptions<Req, Res, E>) => Renderable;
@@ -1,34 +1,45 @@
1
1
  import { Renderable, Signal, TNode, Value } from '@tempots/dom';
2
- import { AsyncResource, ResourceLoadOptions } from '../utils/resource';
2
+ import { QueryResource, QueryResourceLoadOptions } from '../utils/query-resource';
3
+ import { AsyncResult, NonLoading } from '@tempots/std';
3
4
  /**
4
- * Options for displaying the different states of an asynchronous resource.
5
+ * Options for displaying the different states of an asynchronous query.
5
6
  *
6
- * @template V - The type of the value when the resource is successfully loaded.
7
- * @template E - The type of the error when the resource fails to load.
7
+ * @template Res - The type of the value when the query is successfully loaded.
8
+ * @template E - The type of the error when the query fails to load.
8
9
  * @public
9
10
  */
10
- export interface ResourceDisplayOptions<V, E> {
11
- /** Function to render when the resource is loading. */
12
- loading?: (previous: Signal<V | undefined>, reload: () => void) => TNode;
13
- /** Function to render when the resource has failed to load. */
14
- failure?: (error: Signal<E>, reload: () => void) => TNode;
15
- /** Function to render when the resource has successfully loaded. */
16
- success: (value: Signal<V>, reload: () => void) => TNode;
11
+ export interface QueryDisplayOptions<Res, E> {
12
+ /** Function to render when the query is loading. */
13
+ pending?: (options: {
14
+ previous: Signal<Res | undefined>;
15
+ reload: () => void;
16
+ cancel: (newState?: NonLoading<Res, E>) => void;
17
+ }) => TNode;
18
+ /** Function to render when the query has failed to load. */
19
+ failure?: (options: {
20
+ error: Signal<E>;
21
+ reload: () => void;
22
+ }) => TNode;
23
+ /** Function to render when the query has successfully loaded. */
24
+ success: (options: {
25
+ value: Signal<Res>;
26
+ reload: () => void;
27
+ }) => TNode;
17
28
  }
18
29
  /**
19
- * Component to display an asynchronous resource based on its current status.
30
+ * Component to display an asynchronous query based on its current status.
20
31
  *
21
- * @template V - The type of the value when the resource is successfully loaded.
22
- * @template E - The type of the error when the resource fails to load.
32
+ * @template Res - The type of the value when the query is successfully loaded.
33
+ * @template E - The type of the error when the query fails to load.
23
34
  *
24
- * @param {AsyncResource<V, E>} resource - The asynchronous resource to display.
25
- * @param {ResourceDisplayOptions<V, E>} options - The display options for the resource.
26
- * @returns {TNode} A node representing the current state of the resource.
35
+ * @param {QueryResource<Res, E>} query - The asynchronous query to display.
36
+ * @param {QueryDisplayOptions<Res, E>} options - The display options for the query.
37
+ * @returns {TNode} A node representing the current state of the query.
27
38
  * @public
28
39
  */
29
- export declare const ResourceDisplay: <V, E>(resource: AsyncResource<V, E>, options: ResourceDisplayOptions<V, E>) => Renderable<import('@tempots/dom').DOMContext>;
40
+ export declare const QueryDisplay: <Res, E>(query: QueryResource<Res, E>, options: QueryDisplayOptions<Res, E>) => Renderable;
30
41
  /**
31
- * Creates a reactive resource component for handling asynchronous data loading.
42
+ * Creates a reactive query component for handling asynchronous data loading.
32
43
  *
33
44
  * This component provides a declarative way to handle async operations with proper
34
45
  * loading, success, and error states. It automatically manages the lifecycle of
@@ -39,14 +50,13 @@ export declare const ResourceDisplay: <V, E>(resource: AsyncResource<V, E>, opti
39
50
  * // Basic API data loading
40
51
  * const userId = prop(1)
41
52
  *
42
- * const UserProfile = Resource({
53
+ * const UserProfile = Query({
43
54
  * request: userId,
44
55
  * load: async ({ request }) => {
45
56
  * const response = await fetch(`/api/users/${request}`)
46
57
  * if (!response.ok) throw new Error('Failed to load user')
47
58
  * return response.json()
48
- * }
49
- * })({
59
+ * },
50
60
  * loading: () => html.div('Loading user...'),
51
61
  * failure: (error, reload) => html.div(
52
62
  * 'Error: ', error,
@@ -61,11 +71,11 @@ export declare const ResourceDisplay: <V, E>(resource: AsyncResource<V, E>, opti
61
71
  *
62
72
  * @example
63
73
  * ```typescript
64
- * // Resource with dependencies
74
+ * // Query with dependencies
65
75
  * const searchQuery = prop('')
66
76
  * const filters = prop({ category: 'all', sort: 'name' })
67
77
  *
68
- * const SearchResults = Resource({
78
+ * const SearchResults = Query({
69
79
  * request: computed(() => ({
70
80
  * query: searchQuery.value,
71
81
  * ...filters.value
@@ -77,8 +87,7 @@ export declare const ResourceDisplay: <V, E>(resource: AsyncResource<V, E>, opti
77
87
  * })
78
88
  * return response.json()
79
89
  * },
80
- * mapError: (error) => error instanceof Error ? error.message : 'Unknown error'
81
- * })({
90
+ * convertError: (error) => error instanceof Error ? error.message : 'Unknown error',
82
91
  * loading: (previous) => html.div(
83
92
  * 'Searching...',
84
93
  * previous.value && html.div('Previous results:', previous.value.length)
@@ -97,10 +106,10 @@ export declare const ResourceDisplay: <V, E>(resource: AsyncResource<V, E>, opti
97
106
  *
98
107
  * @example
99
108
  * ```typescript
100
- * // File upload resource
109
+ * // File upload query
101
110
  * const selectedFile = prop<File | null>(null)
102
111
  *
103
- * const FileUpload = Resource({
112
+ * const FileUpload = Query({
104
113
  * request: selectedFile,
105
114
  * load: async ({ request }) => {
106
115
  * if (!request) throw new Error('No file selected')
@@ -115,8 +124,7 @@ export declare const ResourceDisplay: <V, E>(resource: AsyncResource<V, E>, opti
115
124
  *
116
125
  * if (!response.ok) throw new Error('Upload failed')
117
126
  * return response.json()
118
- * }
119
- * })({
127
+ * },
120
128
  * loading: () => html.div(
121
129
  * attr.class('upload-progress'),
122
130
  * 'Uploading file...'
@@ -137,18 +145,27 @@ export declare const ResourceDisplay: <V, E>(resource: AsyncResource<V, E>, opti
137
145
  * })
138
146
  * ```
139
147
  *
140
- * @template R - The type of the request parameter
141
- * @template V - The type of the successful result value
148
+ * @template Req - The type of the request parameter
149
+ * @template Res - The type of the successful result value
142
150
  * @template E - The type of the error (defaults to unknown)
143
- * @param config - Configuration object for the resource
144
- * @param config.request - Signal or value representing the request parameters
145
- * @param config.load - Async function that loads the resource
146
- * @param config.mapError - Optional function to transform errors into a specific type
151
+ * @param options - Configuration object for the query
152
+ * @param options.request - Signal or value representing the request parameters
153
+ * @param options.load - Async function that loads the query
154
+ * @param options.convertError - Optional function to transform errors into a specific type
155
+ * @param options.onSuccess - Optional callback for successful loads
156
+ * @param options.onError - Optional callback for failed loads
157
+ * @param options.onSettled - Optional callback for both successful and failed loads
158
+ * @param options.success - Function to render when the query has successfully loaded
159
+ * @param options.pending - Optional function to render when the query is loading
160
+ * @param options.failure - Optional function to render when the query has failed to load
147
161
  * @returns Function that takes display options and returns a renderable component
148
162
  * @public
149
163
  */
150
- export declare const Resource: <R, V, E = unknown>({ request, load, mapError, }: {
151
- request: Value<R>;
152
- load: (options: ResourceLoadOptions<R, V, E>) => Promise<V>;
153
- mapError?: (error: unknown) => E;
154
- }) => ((displayOptions: ResourceDisplayOptions<V, E>) => Renderable);
164
+ export declare const Query: <Req, Res, E = unknown>({ request, load, convertError, onSuccess, onError, onSettled, success, pending, failure, }: {
165
+ request: Value<Req>;
166
+ load: (options: QueryResourceLoadOptions<Req, Res, E>) => Promise<Res>;
167
+ convertError?: (error: unknown) => E;
168
+ onSuccess?: (value: Res, req: Req) => void;
169
+ onError?: (error: E, req: Req) => void;
170
+ onSettled?: (result: AsyncResult<Res, E>, req: Req) => void;
171
+ } & QueryDisplayOptions<Res, E>) => Renderable;
@@ -246,7 +246,7 @@ export declare class Rect {
246
246
  *
247
247
  * @public
248
248
  */
249
- export declare function getAbsoluteRect(el: Element): Rect;
249
+ export declare function getAbsoluteRect(el: HTMLElement): Rect;
250
250
  /**
251
251
  * Creates a renderable function that monitors the size of an element and provides it as a signal.
252
252
  *
@@ -0,0 +1,59 @@
1
+ import { Signal } from '@tempots/dom';
2
+ import { AsyncResult, NonLoading } from '@tempots/std';
3
+ /**
4
+ * A write-side wrapper for async state around POST/PUT/PATCH/DELETE.
5
+ * Mirrors AsyncResource but the action is explicit (execute), not implicit (reload).
6
+ *
7
+ * @template Req - The request payload/type you send.
8
+ * @template Res - The response/value you get back on success.
9
+ * @template E - The error type on failure.
10
+ */
11
+ export interface MutationResource<Req, Res, E> {
12
+ /** Current async status (Idle | Loading | Success | Failure). */
13
+ readonly status: Signal<AsyncResult<Res, E>>;
14
+ /** Latest successful value (if any). */
15
+ readonly value: Signal<Res | undefined>;
16
+ /** Latest error (if any). */
17
+ readonly error: Signal<E | undefined>;
18
+ /** Whether a mutation is currently in flight. */
19
+ readonly pending: Signal<boolean>;
20
+ /** Execute the mutation. */
21
+ readonly execute: (request: Req, options?: MutationResourceExecuteOptions<Req, Res, E>) => void;
22
+ /** Abort the current in-flight request (if any) and clean up. */
23
+ readonly cancel: (newState?: NonLoading<Res, E>) => void;
24
+ /** Dispose of resources, aborting any in-flight request. */
25
+ readonly dispose: () => void;
26
+ }
27
+ /**
28
+ * Execution-time options for a mutation.
29
+ * Useful for optimistic UI and side-effects.
30
+ */
31
+ export interface MutationResourceExecuteOptions<Req, Res, E> {
32
+ /** The request to execute the mutation. */
33
+ readonly request: Req;
34
+ /** External abort signal for this single execution. */
35
+ readonly abortSignal: AbortSignal;
36
+ /** The previous result of the mutation, if any. */
37
+ readonly previous: AsyncResult<Res, E>;
38
+ /**
39
+ * Optionally provide an optimistic value to set immediately.
40
+ * This will set status to Loading with value prefilled.
41
+ */
42
+ readonly optimisticValue?: Res;
43
+ /**
44
+ * Optionally derive an optimistic value from the request.
45
+ * Runs only if optimisticValue is not provided.
46
+ */
47
+ readonly optimisticFromRequest?: (req: Req) => Res;
48
+ /** Side-effects */
49
+ readonly onSuccess?: (value: Res, req: Req) => void;
50
+ readonly onError?: (error: E, req: Req) => void;
51
+ readonly onSettled?: (result: AsyncResult<Res, E>, req: Req) => void;
52
+ }
53
+ export declare const makeMutationResource: <Req, Res, E>({ mutate, convertError, onSuccess, onError, onSettled, }: {
54
+ mutate: (options: MutationResourceExecuteOptions<Req, Res, E>) => Promise<Res>;
55
+ convertError: (error: unknown) => E;
56
+ onSuccess?: (value: Res, req: Req) => void;
57
+ onError?: (error: E, req: Req) => void;
58
+ onSettled?: (result: AsyncResult<Res, E>, req: Req) => void;
59
+ }) => MutationResource<Req, Res, E>;
@@ -0,0 +1,67 @@
1
+ import { Signal, Value } from '@tempots/dom';
2
+ import { AsyncResult, NonLoading } from '@tempots/std';
3
+ /**
4
+ * Represents an asynchronous query with its current status, value, error, and loading state.
5
+ * Provides methods to reload the query and dispose of it.
6
+ *
7
+ * @template Res - The type of the value when the query is successfully loaded.
8
+ * @template E - The type of the error when the query fails to load.
9
+ * @public
10
+ */
11
+ export interface QueryResource<Res, E> {
12
+ /** The current status of the query as an AsyncResult. */
13
+ readonly status: Signal<AsyncResult<Res, E>>;
14
+ /** Abort the current in-flight request (if any) and clean up. */
15
+ readonly cancel: (newState?: NonLoading<Res, E>) => void;
16
+ /** Disposes of the query, aborting any ongoing requests and cleaning up. */
17
+ readonly dispose: () => void;
18
+ /** The current value of the query, or undefined if not loaded or failed. */
19
+ readonly value: Signal<Res | undefined>;
20
+ /** The current error of the query, or undefined if not failed. */
21
+ readonly error: Signal<E | undefined>;
22
+ /** Whether the query is currently loading. */
23
+ readonly loading: Signal<boolean>;
24
+ /** Reloads the query using the current request. */
25
+ readonly reload: () => void;
26
+ }
27
+ /**
28
+ * Options for loading a query, including the request, abort signal, and previous result.
29
+ *
30
+ * @template Req - The type of the request.
31
+ * @template Res - The type of the value when the query is successfully loaded.
32
+ * @template E - The type of the error when the query fails to load.
33
+ * @public
34
+ */
35
+ export interface QueryResourceLoadOptions<Req, Res, E> {
36
+ /** The request to load the query. */
37
+ readonly request: Req;
38
+ /** The signal to abort the loading process if needed. */
39
+ readonly abortSignal: AbortSignal;
40
+ /** The previous result of the query loading, if any. */
41
+ readonly previous: AsyncResult<Res, E>;
42
+ /** Side-effects */
43
+ readonly onSuccess?: (value: Res, req: Req) => void;
44
+ readonly onError?: (error: E, req: Req) => void;
45
+ readonly onSettled?: (result: AsyncResult<Res, E>, req: Req) => void;
46
+ }
47
+ /**
48
+ * Creates an asynchronous query that can be loaded, reloaded, and disposed of.
49
+ *
50
+ * @template R - The type of the request.
51
+ * @template V - The type of the value when the query is successfully loaded.
52
+ * @template E - The type of the error when the query fails to load.
53
+ *
54
+ * @param request - The request to load the query.
55
+ * @param load - The function to load the query.
56
+ * @param convertError - The function to convert an unknown error into a specific error type.
57
+ * @returns The created asynchronous query.
58
+ * @public
59
+ */
60
+ export declare const makeQueryResource: <Req, Res, E>({ request, load, convertError, onSuccess, onError, onSettled, }: {
61
+ request: Value<Req>;
62
+ load: (options: QueryResourceLoadOptions<Req, Res, E>) => Promise<Res>;
63
+ convertError: (error: unknown) => E;
64
+ onSuccess?: (value: Res, req: Req) => void;
65
+ onError?: (error: E, req: Req) => void;
66
+ onSettled?: (result: AsyncResult<Res, E>, req: Req) => void;
67
+ }) => QueryResource<Res, E>;
@@ -1,54 +0,0 @@
1
- import { Signal, Value } from '@tempots/dom';
2
- import { AsyncResult } from '@tempots/std';
3
- /**
4
- * Represents an asynchronous resource with its current status, value, error, and loading state.
5
- * Provides methods to reload the resource and dispose of it.
6
- *
7
- * @template V - The type of the value when the resource is successfully loaded.
8
- * @template E - The type of the error when the resource fails to load.
9
- * @public
10
- */
11
- export interface AsyncResource<V, E> {
12
- /** The current status of the resource as an AsyncResult. */
13
- readonly status: Signal<AsyncResult<V, E>>;
14
- /** Disposes of the resource, aborting any ongoing requests and cleaning up. */
15
- readonly dispose: () => void;
16
- /** The current value of the resource, or undefined if not loaded or failed. */
17
- readonly value: Signal<V | undefined>;
18
- /** The current error of the resource, or undefined if not failed. */
19
- readonly error: Signal<E | undefined>;
20
- /** Whether the resource is currently loading. */
21
- readonly loading: Signal<boolean>;
22
- /** Reloads the resource using the current request. */
23
- readonly reload: () => void;
24
- }
25
- /**
26
- * Options for loading a resource, including the request, abort signal, and previous result.
27
- *
28
- * @template R - The type of the request.
29
- * @template V - The type of the value when the resource is successfully loaded.
30
- * @template E - The type of the error when the resource fails to load.
31
- * @public
32
- */
33
- export interface ResourceLoadOptions<R, V, E> {
34
- /** The request to load the resource. */
35
- readonly request: R;
36
- /** The signal to abort the loading process if needed. */
37
- readonly abortSignal: AbortSignal;
38
- /** The previous result of the resource loading, if any. */
39
- readonly previous: AsyncResult<V, E>;
40
- }
41
- /**
42
- * Creates an asynchronous resource that can be loaded, reloaded, and disposed of.
43
- *
44
- * @template R - The type of the request.
45
- * @template V - The type of the value when the resource is successfully loaded.
46
- * @template E - The type of the error when the resource fails to load.
47
- *
48
- * @param request - The request to load the resource.
49
- * @param load - The function to load the resource.
50
- * @param convertError - The function to convert an unknown error into a specific error type.
51
- * @returns The created asynchronous resource.
52
- * @public
53
- */
54
- export declare const makeResource: <R, V, E>(request: Value<R>, load: (options: ResourceLoadOptions<R, V, E>) => Promise<V>, convertError: (error: unknown) => E) => AsyncResource<V, E>;