@hairy/react-lib 1.24.0 → 1.26.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/dist/index.cjs CHANGED
@@ -37,13 +37,14 @@ __export(index_exports, {
37
37
  Injector: () => Injector,
38
38
  Switch: () => Switch,
39
39
  Then: () => Then,
40
- Trans: () => Trans,
40
+ Trigger: () => Trigger,
41
41
  Unless: () => Unless,
42
42
  cls: () => cls,
43
43
  defineAsyncStore: () => defineAsyncStore,
44
44
  defineStore: () => defineStore,
45
45
  proxyWithPersistant: () => proxyWithPersistant,
46
- ref: () => ref,
46
+ ref: () => ref2,
47
+ track: () => track,
47
48
  useAsyncCallback: () => useAsyncCallback,
48
49
  useAsyncState: () => useAsyncState,
49
50
  useDebounce: () => useDebounce,
@@ -92,6 +93,51 @@ cls.append = function(value, newClass) {
92
93
  return value ? `${value} ${newClass}` : newClass;
93
94
  };
94
95
 
96
+ // ../util-core/src/util/noop.ts
97
+ var noop = () => {
98
+ };
99
+
100
+ // ../util-core/src/util/deferred.ts
101
+ var Deferred = class extends Promise {
102
+ resolve;
103
+ reject;
104
+ constructor(executor = noop) {
105
+ let _resolve, _reject;
106
+ super((resolve_, reject_) => {
107
+ _resolve = resolve_;
108
+ _reject = reject_;
109
+ return executor(resolve_, reject_);
110
+ });
111
+ this.resolve = (value) => {
112
+ _resolve(value);
113
+ return this;
114
+ };
115
+ this.reject = (reason) => {
116
+ _reject(reason);
117
+ return this;
118
+ };
119
+ }
120
+ };
121
+
122
+ // ../util-core/src/util/json.ts
123
+ function jsonTryParse(text) {
124
+ try {
125
+ return JSON.parse(text || "");
126
+ } catch {
127
+ return void 0;
128
+ }
129
+ }
130
+
131
+ // src/utils/track.ts
132
+ var import_valtio = require("valtio");
133
+ function track(fn, ...args) {
134
+ const deferred = (0, import_valtio.ref)(new Deferred());
135
+ const exposer = { fn, args, deferred, id: ++Trigger.id };
136
+ Trigger.tasks.set(exposer.id, exposer);
137
+ deferred.then(() => Trigger.tasks.delete(exposer.id));
138
+ return deferred;
139
+ }
140
+
95
141
  // src/utils/wrapper.ts
96
142
  var import_react = require("react");
97
143
  function wrapper(tag, props, children) {
@@ -184,28 +230,36 @@ function repack(c) {
184
230
  return c.component ? c : { component: c };
185
231
  }
186
232
 
187
- // src/components/utils/Trans.ts
188
- var import_html_parse_stringify = __toESM(require("html-parse-stringify"), 1);
233
+ // src/components/utils/Trigger.ts
189
234
  var import_react6 = require("react");
190
- var import_react_i18next = require("react-i18next");
191
- function Trans({ i18nKey, ...additionalProps }) {
192
- const translation = (0, import_react_i18next.useTranslation)().t(i18nKey, additionalProps);
193
- return renderNodes(import_html_parse_stringify.default.parse(translation), additionalProps);
194
- }
195
- function renderNodes(tokens, values) {
196
- let index = 0;
197
- return tokens.map((token) => {
198
- if (token.type === "text")
199
- return token.content;
200
- index++;
201
- const props = { ...token.attrs, key: index };
202
- return token.voidElement ? values[token.name] ? (0, import_react6.createElement)("span", { key: index }, values[token.name]) : (0, import_react6.createElement)(token.name, props) : (0, import_react6.createElement)(token.name, props, renderNodes(token.children, {}));
203
- });
235
+ var import_valtio2 = require("valtio");
236
+ var import_utils8 = require("valtio/utils");
237
+ var pendingTasks = (0, import_utils8.proxyMap)();
238
+ function createTracker(exposer) {
239
+ const Component = () => {
240
+ try {
241
+ exposer.deferred.resolve(exposer.fn(...exposer.args));
242
+ } catch (error) {
243
+ exposer.deferred.reject(error);
244
+ }
245
+ return null;
246
+ };
247
+ Component.key = exposer.id;
248
+ return Component;
204
249
  }
250
+ function renderTracker(Tracker) {
251
+ return (0, import_react6.createElement)(Tracker, { key: Tracker.key });
252
+ }
253
+ function Trigger() {
254
+ const values = [...(0, import_valtio2.useSnapshot)(pendingTasks).values()];
255
+ return values.map(createTracker).map(renderTracker);
256
+ }
257
+ Trigger.id = 0;
258
+ Trigger.tasks = pendingTasks;
205
259
 
206
260
  // src/hooks/ref.ts
207
261
  var import_react7 = require("react");
208
- function ref(value) {
262
+ function ref2(value) {
209
263
  function define(value2) {
210
264
  if (typeof value2 === "function")
211
265
  return (prev) => define(value2(prev.value));
@@ -215,8 +269,8 @@ function ref(value) {
215
269
  enumerable: true
216
270
  });
217
271
  }
218
- const [ref2, set] = (0, import_react7.useState)(define(value));
219
- return ref2;
272
+ const [ref3, set] = (0, import_react7.useState)(define(value));
273
+ return ref3;
220
274
  }
221
275
 
222
276
  // src/hooks/useAsyncCallback.ts
@@ -369,23 +423,14 @@ function useWhenever(source, cb, options) {
369
423
  }
370
424
 
371
425
  // src/storage/defineAsyncStore.ts
372
- var import_utils8 = require("valtio/utils");
426
+ var import_utils10 = require("valtio/utils");
373
427
 
374
428
  // src/storage/defineStore.ts
375
429
  var import_react15 = require("react");
376
- var import_valtio2 = require("valtio");
377
-
378
- // ../util-core/src/util/json.ts
379
- function jsonTryParse(text) {
380
- try {
381
- return JSON.parse(text || "");
382
- } catch {
383
- return void 0;
384
- }
385
- }
430
+ var import_valtio4 = require("valtio");
386
431
 
387
432
  // src/storage/persistant.ts
388
- var import_valtio = require("valtio");
433
+ var import_valtio3 = require("valtio");
389
434
  function proxyWithPersistant(keyOrOptions, initialObject) {
390
435
  let options;
391
436
  if (typeof keyOrOptions === "string") {
@@ -395,8 +440,8 @@ function proxyWithPersistant(keyOrOptions, initialObject) {
395
440
  }
396
441
  const storage = options.storage || (typeof localStorage !== "undefined" ? localStorage : void 0);
397
442
  typeof keyOrOptions === "string" && (keyOrOptions = { id: keyOrOptions });
398
- const state = (0, import_valtio.proxy)(jsonTryParse(storage?.getItem(options.id)) || initialObject);
399
- (0, import_valtio.subscribe)(state, () => {
443
+ const state = (0, import_valtio3.proxy)(jsonTryParse(storage?.getItem(options.id)) || initialObject);
444
+ (0, import_valtio3.subscribe)(state, () => {
400
445
  const pick = options.pick || Object.keys(state);
401
446
  const statePick = {};
402
447
  for (const key of pick)
@@ -415,18 +460,18 @@ function defineStore(store, options = {}) {
415
460
  status.finished = false;
416
461
  status.loading = false;
417
462
  status.error = null;
418
- const $status = (0, import_valtio2.proxy)(status);
419
- const $state = options.persist ? proxyWithPersistant(options.persist, state) : (0, import_valtio2.proxy)(state);
463
+ const $status = (0, import_valtio4.proxy)(status);
464
+ const $state = options.persist ? proxyWithPersistant(options.persist, state) : (0, import_valtio4.proxy)(state);
420
465
  const $actions = {};
421
466
  const $getters = {};
422
467
  setupActions($state, actions, $actions, $status);
423
468
  setupGetters(state, $state, getters, $getters);
424
469
  setupStatus($actions, $status);
425
470
  function $subscribe(listener) {
426
- return (0, import_valtio2.subscribe)($state, () => listener($state));
471
+ return (0, import_valtio4.subscribe)($state, () => listener($state));
427
472
  }
428
473
  $subscribe.status = function(listener) {
429
- return (0, import_valtio2.subscribe)($status, () => listener($status));
474
+ return (0, import_valtio4.subscribe)($status, () => listener($status));
430
475
  };
431
476
  function $patch(patch) {
432
477
  if (typeof patch === "function")
@@ -435,10 +480,10 @@ function defineStore(store, options = {}) {
435
480
  Object.assign($state, patch);
436
481
  }
437
482
  function $signal(fn) {
438
- return (0, import_react15.createElement)(() => fn((0, import_valtio2.useSnapshot)($state)));
483
+ return (0, import_react15.createElement)(() => fn((0, import_valtio4.useSnapshot)($state)));
439
484
  }
440
485
  $signal.status = function(fn) {
441
- return (0, import_react15.createElement)(() => fn((0, import_valtio2.useSnapshot)($status)));
486
+ return (0, import_react15.createElement)(() => fn((0, import_valtio4.useSnapshot)($status)));
442
487
  };
443
488
  return {
444
489
  $subscribe,
@@ -451,7 +496,7 @@ function defineStore(store, options = {}) {
451
496
  ...$actions
452
497
  };
453
498
  }
454
- function track(action, status) {
499
+ function track2(action, status) {
455
500
  let loadings = 0;
456
501
  const tracking = () => loadings++ === 0 && (status.loading = true);
457
502
  const done = () => !--loadings && (status.loading = false);
@@ -478,7 +523,7 @@ function track(action, status) {
478
523
  function setupActions($state, actions, $actions, $status) {
479
524
  for (const key in actions) {
480
525
  $status[key] = { finished: false, loading: false, error: null };
481
- $actions[key] = track(actions[key].bind($state), $status[key]);
526
+ $actions[key] = track2(actions[key].bind($state), $status[key]);
482
527
  }
483
528
  }
484
529
  function setupGetters(state, $state, getters, $getters) {
@@ -529,7 +574,7 @@ function defineAsyncStore(fetch, options = {}) {
529
574
  },
530
575
  { persist: options.persist ? { id: options.persist, pick: ["value"] } : void 0 }
531
576
  );
532
- (0, import_utils8.watch)((get) => {
577
+ (0, import_utils10.watch)((get) => {
533
578
  const status = get(store.$status.fetch);
534
579
  store.$state.error = status.error;
535
580
  store.$state.loading = status.loading;
@@ -540,15 +585,15 @@ function defineAsyncStore(fetch, options = {}) {
540
585
  }
541
586
 
542
587
  // src/storage/useStatus.tsx
543
- var import_valtio3 = require("valtio");
588
+ var import_valtio5 = require("valtio");
544
589
  function useStatus(store) {
545
- return (0, import_valtio3.useSnapshot)(store.$status);
590
+ return (0, import_valtio5.useSnapshot)(store.$status);
546
591
  }
547
592
 
548
593
  // src/storage/useStore.ts
549
- var import_valtio4 = require("valtio");
594
+ var import_valtio6 = require("valtio");
550
595
  function useStore(store) {
551
- return (0, import_valtio4.useSnapshot)(store.$state);
596
+ return (0, import_valtio6.useSnapshot)(store.$state);
552
597
  }
553
598
  // Annotate the CommonJS export names for ESM import in node:
554
599
  0 && (module.exports = {
@@ -559,13 +604,14 @@ function useStore(store) {
559
604
  Injector,
560
605
  Switch,
561
606
  Then,
562
- Trans,
607
+ Trigger,
563
608
  Unless,
564
609
  cls,
565
610
  defineAsyncStore,
566
611
  defineStore,
567
612
  proxyWithPersistant,
568
613
  ref,
614
+ track,
569
615
  useAsyncCallback,
570
616
  useAsyncState,
571
617
  useDebounce,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BooleanLike, PromiseFn, PromiseType, AnyFn } from '@hairy/utils';
1
+ import { AnyFn, BooleanLike, Deferred, PromiseFn, PromiseType } from '@hairy/utils';
2
2
  import * as react from 'react';
3
3
  import { JSX, ReactNode, PropsWithChildren, ReactElement, FC, ComponentClass, SetStateAction, DetailedHTMLProps, HTMLAttributes } from 'react';
4
4
  import * as valtio from 'valtio';
@@ -19,6 +19,18 @@ declare namespace cls {
19
19
  var append: (value: any, newClass: any) => any;
20
20
  }
21
21
 
22
+ /**
23
+ * @requires `Trigger` component to be mounted in the tree.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * // Obtain externally
28
+ * import { track } from '@hairy/lib-react'
29
+ * const context = await track(() => useContext(YourContext))
30
+ * console.log(context) // { ... }
31
+ */
32
+ declare function track<T extends AnyFn>(fn: T, ...args: Parameters<T>): Promise<ReturnType<T>>;
33
+
22
34
  type WrapperTag = keyof JSX.IntrinsicElements | Function;
23
35
  type WrapperProps<Kag extends keyof JSX.IntrinsicElements | React.FC | unknown> = {
24
36
  tag?: Kag;
@@ -73,11 +85,39 @@ interface InjectorProps {
73
85
  }
74
86
  declare function Injector(props: InjectorProps): ReactNode;
75
87
 
76
- interface TransProps {
77
- i18nKey: string;
78
- [key: string]: ReactNode;
88
+ interface Exposer {
89
+ deferred: Deferred<any>;
90
+ args: any[];
91
+ fn: AnyFn;
92
+ id: number;
93
+ }
94
+ /**
95
+ * @example
96
+ * ```tsx
97
+ * import { Trigger } from '@hairy/lib-react'
98
+ *
99
+ * // Use triggers to capture context
100
+ * function App() {
101
+ * return (
102
+ * <YourContext.Provider>
103
+ * <Trigger />
104
+ * </YourContext.Provider>
105
+ * )
106
+ * }
107
+ *
108
+ * // Obtain externally
109
+ * import { track } from '@hairy/lib-react'
110
+ * const context = await track(() => useContext(YourContext))
111
+ * console.log(context) // { ... }
112
+ * ```
113
+ */
114
+ declare function Trigger(): ReactNode[];
115
+ declare namespace Trigger {
116
+ var id: number;
117
+ var tasks: Map<number, Exposer> & {
118
+ $$valtioSnapshot: Omit<Map<number, Exposer>, "set" | "delete" | "clear">;
119
+ };
79
120
  }
80
- declare function Trans({ i18nKey, ...additionalProps }: TransProps): ReactNode[];
81
121
 
82
122
  interface Ref<S> {
83
123
  set value(action: SetStateAction<S>);
@@ -258,4 +298,4 @@ declare function useStore<S extends object, A extends Actions<S>, G extends Gett
258
298
 
259
299
  type PropsWithDetailedHTML<T = HTMLDivElement> = DetailedHTMLProps<HTMLAttributes<T>, T>;
260
300
 
261
- export { type Argument, type ArgumentArray, type AsyncStoreOptions, Case, type CaseProps, Default, type DefaultProps, Else, type ElseProps, type EventBusListener, type FetchRequestInterceptCallback, type FetchResponseInterceptCallback, If, type IfProps, type InjectComponent, Injector, type InjectorProps, type Mapping, type PersistantOptions, type PropsWithDetailedHTML, type ReadonlyArgumentArray, type Ref, Switch, type SwitchProps, Then, type ThenProps, Trans, type TransProps, Unless, type UnlessProps, type UseAsyncStateOptions, type Value, type WatchCallback, type WatchOptions, type WrapperProps, type WrapperTag, cls, defineAsyncStore, defineStore, proxyWithPersistant, ref, useAsyncCallback, useAsyncState, useDebounce, useEventBus, useFetchRequestIntercept, useFetchResponseIntercept, useMounted, useStatus, useStore, useWatch, useWhenever, wrapper };
301
+ export { type Argument, type ArgumentArray, type AsyncStoreOptions, Case, type CaseProps, Default, type DefaultProps, Else, type ElseProps, type EventBusListener, type Exposer, type FetchRequestInterceptCallback, type FetchResponseInterceptCallback, If, type IfProps, type InjectComponent, Injector, type InjectorProps, type Mapping, type PersistantOptions, type PropsWithDetailedHTML, type ReadonlyArgumentArray, type Ref, Switch, type SwitchProps, Then, type ThenProps, Trigger, Unless, type UnlessProps, type UseAsyncStateOptions, type Value, type WatchCallback, type WatchOptions, type WrapperProps, type WrapperTag, cls, defineAsyncStore, defineStore, proxyWithPersistant, ref, track, useAsyncCallback, useAsyncState, useDebounce, useEventBus, useFetchRequestIntercept, useFetchResponseIntercept, useMounted, useStatus, useStore, useWatch, useWhenever, wrapper };