@gateweb/react-utils 1.17.0 → 2.1.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.
@@ -1,5 +1,3 @@
1
- import React, { ReactNode } from 'react';
2
- import { AtLeastOne } from './types.mjs';
3
1
  export * from './types.mjs';
4
2
 
5
3
  /**
@@ -708,6 +706,35 @@ declare function invariant(condition: any, message?: string | (() => string)): a
708
706
  */
709
707
  declare const isServer: () => boolean;
710
708
 
709
+ type MaskKeySelector = string | ((key: string, value: unknown, path: Array<string | number>) => boolean);
710
+ /**
711
+ * 深度走訪物件/陣列,將指定鍵名且值為字串的欄位遮罩為固定字串(預設 "******")。
712
+ *
713
+ * - 預設僅遮罩鍵名等於 `password` 的欄位(區分大小寫)
714
+ * - 可傳入「字串鍵名」或「函式選擇器」來自訂要遮罩的欄位
715
+ * - 僅在值為字串時遮罩,其他型別維持原樣
716
+ * - 不變更輸入參考;回傳全新的資料結構
717
+ * - 函式選擇器會收到 `key`、`value` 與 `path`(到該鍵的路徑,陣列用索引)
718
+ * - 支援巢狀物件與陣列
719
+ *
720
+ * @param input - 來源資料
721
+ * @param mask - 遮罩字串,預設為 "******"
722
+ * @param selector - 欄位選擇器,字串或函式,預設 'password'
723
+ * @returns 回傳遮罩後的新資料
724
+ *
725
+ * @example
726
+ * const input = { password: 'secret', user: { password: 'abc' }, list: [{ password: 'x' }, { ok: 1 }] };
727
+ * const output = maskPasswords(input);
728
+ * // { password: '******', user: { password: '******' }, list: [{ password: '******' }, { ok: 1 }] }
729
+ *
730
+ * // 指定鍵名
731
+ * maskPasswords({ secret: 'xxx' }, '***', 'secret'); // { secret: '***' }
732
+ *
733
+ * // 使用函式選擇器(鍵名包含 'pass' 都遮)
734
+ * maskPasswords({ password: 'a', passcode: 'b' }, '***', (k) => k.includes('pass')); // { password: '***', passcode: '***' }
735
+ */
736
+ declare const maskPasswords: <T>(input: T, mask?: string, selector?: MaskKeySelector) => T;
737
+
711
738
  type DeepPartialWithBooleanOverride<T> = {
712
739
  [K in keyof T]?: T[K] extends object ? T[K] extends boolean ? T[K] : DeepPartialWithBooleanOverride<T[K]> | boolean : T[K];
713
740
  };
@@ -1183,162 +1210,6 @@ declare const validateDateString: (dateString: string, format: string) => boolea
1183
1210
  */
1184
1211
  declare const isNil: (value: unknown) => value is null | undefined;
1185
1212
 
1186
- type TQueryProps<Q> = {
1187
- /**
1188
- * the query object
1189
- */
1190
- query: Partial<Q>;
1191
- };
1192
- type TQueryState<Q> = {
1193
- /**
1194
- * trigger the change of query
1195
- *
1196
- * @param query - the new query
1197
- */
1198
- changeQuery: (query: TQueryProps<Q>['query']) => void;
1199
- } & TQueryProps<Q>;
1200
- type TInitialProps<Q> = Partial<TQueryProps<Q> & {
1201
- /**
1202
- * handle the change of query when calling `changeQuery`
1203
- *
1204
- * @param preQuery - the previous query
1205
- * @param newQuery - the new query
1206
- * @returns the custom new query
1207
- */
1208
- handleChangeQuery: (preQuery: TQueryProps<Q>['query'], newQuery: TQueryProps<Q>['query']) => TQueryProps<Q>['query'];
1209
- }>;
1210
- /**
1211
- * Provider to provide the store to the context
1212
- */
1213
- declare const QueryProvider: <Q>({ children, query, handleChangeQuery, }: React.PropsWithChildren<TInitialProps<Q>>) => React.JSX.Element;
1214
- /**
1215
- * hook to get the store from the context
1216
- *
1217
- * because we want the return type of `selector` to be inferred by ts, we use HOF to implement the hook
1218
- *
1219
- * so you should use it like this:
1220
- *
1221
- * ```tsx
1222
- * const useQuery = useQueryContext<MyObject>(); // => will return the store hook
1223
- * const result = useQuery(q => q.query); // => will return the query object
1224
- * ```
1225
- *
1226
- * @example
1227
- *
1228
- * ```tsx
1229
- * const result1 = useQueryContext<MyObject>()(q => '1234');
1230
- * const result2 = useQueryContext<MyObject>()(q => q.changeQuery);
1231
- * const result3 = useQueryContext<MyObject>()(q => q.query);
1232
- * ```
1233
- */
1234
- declare const useQueryContext: <Q>() => <T>(selector: (state: TQueryState<Q>) => T, equalityFn?: (left: T, right: T) => boolean) => T;
1235
-
1236
- /**
1237
- * Creates a strongly-typed React Context and Provider pair for data sharing.
1238
- *
1239
- * This utility helps you avoid prop drilling by providing a reusable way to define
1240
- * context with strict type inference. It returns a custom hook for consuming the context
1241
- * and a Provider component for supplying context values.
1242
- *
1243
- * @template T - The value type for the context.
1244
- * @returns {object} An object containing:
1245
- * - useDataContext: A custom hook to access the context value. Throws an error if used outside the provider.
1246
- * - DataProvider: A Provider component to wrap your component tree and supply the context value.
1247
- *
1248
- * @example
1249
- * // Example usage:
1250
- * const { useDataContext, DataProvider } = createDataContext<{ count: number }>();
1251
- *
1252
- * function Counter() {
1253
- * const { count } = useDataContext();
1254
- * return <span>{count}</span>;
1255
- * }
1256
- *
1257
- * function App() {
1258
- * return (
1259
- * <DataProvider value={{ count: 42 }}>
1260
- * <Counter />
1261
- * </DataProvider>
1262
- * );
1263
- * }
1264
- */
1265
- declare const createDataContext: <T>() => {
1266
- readonly useDataContext: () => T & ({} | null);
1267
- readonly DataProvider: ({ children, value }: {
1268
- children: ReactNode;
1269
- value: T;
1270
- }) => React.JSX.Element;
1271
- };
1272
-
1273
- type TCountdownActions = {
1274
- /** 目前秒數 */
1275
- countdown: number;
1276
- /** 是否正在倒數計時 */
1277
- isCounting: boolean;
1278
- /** 開始倒數計時 */
1279
- start: () => void;
1280
- /** 停止倒數計時 */
1281
- stop: () => void;
1282
- /** 重置倒數計時 */
1283
- reset: () => void;
1284
- };
1285
- /**
1286
- * 倒數計時器
1287
- *
1288
- * 可以透過 start() 來啟動倒數計時器
1289
- * 可以透過 stop() 來停止倒數計時器
1290
- * 可以透過 reset() 來重置倒數計時器
1291
- *
1292
- * @param initialCountdown 倒數計時器初始值
1293
- * @param enableReinitialize 允許重設初始值
1294
- */
1295
- declare const useCountdown: (initialCountdown: number, enableReinitialize?: boolean) => TCountdownActions;
1296
-
1297
- type UseDisclosureReturn = {
1298
- /** Whether the disclosure is currently open. */
1299
- isOpen: boolean;
1300
- /** Open the disclosure (sets isOpen = true). */
1301
- open: () => void;
1302
- /** Close the disclosure (sets isOpen = false). */
1303
- close: () => void;
1304
- /** Toggle the disclosure state (open -> close or close -> open). */
1305
- toggle: () => void;
1306
- };
1307
- /**
1308
- * A small hook to control open/close state.
1309
- *
1310
- * Supports an optional controlled pattern by passing `isOpen` and `onChange`.
1311
- *
1312
- * @example
1313
- * const { isOpen, open, close, toggle } = useDisclosure();
1314
- */
1315
- declare function useDisclosure(initialState?: boolean): UseDisclosureReturn;
1316
-
1317
- type TValueOptions<T> = AtLeastOne<{
1318
- /**
1319
- * The controlled value.
1320
- */
1321
- value?: T;
1322
- /**
1323
- * The default value.
1324
- */
1325
- defaultValue?: T;
1326
- }>;
1327
- /**
1328
- * A hook to manage a value.
1329
- *
1330
- * @example
1331
- *
1332
- * ```tsx
1333
- * const MyComponent = ({ value }: { value?: number }) => {
1334
- * const [currentValue, setCurrentValue] = useValue({ value });
1335
- * };
1336
- * ```
1337
- */
1338
- declare const useValue: <T>({ value, defaultValue }: TValueOptions<T>) => readonly [T, (newValue: T) => void];
1339
-
1340
- declare function mergeRefs<T = any>(refs: Array<React.MutableRefObject<T> | React.LegacyRef<T> | undefined | null>): React.RefCallback<T>;
1341
-
1342
1213
  /**
1343
1214
  * 民國年轉西元年
1344
1215
  * @param dateString 日期字串
@@ -1390,38 +1261,5 @@ declare const generatePeriodArray: () => string[];
1390
1261
  */
1391
1262
  declare const getCurrentPeriod: () => string;
1392
1263
 
1393
- /**
1394
- * Downloads a file from a given source.
1395
- *
1396
- * @param source - The source of the file to be downloaded. It can be a URL string or a Blob object.
1397
- * @param filename - The name of the file to be downloaded. Defaults to the current timestamp if not provided.
1398
- * @param fileExtension - The file extension to be appended to the filename. Optional.
1399
- *
1400
- * @example
1401
- * downloadFile('http://example.com/file.txt', 'testfile', 'txt');
1402
- * downloadFile(new Blob(['test content'], { type: 'text/plain' }), 'testfile', 'txt');
1403
- */
1404
- declare const downloadFile: (source: string | Blob, filename?: string, fileExtension?: string) => void;
1405
-
1406
- /**
1407
- * 從 localStorage 取得資料,支援槽狀取值(Json 物件)
1408
- *
1409
- * @param key 鍵值
1410
- * @param deCode 是否解碼
1411
- * @returns 取得的資料
1412
- * @example
1413
- * const data = getLocalStorage('key');
1414
- *
1415
- * const data = getLocalStorage('key.subKey');
1416
- */
1417
- declare const getLocalStorage: <T>(key: string, deCode?: boolean) => T | undefined;
1418
- /**
1419
- * 將資料(Json 物件)存入 localStorage
1420
- * @param key 鍵值
1421
- * @param value 可序列化的資料
1422
- * @param enCode 是否編碼
1423
- */
1424
- declare const setLocalStorage: (key: string, value: Record<string, any>, enCode?: boolean) => void;
1425
-
1426
- export { ByteSize, MimeTypeMap, OtherMimeType, QueryProvider, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createDataContext, createEnumLikeObject, debounce, decodeBase64, decodeJson, deepClone, deepMerge, downloadFile, encodeBase64, encodeJson, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getLocalStorage, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNil, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskString, mergeConfig, mergeRefs, objectToSearchParams, omit, omitByValue, parseFileInfoFromFilename, parseFilenameFromDisposition, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, renameKey, rocEraToAd, searchParamsToObject, setLocalStorage, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useCountdown, useDisclosure, useQueryContext, useValue, validTaxId, validateDateString, validateFileType, wait };
1427
- export type { MimeTypeExtension, MimeTypeValue, PartialBy, RequiredBy, TCountdownActions, UseDisclosureReturn };
1264
+ export { ByteSize, MimeTypeMap, OtherMimeType, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createEnumLikeObject, debounce, decodeBase64, decodeJson, deepClone, deepMerge, encodeBase64, encodeJson, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNil, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskPasswords, maskString, mergeConfig, objectToSearchParams, omit, omitByValue, parseFileInfoFromFilename, parseFilenameFromDisposition, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, renameKey, rocEraToAd, searchParamsToObject, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, validTaxId, validateDateString, validateFileType, wait };
1265
+ export type { MaskKeySelector, MimeTypeExtension, MimeTypeValue, PartialBy, RequiredBy };