@excom/fetchable-element 0.1.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/.rush/temp/chunked-rush-logs/fetchable-element.apply-exports.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/fetchable-element.build_docs.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/fetchable-element.build_package-metas.chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/all.log +1 -0
- package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/state.json +3 -0
- package/.rush/temp/operation/build_docs/all.log +1 -0
- package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_docs/state.json +3 -0
- package/.rush/temp/operation/build_package-metas/all.log +1 -0
- package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_package-metas/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +3 -0
- package/config/rig.json +6 -0
- package/index.ts +399 -0
- package/package.json +48 -0
- package/rush-logs/fetchable-element.apply-exports.cache.log +1 -0
- package/rush-logs/fetchable-element.apply-exports.log +1 -0
- package/rush-logs/fetchable-element.build_docs.cache.log +1 -0
- package/rush-logs/fetchable-element.build_docs.log +1 -0
- package/rush-logs/fetchable-element.build_package-metas.cache.log +1 -0
- package/rush-logs/fetchable-element.build_package-metas.log +1 -0
- package/support/custom-elements.json +368 -0
- package/support/dist-docs/fetchable-element.md +120 -0
- package/support/docs/README.md +67 -0
- package/support/package-meta.json +218 -0
- package/support/tests/fetch-lifecycle.test.ts +401 -0
- package/support/tests/fetchable-element.test.ts +184 -0
- package/tsconfig.json +5 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"modules": [
|
|
4
|
+
{
|
|
5
|
+
"kind": "javascript-module",
|
|
6
|
+
"path": "index.ts",
|
|
7
|
+
"declarations": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "mixin",
|
|
10
|
+
"name": "FetchableElement",
|
|
11
|
+
"mixins": [
|
|
12
|
+
{
|
|
13
|
+
"name": "AbortableElement",
|
|
14
|
+
"package": "@excom/abortable-element"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "LoadableElement",
|
|
18
|
+
"package": "@excom/loadable-element"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"description": "Composition base that owns the request lifecycle for `fetch()`-backed elements — building request args (attributes, a referenced `<form>`, or a custom override), tracking loading / success / error state (through `LoadableElement`), and canceling in-flight requests (via `AbortableElement`) when superseded or disconnected. Not a registered element on its own (tag is intentionally `noop-tag`) — compose it via `Neutron.compose([FetchableElement, ...])` and the consumer element inherits every attribute, state, and event declared below. Concrete consumers include `<provider-fetch>` (fetch-on-attribute-change), `<super-form>` (fetch-on-submit), and `<web-authn>` (WebAuthn ceremonies that still round-trip to a server). Subclasses call `doFetch(url, requestInit)` — typically built via `getFetchArgs(customFetchArgs?)`, which deep-merges (lowest → highest priority) the element's own attributes, the `<form>` referenced by `form-ref` (action/method/enctype/fields), and any custom args passed in — to run the request and drive `is-loading` / `is-success` / `is-error` / `provision` automatically. A prior in-flight request is canceled before a new one starts.",
|
|
22
|
+
"attributes": [
|
|
23
|
+
{
|
|
24
|
+
"name": "form-ref",
|
|
25
|
+
"type": {
|
|
26
|
+
"text": "string"
|
|
27
|
+
},
|
|
28
|
+
"description": "CSS selector for a `<form>` to source the request from — its `action` (URL), `method`, `enctype` (Content-Type), and field values (as the JSON payload) all take priority over the matching attributes below. Omit to build the request entirely from attributes / custom `doFetch()` args.",
|
|
29
|
+
"fieldName": "formRef",
|
|
30
|
+
"values": [
|
|
31
|
+
"<CSS Selector>"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "has-body",
|
|
36
|
+
"type": {
|
|
37
|
+
"text": "boolean"
|
|
38
|
+
},
|
|
39
|
+
"description": "Force a request body even for methods that don't imply one (`GET` / `HEAD`). Already implied for `POST` / `PUT` / `PATCH`.",
|
|
40
|
+
"fieldName": "hasBody"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "api-url",
|
|
44
|
+
"type": {
|
|
45
|
+
"text": "string"
|
|
46
|
+
},
|
|
47
|
+
"description": "Endpoint URL. When the request has no body, the JSON payload (from `form-ref` or custom `doFetch()` args) is merged in as query params instead.",
|
|
48
|
+
"fieldName": "apiUrl",
|
|
49
|
+
"default": ""
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "api-method",
|
|
53
|
+
"type": {
|
|
54
|
+
"text": "string"
|
|
55
|
+
},
|
|
56
|
+
"description": "HTTP method. Always uppercased before the request is sent.",
|
|
57
|
+
"fieldName": "apiMethod",
|
|
58
|
+
"default": "GET"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "header-accept",
|
|
62
|
+
"type": {
|
|
63
|
+
"text": "string"
|
|
64
|
+
},
|
|
65
|
+
"description": "`Accept` request header.",
|
|
66
|
+
"fieldName": "headerAccept",
|
|
67
|
+
"default": "application/json"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "header-content-type",
|
|
71
|
+
"type": {
|
|
72
|
+
"text": "string"
|
|
73
|
+
},
|
|
74
|
+
"description": "`Content-Type` request header. Dropped entirely when the request has no body.",
|
|
75
|
+
"fieldName": "headerContentType",
|
|
76
|
+
"default": "application/json"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "header-cache-control",
|
|
80
|
+
"type": {
|
|
81
|
+
"text": "string"
|
|
82
|
+
},
|
|
83
|
+
"description": "`Cache-Control` request header. Unset by default (browser default caching applies).",
|
|
84
|
+
"fieldName": "headerCacheControl"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "fetch-redirect",
|
|
88
|
+
"type": {
|
|
89
|
+
"text": "string"
|
|
90
|
+
},
|
|
91
|
+
"description": "`RequestInit.redirect` mode. Unset defers to the browser default (`follow`).",
|
|
92
|
+
"fieldName": "fetchRedirect",
|
|
93
|
+
"values": [
|
|
94
|
+
"follow",
|
|
95
|
+
"error",
|
|
96
|
+
"manual"
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "fetch-credentials",
|
|
101
|
+
"type": {
|
|
102
|
+
"text": "string"
|
|
103
|
+
},
|
|
104
|
+
"description": "`RequestInit.credentials` mode.",
|
|
105
|
+
"fieldName": "fetchCredentials",
|
|
106
|
+
"default": "include",
|
|
107
|
+
"values": [
|
|
108
|
+
"omit",
|
|
109
|
+
"same-origin",
|
|
110
|
+
"include"
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "is-loading",
|
|
115
|
+
"type": {
|
|
116
|
+
"text": "boolean"
|
|
117
|
+
},
|
|
118
|
+
"description": "A request is currently in flight.",
|
|
119
|
+
"fieldName": "isLoading"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "is-success",
|
|
123
|
+
"type": {
|
|
124
|
+
"text": "boolean"
|
|
125
|
+
},
|
|
126
|
+
"description": "The most recent request resolved successfully. Mutually exclusive with `is-error`.",
|
|
127
|
+
"fieldName": "isSuccess"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "is-error",
|
|
131
|
+
"type": {
|
|
132
|
+
"text": "boolean"
|
|
133
|
+
},
|
|
134
|
+
"description": "The most recent request failed (non-2xx status, network error, or a thrown error other than `AbortError`). Fires with the `error` event.",
|
|
135
|
+
"fieldName": "isError"
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
"members": [
|
|
139
|
+
{
|
|
140
|
+
"kind": "field",
|
|
141
|
+
"name": "formRef",
|
|
142
|
+
"type": {
|
|
143
|
+
"text": "string"
|
|
144
|
+
},
|
|
145
|
+
"privacy": "public",
|
|
146
|
+
"readonly": false,
|
|
147
|
+
"description": "CSS selector for a `<form>` to source the request from — its `action` (URL), `method`, `enctype` (Content-Type), and field values (as the JSON payload) all take priority over the matching attributes below. Omit to build the request entirely from attributes / custom `doFetch()` args.",
|
|
148
|
+
"_neutron": {
|
|
149
|
+
"surface": "option"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"kind": "field",
|
|
154
|
+
"name": "hasBody",
|
|
155
|
+
"type": {
|
|
156
|
+
"text": "boolean"
|
|
157
|
+
},
|
|
158
|
+
"privacy": "public",
|
|
159
|
+
"readonly": false,
|
|
160
|
+
"description": "Force a request body even for methods that don't imply one (`GET` / `HEAD`). Already implied for `POST` / `PUT` / `PATCH`.",
|
|
161
|
+
"_neutron": {
|
|
162
|
+
"surface": "option"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"kind": "field",
|
|
167
|
+
"name": "apiUrl",
|
|
168
|
+
"type": {
|
|
169
|
+
"text": "string"
|
|
170
|
+
},
|
|
171
|
+
"privacy": "public",
|
|
172
|
+
"readonly": false,
|
|
173
|
+
"description": "Endpoint URL. When the request has no body, the JSON payload (from `form-ref` or custom `doFetch()` args) is merged in as query params instead.",
|
|
174
|
+
"default": "",
|
|
175
|
+
"_neutron": {
|
|
176
|
+
"surface": "option"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"kind": "field",
|
|
181
|
+
"name": "apiMethod",
|
|
182
|
+
"type": {
|
|
183
|
+
"text": "string"
|
|
184
|
+
},
|
|
185
|
+
"privacy": "public",
|
|
186
|
+
"readonly": false,
|
|
187
|
+
"description": "HTTP method. Always uppercased before the request is sent.",
|
|
188
|
+
"default": "GET",
|
|
189
|
+
"_neutron": {
|
|
190
|
+
"surface": "option"
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"kind": "field",
|
|
195
|
+
"name": "headerAccept",
|
|
196
|
+
"type": {
|
|
197
|
+
"text": "string"
|
|
198
|
+
},
|
|
199
|
+
"privacy": "public",
|
|
200
|
+
"readonly": false,
|
|
201
|
+
"description": "`Accept` request header.",
|
|
202
|
+
"default": "application/json",
|
|
203
|
+
"_neutron": {
|
|
204
|
+
"surface": "option"
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"kind": "field",
|
|
209
|
+
"name": "headerContentType",
|
|
210
|
+
"type": {
|
|
211
|
+
"text": "string"
|
|
212
|
+
},
|
|
213
|
+
"privacy": "public",
|
|
214
|
+
"readonly": false,
|
|
215
|
+
"description": "`Content-Type` request header. Dropped entirely when the request has no body.",
|
|
216
|
+
"default": "application/json",
|
|
217
|
+
"_neutron": {
|
|
218
|
+
"surface": "option"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"kind": "field",
|
|
223
|
+
"name": "headerCacheControl",
|
|
224
|
+
"type": {
|
|
225
|
+
"text": "string"
|
|
226
|
+
},
|
|
227
|
+
"privacy": "public",
|
|
228
|
+
"readonly": false,
|
|
229
|
+
"description": "`Cache-Control` request header. Unset by default (browser default caching applies).",
|
|
230
|
+
"_neutron": {
|
|
231
|
+
"surface": "option"
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"kind": "field",
|
|
236
|
+
"name": "fetchRedirect",
|
|
237
|
+
"type": {
|
|
238
|
+
"text": "string"
|
|
239
|
+
},
|
|
240
|
+
"privacy": "public",
|
|
241
|
+
"readonly": false,
|
|
242
|
+
"description": "`RequestInit.redirect` mode. Unset defers to the browser default (`follow`).",
|
|
243
|
+
"_neutron": {
|
|
244
|
+
"surface": "option"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"kind": "field",
|
|
249
|
+
"name": "fetchCredentials",
|
|
250
|
+
"type": {
|
|
251
|
+
"text": "string"
|
|
252
|
+
},
|
|
253
|
+
"privacy": "public",
|
|
254
|
+
"readonly": false,
|
|
255
|
+
"description": "`RequestInit.credentials` mode.",
|
|
256
|
+
"default": "include",
|
|
257
|
+
"_neutron": {
|
|
258
|
+
"surface": "option"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"kind": "field",
|
|
263
|
+
"name": "isLoading",
|
|
264
|
+
"type": {
|
|
265
|
+
"text": "boolean"
|
|
266
|
+
},
|
|
267
|
+
"privacy": "public",
|
|
268
|
+
"readonly": true,
|
|
269
|
+
"description": "A request is currently in flight.",
|
|
270
|
+
"_neutron": {
|
|
271
|
+
"surface": "state"
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"kind": "field",
|
|
276
|
+
"name": "isSuccess",
|
|
277
|
+
"type": {
|
|
278
|
+
"text": "boolean"
|
|
279
|
+
},
|
|
280
|
+
"privacy": "public",
|
|
281
|
+
"readonly": true,
|
|
282
|
+
"description": "The most recent request resolved successfully. Mutually exclusive with `is-error`.",
|
|
283
|
+
"_neutron": {
|
|
284
|
+
"surface": "state"
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
"kind": "field",
|
|
289
|
+
"name": "isError",
|
|
290
|
+
"type": {
|
|
291
|
+
"text": "boolean"
|
|
292
|
+
},
|
|
293
|
+
"privacy": "public",
|
|
294
|
+
"readonly": true,
|
|
295
|
+
"description": "The most recent request failed (non-2xx status, network error, or a thrown error other than `AbortError`). Fires with the `error` event.",
|
|
296
|
+
"_neutron": {
|
|
297
|
+
"surface": "state"
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"kind": "field",
|
|
302
|
+
"name": "provision",
|
|
303
|
+
"type": {
|
|
304
|
+
"text": "FetchResponse",
|
|
305
|
+
"expanded": "{ bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; }"
|
|
306
|
+
},
|
|
307
|
+
"privacy": "public",
|
|
308
|
+
"readonly": false,
|
|
309
|
+
"description": "Response payload on success, or error payload on failure. Success shape: `{ status, statusText, ok, headers, url, redirected, bodyUsed, type, body }`. Failure shape is either that same response shape (server responded with an error status) or `{ message, stack }` (request never completed). Not reflected as an attribute.",
|
|
310
|
+
"_neutron": {
|
|
311
|
+
"surface": "option"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
],
|
|
315
|
+
"events": [
|
|
316
|
+
{
|
|
317
|
+
"name": "{tag}-loading",
|
|
318
|
+
"description": "Dispatched immediately before the request is sent.",
|
|
319
|
+
"type": {
|
|
320
|
+
"text": "FetchableLoadingEvent",
|
|
321
|
+
"expanded": "CustomEvent & { type: \"{tag}-loading\"; detail: void; bubbles: true; cancelable: true; composed: true }"
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"name": "{tag}-success",
|
|
326
|
+
"description": "Dispatched when the request resolves successfully. `event.detail` is the parsed response (see `provision`).",
|
|
327
|
+
"type": {
|
|
328
|
+
"text": "FetchableSuccessEvent",
|
|
329
|
+
"expanded": "CustomEvent & { type: \"{tag}-success\"; detail: { bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; }; bubbles: true; cancelable: true; composed: true }"
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"name": "{tag}-error",
|
|
334
|
+
"description": "Dispatched when the request fails — non-2xx status, network error, or a thrown error. `event.detail` is the error payload (see `provision`). Not dispatched for aborted requests.",
|
|
335
|
+
"type": {
|
|
336
|
+
"text": "FetchableErrorEvent",
|
|
337
|
+
"expanded": "CustomEvent & { type: \"{tag}-error\"; detail: { bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; } | { message: string; stack?: string }; bubbles: true; cancelable: true; composed: true }"
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
],
|
|
341
|
+
"_neutron": {
|
|
342
|
+
"provisions": [
|
|
343
|
+
{
|
|
344
|
+
"name": "provision",
|
|
345
|
+
"type": {
|
|
346
|
+
"text": "FetchResponse",
|
|
347
|
+
"expanded": "{ bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; }"
|
|
348
|
+
},
|
|
349
|
+
"description": "Response payload on success, or error payload on failure. Success shape: `{ status, statusText, ok, headers, url, redirected, bodyUsed, type, body }`. Failure shape is either that same response shape (server responded with an error status) or `{ message, stack }` (request never completed). Not reflected as an attribute.",
|
|
350
|
+
"fieldName": "provision"
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
],
|
|
356
|
+
"exports": [
|
|
357
|
+
{
|
|
358
|
+
"kind": "js",
|
|
359
|
+
"name": "FetchableElement",
|
|
360
|
+
"declaration": {
|
|
361
|
+
"name": "FetchableElement",
|
|
362
|
+
"module": "index.ts"
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# fetchable-element
|
|
2
|
+
|
|
3
|
+
Composition base that owns the `fetch()` lifecycle for Neutron elements —
|
|
4
|
+
build the request from attributes, a `<form>`, or a custom override, then
|
|
5
|
+
track loading / success / error state automatically.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Shared lifecycle** States, `provision` and events come from [loadable-element](/nucleus/packages/loadable-element)
|
|
10
|
+
|
|
11
|
+
- **Attribute-driven requests** URL, method, headers, redirect, and
|
|
12
|
+
credentials all configurable declaratively
|
|
13
|
+
- **Form-aware** Point `form-ref` at a `<form>` to source action, method,
|
|
14
|
+
enctype, and field values
|
|
15
|
+
- **Merged payloads** Attributes, form, and custom args deep-merge
|
|
16
|
+
(lowest → highest priority)
|
|
17
|
+
- **Lifecycle state** `is-loading` / `is-success` / `is-error` managed
|
|
18
|
+
for you
|
|
19
|
+
- **Provision** `provision` is the parsed response (or error payload) for
|
|
20
|
+
Quark `prop("provision")` — not a reflected attribute
|
|
21
|
+
- **Cancel-safe** Superseded or disconnected requests are aborted via
|
|
22
|
+
`AbortableElement`
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
`@excom/fetchable-element` v0.1.0
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add @excom/fetchable-element
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @excom/fetchable-element
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
yarn add @excom/fetchable-element
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Import
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { /* … */ } from "@excom/fetchable-element";
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
Compose `FetchableElement`, then call `doFetch(url, requestInit)` —
|
|
52
|
+
usually built via `getFetchArgs(customFetchArgs?)` — whenever the
|
|
53
|
+
subclass decides a request should run. Concrete consumers include
|
|
54
|
+
`<provider-fetch>` (fetch on attribute change), `<super-form>` (fetch on
|
|
55
|
+
submit), and `<web-authn>` (WebAuthn ceremonies that still round-trip to
|
|
56
|
+
a server).
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { Neutron } from "@excom/neutron";
|
|
60
|
+
import { FetchableElement } from "@excom/fetchable-element";
|
|
61
|
+
|
|
62
|
+
export const RefreshOnClick = Neutron.compose([
|
|
63
|
+
FetchableElement,
|
|
64
|
+
Neutron({ tag: "refresh-on-click" }),
|
|
65
|
+
])
|
|
66
|
+
.onEvent("click", ({ getFetchArgs }) => ({
|
|
67
|
+
doFetch: getFetchArgs(),
|
|
68
|
+
}));
|
|
69
|
+
|
|
70
|
+
RefreshOnClick.define();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<refresh-on-click api-url="/api/status"></refresh-on-click>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Every prop, state field, and event documented below is inherited
|
|
78
|
+
verbatim by any element that composes `FetchableElement` — it flattens
|
|
79
|
+
directly into that element's own generated docs, so `<provider-fetch>`
|
|
80
|
+
and friends don't redeclare it.
|
|
81
|
+
|
|
82
|
+
### API Reference
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
#### Attributes
|
|
86
|
+
|
|
87
|
+
| Name | Surface | Type | Default | Values | Description |
|
|
88
|
+
| --- | --- | --- | --- | --- | --- |
|
|
89
|
+
| `form-ref` | option | `string` | | `<CSS Selector>` | CSS selector for a `<form>` to source the request from — its `action` (URL), `method`, `enctype` (Content-Type), and field values (as the JSON payload) all take priority over the matching attributes below. Omit to build the request entirely from attributes / custom `doFetch()` args. |
|
|
90
|
+
| `has-body` | option | `boolean` | | | Force a request body even for methods that don't imply one (`GET` / `HEAD`). Already implied for `POST` / `PUT` / `PATCH`. |
|
|
91
|
+
| `api-url` | option | `string` | `""` | | Endpoint URL. When the request has no body, the JSON payload (from `form-ref` or custom `doFetch()` args) is merged in as query params instead. |
|
|
92
|
+
| `api-method` | option | `string` | `"GET"` | | HTTP method. Always uppercased before the request is sent. |
|
|
93
|
+
| `header-accept` | option | `string` | `"application/json"` | | `Accept` request header. |
|
|
94
|
+
| `header-content-type` | option | `string` | `"application/json"` | | `Content-Type` request header. Dropped entirely when the request has no body. |
|
|
95
|
+
| `header-cache-control` | option | `string` | | | `Cache-Control` request header. Unset by default (browser default caching applies). |
|
|
96
|
+
| `fetch-redirect` | option | `string` | | `"follow"` \| `"error"` \| `"manual"` | `RequestInit.redirect` mode. Unset defers to the browser default (`follow`). |
|
|
97
|
+
| `fetch-credentials` | option | `string` | `"include"` | `"omit"` \| `"same-origin"` \| `"include"` | `RequestInit.credentials` mode. |
|
|
98
|
+
| `is-loading` | state | `boolean` | | | A request is currently in flight. |
|
|
99
|
+
| `is-success` | state | `boolean` | | | The most recent request resolved successfully. Mutually exclusive with `is-error`. |
|
|
100
|
+
| `is-error` | state | `boolean` | | | The most recent request failed (non-2xx status, network error, or a thrown error other than `AbortError`). Fires with the `error` event. |
|
|
101
|
+
|
|
102
|
+
#### Provision
|
|
103
|
+
|
|
104
|
+
| Name | Type | Description |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `provision` | `FetchResponse` (`{ bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; }`) | Response payload on success, or error payload on failure. Success shape: `{ status, statusText, ok, headers, url, redirected, bodyUsed, type, body }`. Failure shape is either that same response shape (server responded with an error status) or `{ message, stack }` (request never completed). Not reflected as an attribute. |
|
|
107
|
+
|
|
108
|
+
#### Fires
|
|
109
|
+
|
|
110
|
+
| Name | Type | Description |
|
|
111
|
+
| --- | --- | --- |
|
|
112
|
+
| `{tag}-loading` | `FetchableLoadingEvent` (`CustomEvent & { type: "{tag}-loading"; detail: void; bubbles: true; cancelable: true; composed: true }`) | Dispatched immediately before the request is sent. |
|
|
113
|
+
| `{tag}-success` | `FetchableSuccessEvent` (`CustomEvent & { type: "{tag}-success"; detail: { bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; }; bubbles: true; cancelable: true; composed: true }`) | Dispatched when the request resolves successfully. `event.detail` is the parsed response (see `provision`). |
|
|
114
|
+
| `{tag}-error` | `FetchableErrorEvent` (`CustomEvent & { type: "{tag}-error"; detail: { bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; } \| { message: string; stack?: string }; bubbles: true; cancelable: true; composed: true }`) | Dispatched when the request fails — non-2xx status, network error, or a thrown error. `event.detail` is the error payload (see `provision`). Not dispatched for aborted requests. |
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
There are no demos for this package — see
|
|
119
|
+
[provider-fetch](/nucleus/packages/provider-fetch) for `FetchableElement` in
|
|
120
|
+
action against a real endpoint.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# fetchable-element
|
|
2
|
+
|
|
3
|
+
Composition base that owns the `fetch()` lifecycle for Neutron elements —
|
|
4
|
+
build the request from attributes, a `<form>`, or a custom override, then
|
|
5
|
+
track loading / success / error state automatically.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Shared lifecycle** States, `provision` and events come from [loadable-element](/nucleus/packages/loadable-element)
|
|
10
|
+
|
|
11
|
+
- **Attribute-driven requests** URL, method, headers, redirect, and
|
|
12
|
+
credentials all configurable declaratively
|
|
13
|
+
- **Form-aware** Point `form-ref` at a `<form>` to source action, method,
|
|
14
|
+
enctype, and field values
|
|
15
|
+
- **Merged payloads** Attributes, form, and custom args deep-merge
|
|
16
|
+
(lowest → highest priority)
|
|
17
|
+
- **Lifecycle state** `is-loading` / `is-success` / `is-error` managed
|
|
18
|
+
for you
|
|
19
|
+
- **Provision** `provision` is the parsed response (or error payload) for
|
|
20
|
+
Quark `prop("provision")` — not a reflected attribute
|
|
21
|
+
- **Cancel-safe** Superseded or disconnected requests are aborted via
|
|
22
|
+
`AbortableElement`
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
<include-content is-active template-ref="/views/install-section/install-section.html"></include-content>
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
Compose `FetchableElement`, then call `doFetch(url, requestInit)` —
|
|
31
|
+
usually built via `getFetchArgs(customFetchArgs?)` — whenever the
|
|
32
|
+
subclass decides a request should run. Concrete consumers include
|
|
33
|
+
`<provider-fetch>` (fetch on attribute change), `<super-form>` (fetch on
|
|
34
|
+
submit), and `<web-authn>` (WebAuthn ceremonies that still round-trip to
|
|
35
|
+
a server).
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { Neutron } from "@excom/neutron";
|
|
39
|
+
import { FetchableElement } from "@excom/fetchable-element";
|
|
40
|
+
|
|
41
|
+
export const RefreshOnClick = Neutron.compose([
|
|
42
|
+
FetchableElement,
|
|
43
|
+
Neutron({ tag: "refresh-on-click" }),
|
|
44
|
+
])
|
|
45
|
+
.onEvent("click", ({ getFetchArgs }) => ({
|
|
46
|
+
doFetch: getFetchArgs(),
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
RefreshOnClick.define();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<refresh-on-click api-url="/api/status"></refresh-on-click>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Every prop, state field, and event documented below is inherited
|
|
57
|
+
verbatim by any element that composes `FetchableElement` — it flattens
|
|
58
|
+
directly into that element's own generated docs, so `<provider-fetch>`
|
|
59
|
+
and friends don't redeclare it.
|
|
60
|
+
|
|
61
|
+
### API Reference
|
|
62
|
+
|
|
63
|
+
<include-content is-active template-ref="/views/api-reference/api-reference.html"></include-content>
|
|
64
|
+
|
|
65
|
+
There are no demos for this package — see
|
|
66
|
+
[provider-fetch](/nucleus/packages/provider-fetch) for `FetchableElement` in
|
|
67
|
+
action against a real endpoint.
|