react-util-tools 1.0.25 → 1.0.27

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/index.js CHANGED
@@ -260,6 +260,7 @@ function getDeviceInfo() {
260
260
  }
261
261
 
262
262
  // src/format/index.ts
263
+ import Decimal from "decimal.js";
263
264
  function formatMoney(amount, options = {}) {
264
265
  const {
265
266
  decimals = 2,
@@ -267,20 +268,19 @@ function formatMoney(amount, options = {}) {
267
268
  separator = ",",
268
269
  decimalPoint = "."
269
270
  } = options;
270
- const num = typeof amount === "string" ? parseFloat(amount) : amount;
271
- if (isNaN(num)) {
272
- return `${symbol}0${decimalPoint}${"0".repeat(decimals)}`;
273
- }
274
- const isNegative = num < 0;
275
- const absNum = Math.abs(num);
276
- const fixed = absNum.toFixed(decimals);
277
- const [integerPart, decimalPart] = fixed.split(".");
278
- const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
279
- let result = symbol + formattedInteger;
280
- if (decimals > 0 && decimalPart) {
281
- result += decimalPoint + decimalPart;
282
- }
283
- return isNegative ? `-${result}` : result;
271
+ return tryRun(() => {
272
+ const dec = new Decimal(amount);
273
+ const isNegative = dec.isNegative();
274
+ const absDec = dec.abs();
275
+ const fixed = absDec.toFixed(decimals, Decimal.ROUND_DOWN);
276
+ const [integerPart, decimalPart] = fixed.split(".");
277
+ const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
278
+ let result = symbol + formattedInteger;
279
+ if (decimals > 0 && decimalPart) {
280
+ result += decimalPoint + decimalPart;
281
+ }
282
+ return isNegative ? `-${result}` : result;
283
+ }) ?? `${symbol}0${decimalPoint}${"0".repeat(decimals)}`;
284
284
  }
285
285
  function parseMoney(formattedAmount) {
286
286
  if (!formattedAmount || typeof formattedAmount !== "string") {
@@ -291,68 +291,70 @@ function parseMoney(formattedAmount) {
291
291
  return isNaN(num) ? 0 : num;
292
292
  }
293
293
  function formatNumber(amount, decimals = 2) {
294
- const num = typeof amount === "string" ? parseFloat(amount) : amount;
295
- if (isNaN(num)) {
296
- return "0." + "0".repeat(decimals);
297
- }
298
- const fixed = num.toFixed(decimals);
299
- const [integerPart, decimalPart] = fixed.split(".");
300
- const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
301
- return decimals > 0 && decimalPart ? `${formattedInteger}.${decimalPart}` : formattedInteger;
294
+ return tryRun(() => {
295
+ const dec = new Decimal(amount);
296
+ const fixed = dec.toFixed(decimals, Decimal.ROUND_DOWN);
297
+ const [integerPart, decimalPart] = fixed.split(".");
298
+ const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
299
+ return decimals > 0 && decimalPart ? `${formattedInteger}.${decimalPart}` : formattedInteger;
300
+ }) ?? "0." + "0".repeat(decimals);
302
301
  }
303
302
  function formatMoneyToChinese(amount) {
304
- const num = typeof amount === "string" ? parseFloat(amount) : amount;
305
- if (isNaN(num) || num < 0) {
306
- return "\u96F6\u5143\u6574";
307
- }
308
- const digits = ["\u96F6", "\u58F9", "\u8D30", "\u53C1", "\u8086", "\u4F0D", "\u9646", "\u67D2", "\u634C", "\u7396"];
309
- const units = ["", "\u62FE", "\u4F70", "\u4EDF"];
310
- const bigUnits = ["", "\u4E07", "\u4EBF", "\u5146"];
311
- const decimalUnits = ["\u89D2", "\u5206"];
312
- const [integerPart, decimalPart] = num.toFixed(2).split(".");
313
- let result = "";
314
- if (integerPart === "0") {
315
- result = "\u96F6\u5143";
316
- } else {
317
- const integerStr = integerPart;
318
- const len = integerStr.length;
319
- let zeroCount = 0;
320
- for (let i = 0; i < len; i++) {
321
- const digit = parseInt(integerStr[i]);
322
- const unitIndex = (len - i - 1) % 4;
323
- const bigUnitIndex = Math.floor((len - i - 1) / 4);
324
- if (digit === 0) {
325
- zeroCount++;
326
- } else {
327
- if (zeroCount > 0) {
328
- result += "\u96F6";
303
+ return tryRun(() => {
304
+ const dec = new Decimal(amount);
305
+ if (dec.isNegative()) {
306
+ return "\u96F6\u5143\u6574";
307
+ }
308
+ const num = dec.toNumber();
309
+ const digits = ["\u96F6", "\u58F9", "\u8D30", "\u53C1", "\u8086", "\u4F0D", "\u9646", "\u67D2", "\u634C", "\u7396"];
310
+ const units = ["", "\u62FE", "\u4F70", "\u4EDF"];
311
+ const bigUnits = ["", "\u4E07", "\u4EBF", "\u5146"];
312
+ const decimalUnits = ["\u89D2", "\u5206"];
313
+ const [integerPart, decimalPart] = num.toFixed(2).split(".");
314
+ let result = "";
315
+ if (integerPart === "0") {
316
+ result = "\u96F6\u5143";
317
+ } else {
318
+ const integerStr = integerPart;
319
+ const len = integerStr.length;
320
+ let zeroCount = 0;
321
+ for (let i = 0; i < len; i++) {
322
+ const digit = parseInt(integerStr[i]);
323
+ const unitIndex = (len - i - 1) % 4;
324
+ const bigUnitIndex = Math.floor((len - i - 1) / 4);
325
+ if (digit === 0) {
326
+ zeroCount++;
327
+ } else {
328
+ if (zeroCount > 0) {
329
+ result += "\u96F6";
330
+ }
331
+ result += digits[digit] + units[unitIndex];
332
+ zeroCount = 0;
329
333
  }
330
- result += digits[digit] + units[unitIndex];
331
- zeroCount = 0;
332
- }
333
- if (unitIndex === 0 && bigUnitIndex > 0) {
334
- if (result[result.length - 1] !== bigUnits[bigUnitIndex]) {
335
- result += bigUnits[bigUnitIndex];
334
+ if (unitIndex === 0 && bigUnitIndex > 0) {
335
+ if (result[result.length - 1] !== bigUnits[bigUnitIndex]) {
336
+ result += bigUnits[bigUnitIndex];
337
+ }
336
338
  }
337
339
  }
340
+ result += "\u5143";
338
341
  }
339
- result += "\u5143";
340
- }
341
- if (decimalPart && decimalPart !== "00") {
342
- const jiao = parseInt(decimalPart[0]);
343
- const fen = parseInt(decimalPart[1]);
344
- if (jiao > 0) {
345
- result += digits[jiao] + decimalUnits[0];
346
- } else if (fen > 0) {
347
- result += "\u96F6";
348
- }
349
- if (fen > 0) {
350
- result += digits[fen] + decimalUnits[1];
342
+ if (decimalPart && decimalPart !== "00") {
343
+ const jiao = parseInt(decimalPart[0]);
344
+ const fen = parseInt(decimalPart[1]);
345
+ if (jiao > 0) {
346
+ result += digits[jiao] + decimalUnits[0];
347
+ } else if (fen > 0) {
348
+ result += "\u96F6";
349
+ }
350
+ if (fen > 0) {
351
+ result += digits[fen] + decimalUnits[1];
352
+ }
353
+ } else {
354
+ result += "\u6574";
351
355
  }
352
- } else {
353
- result += "\u6574";
354
- }
355
- return result;
356
+ return result;
357
+ }) ?? "\u96F6\u5143\u6574";
356
358
  }
357
359
  function formatPercent(value, options = {}) {
358
360
  const { decimals = 2, multiply: multiply2 = true } = options;
@@ -395,6 +397,13 @@ function unmaskEmail(maskedEmail, originalEmail) {
395
397
  }
396
398
  return maskedEmail;
397
399
  }
400
+ function tryRun(fn) {
401
+ try {
402
+ return fn();
403
+ } catch (error) {
404
+ return null;
405
+ }
406
+ }
398
407
 
399
408
  // src/date/index.ts
400
409
  import {
@@ -704,19 +713,19 @@ function getUTCWeekNumber(date) {
704
713
  import { default as default2 } from "decimal.js";
705
714
 
706
715
  // src/decimal/utils/index.ts
707
- import Decimal from "decimal.js";
716
+ import Decimal2 from "decimal.js";
708
717
  function safeDecimal(value) {
709
718
  try {
710
- if (value instanceof Decimal) {
719
+ if (value instanceof Decimal2) {
711
720
  return value;
712
721
  }
713
- const decimal = new Decimal(value);
722
+ const decimal = new Decimal2(value);
714
723
  if (decimal.isNaN()) {
715
- return new Decimal(0);
724
+ return new Decimal2(0);
716
725
  }
717
726
  return decimal;
718
727
  } catch {
719
- return new Decimal(0);
728
+ return new Decimal2(0);
720
729
  }
721
730
  }
722
731
  function add(a, b) {
@@ -814,7 +823,7 @@ function round(value, decimalPlaces = 2) {
814
823
  function ceil(value, decimalPlaces = 2) {
815
824
  try {
816
825
  const decimal = safeDecimal(value);
817
- return decimal.toDecimalPlaces(decimalPlaces, Decimal.ROUND_CEIL).toNumber();
826
+ return decimal.toDecimalPlaces(decimalPlaces, Decimal2.ROUND_CEIL).toNumber();
818
827
  } catch {
819
828
  return 0;
820
829
  }
@@ -822,7 +831,7 @@ function ceil(value, decimalPlaces = 2) {
822
831
  function floor(value, decimalPlaces = 2) {
823
832
  try {
824
833
  const decimal = safeDecimal(value);
825
- return decimal.toDecimalPlaces(decimalPlaces, Decimal.ROUND_FLOOR).toNumber();
834
+ return decimal.toDecimalPlaces(decimalPlaces, Decimal2.ROUND_FLOOR).toNumber();
826
835
  } catch {
827
836
  return 0;
828
837
  }
@@ -921,6 +930,237 @@ function aoaToSheet(data, options) {
921
930
  function sheetToAOA(worksheet, options) {
922
931
  return XLSX.utils.sheet_to_json(worksheet, { ...options, header: 1 });
923
932
  }
933
+
934
+ // src/string/index.ts
935
+ function capitalize(str) {
936
+ if (!str) return "";
937
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
938
+ }
939
+ function camelCase(str) {
940
+ if (!str) return "";
941
+ return str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^[A-Z]/, (char) => char.toLowerCase());
942
+ }
943
+ function pascalCase(str) {
944
+ if (!str) return "";
945
+ const camel = camelCase(str);
946
+ return camel.charAt(0).toUpperCase() + camel.slice(1);
947
+ }
948
+ function snakeCase(str) {
949
+ if (!str) return "";
950
+ return str.replace(/([A-Z])/g, "_$1").replace(/[-\s]+/g, "_").replace(/^_/, "").toLowerCase();
951
+ }
952
+ function kebabCase(str) {
953
+ if (!str) return "";
954
+ return str.replace(/([A-Z])/g, "-$1").replace(/[_\s]+/g, "-").replace(/^-/, "").toLowerCase();
955
+ }
956
+ function truncate(str, length2, suffix = "...") {
957
+ if (!str || str.length <= length2) return str;
958
+ return str.slice(0, length2) + suffix;
959
+ }
960
+ function trim(str) {
961
+ return str ? str.trim() : "";
962
+ }
963
+ function trimStart(str) {
964
+ return str ? str.trimStart() : "";
965
+ }
966
+ function trimEnd(str) {
967
+ return str ? str.trimEnd() : "";
968
+ }
969
+ function reverse(str) {
970
+ if (!str) return "";
971
+ return str.split("").reverse().join("");
972
+ }
973
+ function repeat(str, count) {
974
+ if (!str || count <= 0) return "";
975
+ return str.repeat(count);
976
+ }
977
+ function padStart(str, length2, padStr = " ") {
978
+ if (!str) return padStr.repeat(length2);
979
+ return str.padStart(length2, padStr);
980
+ }
981
+ function padEnd(str, length2, padStr = " ") {
982
+ if (!str) return padStr.repeat(length2);
983
+ return str.padEnd(length2, padStr);
984
+ }
985
+ function startsWith(str, searchString) {
986
+ if (!str) return false;
987
+ return str.startsWith(searchString);
988
+ }
989
+ function endsWith(str, searchString) {
990
+ if (!str) return false;
991
+ return str.endsWith(searchString);
992
+ }
993
+ function includes(str, searchString) {
994
+ if (!str) return false;
995
+ return str.includes(searchString);
996
+ }
997
+ function replaceAll(str, search, replacement) {
998
+ if (!str) return "";
999
+ if (typeof search === "string") {
1000
+ return str.split(search).join(replacement);
1001
+ }
1002
+ return str.replace(search, replacement);
1003
+ }
1004
+ function stripHtml(str) {
1005
+ if (!str) return "";
1006
+ return str.replace(/<[^>]*>/g, "");
1007
+ }
1008
+ function escapeHtml(str) {
1009
+ if (!str) return "";
1010
+ const map = {
1011
+ "&": "&amp;",
1012
+ "<": "&lt;",
1013
+ ">": "&gt;",
1014
+ '"': "&quot;",
1015
+ "'": "&#39;"
1016
+ };
1017
+ return str.replace(/[&<>"']/g, (char) => map[char]);
1018
+ }
1019
+ function unescapeHtml(str) {
1020
+ if (!str) return "";
1021
+ const map = {
1022
+ "&amp;": "&",
1023
+ "&lt;": "<",
1024
+ "&gt;": ">",
1025
+ "&quot;": '"',
1026
+ "&#39;": "'"
1027
+ };
1028
+ return str.replace(/&(amp|lt|gt|quot|#39);/g, (entity) => map[entity]);
1029
+ }
1030
+ function toLowerCase(str) {
1031
+ return str ? str.toLowerCase() : "";
1032
+ }
1033
+ function toUpperCase(str) {
1034
+ return str ? str.toUpperCase() : "";
1035
+ }
1036
+ function titleCase(str) {
1037
+ if (!str) return "";
1038
+ return str.toLowerCase().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1039
+ }
1040
+ function isEmpty(str) {
1041
+ return !str || str.trim().length === 0;
1042
+ }
1043
+ function isNotEmpty(str) {
1044
+ return !isEmpty(str);
1045
+ }
1046
+ function length(str) {
1047
+ if (!str) return 0;
1048
+ return Array.from(str).length;
1049
+ }
1050
+ function split(str, separator) {
1051
+ if (!str) return [];
1052
+ return str.split(separator);
1053
+ }
1054
+ function extractNumbers(str) {
1055
+ if (!str) return [];
1056
+ const matches = str.match(/\d+(\.\d+)?/g);
1057
+ return matches ? matches.map(Number) : [];
1058
+ }
1059
+ function removeSpaces(str) {
1060
+ if (!str) return "";
1061
+ return str.replace(/\s+/g, "");
1062
+ }
1063
+ function normalizeSpaces(str) {
1064
+ if (!str) return "";
1065
+ return str.replace(/\s+/g, " ").trim();
1066
+ }
1067
+ function countOccurrences(str, searchString) {
1068
+ if (!str || !searchString) return 0;
1069
+ return str.split(searchString).length - 1;
1070
+ }
1071
+ function randomString(length2, chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") {
1072
+ let result = "";
1073
+ for (let i = 0; i < length2; i++) {
1074
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
1075
+ }
1076
+ return result;
1077
+ }
1078
+ function uuid() {
1079
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
1080
+ const r = Math.random() * 16 | 0;
1081
+ const v = c === "x" ? r : r & 3 | 8;
1082
+ return v.toString(16);
1083
+ });
1084
+ }
1085
+ function maskPhone(phone) {
1086
+ if (!phone || phone.length < 11) return phone;
1087
+ return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
1088
+ }
1089
+ function maskIdCard(idCard) {
1090
+ if (!idCard || idCard.length < 18) return idCard;
1091
+ return idCard.replace(/(\d{6})\d{8}(\d{4})/, "$1********$2");
1092
+ }
1093
+ function maskBankCard(cardNumber) {
1094
+ if (!cardNumber || cardNumber.length < 16) return cardNumber;
1095
+ return cardNumber.replace(/(\d{4})\d+(\d{4})/, "$1 **** **** $2");
1096
+ }
1097
+ function maskName(name) {
1098
+ if (!name) return "";
1099
+ if (name.length === 2) {
1100
+ return name.charAt(0) + "*";
1101
+ }
1102
+ return name.charAt(0) + "*".repeat(name.length - 2) + name.charAt(name.length - 1);
1103
+ }
1104
+ function isValidPhone(phone) {
1105
+ if (!phone) return false;
1106
+ return /^1[3-9]\d{9}$/.test(phone);
1107
+ }
1108
+ function isValidEmail(email) {
1109
+ if (!email) return false;
1110
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
1111
+ }
1112
+ function isValidUrl(url) {
1113
+ if (!url) return false;
1114
+ try {
1115
+ new URL(url);
1116
+ return true;
1117
+ } catch {
1118
+ return false;
1119
+ }
1120
+ }
1121
+ function isValidIdCard(idCard) {
1122
+ if (!idCard) return false;
1123
+ return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(idCard);
1124
+ }
1125
+ function toBase64(str) {
1126
+ if (!str) return "";
1127
+ if (typeof window !== "undefined" && window.btoa) {
1128
+ try {
1129
+ return window.btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (_, p1) => {
1130
+ return String.fromCharCode(parseInt(p1, 16));
1131
+ }));
1132
+ } catch {
1133
+ return "";
1134
+ }
1135
+ }
1136
+ try {
1137
+ const BufferClass = globalThis.Buffer;
1138
+ return BufferClass ? BufferClass.from(str, "utf-8").toString("base64") : "";
1139
+ } catch {
1140
+ return "";
1141
+ }
1142
+ }
1143
+ function fromBase64(base64) {
1144
+ if (!base64) return "";
1145
+ if (typeof window !== "undefined" && window.atob) {
1146
+ try {
1147
+ const binary = window.atob(base64);
1148
+ const bytes = new Uint8Array(binary.length);
1149
+ for (let i = 0; i < binary.length; i++) {
1150
+ bytes[i] = binary.charCodeAt(i);
1151
+ }
1152
+ return new TextDecoder().decode(bytes);
1153
+ } catch {
1154
+ return "";
1155
+ }
1156
+ }
1157
+ try {
1158
+ const BufferClass = globalThis.Buffer;
1159
+ return BufferClass ? BufferClass.from(base64, "base64").toString("utf-8") : "";
1160
+ } catch {
1161
+ return "";
1162
+ }
1163
+ }
924
1164
  export {
925
1165
  default2 as Decimal,
926
1166
  XLSX,
@@ -931,13 +1171,19 @@ export {
931
1171
  addMonthsToDate,
932
1172
  addMonthsUTC,
933
1173
  aoaToSheet,
1174
+ camelCase,
1175
+ capitalize,
934
1176
  ceil,
935
1177
  clearAllCookies,
1178
+ countOccurrences,
936
1179
  debounceFn as debounce,
937
1180
  divide,
1181
+ endsWith,
938
1182
  equals,
1183
+ escapeHtml,
939
1184
  exportExcelFile,
940
1185
  exportJSONToExcel,
1186
+ extractNumbers,
941
1187
  floor,
942
1188
  formatDate,
943
1189
  formatDateOnly,
@@ -950,6 +1196,7 @@ export {
950
1196
  formatUTC,
951
1197
  formatUTCDateOnly,
952
1198
  formatUTCTimeOnly,
1199
+ fromBase64,
953
1200
  fromUTC,
954
1201
  getAllCookies,
955
1202
  getAllQueryParams,
@@ -1004,35 +1251,61 @@ export {
1004
1251
  greaterThan,
1005
1252
  greaterThanOrEqual,
1006
1253
  hasCookie,
1254
+ includes,
1007
1255
  isAfterDate,
1008
1256
  isAndroid,
1009
1257
  isBeforeDate,
1010
1258
  isDesktop,
1259
+ isEmpty,
1011
1260
  isIOS,
1012
1261
  isMobile,
1262
+ isNotEmpty,
1013
1263
  isSameDayDate,
1014
1264
  isTablet,
1015
1265
  isTouchDevice,
1016
1266
  isValidDate,
1267
+ isValidEmail,
1268
+ isValidIdCard,
1269
+ isValidPhone,
1270
+ isValidUrl,
1017
1271
  isWeChat,
1018
1272
  jsonToWorkbook,
1273
+ kebabCase,
1274
+ length,
1019
1275
  lessThan,
1020
1276
  lessThanOrEqual,
1277
+ maskBankCard,
1021
1278
  maskEmail,
1279
+ maskIdCard,
1280
+ maskName,
1281
+ maskPhone,
1022
1282
  multiply,
1023
1283
  negate,
1284
+ normalizeSpaces,
1285
+ padEnd,
1286
+ padStart,
1024
1287
  parseDate,
1025
1288
  parseMoney,
1289
+ pascalCase,
1290
+ randomString,
1026
1291
  read2 as read,
1027
1292
  readExcelFile,
1028
1293
  readExcelToJSON,
1029
1294
  readFile,
1030
1295
  removeCookie,
1296
+ removeSpaces,
1297
+ repeat,
1298
+ replaceAll,
1299
+ reverse,
1031
1300
  round,
1032
1301
  setCookie,
1033
1302
  sheetToAOA,
1034
1303
  sheetToCSV,
1035
1304
  sheetToHTML,
1305
+ snakeCase,
1306
+ split,
1307
+ startsWith,
1308
+ stripHtml,
1036
1309
  subDaysFromDate,
1037
1310
  subDaysUTC,
1038
1311
  subMonthsFromDate,
@@ -1040,10 +1313,20 @@ export {
1040
1313
  subtract,
1041
1314
  tableToSheet,
1042
1315
  throttleFn as throttle,
1316
+ titleCase,
1317
+ toBase64,
1043
1318
  toISOString,
1319
+ toLowerCase,
1044
1320
  toUTC,
1321
+ toUpperCase,
1322
+ trim,
1323
+ trimEnd,
1324
+ trimStart,
1325
+ truncate,
1326
+ unescapeHtml,
1045
1327
  unmaskEmail,
1046
1328
  utils2 as utils,
1329
+ uuid,
1047
1330
  workbookToJSON,
1048
1331
  write,
1049
1332
  writeFile2 as writeFile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-util-tools",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "A collection of useful utilities: throttle, debounce, date formatting, device detection, money formatting, decimal calculations, Excel processing and more",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",