ccstate-react 4.8.0 → 4.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # ccstate-react
2
2
 
3
+ ## 4.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e00d4af: feat: useLoadable support non-promise signals
8
+ - e00d4af: feat: collect floating promise in async computed
9
+
10
+ ### Patch Changes
11
+
12
+ - ccstate@4.10.0
13
+
14
+ ## 4.9.0
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [89440c6]
19
+ - ccstate@4.9.0
20
+
3
21
  ## 4.8.0
4
22
 
5
23
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -48,6 +48,31 @@ function _arrayLikeToArray(r, a) {
48
48
  function _arrayWithHoles(r) {
49
49
  if (Array.isArray(r)) return r;
50
50
  }
51
+ function asyncGeneratorStep(n, t, e, r, o, a, c) {
52
+ try {
53
+ var i = n[a](c),
54
+ u = i.value;
55
+ } catch (n) {
56
+ return void e(n);
57
+ }
58
+ i.done ? t(u) : Promise.resolve(u).then(r, o);
59
+ }
60
+ function _asyncToGenerator(n) {
61
+ return function () {
62
+ var t = this,
63
+ e = arguments;
64
+ return new Promise(function (r, o) {
65
+ var a = n.apply(t, e);
66
+ function _next(n) {
67
+ asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
68
+ }
69
+ function _throw(n) {
70
+ asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
71
+ }
72
+ _next(void 0);
73
+ });
74
+ };
75
+ }
51
76
  function _iterableToArrayLimit(r, l) {
52
77
  var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
53
78
  if (null != t) {
@@ -75,6 +100,307 @@ function _iterableToArrayLimit(r, l) {
75
100
  function _nonIterableRest() {
76
101
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
77
102
  }
103
+ function _regeneratorRuntime() {
104
+ _regeneratorRuntime = function () {
105
+ return e;
106
+ };
107
+ var t,
108
+ e = {},
109
+ r = Object.prototype,
110
+ n = r.hasOwnProperty,
111
+ o = Object.defineProperty || function (t, e, r) {
112
+ t[e] = r.value;
113
+ },
114
+ i = "function" == typeof Symbol ? Symbol : {},
115
+ a = i.iterator || "@@iterator",
116
+ c = i.asyncIterator || "@@asyncIterator",
117
+ u = i.toStringTag || "@@toStringTag";
118
+ function define(t, e, r) {
119
+ return Object.defineProperty(t, e, {
120
+ value: r,
121
+ enumerable: !0,
122
+ configurable: !0,
123
+ writable: !0
124
+ }), t[e];
125
+ }
126
+ try {
127
+ define({}, "");
128
+ } catch (t) {
129
+ define = function (t, e, r) {
130
+ return t[e] = r;
131
+ };
132
+ }
133
+ function wrap(t, e, r, n) {
134
+ var i = e && e.prototype instanceof Generator ? e : Generator,
135
+ a = Object.create(i.prototype),
136
+ c = new Context(n || []);
137
+ return o(a, "_invoke", {
138
+ value: makeInvokeMethod(t, r, c)
139
+ }), a;
140
+ }
141
+ function tryCatch(t, e, r) {
142
+ try {
143
+ return {
144
+ type: "normal",
145
+ arg: t.call(e, r)
146
+ };
147
+ } catch (t) {
148
+ return {
149
+ type: "throw",
150
+ arg: t
151
+ };
152
+ }
153
+ }
154
+ e.wrap = wrap;
155
+ var h = "suspendedStart",
156
+ l = "suspendedYield",
157
+ f = "executing",
158
+ s = "completed",
159
+ y = {};
160
+ function Generator() {}
161
+ function GeneratorFunction() {}
162
+ function GeneratorFunctionPrototype() {}
163
+ var p = {};
164
+ define(p, a, function () {
165
+ return this;
166
+ });
167
+ var d = Object.getPrototypeOf,
168
+ v = d && d(d(values([])));
169
+ v && v !== r && n.call(v, a) && (p = v);
170
+ var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p);
171
+ function defineIteratorMethods(t) {
172
+ ["next", "throw", "return"].forEach(function (e) {
173
+ define(t, e, function (t) {
174
+ return this._invoke(e, t);
175
+ });
176
+ });
177
+ }
178
+ function AsyncIterator(t, e) {
179
+ function invoke(r, o, i, a) {
180
+ var c = tryCatch(t[r], t, o);
181
+ if ("throw" !== c.type) {
182
+ var u = c.arg,
183
+ h = u.value;
184
+ return h && "object" == typeof h && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) {
185
+ invoke("next", t, i, a);
186
+ }, function (t) {
187
+ invoke("throw", t, i, a);
188
+ }) : e.resolve(h).then(function (t) {
189
+ u.value = t, i(u);
190
+ }, function (t) {
191
+ return invoke("throw", t, i, a);
192
+ });
193
+ }
194
+ a(c.arg);
195
+ }
196
+ var r;
197
+ o(this, "_invoke", {
198
+ value: function (t, n) {
199
+ function callInvokeWithMethodAndArg() {
200
+ return new e(function (e, r) {
201
+ invoke(t, n, e, r);
202
+ });
203
+ }
204
+ return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
205
+ }
206
+ });
207
+ }
208
+ function makeInvokeMethod(e, r, n) {
209
+ var o = h;
210
+ return function (i, a) {
211
+ if (o === f) throw Error("Generator is already running");
212
+ if (o === s) {
213
+ if ("throw" === i) throw a;
214
+ return {
215
+ value: t,
216
+ done: !0
217
+ };
218
+ }
219
+ for (n.method = i, n.arg = a;;) {
220
+ var c = n.delegate;
221
+ if (c) {
222
+ var u = maybeInvokeDelegate(c, n);
223
+ if (u) {
224
+ if (u === y) continue;
225
+ return u;
226
+ }
227
+ }
228
+ if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
229
+ if (o === h) throw o = s, n.arg;
230
+ n.dispatchException(n.arg);
231
+ } else "return" === n.method && n.abrupt("return", n.arg);
232
+ o = f;
233
+ var p = tryCatch(e, r, n);
234
+ if ("normal" === p.type) {
235
+ if (o = n.done ? s : l, p.arg === y) continue;
236
+ return {
237
+ value: p.arg,
238
+ done: n.done
239
+ };
240
+ }
241
+ "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg);
242
+ }
243
+ };
244
+ }
245
+ function maybeInvokeDelegate(e, r) {
246
+ var n = r.method,
247
+ o = e.iterator[n];
248
+ if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y;
249
+ var i = tryCatch(o, e.iterator, r.arg);
250
+ if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y;
251
+ var a = i.arg;
252
+ return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y);
253
+ }
254
+ function pushTryEntry(t) {
255
+ var e = {
256
+ tryLoc: t[0]
257
+ };
258
+ 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e);
259
+ }
260
+ function resetTryEntry(t) {
261
+ var e = t.completion || {};
262
+ e.type = "normal", delete e.arg, t.completion = e;
263
+ }
264
+ function Context(t) {
265
+ this.tryEntries = [{
266
+ tryLoc: "root"
267
+ }], t.forEach(pushTryEntry, this), this.reset(!0);
268
+ }
269
+ function values(e) {
270
+ if (e || "" === e) {
271
+ var r = e[a];
272
+ if (r) return r.call(e);
273
+ if ("function" == typeof e.next) return e;
274
+ if (!isNaN(e.length)) {
275
+ var o = -1,
276
+ i = function next() {
277
+ for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next;
278
+ return next.value = t, next.done = !0, next;
279
+ };
280
+ return i.next = i;
281
+ }
282
+ }
283
+ throw new TypeError(typeof e + " is not iterable");
284
+ }
285
+ return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", {
286
+ value: GeneratorFunctionPrototype,
287
+ configurable: !0
288
+ }), o(GeneratorFunctionPrototype, "constructor", {
289
+ value: GeneratorFunction,
290
+ configurable: !0
291
+ }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) {
292
+ var e = "function" == typeof t && t.constructor;
293
+ return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name));
294
+ }, e.mark = function (t) {
295
+ return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t;
296
+ }, e.awrap = function (t) {
297
+ return {
298
+ __await: t
299
+ };
300
+ }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () {
301
+ return this;
302
+ }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) {
303
+ void 0 === i && (i = Promise);
304
+ var a = new AsyncIterator(wrap(t, r, n, o), i);
305
+ return e.isGeneratorFunction(r) ? a : a.next().then(function (t) {
306
+ return t.done ? t.value : a.next();
307
+ });
308
+ }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () {
309
+ return this;
310
+ }), define(g, "toString", function () {
311
+ return "[object Generator]";
312
+ }), e.keys = function (t) {
313
+ var e = Object(t),
314
+ r = [];
315
+ for (var n in e) r.push(n);
316
+ return r.reverse(), function next() {
317
+ for (; r.length;) {
318
+ var t = r.pop();
319
+ if (t in e) return next.value = t, next.done = !1, next;
320
+ }
321
+ return next.done = !0, next;
322
+ };
323
+ }, e.values = values, Context.prototype = {
324
+ constructor: Context,
325
+ reset: function (e) {
326
+ if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t);
327
+ },
328
+ stop: function () {
329
+ this.done = !0;
330
+ var t = this.tryEntries[0].completion;
331
+ if ("throw" === t.type) throw t.arg;
332
+ return this.rval;
333
+ },
334
+ dispatchException: function (e) {
335
+ if (this.done) throw e;
336
+ var r = this;
337
+ function handle(n, o) {
338
+ return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o;
339
+ }
340
+ for (var o = this.tryEntries.length - 1; o >= 0; --o) {
341
+ var i = this.tryEntries[o],
342
+ a = i.completion;
343
+ if ("root" === i.tryLoc) return handle("end");
344
+ if (i.tryLoc <= this.prev) {
345
+ var c = n.call(i, "catchLoc"),
346
+ u = n.call(i, "finallyLoc");
347
+ if (c && u) {
348
+ if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
349
+ if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
350
+ } else if (c) {
351
+ if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
352
+ } else {
353
+ if (!u) throw Error("try statement without catch or finally");
354
+ if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
355
+ }
356
+ }
357
+ }
358
+ },
359
+ abrupt: function (t, e) {
360
+ for (var r = this.tryEntries.length - 1; r >= 0; --r) {
361
+ var o = this.tryEntries[r];
362
+ if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) {
363
+ var i = o;
364
+ break;
365
+ }
366
+ }
367
+ i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null);
368
+ var a = i ? i.completion : {};
369
+ return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a);
370
+ },
371
+ complete: function (t, e) {
372
+ if ("throw" === t.type) throw t.arg;
373
+ return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y;
374
+ },
375
+ finish: function (t) {
376
+ for (var e = this.tryEntries.length - 1; e >= 0; --e) {
377
+ var r = this.tryEntries[e];
378
+ if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y;
379
+ }
380
+ },
381
+ catch: function (t) {
382
+ for (var e = this.tryEntries.length - 1; e >= 0; --e) {
383
+ var r = this.tryEntries[e];
384
+ if (r.tryLoc === t) {
385
+ var n = r.completion;
386
+ if ("throw" === n.type) {
387
+ var o = n.arg;
388
+ resetTryEntry(r);
389
+ }
390
+ return o;
391
+ }
392
+ }
393
+ throw Error("illegal catch attempt");
394
+ },
395
+ delegateYield: function (e, r, n) {
396
+ return this.delegate = {
397
+ iterator: values(e),
398
+ resultName: r,
399
+ nextLoc: n
400
+ }, "next" === this.method && (this.arg = t), y;
401
+ }
402
+ }, e;
403
+ }
78
404
  function _slicedToArray(r, e) {
79
405
  return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
80
406
  }
@@ -86,8 +412,48 @@ function _unsupportedIterableToArray(r, a) {
86
412
  }
87
413
  }
88
414
 
415
+ var internalFloatingPromises$ = ccstate.state(new Set());
416
+ var collectFloatingPromise$ = ccstate.command(function (_ref, promise, signal) {
417
+ var set = _ref.set;
418
+ signal.addEventListener('abort', function () {
419
+ set(internalFloatingPromises$, function (prev) {
420
+ var ret = new Set(prev);
421
+ ret["delete"](promise);
422
+ return ret;
423
+ });
424
+ });
425
+ set(internalFloatingPromises$, function (prev) {
426
+ var ret = new Set(prev);
427
+ ret.add(promise);
428
+ return ret;
429
+ });
430
+ });
431
+ var floatingPromises$ = ccstate.computed(function (get) {
432
+ return get(internalFloatingPromises$);
433
+ });
434
+ var asyncGetSettled$ = ccstate.computed(/*#__PURE__*/function () {
435
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(get) {
436
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
437
+ while (1) switch (_context.prev = _context.next) {
438
+ case 0:
439
+ _context.next = 2;
440
+ return Promise.all(get(floatingPromises$));
441
+ case 2:
442
+ return _context.abrupt("return", _context.sent);
443
+ case 3:
444
+ case "end":
445
+ return _context.stop();
446
+ }
447
+ }, _callee);
448
+ }));
449
+ return function (_x) {
450
+ return _ref2.apply(this, arguments);
451
+ };
452
+ }());
453
+
89
454
  function useLoadableInternal(atom, keepLastResolved) {
90
455
  var promise = useGet(atom);
456
+ var collectFloatingPromise = useSet(collectFloatingPromise$);
91
457
  var _useState = react.useState({
92
458
  state: 'loading'
93
459
  }),
@@ -95,26 +461,36 @@ function useLoadableInternal(atom, keepLastResolved) {
95
461
  promiseResult = _useState2[0],
96
462
  setPromiseResult = _useState2[1];
97
463
  react.useEffect(function () {
464
+ if (!(promise instanceof Promise)) {
465
+ setPromiseResult({
466
+ state: 'hasData',
467
+ data: promise
468
+ });
469
+ return;
470
+ }
98
471
  var ctrl = new AbortController();
472
+ var settledController = new AbortController();
99
473
  var signal = ctrl.signal;
100
474
  if (!keepLastResolved) {
101
475
  setPromiseResult({
102
476
  state: 'loading'
103
477
  });
104
478
  }
105
- void promise.then(function (ret) {
479
+ collectFloatingPromise(promise.then(function (ret) {
480
+ settledController.abort();
106
481
  if (signal.aborted) return;
107
482
  setPromiseResult({
108
483
  state: 'hasData',
109
484
  data: ret
110
485
  });
111
- })["catch"](function (error) {
486
+ }, function (error) {
487
+ settledController.abort();
112
488
  if (signal.aborted) return;
113
489
  setPromiseResult({
114
490
  state: 'hasError',
115
491
  error: error
116
492
  });
117
- });
493
+ }), AbortSignal.any([signal, settledController.signal]));
118
494
  return function () {
119
495
  ctrl.abort();
120
496
  };
@@ -138,6 +514,7 @@ function useLastResolved(atom) {
138
514
  }
139
515
 
140
516
  exports.StoreProvider = StoreProvider;
517
+ exports.asyncGetSettled$ = asyncGetSettled$;
141
518
  exports.useGet = useGet;
142
519
  exports.useLastLoadable = useLastLoadable;
143
520
  exports.useLastResolved = useLastResolved;
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as ccstate from 'ccstate';
1
2
  import { State, Computed, Command, StateArg, Store } from 'ccstate';
2
3
  import * as react from 'react';
3
4
 
@@ -8,8 +9,8 @@ type CommandInvoker<T, CommandArgs extends unknown[]> = (...args: CommandArgs) =
8
9
  declare function useSet<T>(signal: State<T>): ValueSetter<T>;
9
10
  declare function useSet<T, CommandArgs extends unknown[]>(signal: Command<T, CommandArgs>): CommandInvoker<T, CommandArgs>;
10
11
 
11
- declare function useResolved<T>(atom: State<Promise<T>> | Computed<Promise<T>>): T | undefined;
12
- declare function useLastResolved<T>(atom: State<Promise<T>> | Computed<Promise<T>>): T | undefined;
12
+ declare function useResolved<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Awaited<T> | undefined;
13
+ declare function useLastResolved<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Awaited<T> | undefined;
13
14
 
14
15
  type Loadable<T> = {
15
16
  state: 'loading';
@@ -20,9 +21,11 @@ type Loadable<T> = {
20
21
  state: 'hasError';
21
22
  error: unknown;
22
23
  };
23
- declare function useLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T>>): Loadable<T>;
24
- declare function useLastLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T>>): Loadable<T>;
24
+ declare function useLoadable<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Loadable<Awaited<T>>;
25
+ declare function useLastLoadable<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Loadable<Awaited<T>>;
25
26
 
26
27
  declare const StoreProvider: react.Provider<Store | null>;
27
28
 
28
- export { StoreProvider, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
29
+ declare const asyncGetSettled$: ccstate.Computed<Promise<unknown[]>>;
30
+
31
+ export { StoreProvider, asyncGetSettled$, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as ccstate from 'ccstate';
1
2
  import { State, Computed, Command, StateArg, Store } from 'ccstate';
2
3
  import * as react from 'react';
3
4
 
@@ -8,8 +9,8 @@ type CommandInvoker<T, CommandArgs extends unknown[]> = (...args: CommandArgs) =
8
9
  declare function useSet<T>(signal: State<T>): ValueSetter<T>;
9
10
  declare function useSet<T, CommandArgs extends unknown[]>(signal: Command<T, CommandArgs>): CommandInvoker<T, CommandArgs>;
10
11
 
11
- declare function useResolved<T>(atom: State<Promise<T>> | Computed<Promise<T>>): T | undefined;
12
- declare function useLastResolved<T>(atom: State<Promise<T>> | Computed<Promise<T>>): T | undefined;
12
+ declare function useResolved<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Awaited<T> | undefined;
13
+ declare function useLastResolved<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Awaited<T> | undefined;
13
14
 
14
15
  type Loadable<T> = {
15
16
  state: 'loading';
@@ -20,9 +21,11 @@ type Loadable<T> = {
20
21
  state: 'hasError';
21
22
  error: unknown;
22
23
  };
23
- declare function useLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T>>): Loadable<T>;
24
- declare function useLastLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T>>): Loadable<T>;
24
+ declare function useLoadable<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Loadable<Awaited<T>>;
25
+ declare function useLastLoadable<T>(atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>): Loadable<Awaited<T>>;
25
26
 
26
27
  declare const StoreProvider: react.Provider<Store | null>;
27
28
 
28
- export { StoreProvider, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
29
+ declare const asyncGetSettled$: ccstate.Computed<Promise<unknown[]>>;
30
+
31
+ export { StoreProvider, asyncGetSettled$, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createContext, useContext, useSyncExternalStore, useCallback, useState, useEffect } from 'react';
2
- import { getDefaultStore, command } from 'ccstate';
2
+ import { getDefaultStore, command, state, computed } from 'ccstate';
3
3
 
4
4
  var StoreContext = createContext(null);
5
5
  var StoreProvider = StoreContext.Provider;
@@ -46,6 +46,31 @@ function _arrayLikeToArray(r, a) {
46
46
  function _arrayWithHoles(r) {
47
47
  if (Array.isArray(r)) return r;
48
48
  }
49
+ function asyncGeneratorStep(n, t, e, r, o, a, c) {
50
+ try {
51
+ var i = n[a](c),
52
+ u = i.value;
53
+ } catch (n) {
54
+ return void e(n);
55
+ }
56
+ i.done ? t(u) : Promise.resolve(u).then(r, o);
57
+ }
58
+ function _asyncToGenerator(n) {
59
+ return function () {
60
+ var t = this,
61
+ e = arguments;
62
+ return new Promise(function (r, o) {
63
+ var a = n.apply(t, e);
64
+ function _next(n) {
65
+ asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
66
+ }
67
+ function _throw(n) {
68
+ asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
69
+ }
70
+ _next(void 0);
71
+ });
72
+ };
73
+ }
49
74
  function _iterableToArrayLimit(r, l) {
50
75
  var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
51
76
  if (null != t) {
@@ -73,6 +98,307 @@ function _iterableToArrayLimit(r, l) {
73
98
  function _nonIterableRest() {
74
99
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
75
100
  }
101
+ function _regeneratorRuntime() {
102
+ _regeneratorRuntime = function () {
103
+ return e;
104
+ };
105
+ var t,
106
+ e = {},
107
+ r = Object.prototype,
108
+ n = r.hasOwnProperty,
109
+ o = Object.defineProperty || function (t, e, r) {
110
+ t[e] = r.value;
111
+ },
112
+ i = "function" == typeof Symbol ? Symbol : {},
113
+ a = i.iterator || "@@iterator",
114
+ c = i.asyncIterator || "@@asyncIterator",
115
+ u = i.toStringTag || "@@toStringTag";
116
+ function define(t, e, r) {
117
+ return Object.defineProperty(t, e, {
118
+ value: r,
119
+ enumerable: !0,
120
+ configurable: !0,
121
+ writable: !0
122
+ }), t[e];
123
+ }
124
+ try {
125
+ define({}, "");
126
+ } catch (t) {
127
+ define = function (t, e, r) {
128
+ return t[e] = r;
129
+ };
130
+ }
131
+ function wrap(t, e, r, n) {
132
+ var i = e && e.prototype instanceof Generator ? e : Generator,
133
+ a = Object.create(i.prototype),
134
+ c = new Context(n || []);
135
+ return o(a, "_invoke", {
136
+ value: makeInvokeMethod(t, r, c)
137
+ }), a;
138
+ }
139
+ function tryCatch(t, e, r) {
140
+ try {
141
+ return {
142
+ type: "normal",
143
+ arg: t.call(e, r)
144
+ };
145
+ } catch (t) {
146
+ return {
147
+ type: "throw",
148
+ arg: t
149
+ };
150
+ }
151
+ }
152
+ e.wrap = wrap;
153
+ var h = "suspendedStart",
154
+ l = "suspendedYield",
155
+ f = "executing",
156
+ s = "completed",
157
+ y = {};
158
+ function Generator() {}
159
+ function GeneratorFunction() {}
160
+ function GeneratorFunctionPrototype() {}
161
+ var p = {};
162
+ define(p, a, function () {
163
+ return this;
164
+ });
165
+ var d = Object.getPrototypeOf,
166
+ v = d && d(d(values([])));
167
+ v && v !== r && n.call(v, a) && (p = v);
168
+ var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p);
169
+ function defineIteratorMethods(t) {
170
+ ["next", "throw", "return"].forEach(function (e) {
171
+ define(t, e, function (t) {
172
+ return this._invoke(e, t);
173
+ });
174
+ });
175
+ }
176
+ function AsyncIterator(t, e) {
177
+ function invoke(r, o, i, a) {
178
+ var c = tryCatch(t[r], t, o);
179
+ if ("throw" !== c.type) {
180
+ var u = c.arg,
181
+ h = u.value;
182
+ return h && "object" == typeof h && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) {
183
+ invoke("next", t, i, a);
184
+ }, function (t) {
185
+ invoke("throw", t, i, a);
186
+ }) : e.resolve(h).then(function (t) {
187
+ u.value = t, i(u);
188
+ }, function (t) {
189
+ return invoke("throw", t, i, a);
190
+ });
191
+ }
192
+ a(c.arg);
193
+ }
194
+ var r;
195
+ o(this, "_invoke", {
196
+ value: function (t, n) {
197
+ function callInvokeWithMethodAndArg() {
198
+ return new e(function (e, r) {
199
+ invoke(t, n, e, r);
200
+ });
201
+ }
202
+ return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
203
+ }
204
+ });
205
+ }
206
+ function makeInvokeMethod(e, r, n) {
207
+ var o = h;
208
+ return function (i, a) {
209
+ if (o === f) throw Error("Generator is already running");
210
+ if (o === s) {
211
+ if ("throw" === i) throw a;
212
+ return {
213
+ value: t,
214
+ done: !0
215
+ };
216
+ }
217
+ for (n.method = i, n.arg = a;;) {
218
+ var c = n.delegate;
219
+ if (c) {
220
+ var u = maybeInvokeDelegate(c, n);
221
+ if (u) {
222
+ if (u === y) continue;
223
+ return u;
224
+ }
225
+ }
226
+ if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
227
+ if (o === h) throw o = s, n.arg;
228
+ n.dispatchException(n.arg);
229
+ } else "return" === n.method && n.abrupt("return", n.arg);
230
+ o = f;
231
+ var p = tryCatch(e, r, n);
232
+ if ("normal" === p.type) {
233
+ if (o = n.done ? s : l, p.arg === y) continue;
234
+ return {
235
+ value: p.arg,
236
+ done: n.done
237
+ };
238
+ }
239
+ "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg);
240
+ }
241
+ };
242
+ }
243
+ function maybeInvokeDelegate(e, r) {
244
+ var n = r.method,
245
+ o = e.iterator[n];
246
+ if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y;
247
+ var i = tryCatch(o, e.iterator, r.arg);
248
+ if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y;
249
+ var a = i.arg;
250
+ return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y);
251
+ }
252
+ function pushTryEntry(t) {
253
+ var e = {
254
+ tryLoc: t[0]
255
+ };
256
+ 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e);
257
+ }
258
+ function resetTryEntry(t) {
259
+ var e = t.completion || {};
260
+ e.type = "normal", delete e.arg, t.completion = e;
261
+ }
262
+ function Context(t) {
263
+ this.tryEntries = [{
264
+ tryLoc: "root"
265
+ }], t.forEach(pushTryEntry, this), this.reset(!0);
266
+ }
267
+ function values(e) {
268
+ if (e || "" === e) {
269
+ var r = e[a];
270
+ if (r) return r.call(e);
271
+ if ("function" == typeof e.next) return e;
272
+ if (!isNaN(e.length)) {
273
+ var o = -1,
274
+ i = function next() {
275
+ for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next;
276
+ return next.value = t, next.done = !0, next;
277
+ };
278
+ return i.next = i;
279
+ }
280
+ }
281
+ throw new TypeError(typeof e + " is not iterable");
282
+ }
283
+ return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", {
284
+ value: GeneratorFunctionPrototype,
285
+ configurable: !0
286
+ }), o(GeneratorFunctionPrototype, "constructor", {
287
+ value: GeneratorFunction,
288
+ configurable: !0
289
+ }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) {
290
+ var e = "function" == typeof t && t.constructor;
291
+ return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name));
292
+ }, e.mark = function (t) {
293
+ return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t;
294
+ }, e.awrap = function (t) {
295
+ return {
296
+ __await: t
297
+ };
298
+ }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () {
299
+ return this;
300
+ }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) {
301
+ void 0 === i && (i = Promise);
302
+ var a = new AsyncIterator(wrap(t, r, n, o), i);
303
+ return e.isGeneratorFunction(r) ? a : a.next().then(function (t) {
304
+ return t.done ? t.value : a.next();
305
+ });
306
+ }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () {
307
+ return this;
308
+ }), define(g, "toString", function () {
309
+ return "[object Generator]";
310
+ }), e.keys = function (t) {
311
+ var e = Object(t),
312
+ r = [];
313
+ for (var n in e) r.push(n);
314
+ return r.reverse(), function next() {
315
+ for (; r.length;) {
316
+ var t = r.pop();
317
+ if (t in e) return next.value = t, next.done = !1, next;
318
+ }
319
+ return next.done = !0, next;
320
+ };
321
+ }, e.values = values, Context.prototype = {
322
+ constructor: Context,
323
+ reset: function (e) {
324
+ if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t);
325
+ },
326
+ stop: function () {
327
+ this.done = !0;
328
+ var t = this.tryEntries[0].completion;
329
+ if ("throw" === t.type) throw t.arg;
330
+ return this.rval;
331
+ },
332
+ dispatchException: function (e) {
333
+ if (this.done) throw e;
334
+ var r = this;
335
+ function handle(n, o) {
336
+ return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o;
337
+ }
338
+ for (var o = this.tryEntries.length - 1; o >= 0; --o) {
339
+ var i = this.tryEntries[o],
340
+ a = i.completion;
341
+ if ("root" === i.tryLoc) return handle("end");
342
+ if (i.tryLoc <= this.prev) {
343
+ var c = n.call(i, "catchLoc"),
344
+ u = n.call(i, "finallyLoc");
345
+ if (c && u) {
346
+ if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
347
+ if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
348
+ } else if (c) {
349
+ if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
350
+ } else {
351
+ if (!u) throw Error("try statement without catch or finally");
352
+ if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
353
+ }
354
+ }
355
+ }
356
+ },
357
+ abrupt: function (t, e) {
358
+ for (var r = this.tryEntries.length - 1; r >= 0; --r) {
359
+ var o = this.tryEntries[r];
360
+ if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) {
361
+ var i = o;
362
+ break;
363
+ }
364
+ }
365
+ i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null);
366
+ var a = i ? i.completion : {};
367
+ return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a);
368
+ },
369
+ complete: function (t, e) {
370
+ if ("throw" === t.type) throw t.arg;
371
+ return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y;
372
+ },
373
+ finish: function (t) {
374
+ for (var e = this.tryEntries.length - 1; e >= 0; --e) {
375
+ var r = this.tryEntries[e];
376
+ if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y;
377
+ }
378
+ },
379
+ catch: function (t) {
380
+ for (var e = this.tryEntries.length - 1; e >= 0; --e) {
381
+ var r = this.tryEntries[e];
382
+ if (r.tryLoc === t) {
383
+ var n = r.completion;
384
+ if ("throw" === n.type) {
385
+ var o = n.arg;
386
+ resetTryEntry(r);
387
+ }
388
+ return o;
389
+ }
390
+ }
391
+ throw Error("illegal catch attempt");
392
+ },
393
+ delegateYield: function (e, r, n) {
394
+ return this.delegate = {
395
+ iterator: values(e),
396
+ resultName: r,
397
+ nextLoc: n
398
+ }, "next" === this.method && (this.arg = t), y;
399
+ }
400
+ }, e;
401
+ }
76
402
  function _slicedToArray(r, e) {
77
403
  return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
78
404
  }
@@ -84,8 +410,48 @@ function _unsupportedIterableToArray(r, a) {
84
410
  }
85
411
  }
86
412
 
413
+ var internalFloatingPromises$ = state(new Set());
414
+ var collectFloatingPromise$ = command(function (_ref, promise, signal) {
415
+ var set = _ref.set;
416
+ signal.addEventListener('abort', function () {
417
+ set(internalFloatingPromises$, function (prev) {
418
+ var ret = new Set(prev);
419
+ ret["delete"](promise);
420
+ return ret;
421
+ });
422
+ });
423
+ set(internalFloatingPromises$, function (prev) {
424
+ var ret = new Set(prev);
425
+ ret.add(promise);
426
+ return ret;
427
+ });
428
+ });
429
+ var floatingPromises$ = computed(function (get) {
430
+ return get(internalFloatingPromises$);
431
+ });
432
+ var asyncGetSettled$ = computed(/*#__PURE__*/function () {
433
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(get) {
434
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
435
+ while (1) switch (_context.prev = _context.next) {
436
+ case 0:
437
+ _context.next = 2;
438
+ return Promise.all(get(floatingPromises$));
439
+ case 2:
440
+ return _context.abrupt("return", _context.sent);
441
+ case 3:
442
+ case "end":
443
+ return _context.stop();
444
+ }
445
+ }, _callee);
446
+ }));
447
+ return function (_x) {
448
+ return _ref2.apply(this, arguments);
449
+ };
450
+ }());
451
+
87
452
  function useLoadableInternal(atom, keepLastResolved) {
88
453
  var promise = useGet(atom);
454
+ var collectFloatingPromise = useSet(collectFloatingPromise$);
89
455
  var _useState = useState({
90
456
  state: 'loading'
91
457
  }),
@@ -93,26 +459,36 @@ function useLoadableInternal(atom, keepLastResolved) {
93
459
  promiseResult = _useState2[0],
94
460
  setPromiseResult = _useState2[1];
95
461
  useEffect(function () {
462
+ if (!(promise instanceof Promise)) {
463
+ setPromiseResult({
464
+ state: 'hasData',
465
+ data: promise
466
+ });
467
+ return;
468
+ }
96
469
  var ctrl = new AbortController();
470
+ var settledController = new AbortController();
97
471
  var signal = ctrl.signal;
98
472
  if (!keepLastResolved) {
99
473
  setPromiseResult({
100
474
  state: 'loading'
101
475
  });
102
476
  }
103
- void promise.then(function (ret) {
477
+ collectFloatingPromise(promise.then(function (ret) {
478
+ settledController.abort();
104
479
  if (signal.aborted) return;
105
480
  setPromiseResult({
106
481
  state: 'hasData',
107
482
  data: ret
108
483
  });
109
- })["catch"](function (error) {
484
+ }, function (error) {
485
+ settledController.abort();
110
486
  if (signal.aborted) return;
111
487
  setPromiseResult({
112
488
  state: 'hasError',
113
489
  error: error
114
490
  });
115
- });
491
+ }), AbortSignal.any([signal, settledController.signal]));
116
492
  return function () {
117
493
  ctrl.abort();
118
494
  };
@@ -135,4 +511,4 @@ function useLastResolved(atom) {
135
511
  return loadable.state === 'hasData' ? loadable.data : undefined;
136
512
  }
137
513
 
138
- export { StoreProvider, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
514
+ export { StoreProvider, asyncGetSettled$, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstate-react",
3
- "version": "4.8.0",
3
+ "version": "4.10.0",
4
4
  "description": "CCState React Hooks",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,7 +25,7 @@
25
25
  "react": ">=17.0.0"
26
26
  },
27
27
  "dependencies": {
28
- "ccstate": "^4.8.0"
28
+ "ccstate": "^4.10.0"
29
29
  },
30
30
  "peerDependenciesMeta": {
31
31
  "@types/react": {
@@ -55,7 +55,7 @@
55
55
  "shx": "^0.3.4",
56
56
  "signal-timers": "^1.0.4",
57
57
  "vitest": "^2.1.8",
58
- "ccstate": "^4.8.0"
58
+ "ccstate": "^4.10.0"
59
59
  },
60
60
  "scripts": {
61
61
  "build": "rollup -c",
@@ -3,13 +3,14 @@
3
3
  import '@testing-library/jest-dom/vitest';
4
4
  import { render, cleanup, screen } from '@testing-library/react';
5
5
  import userEvent from '@testing-library/user-event';
6
- import { afterEach, expect, it } from 'vitest';
6
+ import { afterEach, expect, it, vi } from 'vitest';
7
7
  import { computed, createStore, state } from 'ccstate';
8
8
  import type { Computed, State } from 'ccstate';
9
9
  import { StrictMode, useEffect } from 'react';
10
10
  import { StoreProvider, useSet, useLoadable } from '..';
11
11
  import { delay } from 'signal-timers';
12
12
  import { useLastLoadable } from '../useLoadable';
13
+ import { asyncGetSettled$, floatingPromises$ } from '../floating-promise';
13
14
 
14
15
  afterEach(() => {
15
16
  cleanup();
@@ -530,3 +531,68 @@ it('use lastLoadable will will not use old promise error if new promise is made'
530
531
  await delay(0);
531
532
  expect(screen.getByText('num2')).toBeInTheDocument();
532
533
  });
534
+
535
+ it('useLoadable accept sync computed', async () => {
536
+ const base$ = state(0);
537
+ function App() {
538
+ const base = useLoadable(base$);
539
+
540
+ return <div>{base.state}</div>;
541
+ }
542
+
543
+ render(<App />);
544
+
545
+ expect(await screen.findByText('hasData')).toBeInTheDocument();
546
+ });
547
+
548
+ it('will collect floating promises', async () => {
549
+ const trace = vi.fn();
550
+ const asyncComputed$ = computed(async () => {
551
+ await Promise.resolve();
552
+ trace();
553
+ });
554
+
555
+ const store = createStore();
556
+ function App() {
557
+ const result = useLoadable(asyncComputed$);
558
+
559
+ return <div>{result.state}</div>;
560
+ }
561
+
562
+ render(
563
+ <StoreProvider value={store}>
564
+ <App />
565
+ </StoreProvider>,
566
+ );
567
+
568
+ expect(trace).not.toBeCalled();
569
+
570
+ await store.get(asyncGetSettled$);
571
+
572
+ expect(trace).toBeCalled();
573
+ });
574
+
575
+ it('will auto remove from collected floating promise when settled', async () => {
576
+ const asyncComputed$ = computed(async () => {
577
+ await Promise.resolve();
578
+ });
579
+
580
+ const store = createStore();
581
+ function App() {
582
+ const result = useLoadable(asyncComputed$);
583
+
584
+ return <div>{result.state}</div>;
585
+ }
586
+
587
+ render(
588
+ <StoreProvider value={store}>
589
+ <App />
590
+ </StoreProvider>,
591
+ );
592
+
593
+ expect(store.get(floatingPromises$)).toHaveLength(1);
594
+
595
+ await store.get(asyncGetSettled$);
596
+
597
+ expect(store.get(floatingPromises$)).toHaveLength(0);
598
+ });
@@ -100,3 +100,16 @@ it('use lastLoadable should not update when new promise pending', async () => {
100
100
  await delay(0);
101
101
  expect(screen.getByText('num2')).toBeInTheDocument();
102
102
  });
103
+
104
+ it('useResolved accept sync computed', async () => {
105
+ const base$ = state(0);
106
+ function App() {
107
+ const base = useResolved(base$);
108
+
109
+ return <div>{base}</div>;
110
+ }
111
+
112
+ render(<App />);
113
+
114
+ expect(await screen.findByText('0')).toBeInTheDocument();
115
+ });
@@ -0,0 +1,27 @@
1
+ import { command, computed, state } from 'ccstate';
2
+
3
+ const internalFloatingPromises$ = state(new Set<Promise<unknown>>());
4
+
5
+ export const collectFloatingPromise$ = command(({ set }, promise: Promise<unknown>, signal: AbortSignal) => {
6
+ signal.addEventListener('abort', () => {
7
+ set(internalFloatingPromises$, (prev) => {
8
+ const ret = new Set(prev);
9
+ ret.delete(promise);
10
+ return ret;
11
+ });
12
+ });
13
+
14
+ set(internalFloatingPromises$, (prev) => {
15
+ const ret = new Set(prev);
16
+ ret.add(promise);
17
+ return ret;
18
+ });
19
+ });
20
+
21
+ export const floatingPromises$ = computed((get) => {
22
+ return get(internalFloatingPromises$);
23
+ });
24
+
25
+ export const asyncGetSettled$ = computed(async (get) => {
26
+ return await Promise.all(get(floatingPromises$));
27
+ });
package/src/index.ts CHANGED
@@ -3,3 +3,4 @@ export { useSet } from './useSet';
3
3
  export { useResolved, useLastResolved } from './useResolved';
4
4
  export { useLoadable, useLastLoadable } from './useLoadable';
5
5
  export { StoreProvider } from './provider';
6
+ export { asyncGetSettled$ } from './floating-promise';
@@ -1,6 +1,8 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import { useGet } from './useGet';
3
3
  import type { Computed, State } from 'ccstate';
4
+ import { useSet } from './useSet';
5
+ import { collectFloatingPromise$ } from './floating-promise';
4
6
 
5
7
  type Loadable<T> =
6
8
  | {
@@ -16,16 +18,28 @@ type Loadable<T> =
16
18
  };
17
19
 
18
20
  function useLoadableInternal<T>(
19
- atom: State<Promise<T>> | Computed<Promise<T>>,
21
+ atom: State<Promise<T> | T> | Computed<Promise<T> | T>,
20
22
  keepLastResolved: boolean,
21
23
  ): Loadable<T> {
22
24
  const promise = useGet(atom);
25
+ const collectFloatingPromise = useSet(collectFloatingPromise$);
26
+
23
27
  const [promiseResult, setPromiseResult] = useState<Loadable<T>>({
24
28
  state: 'loading',
25
29
  });
26
30
 
27
31
  useEffect(() => {
32
+ if (!(promise instanceof Promise)) {
33
+ setPromiseResult({
34
+ state: 'hasData',
35
+ data: promise,
36
+ });
37
+
38
+ return;
39
+ }
40
+
28
41
  const ctrl = new AbortController();
42
+ const settledController = new AbortController();
29
43
  const signal = ctrl.signal;
30
44
 
31
45
  if (!keepLastResolved) {
@@ -34,23 +48,29 @@ function useLoadableInternal<T>(
34
48
  });
35
49
  }
36
50
 
37
- void promise
38
- .then((ret) => {
39
- if (signal.aborted) return;
51
+ collectFloatingPromise(
52
+ promise.then(
53
+ (ret) => {
54
+ settledController.abort();
55
+ if (signal.aborted) return;
40
56
 
41
- setPromiseResult({
42
- state: 'hasData',
43
- data: ret,
44
- });
45
- })
46
- .catch((error: unknown) => {
47
- if (signal.aborted) return;
57
+ setPromiseResult({
58
+ state: 'hasData',
59
+ data: ret,
60
+ });
61
+ },
62
+ (error: unknown) => {
63
+ settledController.abort();
64
+ if (signal.aborted) return;
48
65
 
49
- setPromiseResult({
50
- state: 'hasError',
51
- error,
52
- });
53
- });
66
+ setPromiseResult({
67
+ state: 'hasError',
68
+ error,
69
+ });
70
+ },
71
+ ),
72
+ AbortSignal.any([signal, settledController.signal]),
73
+ );
54
74
 
55
75
  return () => {
56
76
  ctrl.abort();
@@ -60,10 +80,14 @@ function useLoadableInternal<T>(
60
80
  return promiseResult;
61
81
  }
62
82
 
63
- export function useLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T>>): Loadable<T> {
83
+ export function useLoadable<T>(
84
+ atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>,
85
+ ): Loadable<Awaited<T>> {
64
86
  return useLoadableInternal(atom, false);
65
87
  }
66
88
 
67
- export function useLastLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T>>): Loadable<T> {
89
+ export function useLastLoadable<T>(
90
+ atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>,
91
+ ): Loadable<Awaited<T>> {
68
92
  return useLoadableInternal(atom, true);
69
93
  }
@@ -1,12 +1,16 @@
1
1
  import { useLastLoadable, useLoadable } from './useLoadable';
2
2
  import type { Computed, State } from 'ccstate';
3
3
 
4
- export function useResolved<T>(atom: State<Promise<T>> | Computed<Promise<T>>): T | undefined {
4
+ export function useResolved<T>(
5
+ atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>,
6
+ ): Awaited<T> | undefined {
5
7
  const loadable = useLoadable(atom);
6
8
  return loadable.state === 'hasData' ? loadable.data : undefined;
7
9
  }
8
10
 
9
- export function useLastResolved<T>(atom: State<Promise<T>> | Computed<Promise<T>>): T | undefined {
11
+ export function useLastResolved<T>(
12
+ atom: State<Promise<Awaited<T>> | Awaited<T>> | Computed<Promise<Awaited<T>> | Awaited<T>>,
13
+ ): Awaited<T> | undefined {
10
14
  const loadable = useLastLoadable(atom);
11
15
  return loadable.state === 'hasData' ? loadable.data : undefined;
12
16
  }