@aiszlab/relax 1.2.11 → 1.2.13

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.
@@ -1,6 +1,6 @@
1
1
  import { type Dispatch, type SetStateAction } from 'react';
2
2
  import { type State } from '../is/is-state-getter';
3
- interface Props<T> {
3
+ interface Dependencies<T> {
4
4
  defaultState?: State<T>;
5
5
  }
6
6
  /**
@@ -9,5 +9,5 @@ interface Props<T> {
9
9
  * @description
10
10
  * controlled state
11
11
  */
12
- export declare const useControlledState: <T>(controlledState: State<T>, { defaultState }?: Props<T>) => [T, Dispatch<SetStateAction<T>>];
12
+ export declare const useControlledState: <T>(controlledState: T, { defaultState }?: Dependencies<T>) => [T, Dispatch<SetStateAction<T>>];
13
13
  export {};
@@ -10,35 +10,27 @@ import { isUndefined } from '../is/is-undefined.js';
10
10
  */
11
11
  const useControlledState = (controlledState, { defaultState } = {}) => {
12
12
  /// initialize state
13
- const [state, setState] = useState(() => {
14
- // state function, run it for value
15
- if (isStateGetter(controlledState))
16
- return controlledState();
17
- // not controlled use default prop
18
- if (isUndefined(controlledState)) {
19
- if (isUndefined(defaultState))
20
- return controlledState;
21
- if (isStateGetter(defaultState))
22
- return defaultState();
23
- return defaultState;
24
- }
13
+ const [_state, _setState] = useState(() => {
25
14
  // default use controlled state
26
- return controlledState;
15
+ if (!isUndefined(controlledState)) {
16
+ return controlledState;
17
+ }
18
+ // not controlled use default prop
19
+ if (isUndefined(defaultState))
20
+ return controlledState;
21
+ if (isStateGetter(defaultState))
22
+ return defaultState();
23
+ return defaultState;
27
24
  });
25
+ /// sync value back to `undefined` when it from control to un-control
28
26
  useEffect(() => {
29
- // when state is not controlled
30
- if (isUndefined(controlledState))
31
- return;
32
- // if input state is function, mean it is not controlled
33
- if (isStateGetter(controlledState))
34
- return;
35
- // if state is equal with value
36
- if (controlledState === state)
27
+ if (!isUndefined(controlledState))
37
28
  return;
38
- // update inner state
39
- setState(controlledState);
29
+ _setState(controlledState);
40
30
  }, [controlledState]);
41
- return [state, setState];
31
+ /// use controlled
32
+ const state = !isUndefined(controlledState) ? controlledState : _state;
33
+ return [state, _setState];
42
34
  };
43
35
 
44
36
  export { useControlledState };
@@ -11,7 +11,7 @@ interface Options {
11
11
  * @description
12
12
  * debounce callback
13
13
  */
14
- export declare const useDebounceCallback: <T>(callable: Function, options: Options) => {
14
+ export declare const useDebounceCallback: <T>(callable: Function, { delay }?: Options) => {
15
15
  next: (value: T) => void;
16
16
  complete: () => void;
17
17
  cancel: () => void;
@@ -7,10 +7,9 @@ import { Observable, debounceTime } from 'rxjs';
7
7
  * @description
8
8
  * debounce callback
9
9
  */
10
- const useDebounceCallback = (callable, options) => {
11
- var _a;
12
- // delay
13
- const delay = (_a = options.delay) !== null && _a !== void 0 ? _a : 1000;
10
+ const useDebounceCallback = (callable, { delay = 1000 } = {
11
+ delay: 1000
12
+ }) => {
14
13
  // runner
15
14
  const runner = useRef();
16
15
  // listener
@@ -20,7 +19,7 @@ const useDebounceCallback = (callable, options) => {
20
19
  listener.current = new Observable((subscriber) => {
21
20
  runner.current = subscriber;
22
21
  })
23
- .pipe(debounceTime(options.delay))
22
+ .pipe(debounceTime(delay))
24
23
  .subscribe({
25
24
  next: (value) => {
26
25
  callable(value);
@@ -0,0 +1,3 @@
1
+ type Callback<U extends Array<unknown>, R> = (...args: U) => R;
2
+ export declare const useEvent: <U extends unknown[], R>(callback: Callback<U, R>) => Callback<U, R>;
3
+ export {};
@@ -0,0 +1,9 @@
1
+ import { useRef, useCallback } from 'react';
2
+
3
+ const useEvent = (callback) => {
4
+ const ref = useRef();
5
+ ref.current = callback;
6
+ return useCallback((...args) => ref.current(...args), []);
7
+ };
8
+
9
+ export { useEvent };
@@ -1,4 +1,5 @@
1
1
  import { useLayoutEffect } from 'react';
2
+ import { callAsEffect } from '../utils/thenable-effect-callback.js';
2
3
 
3
4
  /**
4
5
  * @author murukal
@@ -8,16 +9,7 @@ import { useLayoutEffect } from 'react';
8
9
  */
9
10
  const useMount = (callable) => {
10
11
  useLayoutEffect(() => {
11
- const called = callable();
12
- // if result is void
13
- if (!called) {
14
- return void 0;
15
- }
16
- // if result is promise like, return void
17
- if (called.then) {
18
- return void 0;
19
- }
20
- return called;
12
+ return callAsEffect(callable);
21
13
  }, []);
22
14
  };
23
15
 
@@ -1,4 +1,5 @@
1
1
  import { useEffect } from 'react';
2
+ import { callAsEffect } from '../utils/thenable-effect-callback.js';
2
3
 
3
4
  /**
4
5
  * @author murukal
@@ -8,16 +9,7 @@ import { useEffect } from 'react';
8
9
  */
9
10
  const useMounted = (callable) => {
10
11
  useEffect(() => {
11
- const called = callable();
12
- // if result is void
13
- if (!called) {
14
- return void 0;
15
- }
16
- // if result is promise like, return void
17
- if (called.then) {
18
- return void 0;
19
- }
20
- return called;
12
+ return callAsEffect(callable);
21
13
  }, []);
22
14
  };
23
15
 
@@ -0,0 +1,19 @@
1
+ interface Options {
2
+ /**
3
+ * The delay time (in milliseconds) until the throttle function is called.
4
+ * default 1000
5
+ */
6
+ readonly duration: number;
7
+ }
8
+ /**
9
+ * @author murukal
10
+ *
11
+ * @description
12
+ * throttle callback
13
+ */
14
+ export declare const useThrottleCallback: <T>(callable: Function, { duration }?: Options) => {
15
+ next: (value: T) => void;
16
+ complete: () => void;
17
+ cancel: () => void;
18
+ };
19
+ export {};
@@ -0,0 +1,65 @@
1
+ import { useRef, useCallback, useEffect } from 'react';
2
+ import { Observable, throttleTime } from 'rxjs';
3
+
4
+ /**
5
+ * @author murukal
6
+ *
7
+ * @description
8
+ * throttle callback
9
+ */
10
+ const useThrottleCallback = (callable, { duration = 1000 } = {
11
+ duration: 1000
12
+ }) => {
13
+ // runner
14
+ const runner = useRef();
15
+ // listener
16
+ const listener = useRef();
17
+ /// initialze listener function for debouce
18
+ const initialize = useCallback(() => {
19
+ listener.current = new Observable((subscriber) => {
20
+ runner.current = subscriber;
21
+ })
22
+ .pipe(throttleTime(duration))
23
+ .subscribe({
24
+ next: (value) => {
25
+ callable(value);
26
+ },
27
+ complete: () => {
28
+ initialize();
29
+ }
30
+ });
31
+ }, [callable, duration]);
32
+ /// initialize debounce function
33
+ /// when delay / callable changed, need reinitialize
34
+ useEffect(() => {
35
+ initialize();
36
+ // dispose
37
+ return () => {
38
+ var _a;
39
+ (_a = listener.current) === null || _a === void 0 ? void 0 : _a.unsubscribe();
40
+ };
41
+ }, [initialize]);
42
+ /// next function has been debounced for hooks user
43
+ const next = useCallback((value) => {
44
+ var _a;
45
+ (_a = runner.current) === null || _a === void 0 ? void 0 : _a.next(value);
46
+ }, []);
47
+ /// flush the debounce
48
+ const complete = useCallback(() => {
49
+ var _a;
50
+ (_a = runner.current) === null || _a === void 0 ? void 0 : _a.complete();
51
+ }, []);
52
+ /// cancel only valid in debounce time
53
+ /// if the callback has been called, it can not be canceled
54
+ const cancel = useCallback(() => {
55
+ var _a;
56
+ (_a = listener.current) === null || _a === void 0 ? void 0 : _a.unsubscribe();
57
+ }, []);
58
+ return {
59
+ next,
60
+ complete,
61
+ cancel
62
+ };
63
+ };
64
+
65
+ export { useThrottleCallback };
@@ -0,0 +1,3 @@
1
+ import { DependencyList } from 'react';
2
+ import { ThenableEffectCallback } from '../utils/thenable-effect-callback';
3
+ export declare const useUpdateEffect: (callable: ThenableEffectCallback, deps?: DependencyList) => void;
@@ -0,0 +1,22 @@
1
+ import { useRef, useEffect } from 'react';
2
+ import 'rxjs';
3
+ import { callAsEffect } from '../utils/thenable-effect-callback.js';
4
+ import { useMounted } from './use-mounted.js';
5
+ import './use-scroll-locker.js';
6
+ import '../dom/scroll-to.js';
7
+ import './use-toggleable.js';
8
+ import 'react-is';
9
+
10
+ const useUpdateEffect = (callable, deps) => {
11
+ const isMounted = useRef(false);
12
+ useEffect(() => {
13
+ if (!isMounted.current)
14
+ return void 0;
15
+ return callAsEffect(callable);
16
+ }, deps);
17
+ useMounted(() => {
18
+ isMounted.current = true;
19
+ });
20
+ };
21
+
22
+ export { useUpdateEffect };
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  export { useBoolean } from './hooks/use-boolean';
6
6
  export { useDebounceCallback } from './hooks/use-debounce-callback';
7
+ export { useThrottleCallback } from './hooks/use-throttle-callback';
7
8
  export { useImageLoader } from './hooks/use-image-loader';
8
9
  export { useMount } from './hooks/use-mount';
9
10
  export { useMounted } from './hooks/use-mounted';
@@ -15,6 +16,8 @@ export { useForceUpdate } from './hooks/use-force-update';
15
16
  export { useScrollable } from './hooks/use-scrollable';
16
17
  export { useRefs } from './hooks/use-refs';
17
18
  export { useToggleable } from './hooks/use-toggleable';
19
+ export { useEvent } from './hooks/use-event';
20
+ export { useUpdateEffect } from './hooks/use-update-effect';
18
21
  /**
19
22
  * @description
20
23
  * is
@@ -32,6 +35,7 @@ export { isMobile } from './is/is-mobile';
32
35
  export { isOverflow } from './is/is-overflow';
33
36
  export { isStyleElement } from './is/is-style-element';
34
37
  export { isFunction } from './is/is-function';
38
+ export { isThenable } from './is/is-thenable';
35
39
  /**
36
40
  * @description
37
41
  * utils
@@ -39,4 +43,5 @@ export { isFunction } from './is/is-function';
39
43
  export { type Nullable } from './utils/null-able';
40
44
  export { type Partialable } from './utils/partial-able';
41
45
  export { type RequiredIn } from './utils/required-in';
46
+ export { type ThenableEffectCallback, callAsEffect } from './utils/thenable-effect-callback';
42
47
  export { unique, uniqueBy } from './utils/unique';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { useBoolean } from './hooks/use-boolean.js';
2
2
  export { useDebounceCallback } from './hooks/use-debounce-callback.js';
3
+ export { useThrottleCallback } from './hooks/use-throttle-callback.js';
3
4
  export { useImageLoader } from './hooks/use-image-loader.js';
4
5
  export { useMount } from './hooks/use-mount.js';
5
6
  export { useMounted } from './hooks/use-mounted.js';
@@ -11,6 +12,8 @@ export { useForceUpdate } from './hooks/use-force-update.js';
11
12
  export { useScrollable } from './hooks/use-scrollable.js';
12
13
  export { useRefs } from './hooks/use-refs.js';
13
14
  export { useToggleable } from './hooks/use-toggleable.js';
15
+ export { useEvent } from './hooks/use-event.js';
16
+ export { useUpdateEffect } from './hooks/use-update-effect.js';
14
17
  export { isRefable } from './is/is-refable.js';
15
18
  export { isUndefined } from './is/is-undefined.js';
16
19
  export { isStateGetter } from './is/is-state-getter.js';
@@ -24,4 +27,6 @@ export { isMobile } from './is/is-mobile.js';
24
27
  export { isOverflow } from './is/is-overflow.js';
25
28
  export { isStyleElement } from './is/is-style-element.js';
26
29
  export { isFunction } from './is/is-function.js';
30
+ export { isThenable } from './is/is-thenable.js';
31
+ export { callAsEffect } from './utils/thenable-effect-callback.js';
27
32
  export { unique, uniqueBy } from './utils/unique.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @description
3
+ * is thenable
4
+ */
5
+ export declare const isThenable: <T>(value: T | PromiseLike<T>) => value is PromiseLike<T>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @description
3
+ * is thenable
4
+ */
5
+ const isThenable = (value) => {
6
+ return !!value.then;
7
+ };
8
+
9
+ export { isThenable };
@@ -0,0 +1,11 @@
1
+ import type { EffectCallback } from 'react';
2
+ /**
3
+ * @description
4
+ * thenable effect callback
5
+ */
6
+ export type ThenableEffectCallback = () => ReturnType<EffectCallback> | PromiseLike<ReturnType<EffectCallback>>;
7
+ /**
8
+ * @description
9
+ * call thenable effect callback
10
+ */
11
+ export declare const callAsEffect: (callable: ThenableEffectCallback) => ReturnType<EffectCallback>;
@@ -0,0 +1,18 @@
1
+ import { isThenable } from '../is/is-thenable.js';
2
+
3
+ /**
4
+ * @description
5
+ * call thenable effect callback
6
+ */
7
+ const callAsEffect = (callable) => {
8
+ const called = callable();
9
+ // if result is void
10
+ if (!called)
11
+ return void 0;
12
+ // if result is promise like, return void
13
+ if (isThenable(called))
14
+ return void 0;
15
+ return called;
16
+ };
17
+
18
+ export { callAsEffect };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiszlab/relax",
3
- "version": "1.2.11",
3
+ "version": "1.2.13",
4
4
  "description": "react utils collection",
5
5
  "type": "module",
6
6
  "exports": {
@@ -24,9 +24,9 @@
24
24
  "@rollup/plugin-babel": "^6.0.3",
25
25
  "@rollup/plugin-node-resolve": "^15.1.0",
26
26
  "@rollup/plugin-typescript": "^11.1.1",
27
- "@types/react": "^18.2.12",
28
- "@types/react-dom": "^18.2.5",
29
- "@types/react-is": "^18.2.2",
27
+ "@types/react": "^18",
28
+ "@types/react-dom": "^18",
29
+ "@types/react-is": "^18",
30
30
  "rollup": "^3.27.0",
31
31
  "typescript": "^5.1.3"
32
32
  },