extra-react-hooks 0.8.12 → 0.9.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/README.md CHANGED
@@ -249,3 +249,20 @@ function useNumberInput(params: {
249
249
  ```ts
250
250
  function useMediaQuery(query: string): boolean
251
251
  ```
252
+
253
+ ### useDerivedState
254
+ ```ts
255
+ function useDerivedState<T>(value: T): [
256
+ derivedState: T
257
+ , setDerivedState: (newDerivedState: T) => void
258
+ ]
259
+ ```
260
+
261
+ ### usePromise
262
+ ```ts
263
+ function usePromise<T>(promise: PromiseLike<T>): T | undefined
264
+ ```
265
+
266
+ Similar to `use(promise)`,
267
+ but it also works in environments without `<Suspense>` or server components.
268
+ Errors thrown can be caught by error boundaries.
package/lib/index.d.ts CHANGED
@@ -26,3 +26,5 @@ export * from './use-isomorphic-layout-effect.js';
26
26
  export * from './use-debounce.js';
27
27
  export * from './use-number-input.js';
28
28
  export * from './use-media-query.js';
29
+ export * from './use-derived-state.js';
30
+ export * from './/use-promise.js';
package/lib/index.js CHANGED
@@ -26,4 +26,6 @@ export * from './use-isomorphic-layout-effect.js';
26
26
  export * from './use-debounce.js';
27
27
  export * from './use-number-input.js';
28
28
  export * from './use-media-query.js';
29
+ export * from './use-derived-state.js';
30
+ export * from './/use-promise.js';
29
31
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,eAAe,CAAA;AAC7B,cAAc,qBAAqB,CAAA;AACnC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,kBAAkB,CAAA;AAChC,cAAc,mCAAmC,CAAA;AACjD,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,eAAe,CAAA;AAC7B,cAAc,qBAAqB,CAAA;AACnC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,kBAAkB,CAAA;AAChC,cAAc,mCAAmC,CAAA;AACjD,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,mBAAmB,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { useRef } from 'react';
2
- import { setTimeout } from 'extra-timers';
2
+ import { setTimeout } from '@blackglory/prelude';
3
3
  import { useIIFE } from './use-iife.js';
4
4
  export function useDebounce(fn, timeout, deps) {
5
5
  const fnRef = useRef(fn);
@@ -1 +1 @@
1
- {"version":3,"file":"use-debounce.js","sourceRoot":"","sources":["../src/use-debounce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,UAAU,WAAW,CACzB,EAA2B,EAC3B,OAAe,EACf,IAA2B;IAE3B,MAAM,KAAK,GAAG,MAAM,CAA0B,EAAE,CAAC,CAAA;IACjD,MAAM,gBAAgB,GAAG,MAAM,CAAa,SAAS,CAAC,CAAA;IAEtD,OAAO,CAAC,GAAG,EAAE;QACX,KAAK,CAAC,OAAO,GAAG,EAAE,CAAA;IACpB,CAAC,EAAE,IAAI,CAAC,CAAA;IAER,OAAO,CAAC,GAAG,IAAU,EAAQ,EAAE;;QAC7B,MAAA,gBAAgB,CAAC,OAAO,gEAAI,CAAA;QAE5B,gBAAgB,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE;YAClD,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;YAEtB,gBAAgB,CAAC,OAAO,GAAG,SAAS,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"use-debounce.js","sourceRoot":"","sources":["../src/use-debounce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,UAAU,WAAW,CACzB,EAA2B,EAC3B,OAAe,EACf,IAA2B;IAE3B,MAAM,KAAK,GAAG,MAAM,CAA0B,EAAE,CAAC,CAAA;IACjD,MAAM,gBAAgB,GAAG,MAAM,CAAa,SAAS,CAAC,CAAA;IAEtD,OAAO,CAAC,GAAG,EAAE;QACX,KAAK,CAAC,OAAO,GAAG,EAAE,CAAA;IACpB,CAAC,EAAE,IAAI,CAAC,CAAA;IAER,OAAO,CAAC,GAAG,IAAU,EAAQ,EAAE;;QAC7B,MAAA,gBAAgB,CAAC,OAAO,gEAAI,CAAA;QAE5B,gBAAgB,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE;YAClD,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;YAEtB,gBAAgB,CAAC,OAAO,GAAG,SAAS,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function useDerivedState<T>(value: T): [
2
+ derivedState: T,
3
+ setDerivedState: (newDerivedState: T) => void
4
+ ];
@@ -0,0 +1,20 @@
1
+ import { useRef, useCallback } from 'react';
2
+ import { useIIFE } from './use-iife.js';
3
+ import { useForceUpdate } from './use-force-update.js';
4
+ export function useDerivedState(value) {
5
+ const forceUpdate = useForceUpdate();
6
+ const stateRef = useRef(value);
7
+ useIIFE(() => {
8
+ stateRef.current = value;
9
+ }, [value]);
10
+ return [
11
+ stateRef.current,
12
+ useCallback(newState => {
13
+ if (stateRef.current !== newState) {
14
+ stateRef.current = newState;
15
+ forceUpdate();
16
+ }
17
+ }, [])
18
+ ];
19
+ }
20
+ //# sourceMappingURL=use-derived-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-derived-state.js","sourceRoot":"","sources":["../src/use-derived-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,MAAM,UAAU,eAAe,CAAI,KAAQ;IAIzC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,QAAQ,GAAG,MAAM,CAAI,KAAK,CAAC,CAAA;IAEjC,OAAO,CAAC,GAAG,EAAE;QACX,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAA;IAC1B,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,OAAO;QACL,QAAQ,CAAC,OAAO;QAChB,WAAW,CAAC,QAAQ,CAAC,EAAE;YACrB,IAAI,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAClC,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAA;gBAE3B,WAAW,EAAE,CAAA;YACf,CAAC;QACH,CAAC,EAAE,EAAE,CAAC;KACP,CAAA;AACH,CAAC"}
@@ -1,7 +1,6 @@
1
1
  import { useEffect } from 'react';
2
- import { go, pass } from '@blackglory/prelude';
2
+ import { go, pass, CustomError } from '@blackglory/prelude';
3
3
  import { AbortController } from 'extra-abort';
4
- import { CustomError } from '@blackglory/errors';
5
4
  class InternalAbortError extends CustomError {
6
5
  }
7
6
  export function useEffectAsync(effect, deps) {
@@ -1 +1 @@
1
- {"version":3,"file":"use-effect-async.js","sourceRoot":"","sources":["../src/use-effect-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,MAAM,kBAAmB,SAAQ,WAAW;CAAG;AAE/C,MAAM,UAAU,cAAc,CAC5B,MAAkD,EAClD,IAA2B;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QAExC,EAAE,CAAC,KAAK,IAAI,EAAE;YACZ,IAAI,CAAC;gBACH,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;gBAElC,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YACjC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;oBACtC,IAAI,EAAE,CAAA;gBACR,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAA;IACzD,CAAC,EAAE,IAAI,CAAC,CAAA;AACV,CAAC"}
1
+ {"version":3,"file":"use-effect-async.js","sourceRoot":"","sources":["../src/use-effect-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,kBAAmB,SAAQ,WAAW;CAAG;AAE/C,MAAM,UAAU,cAAc,CAC5B,MAAkD,EAClD,IAA2B;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QAExC,EAAE,CAAC,KAAK,IAAI,EAAE;YACZ,IAAI,CAAC;gBACH,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;gBAElC,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YACjC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;oBACtC,IAAI,EAAE,CAAA;gBACR,CAAC;qBAAM,CAAC;oBAEN,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAA;IACzD,CAAC,EAAE,IAAI,CAAC,CAAA;AACV,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-iife-async.js","sourceRoot":"","sources":["../src/use-iife-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,kBAAmB,SAAQ,WAAW;CAAG;AAE/C,MAAM,UAAU,YAAY,CAC1B,IAAgD,EAChD,IAA2B;IAE3B,OAAO,CAAC,GAAG,EAAE;QACX,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QAExC,EAAE,CAAC,KAAK,IAAI,EAAE;YACZ,IAAI,CAAC;gBACH,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;gBAElC,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YAC/B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;oBACtC,IAAI,EAAE,CAAA;gBACR,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAA;IACzD,CAAC,EAAE,IAAI,CAAC,CAAA;AACV,CAAC"}
1
+ {"version":3,"file":"use-iife-async.js","sourceRoot":"","sources":["../src/use-iife-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,kBAAmB,SAAQ,WAAW;CAAG;AAE/C,MAAM,UAAU,YAAY,CAC1B,IAAgD,EAChD,IAA2B;IAE3B,OAAO,CAAC,GAAG,EAAE;QACX,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QAExC,EAAE,CAAC,KAAK,IAAI,EAAE;YACZ,IAAI,CAAC;gBACH,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;gBAElC,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YAC/B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;oBACtC,IAAI,EAAE,CAAA;gBACR,CAAC;qBAAM,CAAC;oBAEN,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAA;IACzD,CAAC,EAAE,IAAI,CAAC,CAAA;AACV,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { NonEmptyArray } from '@blackglory/prelude';
2
- import { IOptionState } from "./types.js";
2
+ import { IOptionState } from './types.js';
3
3
  export declare function useMultipleSelection<T>(options: NonEmptyArray<T>, defaultSelectedIndexes?: number[]): {
4
4
  selectedIndexes: number[];
5
5
  optionStates: IOptionState[];
@@ -1,6 +1,6 @@
1
1
  import { useState, useMemo, useCallback } from 'react';
2
2
  import { assert, toArray } from '@blackglory/prelude';
3
- import { useIIFE } from "./use-iife.js";
3
+ import { useIIFE } from './use-iife.js';
4
4
  export function useMultipleSelection(options, defaultSelectedIndexes = []) {
5
5
  useIIFE(() => {
6
6
  for (const index of defaultSelectedIndexes) {
@@ -1 +1 @@
1
- {"version":3,"file":"use-multiple-selection.js","sourceRoot":"","sources":["../src/use-multiple-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAiB,MAAM,qBAAqB,CAAA;AAEpE,OAAO,EAAE,OAAO,EAAE,sBAAwB;AAE1C,MAAM,UAAU,oBAAoB,CAClC,OAAyB,EACzB,yBAAmC,EAAE;IAQrC,OAAO,CAAC,GAAG,EAAE;QACX,KAAK,MAAM,KAAK,IAAI,sBAAsB,EAAE,CAAC;YAC3C,MAAM,CACJ,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,EACpC,0FAA0F,CAC3F,CAAA;QACH,CAAC;IACH,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAE5B,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,IAAI,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAEvF,OAAO;QACL,eAAe,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC;QAC3E,YAAY,EAAE,OAAO,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACrE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,eAAe,CAAC,CAAC;QAC9C,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;QAC/B,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC;KACpC,CAAA;IAED,SAAS,kBAAkB;QACzB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;YAC9B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;YAClC,OAAO,EAAE,QAAQ,EAAE,CAAA;QACrB,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,UAAU,CAAC,KAAa;QAC/B,OAAO,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IAED,SAAS,MAAM,CAAC,KAAa;QAC3B,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,QAAQ,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,CAAA;QACf,CAAC;IACH,CAAC;IAED,SAAS,MAAM,CAAC,KAAa;QAC3B,kBAAkB,CAAC,eAAe,CAAC,EAAE;YACnC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;YACvC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACjB,OAAO,MAAM,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,QAAQ,CAAC,KAAa;QAC7B,kBAAkB,CAAC,eAAe,CAAC,EAAE;YACnC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;YACvC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACpB,OAAO,MAAM,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"use-multiple-selection.js","sourceRoot":"","sources":["../src/use-multiple-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAiB,MAAM,qBAAqB,CAAA;AAEpE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAE1C,MAAM,UAAU,oBAAoB,CAClC,OAAyB,EACzB,yBAAmC,EAAE;IAQrC,OAAO,CAAC,GAAG,EAAE;QACX,KAAK,MAAM,KAAK,IAAI,sBAAsB,EAAE,CAAC;YAC3C,MAAM,CACJ,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,EACpC,0FAA0F,CAC3F,CAAA;QACH,CAAC;IACH,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAE5B,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,IAAI,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAEvF,OAAO;QACL,eAAe,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC;QAC3E,YAAY,EAAE,OAAO,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACrE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,eAAe,CAAC,CAAC;QAC9C,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;QAC/B,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC;KACpC,CAAA;IAED,SAAS,kBAAkB;QACzB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;YAC9B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;YAClC,OAAO,EAAE,QAAQ,EAAE,CAAA;QACrB,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,UAAU,CAAC,KAAa;QAC/B,OAAO,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IAED,SAAS,MAAM,CAAC,KAAa;QAC3B,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,QAAQ,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,CAAA;QACf,CAAC;IACH,CAAC;IAED,SAAS,MAAM,CAAC,KAAa;QAC3B,kBAAkB,CAAC,eAAe,CAAC,EAAE;YACnC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;YACvC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACjB,OAAO,MAAM,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,QAAQ,CAAC,KAAa;QAC7B,kBAAkB,CAAC,eAAe,CAAC,EAAE;YACnC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;YACvC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACpB,OAAO,MAAM,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC"}
@@ -1,7 +1,5 @@
1
- import { useRef } from 'react';
2
- import { isntNaN } from 'extra-utils';
3
- import { useIIFE } from './use-iife.js';
4
- import { useForceUpdate } from './use-force-update.js';
1
+ import { isntNaN } from '@blackglory/prelude';
2
+ import { useDerivedState } from './use-derived-state.js';
5
3
  export function useNumberInput({ value, lazy, onChange }) {
6
4
  const [displayValue, setDisplayValue] = useDerivedState(value.toString());
7
5
  return {
@@ -27,16 +25,16 @@ export function useNumberInput({ value, lazy, onChange }) {
27
25
  if (e.target.checkValidity()) {
28
26
  const newValue = e.target.valueAsNumber;
29
27
  if (isntNaN(newValue) && newValue !== value) {
30
- setDisplayValue(newValue.toString(), true);
28
+ setDisplayValue(newValue.toString());
31
29
  onChange(newValue, true);
32
30
  }
33
31
  else {
34
- setDisplayValue(value.toString(), true);
32
+ setDisplayValue(value.toString());
35
33
  onChange(value, true);
36
34
  }
37
35
  }
38
36
  else {
39
- setDisplayValue(value.toString(), true);
37
+ setDisplayValue(value.toString());
40
38
  onChange(value, true);
41
39
  }
42
40
  }
@@ -44,20 +42,4 @@ export function useNumberInput({ value, lazy, onChange }) {
44
42
  }
45
43
  };
46
44
  }
47
- function useDerivedState(dep) {
48
- const forceUpdate = useForceUpdate();
49
- const stateRef = useRef(dep);
50
- useIIFE(() => {
51
- stateRef.current = dep;
52
- }, [dep]);
53
- return [
54
- stateRef.current,
55
- (newState, force = false) => {
56
- if (force || stateRef.current !== newState) {
57
- stateRef.current = newState;
58
- forceUpdate();
59
- }
60
- }
61
- ];
62
- }
63
45
  //# sourceMappingURL=use-number-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-number-input.js","sourceRoot":"","sources":["../src/use-number-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAQrD;IASC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,eAAe,CAAS,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAEjF,OAAO;QACL,aAAa;YACX,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,YAAY;gBAGnB,QAAQ,CAAC,CAAC;oBACR,IAAI,IAAI,EAAE,CAAC;wBACT,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;wBAEzB,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBACjC,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;4BAC9B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;4BAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCAC5C,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;4BAC3B,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,CAAC;oBACN,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC;wBAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;wBAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;4BAC5C,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;4BAE1C,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;wBAC1B,CAAC;6BAAM,CAAC;4BACN,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;4BAEvC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;wBACvB,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;wBAEvC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;oBACvB,CAAC;gBACH,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAI,GAAM;IAIhC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,QAAQ,GAAG,MAAM,CAAI,GAAG,CAAC,CAAA;IAE/B,OAAO,CAAC,GAAG,EAAE;QACX,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAA;IACxB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IAET,OAAO;QACL,QAAQ,CAAC,OAAO;QAChB,CAAC,QAAQ,EAAE,KAAK,GAAG,KAAK,EAAE,EAAE;YAC1B,IAAI,KAAK,IAAI,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC3C,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAA;gBAE3B,WAAW,EAAE,CAAA;YACf,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"use-number-input.js","sourceRoot":"","sources":["../src/use-number-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAQrD;IASC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,eAAe,CAAS,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAEjF,OAAO;QACL,aAAa;YACX,OAAO;gBACL,IAAI,EAAE,QAAQ;gBAId,KAAK,EAAE,YAAY;gBAGnB,QAAQ,CAAC,CAAC;oBACR,IAAI,IAAI,EAAE,CAAC;wBACT,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;wBAEzB,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBACjC,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;4BAC9B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;4BAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCAC5C,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;4BAC3B,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,CAAC;oBACN,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC;wBAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;wBAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;4BAC5C,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;4BAEpC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;wBAC1B,CAAC;6BAAM,CAAC;4BACN,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;4BAEjC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;wBACvB,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;wBAEjC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;oBACvB,CAAC;gBACH,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function usePromise<T>(promise: PromiseLike<T>): T | undefined;
@@ -0,0 +1,21 @@
1
+ import { useState } from 'react';
2
+ import { withAbortSignal } from 'extra-abort';
3
+ import { isntUndefined, getErrorResultPromise } from '@blackglory/prelude';
4
+ import { useEffectAsync } from './use-effect-async.js';
5
+ export function usePromise(promise) {
6
+ const [result, setResult] = useState();
7
+ useEffectAsync(async (signal) => {
8
+ setResult(undefined);
9
+ const [error, result] = await withAbortSignal(signal, () => getErrorResultPromise(promise));
10
+ setResult(() => {
11
+ if (isntUndefined(error)) {
12
+ throw error;
13
+ }
14
+ else {
15
+ return result;
16
+ }
17
+ });
18
+ }, [promise]);
19
+ return result;
20
+ }
21
+ //# sourceMappingURL=use-promise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-promise.js","sourceRoot":"","sources":["../src/use-promise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,MAAM,UAAU,UAAU,CAAI,OAAuB;IACnD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,EAAK,CAAA;IAGzC,cAAc,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;QAC5B,SAAS,CAAC,SAAS,CAAC,CAAA;QAEpB,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,eAAe,CAC3C,MAAM,EACN,GAAG,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,CACrC,CAAA;QAED,SAAS,CAAC,GAAG,EAAE;YACb,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;gBAEzB,MAAM,KAAK,CAAA;YACb,CAAC;iBAAM,CAAC;gBACN,OAAO,MAAM,CAAA;YACf,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAEb,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { NonEmptyArray } from '@blackglory/prelude';
2
- import { IOptionState } from "./types.js";
2
+ import { IOptionState } from './types.js';
3
3
  export declare function useSingleSelection<T>(options: NonEmptyArray<T>, defaultSelectedIndex: number): {
4
4
  selectedIndex: number;
5
5
  optionStates: IOptionState[];
@@ -1,6 +1,6 @@
1
1
  import { useState, useMemo, useCallback } from 'react';
2
2
  import { assert } from '@blackglory/prelude';
3
- import { useIIFE } from "./use-iife.js";
3
+ import { useIIFE } from './use-iife.js';
4
4
  export function useSingleSelection(options, defaultSelectedIndex) {
5
5
  useIIFE(() => {
6
6
  assert(defaultSelectedIndex >= 0 && defaultSelectedIndex < options.length, 'The parameter defaultSelectedIndex must be in the range of 0 to values.length');
@@ -1 +1 @@
1
- {"version":3,"file":"use-single-selection.js","sourceRoot":"","sources":["../src/use-single-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,MAAM,EAAiB,MAAM,qBAAqB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,sBAAwB;AAE1C,MAAM,UAAU,kBAAkB,CAChC,OAAyB,EACzB,oBAA4B;IAM5B,OAAO,CAAC,GAAG,EAAE;QACX,MAAM,CACJ,oBAAoB,IAAI,CAAC,IAAI,oBAAoB,GAAG,OAAO,CAAC,MAAM,EAClE,+EAA+E,CAChF,CAAA;IACH,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAA;IAE1B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAAA;IAExE,OAAO;QACL,aAAa;QACb,YAAY,EAAE,OAAO,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACnE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;KAChC,CAAA;IAED,SAAS,kBAAkB;QACzB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAChC,QAAQ,EAAE,KAAK,KAAK,aAAa;SAClC,CAAC,CAAC,CAAA;IACL,CAAC;IAED,SAAS,MAAM,CAAC,KAAa;QAC3B,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"use-single-selection.js","sourceRoot":"","sources":["../src/use-single-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,MAAM,EAAiB,MAAM,qBAAqB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAE1C,MAAM,UAAU,kBAAkB,CAChC,OAAyB,EACzB,oBAA4B;IAM5B,OAAO,CAAC,GAAG,EAAE;QACX,MAAM,CACJ,oBAAoB,IAAI,CAAC,IAAI,oBAAoB,GAAG,OAAO,CAAC,MAAM,EAClE,+EAA+E,CAChF,CAAA;IACH,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAA;IAE1B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAAA;IAExE,OAAO;QACL,aAAa;QACb,YAAY,EAAE,OAAO,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACnE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;KAChC,CAAA;IAED,SAAS,kBAAkB;QACzB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAChC,QAAQ,EAAE,KAAK,KAAK,aAAa;SAClC,CAAC,CAAC,CAAA;IACL,CAAC;IAED,SAAS,MAAM,CAAC,KAAa;QAC3B,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extra-react-hooks",
3
- "version": "0.8.12",
3
+ "version": "0.9.0",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
@@ -12,66 +12,61 @@
12
12
  "types": "lib/index.d.ts",
13
13
  "sideEffects": false,
14
14
  "engines": {
15
- "node": ">=18.17.0"
15
+ "node": ">=22"
16
16
  },
17
17
  "repository": "git@github.com:BlackGlory/extra-react-hooks.git",
18
18
  "author": "BlackGlory <woshenmedoubuzhidao@blackglory.me>",
19
19
  "license": "MIT",
20
20
  "scripts": {
21
- "prepare": "ts-patch install -s",
22
21
  "lint": "eslint --quiet src __tests__",
23
22
  "test": "vitest --run",
24
- "prepublishOnly": "run-s prepare clean build",
23
+ "prepublishOnly": "run-s clean build",
25
24
  "clean": "rimraf lib",
26
- "build": "tsc --project tsconfig.build.json --outDir lib",
25
+ "build": "tsc --project tsconfig.build.json && tsc-alias --project tsconfig.build.json",
27
26
  "release": "standard-version"
28
27
  },
29
28
  "husky": {
30
29
  "hooks": {
31
- "pre-commit": "run-s prepare lint build test",
30
+ "pre-commit": "run-s clean lint build test",
32
31
  "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
33
32
  }
34
33
  },
35
34
  "devDependencies": {
36
- "@blackglory/wait-for": "^0.7.4",
37
- "@commitlint/cli": "^17.6.5",
38
- "@commitlint/config-conventional": "^17.6.5",
39
- "@eslint/js": "^9.18.0",
40
- "@testing-library/dom": "^10.4.0",
41
- "@testing-library/react": "^16.1.0",
42
- "@testing-library/user-event": "^14.6.1",
43
- "@types/react": "^19.0.7",
44
- "@vitejs/plugin-react": "^4.3.4",
45
- "@vitest/browser": "^3.0.9",
46
- "eslint": "^9.18.0",
47
- "eslint-plugin-react": "^7.37.4",
48
- "eslint-plugin-react-hooks": "^5.1.0",
35
+ "@blackglory/wait-for": "^0.8.5",
36
+ "@commitlint/cli": "^21.2.4",
37
+ "@commitlint/config-conventional": "^21.2.4",
38
+ "@eslint/js": "^10.0.1",
39
+ "@testing-library/dom": "^10.4.2",
40
+ "@testing-library/react": "^16.3.3",
41
+ "@testing-library/user-event": "^14.6.8",
42
+ "@types/react": "^19.3.0",
43
+ "@vitejs/plugin-react": "^6.1.2",
44
+ "@vitest/browser-playwright": "^5.0.5",
45
+ "eslint": "^10.13.0",
46
+ "eslint-plugin-react": "^7.37.5",
47
+ "eslint-plugin-react-hooks": "^7.1.1",
49
48
  "husky": "4",
50
49
  "npm-run-all": "^4.1.5",
51
- "playwright": "^1.51.1",
52
- "react": "^19.0.0",
53
- "react-dom": "^19.0.0",
54
- "react-test-renderer": "^19.0.0",
55
- "return-style": "^3.0.1",
56
- "rimraf": "^4.3.0",
50
+ "playwright": "^1.64.1",
51
+ "react": "^19.3.1",
52
+ "react-dom": "^19.3.1",
53
+ "react-error-boundary": "^6.1.6",
54
+ "react-test-renderer": "^19.3.1",
55
+ "rimraf": "^6.1.3",
57
56
  "standard-version": "^9.3.2",
58
- "ts-patch": "^3.3.0",
57
+ "tsc-alias": "^1.9.9",
59
58
  "tslib": "^2.8.1",
60
- "typescript": "5.7.3",
61
- "typescript-eslint": "^8.20.0",
62
- "typescript-transform-paths": "^3.5.3",
63
- "vite": "^6.2.3",
64
- "vite-tsconfig-paths": "^5.1.4",
65
- "vitest": "^3.0.9"
59
+ "typescript": "6",
60
+ "typescript-eslint": "^8.72.0",
61
+ "vite": "^8.3.5",
62
+ "vite-tsconfig-paths": "^6.1.1",
63
+ "vitest": "^5.0.5"
66
64
  },
67
65
  "dependencies": {
68
- "@blackglory/errors": "^3.0.3",
69
- "@blackglory/prelude": "^0.4.0",
70
- "extra-abort": "^0.4.0",
66
+ "@blackglory/prelude": "^0.5.0",
67
+ "extra-abort": "^0.5.1",
71
68
  "extra-fsm": "^0.2.1",
72
- "extra-timers": "^0.2.6",
73
- "extra-utils": "^5.17.0",
74
- "rxjs": "^7.8.1"
69
+ "rxjs": "^7.8.2"
75
70
  },
76
71
  "peerDependencies": {
77
72
  "react": "^19"
package/src/index.ts CHANGED
@@ -26,3 +26,5 @@ export * from './use-isomorphic-layout-effect.js'
26
26
  export * from './use-debounce.js'
27
27
  export * from './use-number-input.js'
28
28
  export * from './use-media-query.js'
29
+ export * from './use-derived-state.js'
30
+ export * from './/use-promise.js'
@@ -1,5 +1,5 @@
1
1
  import { useRef } from 'react'
2
- import { setTimeout } from 'extra-timers'
2
+ import { setTimeout } from '@blackglory/prelude'
3
3
  import { useIIFE } from './use-iife.js'
4
4
 
5
5
  export function useDebounce<Args extends unknown[]>(
@@ -0,0 +1,26 @@
1
+ import { useRef, useCallback } from 'react'
2
+ import { useIIFE } from './use-iife.js'
3
+ import { useForceUpdate } from './use-force-update.js'
4
+
5
+ export function useDerivedState<T>(value: T): [
6
+ derivedState: T
7
+ , setDerivedState: (newDerivedState: T) => void
8
+ ] {
9
+ const forceUpdate = useForceUpdate()
10
+ const stateRef = useRef<T>(value)
11
+
12
+ useIIFE(() => {
13
+ stateRef.current = value
14
+ }, [value])
15
+
16
+ return [
17
+ stateRef.current
18
+ , useCallback(newState => {
19
+ if (stateRef.current !== newState) {
20
+ stateRef.current = newState
21
+
22
+ forceUpdate()
23
+ }
24
+ }, [])
25
+ ]
26
+ }
@@ -1,7 +1,6 @@
1
1
  import { useEffect } from 'react'
2
- import { go, pass } from '@blackglory/prelude'
2
+ import { go, pass, CustomError } from '@blackglory/prelude'
3
3
  import { AbortController } from 'extra-abort'
4
- import { CustomError } from '@blackglory/errors'
5
4
 
6
5
  class InternalAbortError extends CustomError {}
7
6
 
@@ -21,6 +20,7 @@ export function useEffectAsync(
21
20
  if (err instanceof InternalAbortError) {
22
21
  pass()
23
22
  } else {
23
+ // 预期effect会捕获自身产生的错误, 如果未能捕获, 则让程序崩溃.
24
24
  throw err
25
25
  }
26
26
  }
@@ -19,6 +19,7 @@ export function useIIFEAsync(
19
19
  if (err instanceof InternalAbortError) {
20
20
  pass()
21
21
  } else {
22
+ // 预期iife会捕获自身产生的错误, 如果未能捕获, 则让程序崩溃.
22
23
  throw err
23
24
  }
24
25
  }
@@ -1,7 +1,5 @@
1
- import { useRef } from 'react'
2
- import { isntNaN } from 'extra-utils'
3
- import { useIIFE } from './use-iife.js'
4
- import { useForceUpdate } from './use-force-update.js'
1
+ import { isntNaN } from '@blackglory/prelude'
2
+ import { useDerivedState } from './use-derived-state.js'
5
3
 
6
4
  export function useNumberInput({ value, lazy, onChange }: {
7
5
  value: number
@@ -26,8 +24,11 @@ export function useNumberInput({ value, lazy, onChange }: {
26
24
  getInputProps() {
27
25
  return {
28
26
  type: 'number'
27
+ // `input[type='number']`的特异行为:
28
+ // 如果设置的value与元素内部的值在数字上相同, 则界面不会发生更新.
29
+ // 要解决这个问题需要对DOM快速更新两次: 清空, 然后重新设置值, 不适用于React的受控组件模型.
29
30
  , value: displayValue
30
- // `input[type='number']`有一些特异行为:
31
+ // `input[type='number']`的特异行为:
31
32
  // 如果只是在数字后面输入点`.`, 不会触发change事件.
32
33
  , onChange(e) {
33
34
  if (lazy) {
@@ -49,16 +50,16 @@ export function useNumberInput({ value, lazy, onChange }: {
49
50
  const newValue = e.target.valueAsNumber
50
51
 
51
52
  if (isntNaN(newValue) && newValue !== value) {
52
- setDisplayValue(newValue.toString(), true)
53
+ setDisplayValue(newValue.toString())
53
54
 
54
55
  onChange(newValue, true)
55
56
  } else {
56
- setDisplayValue(value.toString(), true)
57
+ setDisplayValue(value.toString())
57
58
 
58
59
  onChange(value, true)
59
60
  }
60
61
  } else {
61
- setDisplayValue(value.toString(), true)
62
+ setDisplayValue(value.toString())
62
63
 
63
64
  onChange(value, true)
64
65
  }
@@ -67,26 +68,3 @@ export function useNumberInput({ value, lazy, onChange }: {
67
68
  }
68
69
  }
69
70
  }
70
-
71
- function useDerivedState<T>(dep: T): [
72
- state: T
73
- , setState: (newState: T, force?: boolean) => void
74
- ] {
75
- const forceUpdate = useForceUpdate()
76
- const stateRef = useRef<T>(dep)
77
-
78
- useIIFE(() => {
79
- stateRef.current = dep
80
- }, [dep])
81
-
82
- return [
83
- stateRef.current
84
- , (newState, force = false) => {
85
- if (force || stateRef.current !== newState) {
86
- stateRef.current = newState
87
-
88
- forceUpdate()
89
- }
90
- }
91
- ]
92
- }
@@ -0,0 +1,29 @@
1
+ import { useState } from 'react'
2
+ import { withAbortSignal } from 'extra-abort'
3
+ import { isntUndefined, getErrorResultPromise } from '@blackglory/prelude'
4
+ import { useEffectAsync } from './use-effect-async.js'
5
+
6
+ export function usePromise<T>(promise: PromiseLike<T>): T | undefined {
7
+ const [result, setResult] = useState<T>()
8
+
9
+ // React强制要求状态更新不能发生在组件加载时, 因此不能使用`useIIFEAsync()`.
10
+ useEffectAsync(async signal => {
11
+ setResult(undefined)
12
+
13
+ const [error, result] = await withAbortSignal(
14
+ signal
15
+ , () => getErrorResultPromise(promise)
16
+ )
17
+
18
+ setResult(() => {
19
+ if (isntUndefined(error)) {
20
+ // 将异步错误转变为同步错误.
21
+ throw error
22
+ } else {
23
+ return result
24
+ }
25
+ })
26
+ }, [promise])
27
+
28
+ return result
29
+ }