@gateweb/react-utils 1.7.0 → 1.8.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/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-CNjGBIUB.js');
5
- var react = require('react');
4
+ var queryStoreClient = require('./queryStore-client-q_SLGgYH.js');
5
+ var useCountdownClient = require('./useCountdown-client-uiqhgllY.js');
6
+ var React = require('react');
6
7
  var downloadClient = require('./download-client-DKxkL92w.js');
7
8
  var webStorageClient = require('./webStorage-client-BGQKUfrO.js');
8
9
 
@@ -10,302 +11,149 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
11
 
11
12
  var dayjs__default = /*#__PURE__*/_interopDefault(dayjs);
12
13
 
14
+ const FILE_SIZE_UNITS$1 = [
15
+ 'Bytes',
16
+ 'KB',
17
+ 'MB',
18
+ 'GB',
19
+ 'TB',
20
+ 'PB',
21
+ 'EB',
22
+ 'ZB',
23
+ 'YB'
24
+ ];
13
25
  /**
14
- * convert CamelCase string to PascalCase string
15
- * @param str the string to convert
16
- * @example
17
- * camelString2PascalString('camelCase') // 'CamelCase'
18
- * camelString2PascalString('camelCaseTest') // 'CamelCaseTest'
19
- */ const camelString2PascalString = (str)=>`${str[0].toUpperCase()}${str.slice(1)}`;
20
- /**
21
- * convert CamelCase string to SnakeCase string
22
- * @param str the string to convert
23
- * @example
24
- * camelString2SnakeString('camelCase') // 'camel_case'
25
- * camelString2SnakeString('camelCaseTest') // 'camel_case_test'
26
- */ const camelString2SnakeString = (str)=>str.replace(/[A-Z]/g, (letter)=>`_${letter.toLowerCase()}`);
27
- /**
28
- * convert PascalCase string to CamelCase string
29
- * @param str the string to convert
30
- * @example
31
- * pascalString2CamelString('PascalCase') // 'pascalCase'
32
- * pascalString2CamelString('PascalCaseTest') // 'pascalCaseTest'
33
- */ const pascalString2CamelString = (str)=>`${str[0].toLowerCase()}${str.slice(1)}`;
34
- /**
35
- * convert PascalCase string to SnakeCase string
36
- * @param str the string to convert
37
- * @example
38
- * pascalString2SnakeString('PascalCase') // 'pascal_case'
39
- * pascalString2SnakeString('PascalCaseTest') // 'pascal_case_test'
40
- */ const pascalString2SnakeString = (str)=>camelString2SnakeString(pascalString2CamelString(str));
41
- /**
42
- * convert SnakeCase string to CamelCase string
43
- * @param str the string to convert
44
- * @example
45
- * snakeString2CamelString('snake_case') // 'snakeCase'
46
- * snakeString2CamelString('snake_case_test') // 'snakeCaseTest'
47
- */ const snakeString2CamelString = (str)=>str.replace(/(_[a-z])/g, (group)=>group.toUpperCase().replace('_', ''));
48
- /**
49
- * convert SnakeCase string to PascalCase string
50
- * @param str the string to convert
51
- * @example
52
- * snakeString2PascalString('snake_case') // 'SnakeCase'
53
- * snakeString2PascalString('snake_case_test') // 'SnakeCaseTest'
54
- */ const snakeString2PascalString = (str)=>camelString2PascalString(snakeString2CamelString(str));
55
- const transformFun = {
56
- CamelToPascal: camelString2PascalString,
57
- CamelToSnake: camelString2SnakeString,
58
- PascalToCamel: pascalString2CamelString,
59
- PascalToSnake: pascalString2SnakeString,
60
- SnakeToCamel: snakeString2CamelString,
61
- SnakeToPascal: snakeString2PascalString
62
- };
63
- const transformObjectKey = (obj, transformFunName)=>{
64
- if (!obj || typeof obj !== 'object') return obj;
65
- if (Array.isArray(obj)) return obj.map((item)=>transformObjectKey(item, transformFunName));
66
- return Object.keys(obj).reduce((acc, key)=>({
67
- ...acc,
68
- [transformFun[transformFunName](key)]: transformObjectKey(obj[key], transformFunName)
69
- }), {});
70
- };
71
- /**
72
- * convert object key from CamelCase to PascalCase
73
- * @param obj the object to convert
74
- * @example
75
- * const obj = {
76
- * fooBar: 'fooBar',
77
- * fooBar2: 'fooBar2',
78
- * fooBar3: {
79
- * fooBar4: 'fooBar4',
80
- * fooBar5: 'fooBar5',
81
- * },
82
- * };
83
- * const result = camelCase2PascalCase(obj);
84
- * console.log(result); // { FooBar: 'fooBar', FooBar2: 'fooBar2', FooBar3: { FooBar4: 'fooBar4', FooBar5: 'fooBar5' } }
85
- */ const camelCase2PascalCase = (obj)=>transformObjectKey(obj, 'CamelToPascal');
86
- /**
87
- * convert object key from CamelCase to SnakeCase
88
- * @param obj the object to convert
89
- * @example
90
- * const obj = {
91
- * fooBar: 'fooBar',
92
- * fooBar2: 'fooBar2',
93
- * fooBar3: {
94
- * fooBar4: 'fooBar4',
95
- * fooBar5: 'fooBar5',
96
- * },
97
- * };
98
- * const result = camelCase2SnakeCase(obj);
99
- * console.log(result); // { foo_bar: 'fooBar', foo_bar2: 'fooBar2', foo_bar3: { foo_bar4: 'fooBar4', foo_bar5: 'fooBar5' } }
100
- */ const camelCase2SnakeCase = (obj)=>transformObjectKey(obj, 'CamelToSnake');
101
- /**
102
- * convert object key from PascalCase to CamelCase
103
- * @param obj the object to convert
104
- * @example
105
- * const obj = {
106
- * FooBar: 'fooBar',
107
- * FooBar2: 'fooBar2',
108
- * FooBar3: {
109
- * FooBar4: 'fooBar4',
110
- * FooBar5: 'fooBar5',
111
- * },
112
- * };
113
- * const result = pascalCase2CamelCase(obj);
114
- * console.log(result); // { fooBar: 'fooBar', fooBar2: 'fooBar2', fooBar3: { fooBar4: 'fooBar4', fooBar5: 'fooBar5' } }
115
- */ const pascalCase2CamelCase = (obj)=>transformObjectKey(obj, 'PascalToCamel');
116
- /**
117
- * convert object key from PascalCase to SnakeCase
118
- * @param obj the object to convert
119
- * @example
120
- * const obj = {
121
- * FooBar: 'fooBar',
122
- * FooBar2: 'fooBar2',
123
- * FooBar3: {
124
- * FooBar4: 'fooBar4',
125
- * FooBar5: 'fooBar5',
126
- * },
127
- * };
128
- * const result = pascalCase2SnakeCase(obj);
129
- * console.log(result); // { foo_bar: 'fooBar', foo_bar2: 'fooBar2', foo_bar3: { foo_bar4: 'fooBar4', foo_bar5: 'fooBar5' } }
130
- */ const pascalCase2SnakeCase = (obj)=>transformObjectKey(obj, 'PascalToSnake');
131
- /**
132
- * convert object key from SnakeCase to CamelCase
133
- * @param obj the object to convert
134
- * @example
135
- * const obj = {
136
- * foo_bar: 'fooBar',
137
- * foo_bar2: 'fooBar2',
138
- * foo_bar3: {
139
- * foo_bar4: 'fooBar4',
140
- * foo_bar5: 'fooBar5',
141
- * },
142
- * };
143
- * const result = snakeCase2CamelCase(obj);
144
- * console.log(result); // { fooBar: 'fooBar', fooBar2: 'fooBar2', fooBar3: { fooBar4: 'fooBar4', fooBar5: 'fooBar5' } }
145
- */ const snakeCase2CamelCase = (obj)=>transformObjectKey(obj, 'SnakeToCamel');
146
- /**
147
- * convert object key from SnakeCase to PascalCase
148
- * @param obj the object to convert
149
- * @example
150
- * const obj = {
151
- * foo_bar: 'fooBar',
152
- * foo_bar2: 'fooBar2',
153
- * foo_bar3: {
154
- * foo_bar4: 'fooBar4',
155
- * foo_bar5: 'fooBar5',
156
- * },
157
- * };
158
- * const result = snakeCase2PascalCase(obj);
159
- * console.log(result); // { FooBar: 'fooBar', FooBar2: 'fooBar2', FooBar3: { FooBar4: 'fooBar4', FooBar5: 'fooBar5' } }
160
- */ const snakeCase2PascalCase = (obj)=>transformObjectKey(obj, 'SnakeToPascal');
161
-
162
- /**
163
- * 檢查稅務編號是否符合正確的編號規則。
164
- *
165
- * @param {string} taxId - 要檢查的8位數稅務編號。
166
- * @returns {boolean} - 如果符合規則則返回 true,否則返回 false。
167
- *
168
- * ### 編號檢查規則:
169
- * 1. **基本格式檢查**:
170
- * - 編號必須為 8 位數字。
171
- * - 不得為「00000000」或「11111111」,這些編號被視為無效。
172
- *
173
- * 2. **驗證邏輯**:
174
- * - 使用一組驗證運算子:`[1, 2, 1, 2, 1, 2, 4, 1]`。
175
- * - 將稅務編號的每一位數字與對應的運算子相乘後,使用 `calculate` 函數計算各位數的和。
176
- * - 計算公式為:`(product % 10) + (product - (product % 10)) / 10`
177
- * - 將所有位數經計算後的結果加總為 `sum`。
178
- *
179
- * 3. **檢查規則**:
180
- * - 如果總和 `sum` 可以被 5 整除,則編號有效。
181
- * - 或者,若第七位數為 7,且 `(sum + 1) % 5 === 0`,則編號有效。
182
- *
183
- * @example
184
- *
185
- * validTaxId('22099131') // true
186
- * validTaxId('84149961') // true
187
- * validTaxId('00000000') // false
188
- * validTaxId('11111111') // false
189
- * validTaxId('22099132') // false
190
- */ const validTaxId = (taxId)=>{
191
- const invalidList = '00000000,11111111';
192
- if (/^\d{8}$/.test(taxId) === false || invalidList.indexOf(taxId) >= 0) {
193
- return false;
26
+ * 代表字節大小的類,提供各種格式化和轉換方法
27
+ */ class ByteSize {
28
+ /**
29
+ * 建立一個新的 ByteSize 實例
30
+ * @param bytes 位元組數值
31
+ */ constructor(bytes){
32
+ this.bytes = bytes;
194
33
  }
195
- const validateOperator = [
196
- 1,
197
- 2,
198
- 1,
199
- 2,
200
- 1,
201
- 2,
202
- 4,
203
- 1
204
- ];
205
- const calculate = (product)=>product % 10 + (product - product % 10) / 10;
206
- const sum = validateOperator.reduce((pre, cur, index)=>pre + calculate(Number(taxId[index]) * cur), 0);
207
- return sum % 5 === 0 || taxId[6] === '7' && (sum + 1) % 5 === 0;
208
- };
209
- /**
210
- * 驗證日期格式是否正確
211
- *
212
- * @param dateString 日期字串
213
- * @param format 日期格式
214
- * @example
215
- *
216
- * validateDateString('20210201', 'YYYYMMDD') // true
217
- * validateDateString('2021-02-01', 'YYYY-MM-DD') // true
218
- * validateDateString('20210201', 'YYYY-MM-DD') // false
219
- * validateDateString('20210201', 'YYYYMM') // false
220
- */ const validateDateString = (dateString, format)=>{
221
- if (!dateString) return false;
222
- // 根據 format 生成正則表達式
223
- const regexPattern = format.replace(/YYYY/, '\\d{4}').replace(/MM/, '\\d{2}').replace(/DD/, '\\d{2}').replace(/HH/, '\\d{2}').replace(/mm/, '\\d{2}').replace(/ss/, '\\d{2}');
224
- const regex = new RegExp(`^${regexPattern}$`);
225
- // 先用正則驗證格式
226
- if (!regex.test(dateString)) return false;
227
- // 再用 dayjs 驗證是否為有效日期
228
- return dayjs__default.default(dateString, format, true).isValid();
229
- };
230
-
231
- /**
232
- * 取得去年今年以及明年期別陣列
233
- *
234
- * @example
235
- * // 假設 今年為 112 年
236
- * generatePeriodArray() // 11102 ~ 11312
237
- */ const generatePeriodArray = ()=>{
238
- const currentYear = new Date().getFullYear() - 1911;
239
- const months = [
240
- '02',
241
- '04',
242
- '06',
243
- '08',
244
- '10',
245
- '12'
246
- ];
247
- const years = [
248
- currentYear - 1,
249
- currentYear,
250
- currentYear + 1
251
- ];
252
- return years.flatMap((year)=>months.map((month)=>`${year}${month}`));
253
- };
254
- /**
255
- * 取得當前期別
256
- *
257
- * 報稅期限次期開始15日內
258
- *
259
- * 雙數月沒有特殊規則,期別皆為當月開頭
260
- *
261
- * 單數月15號以前,期別為上個月否則為下個月開頭
262
- *
263
- * @example
264
- *
265
- * // 假設今天是 111-02-15
266
- * getCurrentPeriod() // 11102
267
- * // 假設今天是 111-02-16
268
- * getCurrentPeriod() // 11102
269
- * // 假設今天是 111-03-15
270
- * getCurrentPeriod() // 11102
271
- * // 假設今天是 111-03-16
272
- * getCurrentPeriod() // 11104
273
- */ const getCurrentPeriod = ()=>{
274
- const now = dayjs__default.default();
275
- const currentDate = now.format('DD');
276
- const currentYear = now.format('YYYY');
277
- const currentMonth = now.format('MM');
278
- let endMonth;
279
- if (Number(currentMonth) % 2 === 1) {
280
- endMonth = dayjs__default.default(`${currentYear}${currentMonth}`, 'YYYYMM').add(Number(currentDate) <= 15 ? -1 : 1, 'month').format('YYYYMM');
281
- } else {
282
- endMonth = `${currentYear}${currentMonth}`;
34
+ /**
35
+ * 取得原始位元組數值
36
+ */ get value() {
37
+ return this.bytes;
283
38
  }
284
- return dayjs__default.default(endMonth, 'YYYYMM').subtract(1911, 'year').format('YYYYMM').substring(1);
285
- };
39
+ /**
40
+ * 將位元組轉換為指定單位的數值
41
+ *
42
+ * @param unit 目標單位 (例如 'KB', 'MB', 'GB')
43
+ * @returns 轉換後的數值
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const size = createByteSize(1024);
48
+ * size.to('KB'); // 1
49
+ * size.to('MB'); // 0.0009765625
50
+ * ```
51
+ */ to(unit) {
52
+ if (!FILE_SIZE_UNITS$1.includes(unit)) {
53
+ console.warn(`Invalid unit: ${unit}. Valid units are: ${FILE_SIZE_UNITS$1.join(', ')}`);
54
+ return this.bytes;
55
+ }
56
+ const k = 1024;
57
+ const i = FILE_SIZE_UNITS$1.indexOf(unit);
58
+ return this.bytes / k ** i;
59
+ }
60
+ /**
61
+ * 轉換為適當單位的可讀字符串
62
+ *
63
+ * @param unit 指定單位 (例如 'KB', 'MB', 'GB'),不指定則自動選擇最適合的單位
64
+ * @param decimals 小數點位數 (預設為 2)
65
+ * @returns 格式化後的字符串
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const size = createByteSize(1024);
70
+ * size.format(); // '1.00 KB'
71
+ * size.format('KB'); // '1.00 KB'
72
+ * size.format('MB', 3); // '0.001 MB'
73
+ * ```
74
+ */ format(unit, decimals = 2) {
75
+ if (this.bytes === 0) return `0 ${unit || 'Bytes'}`;
76
+ const k = 1024;
77
+ // 如果指定了有效單位,則使用;否則,計算最適合的單位
78
+ const i = unit && FILE_SIZE_UNITS$1.includes(unit) ? FILE_SIZE_UNITS$1.indexOf(unit) : Math.floor(Math.log(this.bytes) / Math.log(k));
79
+ return `${(this.bytes / k ** i).toFixed(decimals)} ${FILE_SIZE_UNITS$1[i]}`;
80
+ }
81
+ /**
82
+ * 比較兩個 ByteSize 實例
83
+ *
84
+ * @param other 要比較的另一個 ByteSize 實例
85
+ * @returns 比較結果:-1 表示小於,0 表示等於,1 表示大於
86
+ */ compareTo(other) {
87
+ if (this.bytes < other.value) return -1;
88
+ if (this.bytes > other.value) return 1;
89
+ return 0;
90
+ }
91
+ /**
92
+ * 轉換為字符串表示
93
+ * @returns 預設格式化的字符串
94
+ */ toString() {
95
+ return this.format();
96
+ }
97
+ }
286
98
  /**
287
- * 民國年轉西元年
288
- * @param dateString 日期字串
289
- * @param format 日期格式
290
- * @example
99
+ * 將位元組轉換為可讀字符串 (保留舊的 API 以確保向後兼容)
291
100
  *
292
- * rocEraToAd('1100201') // 20210201
293
- * rocEraToAd('11002', 'YYYYMM') // 202102
294
- */ const rocEraToAd = (dateString, format = 'YYYYMMDD')=>{
295
- if (!validateDateString(`0${dateString}`, format)) return dateString;
296
- return dayjs__default.default(`0${dateString}`, format).add(1911, 'year').format(format);
297
- };
298
- /**
299
- * 西元年轉民國年
300
- * @param dateString 日期字串
301
- * @param format 日期格式
302
- * @example
101
+ * @param bytes 位元組數值
102
+ * @param unit 目標單位 (例如 'KB', 'MB', 'GB'),不指定則自動選擇最適合的單位
103
+ * @param decimals 小數點位數 (預設為 2)
104
+ * @returns 格式化後的字符串
303
105
  *
304
- * adToRocEra('20210201') // 1100201
305
- * adToRocEra('202102', 'YYYYMM') // 11002
306
- */ const adToRocEra = (dateString, format = 'YYYYMMDD')=>{
307
- if (!validateDateString(dateString, format)) return dateString;
308
- return dayjs__default.default(dateString, format).add(-1911, 'year').format(format).substring(1);
106
+ * @example
107
+ * ```ts
108
+ * convertBytes(0) // '0 Bytes'
109
+ * convertBytes(1024, 'KB') // '1 KB'
110
+ * convertBytes(1024, 'KB', 2) // '1.00 KB'
111
+ * convertBytes(1024 * 1024, 'MB') // '1 MB'
112
+ * convertBytes(1024 * 1024, 'KB') // '1024 KB'
113
+ * ```
114
+ */ const convertBytes = (bytes, unit, decimals = 2)=>new ByteSize(bytes).format(unit, decimals);
115
+
116
+ /**
117
+ * 檢查兩個值是否相等(包含陣列等引用型別)
118
+ * - 支援基本型別的直接比較
119
+ * - 特別處理空陣列比較
120
+ * - 支援非空陣列的深度比較
121
+ *
122
+ * @param value1 - 第一個值
123
+ * @param value2 - 第二個值
124
+ * @returns 如果值相等則返回 true
125
+ *
126
+ * @example
127
+ * // 基本型別比較
128
+ * isEqual(1, 1); // true
129
+ * isEqual('abc', 'abc'); // true
130
+ * isEqual(null, null); // true
131
+ *
132
+ * // 陣列比較
133
+ * isEqual([], []); // true
134
+ * isEqual([1, 2], [1, 2]); // true
135
+ * isEqual([1, 2], [1, 3]); // false
136
+ */ const isEqual = (value1, value2)=>{
137
+ // 處理基本型別
138
+ if (value1 === value2) {
139
+ return true;
140
+ }
141
+ // 處理空陣列
142
+ if (Array.isArray(value1) && Array.isArray(value2) && value1.length === 0 && value2.length === 0) {
143
+ return true;
144
+ }
145
+ // 兩者都是非 null 的物件(包含陣列)
146
+ if (value1 !== null && value2 !== null && typeof value1 === 'object' && typeof value2 === 'object') {
147
+ // 處理非空陣列
148
+ if (Array.isArray(value1) && Array.isArray(value2)) {
149
+ if (value1.length !== value2.length) {
150
+ return false;
151
+ }
152
+ return value1.every((item, index)=>isEqual(item, value2[index]));
153
+ }
154
+ // 未來可以擴展這裡,增加其他物件型別的深度比較
155
+ }
156
+ return false;
309
157
  };
310
158
 
311
159
  /**
@@ -473,36 +321,6 @@ const transformObjectKey = (obj, transformFunName)=>{
473
321
  }
474
322
  };
475
323
 
476
- /**
477
- * A hook to manage a value.
478
- *
479
- * @example
480
- *
481
- * ```tsx
482
- * const MyComponent = ({ value }: { value?: number }) => {
483
- * const [currentValue, setCurrentValue] = useValue({ value });
484
- * };
485
- * ```
486
- */ const useValue = ({ value, defaultValue })=>{
487
- if (value === undefined && defaultValue === undefined) {
488
- throw new Error('Either `value` or `defaultValue` must be provided.');
489
- }
490
- const isControlled = value !== undefined;
491
- const [internalValue, setInternalValue] = react.useState(defaultValue);
492
- const setValue = react.useCallback((newValue)=>{
493
- if (!isControlled) {
494
- setInternalValue(newValue);
495
- }
496
- }, [
497
- isControlled
498
- ]);
499
- const currentValue = isControlled ? value : internalValue;
500
- return [
501
- currentValue,
502
- setValue
503
- ];
504
- };
505
-
506
324
  // const isProduction: boolean = process.env.NODE_ENV === 'production';
507
325
  const prefix = 'Invariant failed';
508
326
  // Throw an error if the condition fails
@@ -558,10 +376,12 @@ message) {
558
376
  * @param values 要排除的 value
559
377
  *
560
378
  * @example
561
- * const a = { a: undefined, b: null, c: 3, d: 4 };
562
- * const b = omitByValue(a, undefined, null); // { c: 3, d: 4 }
379
+ * const a = { a: undefined, b: null, c: 3, d: 4, e: [] };
380
+ * const b = omitByValue(a, undefined, null, []); // { c: 3, d: 4 }
563
381
  */ const omitByValue = (object, ...values)=>Object.entries(object).reduce((acc, [key, value])=>{
564
- if (values.includes(value)) {
382
+ // 使用深度比較檢查值是否應該被排除
383
+ const shouldOmit = values.some((excludeValue)=>isEqual(value, excludeValue));
384
+ if (shouldOmit) {
565
385
  return acc;
566
386
  }
567
387
  return {
@@ -591,10 +411,12 @@ message) {
591
411
  *
592
412
  * @example
593
413
  *
594
- * const a = { a: 1, b: 2, c: 3, d: 4 };
595
- * const b = pickByValue(a, 1, 2); // { a: 1, b: 2 }
414
+ * const a = { a: 1, b: 2, c: 3, d: 4, e: [] };
415
+ * const b = pickByValue(a, 1, 2, []); // { a: 1, b: 2, e: [] }
596
416
  */ const pickByValue = (object, ...values)=>Object.entries(object).reduce((acc, [key, value])=>{
597
- if (values.includes(value)) {
417
+ // 使用深度比較檢查值是否應該被選擇
418
+ const shouldPick = values.some((pickValue)=>isEqual(value, pickValue));
419
+ if (shouldPick) {
598
420
  return {
599
421
  ...acc,
600
422
  [key]: value
@@ -662,44 +484,320 @@ const isObject = (value)=>value !== null && typeof value === 'object';
662
484
  };
663
485
  };
664
486
  /**
665
- * throttle function
487
+ * throttle function
488
+ *
489
+ * @param {Function} fn function to be executed
490
+ * @param {number} delay time to wait before executing the function
491
+ *
492
+ * @example
493
+ * const throttledFunction = throttle((a: number, b: number) => a + b, 1000);
494
+ * throttledFunction(1, 2); // 3
495
+ * throttledFunction(3, 4); // undefined
496
+ * setTimeout(() => {
497
+ * throttledFunction(5, 6); // 11
498
+ * }, 2000);
499
+ */ const throttle = (fn, delay)=>{
500
+ let wait = false;
501
+ return (...args)=>{
502
+ if (wait) return undefined;
503
+ const val = fn(...args);
504
+ wait = true;
505
+ setTimeout(()=>{
506
+ wait = false;
507
+ }, delay);
508
+ return val;
509
+ };
510
+ };
511
+
512
+ /**
513
+ * Wait for a given amount of time
514
+ * @param ms time to wait in milliseconds
515
+ */ const wait = (ms)=>{
516
+ };
517
+
518
+ /**
519
+ * 將單層物件轉換為 URLSearchParams 物件
520
+ * - 會自動排除 null、undefined、空字串和空陣列的值
521
+ * - 陣列會以逗號連接為字串
522
+ *
523
+ * @param obj - 要轉換的物件,只支援單層物件,其中值可以是 string、number、boolean、null、undefined 或字串陣列
524
+ * @returns URLSearchParams 實例
525
+ *
526
+ * @example
527
+ * const params = { a: '1', b: 123, c: false, d: ['1','2'], e: null, f: undefined, g: '', h: [] };
528
+ * objectToSearchParams(params).toString(); // 'a=1&b=123&c=false&d=1%2C2'
529
+ */ const objectToSearchParams = (obj)=>{
530
+ const searchParams = new URLSearchParams();
531
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
532
+ return searchParams;
533
+ }
534
+ Object.entries(omitByValue(obj, undefined, null, '', [])).forEach(([key, value])=>{
535
+ // 如果是陣列,則以逗號連接
536
+ const paramValue = Array.isArray(value) ? value.join(',') : String(value);
537
+ searchParams.append(key, paramValue);
538
+ });
539
+ return searchParams;
540
+ };
541
+ /**
542
+ * 將字串值轉換為指定的型別
543
+ *
544
+ * @param value - 要轉換的字串值
545
+ * @param targetType - 目標型別
546
+ * @returns 轉換後的值
547
+ */ const convertValueByType = (value, targetType)=>{
548
+ switch(targetType){
549
+ case 'number':
550
+ return value ? Number(value) : 0;
551
+ case 'boolean':
552
+ return value === 'true' || value === '1';
553
+ case 'array':
554
+ return value ? value.split(',') : [];
555
+ case 'string':
556
+ default:
557
+ // 預設為字串,不需要轉換
558
+ return value;
559
+ }
560
+ };
561
+ /**
562
+ * 將 URLSearchParams 或字串轉換為物件
563
+ *
564
+ * @param searchParams - 要轉換的搜尋參數字串或 URLSearchParams 實例
565
+ * @param typeMap - 可選的型別轉換映射表,用於指定每個參數的目標型別
566
+ * @returns
567
+ *
568
+ * @example
569
+ * const queryString = 'a=1&b=123&c=true&d=1,2,3&e=false';
570
+ * const result = searchParamsToObject(queryString);
571
+ * // result: { a: '1', b: '123', c: 'true', d: '1,2,3', e: 'false' }
572
+ * const result = searchParamsToObject(queryString, {
573
+ * a: 'string',
574
+ * b: 'number',
575
+ * c: 'boolean',
576
+ * d: 'array',
577
+ * e: 'boolean',
578
+ * });
579
+ * // result: { a: '1', b: 123, c: true, d: ['1', '2', '3'], e: false }
580
+ */ const searchParamsToObject = (searchParams, typeMap = {})=>{
581
+ const searchParamsInstance = typeof searchParams === 'string' ? new URLSearchParams(searchParams) : searchParams;
582
+ const result = {};
583
+ // 從 URLSearchParams 取得所有參數
584
+ searchParamsInstance.forEach((value, key)=>{
585
+ if (!key) {
586
+ return;
587
+ }
588
+ const targetType = typeMap[key];
589
+ result[key] = convertValueByType(value, targetType);
590
+ });
591
+ return result;
592
+ };
593
+
594
+ /**
595
+ * convert CamelCase string to PascalCase string
596
+ * @param str the string to convert
597
+ * @example
598
+ * camelString2PascalString('camelCase') // 'CamelCase'
599
+ * camelString2PascalString('camelCaseTest') // 'CamelCaseTest'
600
+ */ const camelString2PascalString = (str)=>`${str[0].toUpperCase()}${str.slice(1)}`;
601
+ /**
602
+ * convert CamelCase string to SnakeCase string
603
+ * @param str the string to convert
604
+ * @example
605
+ * camelString2SnakeString('camelCase') // 'camel_case'
606
+ * camelString2SnakeString('camelCaseTest') // 'camel_case_test'
607
+ */ const camelString2SnakeString = (str)=>str.replace(/[A-Z]/g, (letter)=>`_${letter.toLowerCase()}`);
608
+ /**
609
+ * convert PascalCase string to CamelCase string
610
+ * @param str the string to convert
611
+ * @example
612
+ * pascalString2CamelString('PascalCase') // 'pascalCase'
613
+ * pascalString2CamelString('PascalCaseTest') // 'pascalCaseTest'
614
+ */ const pascalString2CamelString = (str)=>`${str[0].toLowerCase()}${str.slice(1)}`;
615
+ /**
616
+ * convert PascalCase string to SnakeCase string
617
+ * @param str the string to convert
618
+ * @example
619
+ * pascalString2SnakeString('PascalCase') // 'pascal_case'
620
+ * pascalString2SnakeString('PascalCaseTest') // 'pascal_case_test'
621
+ */ const pascalString2SnakeString = (str)=>camelString2SnakeString(pascalString2CamelString(str));
622
+ /**
623
+ * convert SnakeCase string to CamelCase string
624
+ * @param str the string to convert
625
+ * @example
626
+ * snakeString2CamelString('snake_case') // 'snakeCase'
627
+ * snakeString2CamelString('snake_case_test') // 'snakeCaseTest'
628
+ */ const snakeString2CamelString = (str)=>str.replace(/(_[a-z])/g, (group)=>group.toUpperCase().replace('_', ''));
629
+ /**
630
+ * convert SnakeCase string to PascalCase string
631
+ * @param str the string to convert
632
+ * @example
633
+ * snakeString2PascalString('snake_case') // 'SnakeCase'
634
+ * snakeString2PascalString('snake_case_test') // 'SnakeCaseTest'
635
+ */ const snakeString2PascalString = (str)=>camelString2PascalString(snakeString2CamelString(str));
636
+ const transformFun = {
637
+ CamelToPascal: camelString2PascalString,
638
+ CamelToSnake: camelString2SnakeString,
639
+ PascalToCamel: pascalString2CamelString,
640
+ PascalToSnake: pascalString2SnakeString,
641
+ SnakeToCamel: snakeString2CamelString,
642
+ SnakeToPascal: snakeString2PascalString
643
+ };
644
+ const transformObjectKey = (obj, transformFunName)=>{
645
+ if (!obj || typeof obj !== 'object') return obj;
646
+ if (Array.isArray(obj)) return obj.map((item)=>transformObjectKey(item, transformFunName));
647
+ return Object.keys(obj).reduce((acc, key)=>({
648
+ ...acc,
649
+ [transformFun[transformFunName](key)]: transformObjectKey(obj[key], transformFunName)
650
+ }), {});
651
+ };
652
+ /**
653
+ * convert object key from CamelCase to PascalCase
654
+ * @param obj the object to convert
655
+ * @example
656
+ * const obj = {
657
+ * fooBar: 'fooBar',
658
+ * fooBar2: 'fooBar2',
659
+ * fooBar3: {
660
+ * fooBar4: 'fooBar4',
661
+ * fooBar5: 'fooBar5',
662
+ * },
663
+ * };
664
+ * const result = camelCase2PascalCase(obj);
665
+ * console.log(result); // { FooBar: 'fooBar', FooBar2: 'fooBar2', FooBar3: { FooBar4: 'fooBar4', FooBar5: 'fooBar5' } }
666
+ */ const camelCase2PascalCase = (obj)=>transformObjectKey(obj, 'CamelToPascal');
667
+ /**
668
+ * convert object key from CamelCase to SnakeCase
669
+ * @param obj the object to convert
670
+ * @example
671
+ * const obj = {
672
+ * fooBar: 'fooBar',
673
+ * fooBar2: 'fooBar2',
674
+ * fooBar3: {
675
+ * fooBar4: 'fooBar4',
676
+ * fooBar5: 'fooBar5',
677
+ * },
678
+ * };
679
+ * const result = camelCase2SnakeCase(obj);
680
+ * console.log(result); // { foo_bar: 'fooBar', foo_bar2: 'fooBar2', foo_bar3: { foo_bar4: 'fooBar4', foo_bar5: 'fooBar5' } }
681
+ */ const camelCase2SnakeCase = (obj)=>transformObjectKey(obj, 'CamelToSnake');
682
+ /**
683
+ * convert object key from PascalCase to CamelCase
684
+ * @param obj the object to convert
685
+ * @example
686
+ * const obj = {
687
+ * FooBar: 'fooBar',
688
+ * FooBar2: 'fooBar2',
689
+ * FooBar3: {
690
+ * FooBar4: 'fooBar4',
691
+ * FooBar5: 'fooBar5',
692
+ * },
693
+ * };
694
+ * const result = pascalCase2CamelCase(obj);
695
+ * console.log(result); // { fooBar: 'fooBar', fooBar2: 'fooBar2', fooBar3: { fooBar4: 'fooBar4', fooBar5: 'fooBar5' } }
696
+ */ const pascalCase2CamelCase = (obj)=>transformObjectKey(obj, 'PascalToCamel');
697
+ /**
698
+ * convert object key from PascalCase to SnakeCase
699
+ * @param obj the object to convert
700
+ * @example
701
+ * const obj = {
702
+ * FooBar: 'fooBar',
703
+ * FooBar2: 'fooBar2',
704
+ * FooBar3: {
705
+ * FooBar4: 'fooBar4',
706
+ * FooBar5: 'fooBar5',
707
+ * },
708
+ * };
709
+ * const result = pascalCase2SnakeCase(obj);
710
+ * console.log(result); // { foo_bar: 'fooBar', foo_bar2: 'fooBar2', foo_bar3: { foo_bar4: 'fooBar4', foo_bar5: 'fooBar5' } }
711
+ */ const pascalCase2SnakeCase = (obj)=>transformObjectKey(obj, 'PascalToSnake');
712
+ /**
713
+ * convert object key from SnakeCase to CamelCase
714
+ * @param obj the object to convert
715
+ * @example
716
+ * const obj = {
717
+ * foo_bar: 'fooBar',
718
+ * foo_bar2: 'fooBar2',
719
+ * foo_bar3: {
720
+ * foo_bar4: 'fooBar4',
721
+ * foo_bar5: 'fooBar5',
722
+ * },
723
+ * };
724
+ * const result = snakeCase2CamelCase(obj);
725
+ * console.log(result); // { fooBar: 'fooBar', fooBar2: 'fooBar2', fooBar3: { fooBar4: 'fooBar4', fooBar5: 'fooBar5' } }
726
+ */ const snakeCase2CamelCase = (obj)=>transformObjectKey(obj, 'SnakeToCamel');
727
+ /**
728
+ * convert object key from SnakeCase to PascalCase
729
+ * @param obj the object to convert
730
+ * @example
731
+ * const obj = {
732
+ * foo_bar: 'fooBar',
733
+ * foo_bar2: 'fooBar2',
734
+ * foo_bar3: {
735
+ * foo_bar4: 'fooBar4',
736
+ * foo_bar5: 'fooBar5',
737
+ * },
738
+ * };
739
+ * const result = snakeCase2PascalCase(obj);
740
+ * console.log(result); // { FooBar: 'fooBar', FooBar2: 'fooBar2', FooBar3: { FooBar4: 'fooBar4', FooBar5: 'fooBar5' } }
741
+ */ const snakeCase2PascalCase = (obj)=>transformObjectKey(obj, 'SnakeToPascal');
742
+
743
+ /**
744
+ * 將數字轉換成金額千分位格式
745
+ *
746
+ * @param num - 數字
747
+ *
748
+ * @example
749
+ *
750
+ * formatAmount(1234567) // '1,234,567'
751
+ */ const formatAmount = (num)=>{
752
+ if (typeof num !== 'number') return '';
753
+ return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
754
+ };
755
+ /**
756
+ * 將字串的第 n - m 個字轉換成星號
757
+ *
758
+ * @param str - 字串
759
+ * @param n - 起始位置
760
+ * @param m - 結束位置
761
+ *
762
+ * @example
763
+ *
764
+ * formatString('123456', 1, 4) // '1****6'
765
+ */ const formatStarMask = (str, n, m)=>str.slice(0, n) + '*'.repeat(m - n + 1) + str.slice(m + 1);
766
+ const FILE_SIZE_UNITS = [
767
+ 'Bytes',
768
+ 'KB',
769
+ 'MB',
770
+ 'GB',
771
+ 'TB',
772
+ 'PB',
773
+ 'EB',
774
+ 'ZB',
775
+ 'YB'
776
+ ];
777
+ /**
778
+ * format file size to human readable string
666
779
  *
667
- * @param {Function} fn function to be executed
668
- * @param {number} delay time to wait before executing the function
780
+ * it will convert bytes to KB, MB, GB, TB, PB, EB, ZB, YB
781
+ *
782
+ * @param bytes file size in bytes
783
+ * @param decimals number of decimal places (default is 2)
669
784
  *
670
785
  * @example
671
- * const throttledFunction = throttle((a: number, b: number) => a + b, 1000);
672
- * throttledFunction(1, 2); // 3
673
- * throttledFunction(3, 4); // undefined
674
- * setTimeout(() => {
675
- * throttledFunction(5, 6); // 11
676
- * }, 2000);
677
- */ const throttle = (fn, delay)=>{
678
- let wait = false;
679
- return (...args)=>{
680
- if (wait) return undefined;
681
- const val = fn(...args);
682
- wait = true;
683
- setTimeout(()=>{
684
- wait = false;
685
- }, delay);
686
- return val;
687
- };
786
+ *
787
+ * ```js
788
+ * formatBytes(0) // 0 Bytes
789
+ * formatBytes(1024) // 1 KB
790
+ * formatBytes(1024, 2) // 1.00 KB
791
+ * formatBytes(1024 * 1024) // 1 MB
792
+ * ```
793
+ * @deprecated use `convertBytes` instead
794
+ */ const formatBytes = (bytes, decimals = 0)=>{
795
+ if (bytes === 0) return '0 Bytes';
796
+ const k = 1024;
797
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
798
+ return `${(bytes / k ** i).toFixed(decimals)} ${FILE_SIZE_UNITS[i]}`;
688
799
  };
689
800
 
690
- function mergeRefs(refs) {
691
- return (value)=>{
692
- refs.forEach((ref)=>{
693
- if (typeof ref === 'function') {
694
- ref(value);
695
- } else if (ref != null) {
696
- // eslint-disable-next-line no-param-reassign
697
- ref.current = value;
698
- }
699
- });
700
- };
701
- }
702
-
703
801
  /**
704
802
  * 中文
705
803
  *
@@ -868,77 +966,211 @@ function mergeRefs(refs) {
868
966
  */ const isTWPhone = ()=>/^(((0[2-9]-?\d{6,8})(#\d{1,5})?)|((0[2-9][0-9]-?\d{6,7})(#\d{1,5})?))$/;
869
967
 
870
968
  /**
871
- * 將數字轉換成金額千分位格式
969
+ * 檢查稅務編號是否符合正確的編號規則。
872
970
  *
873
- * @param num - 數字
971
+ * @param {string} taxId - 要檢查的8位數稅務編號。
972
+ * @returns {boolean} - 如果符合規則則返回 true,否則返回 false。
874
973
  *
875
- * @example
974
+ * ### 編號檢查規則:
975
+ * 1. **基本格式檢查**:
976
+ * - 編號必須為 8 位數字。
977
+ * - 不得為「00000000」或「11111111」,這些編號被視為無效。
876
978
  *
877
- * formatAmount(1234567) // '1,234,567'
878
- */ const formatAmount = (num)=>{
879
- if (typeof num !== 'number') return '';
880
- return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
881
- };
882
- /**
883
- * 將字串的第 n - m 個字轉換成星號
979
+ * 2. **驗證邏輯**:
980
+ * - 使用一組驗證運算子:`[1, 2, 1, 2, 1, 2, 4, 1]`。
981
+ * - 將稅務編號的每一位數字與對應的運算子相乘後,使用 `calculate` 函數計算各位數的和。
982
+ * - 計算公式為:`(product % 10) + (product - (product % 10)) / 10`
983
+ * - 將所有位數經計算後的結果加總為 `sum`。
884
984
  *
885
- * @param str - 字串
886
- * @param n - 起始位置
887
- * @param m - 結束位置
985
+ * 3. **檢查規則**:
986
+ * - 如果總和 `sum` 可以被 5 整除,則編號有效。
987
+ * - 或者,若第七位數為 7,且 `(sum + 1) % 5 === 0`,則編號有效。
888
988
  *
889
989
  * @example
890
990
  *
891
- * formatString('123456', 1, 4) // '1****6'
892
- */ const formatStarMask = (str, n, m)=>str.slice(0, n) + '*'.repeat(m - n + 1) + str.slice(m + 1);
991
+ * validTaxId('22099131') // true
992
+ * validTaxId('84149961') // true
993
+ * validTaxId('00000000') // false
994
+ * validTaxId('11111111') // false
995
+ * validTaxId('22099132') // false
996
+ */ const validTaxId = (taxId)=>{
997
+ const invalidList = '00000000,11111111';
998
+ if (/^\d{8}$/.test(taxId) === false || invalidList.indexOf(taxId) >= 0) {
999
+ return false;
1000
+ }
1001
+ const validateOperator = [
1002
+ 1,
1003
+ 2,
1004
+ 1,
1005
+ 2,
1006
+ 1,
1007
+ 2,
1008
+ 4,
1009
+ 1
1010
+ ];
1011
+ const calculate = (product)=>product % 10 + (product - product % 10) / 10;
1012
+ const sum = validateOperator.reduce((pre, cur, index)=>pre + calculate(Number(taxId[index]) * cur), 0);
1013
+ return sum % 5 === 0 || taxId[6] === '7' && (sum + 1) % 5 === 0;
1014
+ };
893
1015
  /**
894
- * format file size to human readable string
1016
+ * 驗證日期格式是否正確
895
1017
  *
896
- * it will convert bytes to KB, MB, GB, TB, PB, EB, ZB, YB
1018
+ * @param dateString 日期字串
1019
+ * @param format 日期格式
1020
+ * @example
897
1021
  *
898
- * @param bytes file size in bytes
899
- * @param decimals number of decimal places (default is 2)
1022
+ * validateDateString('20210201', 'YYYYMMDD') // true
1023
+ * validateDateString('2021-02-01', 'YYYY-MM-DD') // true
1024
+ * validateDateString('20210201', 'YYYY-MM-DD') // false
1025
+ * validateDateString('20210201', 'YYYYMM') // false
1026
+ */ const validateDateString = (dateString, format)=>{
1027
+ if (!dateString) return false;
1028
+ // 根據 format 生成正則表達式
1029
+ const regexPattern = format.replace(/YYYY/, '\\d{4}').replace(/MM/, '\\d{2}').replace(/DD/, '\\d{2}').replace(/HH/, '\\d{2}').replace(/mm/, '\\d{2}').replace(/ss/, '\\d{2}');
1030
+ const regex = new RegExp(`^${regexPattern}$`);
1031
+ // 先用正則驗證格式
1032
+ if (!regex.test(dateString)) return false;
1033
+ // 再用 dayjs 驗證是否為有效日期
1034
+ return dayjs__default.default(dateString, format, true).isValid();
1035
+ };
1036
+
1037
+ /**
1038
+ * A hook to manage a value.
900
1039
  *
901
1040
  * @example
902
1041
  *
903
- * ```js
904
- * formatBytes(0) // 0 Bytes
905
- * formatBytes(1024) // 1 KB
906
- * formatBytes(1024, 2) // 1.00 KB
907
- * formatBytes(1024 * 1024) // 1 MB
1042
+ * ```tsx
1043
+ * const MyComponent = ({ value }: { value?: number }) => {
1044
+ * const [currentValue, setCurrentValue] = useValue({ value });
1045
+ * };
908
1046
  * ```
909
- */ const formatBytes = (bytes, decimals = 0)=>{
910
- if (bytes === 0) return '0 Bytes';
911
- const k = 1024;
912
- const sizes = [
913
- 'Bytes',
914
- 'KB',
915
- 'MB',
916
- 'GB',
917
- 'TB',
918
- 'PB',
919
- 'EB',
920
- 'ZB',
921
- 'YB'
1047
+ */ const useValue = ({ value, defaultValue })=>{
1048
+ if (value === undefined && defaultValue === undefined) {
1049
+ throw new Error('Either `value` or `defaultValue` must be provided.');
1050
+ }
1051
+ const isControlled = value !== undefined;
1052
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
1053
+ const setValue = React.useCallback((newValue)=>{
1054
+ if (!isControlled) {
1055
+ setInternalValue(newValue);
1056
+ }
1057
+ }, [
1058
+ isControlled
1059
+ ]);
1060
+ const currentValue = isControlled ? value : internalValue;
1061
+ return [
1062
+ currentValue,
1063
+ setValue
922
1064
  ];
923
- const i = Math.floor(Math.log(bytes) / Math.log(k));
924
- return `${(bytes / k ** i).toFixed(decimals)} ${sizes[i]}`;
925
1065
  };
926
1066
 
1067
+ function mergeRefs(refs) {
1068
+ return (value)=>{
1069
+ refs.forEach((ref)=>{
1070
+ if (typeof ref === 'function') {
1071
+ ref(value);
1072
+ } else if (ref != null) {
1073
+ // eslint-disable-next-line no-param-reassign
1074
+ ref.current = value;
1075
+ }
1076
+ });
1077
+ };
1078
+ }
1079
+
927
1080
  /**
928
- * Wait for a given amount of time
929
- * @param ms time to wait in milliseconds
930
- */ const wait = (ms)=>{
1081
+ * 民國年轉西元年
1082
+ * @param dateString 日期字串
1083
+ * @param format 日期格式
1084
+ * @example
1085
+ *
1086
+ * rocEraToAd('1100201') // 20210201
1087
+ * rocEraToAd('11002', 'YYYYMM') // 202102
1088
+ */ const rocEraToAd = (dateString, format = 'YYYYMMDD')=>{
1089
+ if (!validateDateString(`0${dateString}`, format)) return dateString;
1090
+ return dayjs__default.default(`0${dateString}`, format).add(1911, 'year').format(format);
1091
+ };
1092
+ /**
1093
+ * 西元年轉民國年
1094
+ * @param dateString 日期字串
1095
+ * @param format 日期格式
1096
+ * @example
1097
+ *
1098
+ * adToRocEra('20210201') // 1100201
1099
+ * adToRocEra('202102', 'YYYYMM') // 11002
1100
+ */ const adToRocEra = (dateString, format = 'YYYYMMDD')=>{
1101
+ if (!validateDateString(dateString, format)) return dateString;
1102
+ return dayjs__default.default(dateString, format).add(-1911, 'year').format(format).substring(1);
1103
+ };
1104
+
1105
+ /**
1106
+ * 取得去年今年以及明年期別陣列
1107
+ *
1108
+ * @example
1109
+ * // 假設 今年為 112 年
1110
+ * generatePeriodArray() // 11102 ~ 11312
1111
+ */ const generatePeriodArray = ()=>{
1112
+ const currentYear = new Date().getFullYear() - 1911;
1113
+ const months = [
1114
+ '02',
1115
+ '04',
1116
+ '06',
1117
+ '08',
1118
+ '10',
1119
+ '12'
1120
+ ];
1121
+ const years = [
1122
+ currentYear - 1,
1123
+ currentYear,
1124
+ currentYear + 1
1125
+ ];
1126
+ return years.flatMap((year)=>months.map((month)=>`${year}${month}`));
1127
+ };
1128
+ /**
1129
+ * 取得當前期別
1130
+ *
1131
+ * 報稅期限次期開始15日內
1132
+ *
1133
+ * 雙數月沒有特殊規則,期別皆為當月開頭
1134
+ *
1135
+ * 單數月15號以前,期別為上個月否則為下個月開頭
1136
+ *
1137
+ * @example
1138
+ *
1139
+ * // 假設今天是 111-02-15
1140
+ * getCurrentPeriod() // 11102
1141
+ * // 假設今天是 111-02-16
1142
+ * getCurrentPeriod() // 11102
1143
+ * // 假設今天是 111-03-15
1144
+ * getCurrentPeriod() // 11102
1145
+ * // 假設今天是 111-03-16
1146
+ * getCurrentPeriod() // 11104
1147
+ */ const getCurrentPeriod = ()=>{
1148
+ const now = dayjs__default.default();
1149
+ const currentDate = now.format('DD');
1150
+ const currentYear = now.format('YYYY');
1151
+ const currentMonth = now.format('MM');
1152
+ let endMonth;
1153
+ if (Number(currentMonth) % 2 === 1) {
1154
+ endMonth = dayjs__default.default(`${currentYear}${currentMonth}`, 'YYYYMM').add(Number(currentDate) <= 15 ? -1 : 1, 'month').format('YYYYMM');
1155
+ } else {
1156
+ endMonth = `${currentYear}${currentMonth}`;
1157
+ }
1158
+ return dayjs__default.default(endMonth, 'YYYYMM').subtract(1911, 'year').format('YYYYMM').substring(1);
931
1159
  };
932
1160
 
1161
+ exports.QueryProvider = queryStoreClient.QueryProvider;
1162
+ exports.useQueryContext = queryStoreClient.useQueryContext;
933
1163
  exports.useCountdown = useCountdownClient.useCountdown;
934
1164
  exports.downloadFile = downloadClient.downloadFile;
935
1165
  exports.getLocalStorage = webStorageClient.getLocalStorage;
936
1166
  exports.setLocalStorage = webStorageClient.setLocalStorage;
1167
+ exports.ByteSize = ByteSize;
937
1168
  exports.adToRocEra = adToRocEra;
938
1169
  exports.camelCase2PascalCase = camelCase2PascalCase;
939
1170
  exports.camelCase2SnakeCase = camelCase2SnakeCase;
940
1171
  exports.camelString2PascalString = camelString2PascalString;
941
1172
  exports.camelString2SnakeString = camelString2SnakeString;
1173
+ exports.convertBytes = convertBytes;
942
1174
  exports.createEnumLikeObject = createEnumLikeObject;
943
1175
  exports.debounce = debounce;
944
1176
  exports.deepMerge = deepMerge;
@@ -956,6 +1188,7 @@ exports.isDateString = isDateString;
956
1188
  exports.isDateTimeString = isDateTimeString;
957
1189
  exports.isEmail = isEmail;
958
1190
  exports.isEnglish = isEnglish;
1191
+ exports.isEqual = isEqual;
959
1192
  exports.isNonZeroStart = isNonZeroStart;
960
1193
  exports.isNumber = isNumber;
961
1194
  exports.isNumberAtLeastN = isNumberAtLeastN;
@@ -967,6 +1200,7 @@ exports.isTWPhone = isTWPhone;
967
1200
  exports.isTimeString = isTimeString;
968
1201
  exports.isValidPassword = isValidPassword;
969
1202
  exports.mergeRefs = mergeRefs;
1203
+ exports.objectToSearchParams = objectToSearchParams;
970
1204
  exports.omit = omit;
971
1205
  exports.omitByValue = omitByValue;
972
1206
  exports.pascalCase2CamelCase = pascalCase2CamelCase;
@@ -976,6 +1210,7 @@ exports.pascalString2SnakeString = pascalString2SnakeString;
976
1210
  exports.pick = pick;
977
1211
  exports.pickByValue = pickByValue;
978
1212
  exports.rocEraToAd = rocEraToAd;
1213
+ exports.searchParamsToObject = searchParamsToObject;
979
1214
  exports.snakeCase2CamelCase = snakeCase2CamelCase;
980
1215
  exports.snakeCase2PascalCase = snakeCase2PascalCase;
981
1216
  exports.snakeString2CamelString = snakeString2CamelString;