@gateweb/react-utils 1.6.0 → 1.7.1
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/cjs/index.d.ts +86 -1
- package/dist/cjs/index.js +7 -4
- package/dist/cjs/queryStore-client-q_SLGgYH.js +77 -0
- package/dist/cjs/types.d.ts +17 -1
- package/dist/cjs/{useCountdown-client-CNjGBIUB.js → useCountdown-client-uiqhgllY.js} +8 -8
- package/dist/es/index.d.mts +86 -1
- package/dist/es/index.mjs +1 -0
- package/dist/es/queryStore-client-CFQTVwrg.mjs +72 -0
- package/dist/es/types.d.mts +17 -1
- package/package.json +4 -2
package/dist/cjs/index.d.ts
CHANGED
|
@@ -438,6 +438,40 @@ declare const pickByValue: <T extends object, K extends any[]>(object: T, ...val
|
|
|
438
438
|
*
|
|
439
439
|
*/
|
|
440
440
|
declare const deepMerge: <T extends object, U extends object>(target: T, source: U) => T & U;
|
|
441
|
+
/**
|
|
442
|
+
* a utility type to make all properties of an object required
|
|
443
|
+
*
|
|
444
|
+
* @param T - the object type
|
|
445
|
+
* @param K - the keys to make required
|
|
446
|
+
* @param RemoveUndefined - whether to remove undefined from the type
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
*
|
|
450
|
+
* type A = { a?: number; b?: string | undefined; c?: boolean };
|
|
451
|
+
* // Even though b is required, it can be undefined
|
|
452
|
+
* type B = RequiredBy<A, 'a' | 'b'>; // { a: number; b: string | undefined; c?: boolean
|
|
453
|
+
* type C = RequiredBy<A, 'a' | 'b', true>; // { a: number; b: string; c?: boolean }
|
|
454
|
+
*/
|
|
455
|
+
type RequiredBy<T, K extends keyof T, RemoveUndefined extends boolean = false> = Omit<T, K> & {
|
|
456
|
+
[P in K]-?: RemoveUndefined extends true ? Exclude<T[P], undefined> : T[P];
|
|
457
|
+
};
|
|
458
|
+
/**
|
|
459
|
+
* a utility type to make all properties of an object optional
|
|
460
|
+
*
|
|
461
|
+
* @param T - the object type
|
|
462
|
+
* @param K - the keys to make optional
|
|
463
|
+
* @param RemoveUndefined - whether to remove undefined from the type
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
*
|
|
467
|
+
* type A = { a: number; b: string | undefined; c: boolean };
|
|
468
|
+
* // Even though b is optional, it can be undefined
|
|
469
|
+
* type B = PartialBy<A, 'a' | 'b'>; // { a?: number; b?: string | undefined; c: boolean }
|
|
470
|
+
* type C = PartialBy<A, 'a' | 'b', true>; // { a?: number; b?: string; c: boolean }
|
|
471
|
+
*/
|
|
472
|
+
type PartialBy<T, K extends keyof T, RemoveUndefined extends boolean = false> = Omit<T, K> & {
|
|
473
|
+
[P in K]?: RemoveUndefined extends true ? Exclude<T[P], undefined> : T[P];
|
|
474
|
+
};
|
|
441
475
|
|
|
442
476
|
/**
|
|
443
477
|
* debounce function
|
|
@@ -703,6 +737,56 @@ declare const isTWMobile: () => RegExp;
|
|
|
703
737
|
*/
|
|
704
738
|
declare const isTWPhone: () => RegExp;
|
|
705
739
|
|
|
740
|
+
type TQueryProps<Q> = {
|
|
741
|
+
/**
|
|
742
|
+
* the query object
|
|
743
|
+
*/
|
|
744
|
+
query: Partial<Q>;
|
|
745
|
+
};
|
|
746
|
+
type TQueryState<Q> = {
|
|
747
|
+
/**
|
|
748
|
+
* trigger the change of query
|
|
749
|
+
*
|
|
750
|
+
* @param query - the new query
|
|
751
|
+
*/
|
|
752
|
+
changeQuery: (query: TQueryProps<Q>['query']) => void;
|
|
753
|
+
} & TQueryProps<Q>;
|
|
754
|
+
type TInitialProps<Q> = Partial<TQueryProps<Q> & {
|
|
755
|
+
/**
|
|
756
|
+
* handle the change of query when calling `changeQuery`
|
|
757
|
+
*
|
|
758
|
+
* @param preQuery - the previous query
|
|
759
|
+
* @param newQuery - the new query
|
|
760
|
+
* @returns the custom new query
|
|
761
|
+
*/
|
|
762
|
+
handleChangeQuery: (preQuery: TQueryProps<Q>['query'], newQuery: TQueryProps<Q>['query']) => TQueryProps<Q>['query'];
|
|
763
|
+
}>;
|
|
764
|
+
/**
|
|
765
|
+
* Provider to provide the store to the context
|
|
766
|
+
*/
|
|
767
|
+
declare const QueryProvider: <Q>({ children, query, handleChangeQuery, }: React.PropsWithChildren<TInitialProps<Q>>) => React.JSX.Element;
|
|
768
|
+
/**
|
|
769
|
+
* hook to get the store from the context
|
|
770
|
+
*
|
|
771
|
+
* because we want the return type of `selector` to be inferred by ts, we use HOF to implement the hook
|
|
772
|
+
*
|
|
773
|
+
* so you should use it like this:
|
|
774
|
+
*
|
|
775
|
+
* ```tsx
|
|
776
|
+
* const useQuery = useQueryContext<MyObject>(); // => will return the store hook
|
|
777
|
+
* const result = useQuery(q => q.query); // => will return the query object
|
|
778
|
+
* ```
|
|
779
|
+
*
|
|
780
|
+
* @example
|
|
781
|
+
*
|
|
782
|
+
* ```tsx
|
|
783
|
+
* const result1 = useQueryContext<MyObject>()(q => '1234');
|
|
784
|
+
* const result2 = useQueryContext<MyObject>()(q => q.changeQuery);
|
|
785
|
+
* const result3 = useQueryContext<MyObject>()(q => q.query);
|
|
786
|
+
* ```
|
|
787
|
+
*/
|
|
788
|
+
declare const useQueryContext: <Q>() => <T>(selector: (state: TQueryState<Q>) => T, equalityFn?: (left: T, right: T) => boolean) => T;
|
|
789
|
+
|
|
706
790
|
/**
|
|
707
791
|
* 將數字轉換成金額千分位格式
|
|
708
792
|
*
|
|
@@ -827,4 +911,5 @@ declare const getLocalStorage: <T>(key: string, deCode?: boolean) => T | undefin
|
|
|
827
911
|
*/
|
|
828
912
|
declare const setLocalStorage: (key: string, value: Record<string, any>, enCode?: boolean) => void;
|
|
829
913
|
|
|
830
|
-
export {
|
|
914
|
+
export { QueryProvider, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, createEnumLikeObject, debounce, deepMerge, downloadFile, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getLocalStorage, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, mergeRefs, omit, omitByValue, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, setLocalStorage, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useCountdown, useQueryContext, useValue, validTaxId, validateDateString, validateFileType, wait };
|
|
915
|
+
export type { PartialBy, RequiredBy, TCountdownActions };
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
2
|
|
|
3
3
|
var dayjs = require('dayjs');
|
|
4
|
-
var useCountdownClient = require('./useCountdown-client-
|
|
5
|
-
var
|
|
4
|
+
var useCountdownClient = require('./useCountdown-client-uiqhgllY.js');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var queryStoreClient = require('./queryStore-client-q_SLGgYH.js');
|
|
6
7
|
var downloadClient = require('./download-client-DKxkL92w.js');
|
|
7
8
|
var webStorageClient = require('./webStorage-client-BGQKUfrO.js');
|
|
8
9
|
|
|
@@ -488,8 +489,8 @@ const transformObjectKey = (obj, transformFunName)=>{
|
|
|
488
489
|
throw new Error('Either `value` or `defaultValue` must be provided.');
|
|
489
490
|
}
|
|
490
491
|
const isControlled = value !== undefined;
|
|
491
|
-
const [internalValue, setInternalValue] =
|
|
492
|
-
const setValue =
|
|
492
|
+
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
493
|
+
const setValue = React.useCallback((newValue)=>{
|
|
493
494
|
if (!isControlled) {
|
|
494
495
|
setInternalValue(newValue);
|
|
495
496
|
}
|
|
@@ -931,6 +932,8 @@ function mergeRefs(refs) {
|
|
|
931
932
|
};
|
|
932
933
|
|
|
933
934
|
exports.useCountdown = useCountdownClient.useCountdown;
|
|
935
|
+
exports.QueryProvider = queryStoreClient.QueryProvider;
|
|
936
|
+
exports.useQueryContext = queryStoreClient.useQueryContext;
|
|
934
937
|
exports.downloadFile = downloadClient.downloadFile;
|
|
935
938
|
exports.getLocalStorage = webStorageClient.getLocalStorage;
|
|
936
939
|
exports.setLocalStorage = webStorageClient.setLocalStorage;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var React = require('react');
|
|
3
|
+
var zustand = require('zustand');
|
|
4
|
+
var traditional = require('zustand/traditional');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
9
|
+
|
|
10
|
+
const createQueryStore = ({ query, handleChangeQuery })=>zustand.createStore()((set)=>({
|
|
11
|
+
query: {
|
|
12
|
+
...query
|
|
13
|
+
},
|
|
14
|
+
changeQuery: (newQuery)=>{
|
|
15
|
+
set((pre)=>{
|
|
16
|
+
if (handleChangeQuery) {
|
|
17
|
+
return {
|
|
18
|
+
query: handleChangeQuery(pre.query, newQuery)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
query: {
|
|
23
|
+
...pre.query,
|
|
24
|
+
...newQuery
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}));
|
|
30
|
+
const QueryContext = /*#__PURE__*/ React.createContext(null);
|
|
31
|
+
/**
|
|
32
|
+
* Provider to provide the store to the context
|
|
33
|
+
*/ const QueryProvider = ({ children, query, handleChangeQuery })=>{
|
|
34
|
+
const storeRef = React.useRef(null);
|
|
35
|
+
if (!storeRef.current) {
|
|
36
|
+
storeRef.current = createQueryStore({
|
|
37
|
+
query,
|
|
38
|
+
handleChangeQuery
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return /*#__PURE__*/ React__default.default.createElement(QueryContext.Provider, {
|
|
42
|
+
value: storeRef.current
|
|
43
|
+
}, children);
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* hook to get the store from the context
|
|
47
|
+
*
|
|
48
|
+
* because we want the return type of `selector` to be inferred by ts, we use HOF to implement the hook
|
|
49
|
+
*
|
|
50
|
+
* so you should use it like this:
|
|
51
|
+
*
|
|
52
|
+
* ```tsx
|
|
53
|
+
* const useQuery = useQueryContext<MyObject>(); // => will return the store hook
|
|
54
|
+
* const result = useQuery(q => q.query); // => will return the query object
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
*
|
|
59
|
+
* ```tsx
|
|
60
|
+
* const result1 = useQueryContext<MyObject>()(q => '1234');
|
|
61
|
+
* const result2 = useQueryContext<MyObject>()(q => q.changeQuery);
|
|
62
|
+
* const result3 = useQueryContext<MyObject>()(q => q.query);
|
|
63
|
+
* ```
|
|
64
|
+
*/ const useQueryContext = ()=>{
|
|
65
|
+
const store = React.useContext(QueryContext);
|
|
66
|
+
if (!store) throw new Error('Missing QueryContext.Provider in the tree');
|
|
67
|
+
/**
|
|
68
|
+
* the hook to get the store
|
|
69
|
+
*
|
|
70
|
+
* @param selector - the selector to get the state from the store
|
|
71
|
+
* @param equalityFn - the equality function to compare the previous and next state, if it returns `true`, the component will not re-render
|
|
72
|
+
*/ const useStore = (selector, equalityFn)=>traditional.useStoreWithEqualityFn(store, selector, equalityFn);
|
|
73
|
+
return useStore;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
exports.QueryProvider = QueryProvider;
|
|
77
|
+
exports.useQueryContext = useQueryContext;
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -88,6 +88,8 @@ type Entries<T> = {
|
|
|
88
88
|
*
|
|
89
89
|
* @template T - The object type to transform into keys.
|
|
90
90
|
*
|
|
91
|
+
* @deprecated Use `MapToType` instead.
|
|
92
|
+
*
|
|
91
93
|
* @example
|
|
92
94
|
*
|
|
93
95
|
* type Example = { a: number; b: string };
|
|
@@ -171,5 +173,19 @@ type DeepPartial<T> = (T extends (infer U)[] ? DeepPartial<U>[] : {
|
|
|
171
173
|
type TChangeKeyType<T, K extends keyof T, V> = Omit<T, K> & {
|
|
172
174
|
[P in K]: V;
|
|
173
175
|
};
|
|
176
|
+
/**
|
|
177
|
+
* A utility type that transforms an object type `T` into another object type where each value type is replaced with type `A`.
|
|
178
|
+
*
|
|
179
|
+
* @template T - The object type to transform into keys.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
*
|
|
183
|
+
* type Example = { a: number; b: string };
|
|
184
|
+
* type ExampleToBoolean = MapToType<Example, boolean>;
|
|
185
|
+
* // Result: ExampleToBoolean is { a: boolean; b: boolean; }
|
|
186
|
+
*/
|
|
187
|
+
type MapToType<T extends Record<any, any>, A = any> = {
|
|
188
|
+
[K in keyof T]: A;
|
|
189
|
+
};
|
|
174
190
|
|
|
175
|
-
export type { AtLeastOne, DeepPartial, Entries, MapToString, OnlyOne, PopArgs, PushArgs, ShiftArgs, TChangeKeyType, TExtractValueType, UnshiftArgs };
|
|
191
|
+
export type { AtLeastOne, DeepPartial, Entries, MapToString, MapToType, OnlyOne, PopArgs, PushArgs, ShiftArgs, TChangeKeyType, TExtractValueType, UnshiftArgs };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
var
|
|
2
|
+
var React = require('react');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 倒數計時器
|
|
@@ -11,17 +11,17 @@ var react = require('react');
|
|
|
11
11
|
* @param initialCountdown 倒數計時器初始值
|
|
12
12
|
* @param enableReinitialize 允許重設初始值
|
|
13
13
|
*/ const useCountdown = (initialCountdown, enableReinitialize = false)=>{
|
|
14
|
-
const [countdown, setCountdown] =
|
|
15
|
-
const [isCounting, setIsCounting] =
|
|
16
|
-
const initialValues =
|
|
17
|
-
const isMounted =
|
|
18
|
-
|
|
14
|
+
const [countdown, setCountdown] = React.useState(initialCountdown);
|
|
15
|
+
const [isCounting, setIsCounting] = React.useState(false);
|
|
16
|
+
const initialValues = React.useRef(initialCountdown);
|
|
17
|
+
const isMounted = React.useRef(false);
|
|
18
|
+
React.useEffect(()=>{
|
|
19
19
|
isMounted.current = true;
|
|
20
20
|
return ()=>{
|
|
21
21
|
isMounted.current = false;
|
|
22
22
|
};
|
|
23
23
|
}, []);
|
|
24
|
-
|
|
24
|
+
React.useEffect(()=>{
|
|
25
25
|
if (isMounted.current && initialValues.current !== initialCountdown && enableReinitialize) {
|
|
26
26
|
initialValues.current = initialCountdown;
|
|
27
27
|
setCountdown(initialCountdown);
|
|
@@ -30,7 +30,7 @@ var react = require('react');
|
|
|
30
30
|
initialCountdown,
|
|
31
31
|
enableReinitialize
|
|
32
32
|
]);
|
|
33
|
-
|
|
33
|
+
React.useEffect(()=>{
|
|
34
34
|
let timer;
|
|
35
35
|
if (isCounting && countdown > 0) {
|
|
36
36
|
timer = setTimeout(()=>{
|
package/dist/es/index.d.mts
CHANGED
|
@@ -438,6 +438,40 @@ declare const pickByValue: <T extends object, K extends any[]>(object: T, ...val
|
|
|
438
438
|
*
|
|
439
439
|
*/
|
|
440
440
|
declare const deepMerge: <T extends object, U extends object>(target: T, source: U) => T & U;
|
|
441
|
+
/**
|
|
442
|
+
* a utility type to make all properties of an object required
|
|
443
|
+
*
|
|
444
|
+
* @param T - the object type
|
|
445
|
+
* @param K - the keys to make required
|
|
446
|
+
* @param RemoveUndefined - whether to remove undefined from the type
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
*
|
|
450
|
+
* type A = { a?: number; b?: string | undefined; c?: boolean };
|
|
451
|
+
* // Even though b is required, it can be undefined
|
|
452
|
+
* type B = RequiredBy<A, 'a' | 'b'>; // { a: number; b: string | undefined; c?: boolean
|
|
453
|
+
* type C = RequiredBy<A, 'a' | 'b', true>; // { a: number; b: string; c?: boolean }
|
|
454
|
+
*/
|
|
455
|
+
type RequiredBy<T, K extends keyof T, RemoveUndefined extends boolean = false> = Omit<T, K> & {
|
|
456
|
+
[P in K]-?: RemoveUndefined extends true ? Exclude<T[P], undefined> : T[P];
|
|
457
|
+
};
|
|
458
|
+
/**
|
|
459
|
+
* a utility type to make all properties of an object optional
|
|
460
|
+
*
|
|
461
|
+
* @param T - the object type
|
|
462
|
+
* @param K - the keys to make optional
|
|
463
|
+
* @param RemoveUndefined - whether to remove undefined from the type
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
*
|
|
467
|
+
* type A = { a: number; b: string | undefined; c: boolean };
|
|
468
|
+
* // Even though b is optional, it can be undefined
|
|
469
|
+
* type B = PartialBy<A, 'a' | 'b'>; // { a?: number; b?: string | undefined; c: boolean }
|
|
470
|
+
* type C = PartialBy<A, 'a' | 'b', true>; // { a?: number; b?: string; c: boolean }
|
|
471
|
+
*/
|
|
472
|
+
type PartialBy<T, K extends keyof T, RemoveUndefined extends boolean = false> = Omit<T, K> & {
|
|
473
|
+
[P in K]?: RemoveUndefined extends true ? Exclude<T[P], undefined> : T[P];
|
|
474
|
+
};
|
|
441
475
|
|
|
442
476
|
/**
|
|
443
477
|
* debounce function
|
|
@@ -703,6 +737,56 @@ declare const isTWMobile: () => RegExp;
|
|
|
703
737
|
*/
|
|
704
738
|
declare const isTWPhone: () => RegExp;
|
|
705
739
|
|
|
740
|
+
type TQueryProps<Q> = {
|
|
741
|
+
/**
|
|
742
|
+
* the query object
|
|
743
|
+
*/
|
|
744
|
+
query: Partial<Q>;
|
|
745
|
+
};
|
|
746
|
+
type TQueryState<Q> = {
|
|
747
|
+
/**
|
|
748
|
+
* trigger the change of query
|
|
749
|
+
*
|
|
750
|
+
* @param query - the new query
|
|
751
|
+
*/
|
|
752
|
+
changeQuery: (query: TQueryProps<Q>['query']) => void;
|
|
753
|
+
} & TQueryProps<Q>;
|
|
754
|
+
type TInitialProps<Q> = Partial<TQueryProps<Q> & {
|
|
755
|
+
/**
|
|
756
|
+
* handle the change of query when calling `changeQuery`
|
|
757
|
+
*
|
|
758
|
+
* @param preQuery - the previous query
|
|
759
|
+
* @param newQuery - the new query
|
|
760
|
+
* @returns the custom new query
|
|
761
|
+
*/
|
|
762
|
+
handleChangeQuery: (preQuery: TQueryProps<Q>['query'], newQuery: TQueryProps<Q>['query']) => TQueryProps<Q>['query'];
|
|
763
|
+
}>;
|
|
764
|
+
/**
|
|
765
|
+
* Provider to provide the store to the context
|
|
766
|
+
*/
|
|
767
|
+
declare const QueryProvider: <Q>({ children, query, handleChangeQuery, }: React.PropsWithChildren<TInitialProps<Q>>) => React.JSX.Element;
|
|
768
|
+
/**
|
|
769
|
+
* hook to get the store from the context
|
|
770
|
+
*
|
|
771
|
+
* because we want the return type of `selector` to be inferred by ts, we use HOF to implement the hook
|
|
772
|
+
*
|
|
773
|
+
* so you should use it like this:
|
|
774
|
+
*
|
|
775
|
+
* ```tsx
|
|
776
|
+
* const useQuery = useQueryContext<MyObject>(); // => will return the store hook
|
|
777
|
+
* const result = useQuery(q => q.query); // => will return the query object
|
|
778
|
+
* ```
|
|
779
|
+
*
|
|
780
|
+
* @example
|
|
781
|
+
*
|
|
782
|
+
* ```tsx
|
|
783
|
+
* const result1 = useQueryContext<MyObject>()(q => '1234');
|
|
784
|
+
* const result2 = useQueryContext<MyObject>()(q => q.changeQuery);
|
|
785
|
+
* const result3 = useQueryContext<MyObject>()(q => q.query);
|
|
786
|
+
* ```
|
|
787
|
+
*/
|
|
788
|
+
declare const useQueryContext: <Q>() => <T>(selector: (state: TQueryState<Q>) => T, equalityFn?: (left: T, right: T) => boolean) => T;
|
|
789
|
+
|
|
706
790
|
/**
|
|
707
791
|
* 將數字轉換成金額千分位格式
|
|
708
792
|
*
|
|
@@ -827,4 +911,5 @@ declare const getLocalStorage: <T>(key: string, deCode?: boolean) => T | undefin
|
|
|
827
911
|
*/
|
|
828
912
|
declare const setLocalStorage: (key: string, value: Record<string, any>, enCode?: boolean) => void;
|
|
829
913
|
|
|
830
|
-
export {
|
|
914
|
+
export { QueryProvider, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, createEnumLikeObject, debounce, deepMerge, downloadFile, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getLocalStorage, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, mergeRefs, omit, omitByValue, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, setLocalStorage, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useCountdown, useQueryContext, useValue, validTaxId, validateDateString, validateFileType, wait };
|
|
915
|
+
export type { PartialBy, RequiredBy, TCountdownActions };
|
package/dist/es/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
export { u as useCountdown } from './useCountdown-client-t52WIHfq.mjs';
|
|
3
3
|
import { useState, useCallback } from 'react';
|
|
4
|
+
export { Q as QueryProvider, u as useQueryContext } from './queryStore-client-CFQTVwrg.mjs';
|
|
4
5
|
export { d as downloadFile } from './download-client-CnaJ0p_f.mjs';
|
|
5
6
|
export { g as getLocalStorage, s as setLocalStorage } from './webStorage-client-Pd-loNCg.mjs';
|
|
6
7
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useRef, createContext, useContext } from 'react';
|
|
3
|
+
import { createStore } from 'zustand';
|
|
4
|
+
import { useStoreWithEqualityFn } from 'zustand/traditional';
|
|
5
|
+
|
|
6
|
+
const createQueryStore = ({ query, handleChangeQuery })=>createStore()((set)=>({
|
|
7
|
+
query: {
|
|
8
|
+
...query
|
|
9
|
+
},
|
|
10
|
+
changeQuery: (newQuery)=>{
|
|
11
|
+
set((pre)=>{
|
|
12
|
+
if (handleChangeQuery) {
|
|
13
|
+
return {
|
|
14
|
+
query: handleChangeQuery(pre.query, newQuery)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
query: {
|
|
19
|
+
...pre.query,
|
|
20
|
+
...newQuery
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}));
|
|
26
|
+
const QueryContext = /*#__PURE__*/ createContext(null);
|
|
27
|
+
/**
|
|
28
|
+
* Provider to provide the store to the context
|
|
29
|
+
*/ const QueryProvider = ({ children, query, handleChangeQuery })=>{
|
|
30
|
+
const storeRef = useRef(null);
|
|
31
|
+
if (!storeRef.current) {
|
|
32
|
+
storeRef.current = createQueryStore({
|
|
33
|
+
query,
|
|
34
|
+
handleChangeQuery
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return /*#__PURE__*/ React.createElement(QueryContext.Provider, {
|
|
38
|
+
value: storeRef.current
|
|
39
|
+
}, children);
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* hook to get the store from the context
|
|
43
|
+
*
|
|
44
|
+
* because we want the return type of `selector` to be inferred by ts, we use HOF to implement the hook
|
|
45
|
+
*
|
|
46
|
+
* so you should use it like this:
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* const useQuery = useQueryContext<MyObject>(); // => will return the store hook
|
|
50
|
+
* const result = useQuery(q => q.query); // => will return the query object
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
*
|
|
55
|
+
* ```tsx
|
|
56
|
+
* const result1 = useQueryContext<MyObject>()(q => '1234');
|
|
57
|
+
* const result2 = useQueryContext<MyObject>()(q => q.changeQuery);
|
|
58
|
+
* const result3 = useQueryContext<MyObject>()(q => q.query);
|
|
59
|
+
* ```
|
|
60
|
+
*/ const useQueryContext = ()=>{
|
|
61
|
+
const store = useContext(QueryContext);
|
|
62
|
+
if (!store) throw new Error('Missing QueryContext.Provider in the tree');
|
|
63
|
+
/**
|
|
64
|
+
* the hook to get the store
|
|
65
|
+
*
|
|
66
|
+
* @param selector - the selector to get the state from the store
|
|
67
|
+
* @param equalityFn - the equality function to compare the previous and next state, if it returns `true`, the component will not re-render
|
|
68
|
+
*/ const useStore = (selector, equalityFn)=>useStoreWithEqualityFn(store, selector, equalityFn);
|
|
69
|
+
return useStore;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export { QueryProvider as Q, useQueryContext as u };
|
package/dist/es/types.d.mts
CHANGED
|
@@ -88,6 +88,8 @@ type Entries<T> = {
|
|
|
88
88
|
*
|
|
89
89
|
* @template T - The object type to transform into keys.
|
|
90
90
|
*
|
|
91
|
+
* @deprecated Use `MapToType` instead.
|
|
92
|
+
*
|
|
91
93
|
* @example
|
|
92
94
|
*
|
|
93
95
|
* type Example = { a: number; b: string };
|
|
@@ -171,5 +173,19 @@ type DeepPartial<T> = (T extends (infer U)[] ? DeepPartial<U>[] : {
|
|
|
171
173
|
type TChangeKeyType<T, K extends keyof T, V> = Omit<T, K> & {
|
|
172
174
|
[P in K]: V;
|
|
173
175
|
};
|
|
176
|
+
/**
|
|
177
|
+
* A utility type that transforms an object type `T` into another object type where each value type is replaced with type `A`.
|
|
178
|
+
*
|
|
179
|
+
* @template T - The object type to transform into keys.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
*
|
|
183
|
+
* type Example = { a: number; b: string };
|
|
184
|
+
* type ExampleToBoolean = MapToType<Example, boolean>;
|
|
185
|
+
* // Result: ExampleToBoolean is { a: boolean; b: boolean; }
|
|
186
|
+
*/
|
|
187
|
+
type MapToType<T extends Record<any, any>, A = any> = {
|
|
188
|
+
[K in keyof T]: A;
|
|
189
|
+
};
|
|
174
190
|
|
|
175
|
-
export type { AtLeastOne, DeepPartial, Entries, MapToString, OnlyOne, PopArgs, PushArgs, ShiftArgs, TChangeKeyType, TExtractValueType, UnshiftArgs };
|
|
191
|
+
export type { AtLeastOne, DeepPartial, Entries, MapToString, MapToType, OnlyOne, PopArgs, PushArgs, ShiftArgs, TChangeKeyType, TExtractValueType, UnshiftArgs };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gateweb/react-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "React Utils for GateWeb",
|
|
5
5
|
"homepage": "https://github.com/GatewebSolutions/react-utils",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,9 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"dayjs": "^1.11.13",
|
|
39
39
|
"react": "^19.0.0",
|
|
40
|
-
"react-dom": "^19.0.0"
|
|
40
|
+
"react-dom": "^19.0.0",
|
|
41
|
+
"use-sync-external-store": "^1.5.0",
|
|
42
|
+
"zustand": "^5.0.3"
|
|
41
43
|
},
|
|
42
44
|
"devDependencies": {
|
|
43
45
|
"@commitlint/cli": "^19.5.0",
|