@tendaui/components 1.0.0 → 1.0.2
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/LICENSE +21 -21
- package/README.md +176 -176
- package/alert/Alert.tsx +3 -2
- package/button/_example/base.tsx +10 -0
- package/button/_example/icon.tsx +20 -0
- package/color-picker/ColorPickPanel.tsx +9 -0
- package/color-picker/ColorPicker.tsx +67 -0
- package/color-picker/components/panel/alpha.tsx +32 -0
- package/color-picker/components/panel/format/index.tsx +47 -0
- package/color-picker/components/panel/format/inputs.tsx +119 -0
- package/color-picker/components/panel/header.tsx +37 -0
- package/color-picker/components/panel/hue.tsx +20 -0
- package/color-picker/components/panel/index.tsx +191 -0
- package/color-picker/components/panel/saturation.tsx +81 -0
- package/color-picker/components/panel/slider.tsx +76 -0
- package/color-picker/components/panel/swatches.tsx +84 -0
- package/color-picker/components/trigger.tsx +49 -0
- package/color-picker/defaultProps.ts +7 -0
- package/color-picker/helpers.ts +53 -0
- package/color-picker/hooks/useClassNames.ts +9 -0
- package/color-picker/hooks/useStyles.ts +39 -0
- package/color-picker/index.ts +12 -0
- package/color-picker/style/css.js +1 -0
- package/color-picker/style/index.js +1 -0
- package/color-picker/type.ts +143 -0
- package/color-picker/utils/color-picker/cmyk.ts +89 -0
- package/color-picker/utils/color-picker/color.ts +467 -0
- package/color-picker/utils/color-picker/constants.ts +187 -0
- package/color-picker/utils/color-picker/draggable.ts +100 -0
- package/color-picker/utils/color-picker/format.ts +95 -0
- package/color-picker/utils/color-picker/gradient.ts +243 -0
- package/color-picker/utils/color-picker/index.ts +7 -0
- package/color-picker/utils/color-picker/types.ts +33 -0
- package/common/observe.ts +33 -0
- package/common.ts +20 -0
- package/config-provider/ConfigContext.tsx +4 -1
- package/config-provider/index.ts +1 -1
- package/dialog/DialogCard.tsx +4 -6
- package/dialog/hooks/useDialogPosition.ts +1 -2
- package/dialog/plugin.tsx +3 -2
- package/drawer/Drawer.tsx +264 -0
- package/drawer/defaultProps.ts +19 -0
- package/drawer/hooks/useDrag.ts +98 -0
- package/drawer/hooks/useLockStyle.ts +36 -0
- package/drawer/index.ts +5 -0
- package/drawer/style/css.js +1 -0
- package/drawer/style/index.js +1 -0
- package/drawer/type.ts +193 -0
- package/drawer/utils/index.ts +76 -0
- package/fireworks/Fireworks.tsx +138 -0
- package/fireworks/index.ts +10 -0
- package/fireworks/style/css.js +0 -0
- package/fireworks/style/index.js +0 -0
- package/fireworks/type.ts +72 -0
- package/form/FormItem.tsx +5 -5
- package/form/easing.ts +10 -0
- package/form/scroll.ts +124 -0
- package/form/type.ts +519 -519
- package/global-config/default-config.ts +95 -0
- package/global-config/locale/ar_KW.ts +270 -0
- package/global-config/locale/en_US.ts +280 -0
- package/global-config/locale/it_IT.ts +287 -0
- package/global-config/locale/ja_JP.ts +279 -0
- package/global-config/locale/ko_KR.ts +279 -0
- package/global-config/locale/ru_RU.ts +288 -0
- package/global-config/locale/zh_CN.ts +279 -0
- package/global-config/locale/zh_TW.ts +279 -0
- package/global-config/mobile/default-config.ts +6 -0
- package/global-config/mobile/locale/ar_KW.ts +113 -0
- package/global-config/mobile/locale/en_US.ts +114 -0
- package/global-config/mobile/locale/it_IT.ts +114 -0
- package/global-config/mobile/locale/ja_JP.ts +101 -0
- package/global-config/mobile/locale/ko_KR.ts +101 -0
- package/global-config/mobile/locale/ru_RU.ts +113 -0
- package/global-config/mobile/locale/zh_CN.ts +101 -0
- package/global-config/mobile/locale/zh_TW.ts +101 -0
- package/global-config/t.ts +111 -0
- package/hooks/useControlled.ts +3 -3
- package/hooks/useDeepEffect.ts +32 -0
- package/hooks/useGlobalIcon.ts +10 -3
- package/hooks/useLastest.ts +2 -6
- package/hooks/useResizeObserve.ts +36 -0
- package/index.ts +10 -7
- package/input/Input.tsx +4 -1
- package/input/defaultProps.ts +0 -2
- package/input/type.ts +1 -6
- package/input-number/InputNumber.tsx +124 -0
- package/input-number/defaultProps.ts +17 -0
- package/input-number/index.ts +9 -0
- package/input-number/style/css.js +1 -0
- package/input-number/style/index.js +1 -0
- package/input-number/type.ts +147 -0
- package/input-number/useInputNumber.tsx +270 -0
- package/ip-input/IPInput.tsx +516 -0
- package/ip-input/defaultProps.ts +11 -0
- package/ip-input/index.ts +3 -0
- package/ip-input/style/css.js +1 -0
- package/ip-input/style/index.js +1 -0
- package/ip-input/type.ts +115 -0
- package/ip-input/utils.ts +112 -0
- package/layout/Aside.tsx +38 -0
- package/layout/Layout.tsx +104 -0
- package/layout/defaultProps.ts +9 -0
- package/layout/index.ts +9 -0
- package/layout/style/css.js +1 -0
- package/layout/style/index.js +1 -0
- package/layout/type.ts +43 -0
- package/list/List.tsx +144 -0
- package/list/ListItem.tsx +36 -0
- package/list/ListItemMeta.tsx +40 -0
- package/list/defaultProps.ts +11 -0
- package/list/hooks/useListVirtualScroll.ts +82 -0
- package/list/index.ts +11 -0
- package/list/style/css.js +1 -0
- package/list/style/index.js +1 -0
- package/list/type.ts +93 -0
- package/locale/LocalReceiver.ts +55 -0
- package/locale/ar_KW.ts +7 -0
- package/locale/en_US.ts +7 -0
- package/locale/it_IT.ts +6 -0
- package/locale/ja_JP.ts +6 -0
- package/locale/ko_KR.ts +6 -0
- package/locale/ru_RU.ts +6 -0
- package/locale/zh_CN.ts +5 -0
- package/locale/zh_TW.ts +7 -0
- package/notification/NotifyContainer.tsx +2 -2
- package/notification/NotifyContext.tsx +1 -0
- package/package.json +6 -3
- package/popup/Popup.tsx +34 -10
- package/radio/Radio.tsx +24 -0
- package/radio/RadioGroup.tsx +159 -0
- package/radio/defaultProps.ts +18 -0
- package/radio/index.ts +12 -0
- package/radio/style/css.js +0 -0
- package/radio/style/index.js +1 -0
- package/radio/type.ts +115 -0
- package/radio/useKeyboard.ts +36 -0
- package/select/hooks/useOptions.ts +10 -7
- package/select/hooks/usePanelVirtualScroll.ts +1 -1
- package/select/type.ts +382 -382
- package/select-input/type.ts +280 -280
- package/slider/Slider.tsx +270 -0
- package/slider/SliderHandleButton.tsx +50 -0
- package/slider/defaultProps.ts +15 -0
- package/slider/index.ts +9 -0
- package/slider/style/css.js +1 -0
- package/slider/style/index.js +1 -0
- package/slider/type.ts +77 -0
- package/style/all.js +26 -0
- package/styles/_global.scss +39 -39
- package/styles/_vars.scss +358 -386
- package/styles/components/alert/_index.scss +175 -175
- package/styles/components/alert/_vars.scss +39 -39
- package/styles/components/badge/_index.scss +70 -70
- package/styles/components/badge/_vars.scss +25 -25
- package/styles/components/button/_index.scss +499 -511
- package/styles/components/button/_mixins.scss +39 -39
- package/styles/components/button/_vars.scss +120 -122
- package/styles/components/checkbox/_index.scss +158 -158
- package/styles/components/checkbox/_var.scss +60 -60
- package/styles/components/color-picker/_index.scss +586 -0
- package/styles/components/color-picker/_mixins.scss +0 -0
- package/styles/components/color-picker/_vars.scss +84 -0
- package/styles/components/dialog/_animate.scss +135 -135
- package/styles/components/dialog/_index.scss +311 -311
- package/styles/components/dialog/_vars.scss +59 -59
- package/styles/components/drawer/_index.scss +205 -0
- package/styles/components/drawer/_mixins.scss +1 -0
- package/styles/components/drawer/_var.scss +53 -0
- package/styles/components/fireworks/_index.scss +86 -0
- package/styles/components/fireworks/_vars.scss +4 -0
- package/styles/components/form/_index.scss +174 -174
- package/styles/components/form/_mixins.scss +76 -76
- package/styles/components/form/_vars.scss +100 -100
- package/styles/components/input/_index.scss +349 -349
- package/styles/components/input/_mixins.scss +116 -116
- package/styles/components/input/_vars.scss +134 -134
- package/styles/components/input-number/_index.scss +353 -0
- package/styles/components/input-number/_mixins.scss +0 -0
- package/styles/components/input-number/_vars.scss +65 -0
- package/styles/components/ip-input/_index.scss +280 -0
- package/styles/components/layout/_index.scss +47 -0
- package/styles/components/layout/_mixin.scss +0 -0
- package/styles/components/layout/_vars.scss +18 -0
- package/styles/components/layout/doc.scss +74 -0
- package/styles/components/list/_index.scss +172 -0
- package/styles/components/list/_mixins.scss +0 -0
- package/styles/components/list/_vars.scss +41 -0
- package/styles/components/loading/_index.scss +112 -112
- package/styles/components/loading/_vars.scss +39 -39
- package/styles/components/notification/_index.scss +160 -160
- package/styles/components/notification/_mixins.scss +12 -12
- package/styles/components/notification/_vars.scss +59 -59
- package/styles/components/popup/_index.scss +82 -82
- package/styles/components/popup/_mixin.scss +149 -149
- package/styles/components/popup/_var.scss +31 -31
- package/styles/components/radio/_index.scss +376 -0
- package/styles/components/radio/_mixins.scss +0 -0
- package/styles/components/radio/_var.scss +92 -0
- package/styles/components/select/_index.scss +290 -290
- package/styles/components/select/_var.scss +65 -65
- package/styles/components/select-input/_index.scss +5 -5
- package/styles/components/select-input/_var.scss +3 -3
- package/styles/components/slider/_index.scss +241 -0
- package/styles/components/slider/_mixins.scss +0 -0
- package/styles/components/slider/_vars.scss +50 -0
- package/styles/components/switch/_index.scss +279 -279
- package/styles/components/switch/_vars.scss +61 -61
- package/styles/components/table/_index.scss +193 -0
- package/styles/components/table/_var.scss +52 -0
- package/styles/components/tabs/_index.scss +165 -0
- package/styles/components/tabs/_mixins.scss +11 -0
- package/styles/components/tabs/_vars.scss +71 -0
- package/styles/components/tag/_index.scss +316 -316
- package/styles/components/tag/_var.scss +85 -85
- package/styles/components/tag-input/_index.scss +163 -163
- package/styles/components/tag-input/_vars.scss +16 -16
- package/styles/globals.css +250 -250
- package/styles/mixins/_focus.scss +7 -7
- package/styles/mixins/_layout.scss +32 -32
- package/styles/mixins/_reset.scss +10 -10
- package/styles/mixins/_scrollbar.scss +31 -31
- package/styles/mixins/_text.scss +48 -48
- package/styles/rillple.css +16 -16
- package/styles/scrollbar.css +41 -41
- package/styles/themes/_dark.scss +191 -191
- package/styles/themes/_font.scss +69 -79
- package/styles/themes/_index.scss +5 -5
- package/styles/themes/_light.scss +190 -190
- package/styles/themes/_radius.scss +9 -9
- package/styles/themes/_size.scss +68 -68
- package/styles/themes.css +66 -66
- package/styles/utilities/_animation.scss +57 -57
- package/styles/utilities/_tips.scss +9 -9
- package/tab/TabBar.tsx +85 -0
- package/tab/TabNav.tsx +103 -0
- package/tab/TabNavItem.tsx +80 -0
- package/tab/TabPanel.tsx +42 -0
- package/tab/Tabs.tsx +71 -0
- package/tab/defaultProps.ts +19 -0
- package/tab/index.ts +7 -0
- package/tab/style/index.js +1 -0
- package/tab/type.ts +125 -0
- package/tab/useTabClass.ts +20 -0
- package/table/Cell.tsx +109 -0
- package/table/TBody.tsx +77 -0
- package/table/THead.tsx +63 -0
- package/table/TR.tsx +78 -0
- package/table/Table.tsx +73 -0
- package/table/defaultProps.ts +14 -0
- package/table/hooks/index.ts +4 -0
- package/table/hooks/useTableClassName.ts +63 -0
- package/table/hooks/useTableStyle.ts +93 -0
- package/table/index.ts +7 -0
- package/table/style/css.js +1 -0
- package/table/style/index.js +1 -0
- package/table/type.ts +192 -0
- package/tag/Tag.tsx +1 -1
- package/tag-input/hooks/useTagList.tsx +1 -1
- package/utils/dom.ts +4 -0
- package/utils/forwardRefWithStatics.ts +1 -4
- package/utils/input-number/large-number.ts +423 -0
- package/utils/input-number/number.ts +257 -0
- package/utils/isFragment.ts +6 -6
- package/utils/log/index.ts +3 -0
- package/utils/log/log.ts +30 -0
- package/utils/log/types.ts +12 -0
- package/utils/number.ts +21 -0
- package/utils/scroll.ts +26 -0
- package/utils/style.ts +2 -4
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { isString, isNumber, isObject } from "lodash-es";
|
|
2
|
+
import log from "../log/log";
|
|
3
|
+
|
|
4
|
+
export type InputNumberDecimalPlaces = number | { enableRound: boolean; places: number };
|
|
5
|
+
|
|
6
|
+
export function fillZero(length: number) {
|
|
7
|
+
return new Array(length).fill(0).join("");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 大数,是否是一个数字,数字字符包括 - . e [0-9]
|
|
12
|
+
*/
|
|
13
|
+
export function isInputNumber(num: number | string): boolean {
|
|
14
|
+
if (!num) return true;
|
|
15
|
+
if (isNumber(num)) return !Number.isNaN(num);
|
|
16
|
+
const r = /^[0-9|e|E|-]+\.*[0-9|e|E|-]*$/.test(num);
|
|
17
|
+
if (!r) return false;
|
|
18
|
+
// only allow one [.e] and two [-]
|
|
19
|
+
let eCount = 0;
|
|
20
|
+
let negativeCount = 0;
|
|
21
|
+
let dotCount = 0;
|
|
22
|
+
for (let i = 0, len = num.length; i < len; i++) {
|
|
23
|
+
if (num[i] === ".") {
|
|
24
|
+
dotCount += 1;
|
|
25
|
+
if (dotCount > 1) return false;
|
|
26
|
+
}
|
|
27
|
+
if (/(e|E)+/.test(num[i])) {
|
|
28
|
+
eCount += 1;
|
|
29
|
+
if (eCount > 1) return false;
|
|
30
|
+
}
|
|
31
|
+
if (num[i] === "-") {
|
|
32
|
+
negativeCount += 1;
|
|
33
|
+
if (negativeCount > 2) return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 整数,去除前面的无效 0(本身是 0 除外);小数去除末尾的无效 0
|
|
40
|
+
export function removeInvalidZero(num: string, decimal = false) {
|
|
41
|
+
if (num.indexOf(".") !== -1) {
|
|
42
|
+
log.error("InputNumber", "num is not a integer number.");
|
|
43
|
+
return num;
|
|
44
|
+
}
|
|
45
|
+
if (!num || (num === "0" && decimal)) return "";
|
|
46
|
+
if (num === "0") return num;
|
|
47
|
+
return (decimal ? num.replace(/0+$/, "") : num.replace(/^0+/, "")) || "0";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 大数加法,仅支持正整数(没有精度问题)
|
|
52
|
+
* @param num1 被加数
|
|
53
|
+
* @param num2 加数
|
|
54
|
+
*/
|
|
55
|
+
export function largeIntNumberAdd(num1: string, num2: string, decimal = false): string {
|
|
56
|
+
const number1 = removeInvalidZero(num1, decimal);
|
|
57
|
+
const number2 = removeInvalidZero(num2, decimal);
|
|
58
|
+
const isFirstLarger = number1.length > number2.length;
|
|
59
|
+
const maxNumber = isFirstLarger ? number1 : number2;
|
|
60
|
+
const minNumber = isFirstLarger ? number2 : number1;
|
|
61
|
+
const newNumber: string[] = [];
|
|
62
|
+
const step = [];
|
|
63
|
+
const diff = decimal ? 0 : maxNumber.length - minNumber.length;
|
|
64
|
+
const len = decimal ? minNumber.length : maxNumber.length;
|
|
65
|
+
for (let i = len - 1; i >= 0; i--) {
|
|
66
|
+
const minIndex = i - diff;
|
|
67
|
+
// 第一个数,加第二个数,加进位
|
|
68
|
+
const count = Number(maxNumber[i]) + (Number(minNumber[minIndex]) || 0) + (step[i] || 0);
|
|
69
|
+
if (count >= 10) {
|
|
70
|
+
step[i - 1] = 1;
|
|
71
|
+
}
|
|
72
|
+
newNumber.unshift(String(count % 10));
|
|
73
|
+
}
|
|
74
|
+
// 999 + 1 = 1000,之类的进位
|
|
75
|
+
if (step[-1]) {
|
|
76
|
+
newNumber.unshift("1");
|
|
77
|
+
}
|
|
78
|
+
if (decimal) {
|
|
79
|
+
return newNumber.concat(maxNumber.slice(len, maxNumber.length)).join("");
|
|
80
|
+
}
|
|
81
|
+
return newNumber.join("");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 大数加法,支持小数和整数(没有精度问题)
|
|
86
|
+
* @param num1 被加数
|
|
87
|
+
* @param num2 加数
|
|
88
|
+
*/
|
|
89
|
+
export function largePositiveNumberAdd(num1: string, num2: string): string {
|
|
90
|
+
const [intNumber1 = "0", decimalNumber1 = "0"] = num1.split(".");
|
|
91
|
+
const [intNumber2 = "0", decimalNumber2 = "0"] = num2.split(".");
|
|
92
|
+
const integerSum = largeIntNumberAdd(intNumber1, intNumber2);
|
|
93
|
+
// 如果不存在小数,则直接返回整数相加结果
|
|
94
|
+
if (decimalNumber1 === "0" && decimalNumber2 === "0") return integerSum;
|
|
95
|
+
const newDecimalNumber1 = removeInvalidZero(decimalNumber1, true);
|
|
96
|
+
const newDecimalNumber2 = removeInvalidZero(decimalNumber2, true);
|
|
97
|
+
// 小数点相加
|
|
98
|
+
const decimalNumberSum = largeIntNumberAdd(newDecimalNumber1, newDecimalNumber2, true);
|
|
99
|
+
// 组合整数部分和小数部分
|
|
100
|
+
const decimalLength = decimalNumberSum.length;
|
|
101
|
+
// 如果小数相加进位
|
|
102
|
+
if (decimalLength > newDecimalNumber1.length && decimalLength > newDecimalNumber2.length) {
|
|
103
|
+
return [removeInvalidZero(largeIntNumberAdd(integerSum, "1")), removeInvalidZero(decimalNumberSum.slice(1), true)]
|
|
104
|
+
.filter((v: string) => v)
|
|
105
|
+
.join(".");
|
|
106
|
+
}
|
|
107
|
+
return [removeInvalidZero(integerSum), removeInvalidZero(decimalNumberSum, true)].filter((v: string) => v).join(".");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 比较两个大数的大小,仅正整数有效
|
|
112
|
+
*/
|
|
113
|
+
function compareLargeIntegerNumber(num1: string, num2: string): 1 | -1 | 0 {
|
|
114
|
+
const number1 = removeInvalidZero(num1);
|
|
115
|
+
const number2 = removeInvalidZero(num2);
|
|
116
|
+
if (number1.length === number2.length) {
|
|
117
|
+
for (let i = 0, len = number1.length; i < len; i++) {
|
|
118
|
+
if (number1[i] > number2[i]) return 1;
|
|
119
|
+
if (number1[i] < number2[i]) return -1;
|
|
120
|
+
}
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
return number1.length > number2.length ? 1 : -1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function compareLargeDecimalNumber(num1: string, num2: string) {
|
|
127
|
+
const number1 = num1 && num1 !== "0" ? num1.replace(/0+$/, "") : "0";
|
|
128
|
+
const number2 = num2 && num2 !== "0" ? num2.replace(/0+$/, "") : "0";
|
|
129
|
+
const maxLength = Math.max(number1.length, number2.length);
|
|
130
|
+
for (let i = 0, len = maxLength; i < len; i++) {
|
|
131
|
+
if ((number1[i] || 0) > (number2[i] || 0)) return 1;
|
|
132
|
+
if ((number1[i] || 0) < (number2[i] || 0)) return -1;
|
|
133
|
+
}
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 2e3 => 2000
|
|
139
|
+
* 0.2e3 => 200
|
|
140
|
+
*/
|
|
141
|
+
export function formatENumber(num: string): string {
|
|
142
|
+
const [num1, num2] = num.split("e");
|
|
143
|
+
if (!num2) return num;
|
|
144
|
+
const [integer, initDecimal = ""] = num.split(".");
|
|
145
|
+
const zeroCount = Number(num2);
|
|
146
|
+
const [decimal] = initDecimal.split("e");
|
|
147
|
+
if (zeroCount > decimal.length) {
|
|
148
|
+
const multipleZero = fillZero(zeroCount - decimal.length);
|
|
149
|
+
return num1.replace(/(^0+|\.)/g, "") + multipleZero;
|
|
150
|
+
}
|
|
151
|
+
const n1 = integer.replace(/^0+/, "") + decimal.slice(0, zeroCount);
|
|
152
|
+
const d2 = decimal.slice(zeroCount);
|
|
153
|
+
return d2 ? [n1, d2].join(".") : n1;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 比较两个大数的大小
|
|
158
|
+
*/
|
|
159
|
+
export function compareLargeNumber(num1: string, num2: string): 1 | -1 | 0 {
|
|
160
|
+
const [integer1, decimal1] = formatENumber(num1).split(".");
|
|
161
|
+
const [integer2, decimal2] = formatENumber(num2).split(".");
|
|
162
|
+
const result = compareLargeIntegerNumber(integer1.replace("-", ""), integer2.replace("-", ""));
|
|
163
|
+
const integer1IsNegative = integer1.includes("-");
|
|
164
|
+
const integer2IsNegative = integer2.includes("-");
|
|
165
|
+
if (integer1IsNegative && !integer2IsNegative) return -1;
|
|
166
|
+
if (!integer1IsNegative && integer2IsNegative) return 1;
|
|
167
|
+
if (integer1IsNegative && integer2IsNegative) {
|
|
168
|
+
if (result === 0) return 0;
|
|
169
|
+
return result > 0 ? -1 : 1;
|
|
170
|
+
}
|
|
171
|
+
if (result === 0) {
|
|
172
|
+
return compareLargeDecimalNumber(decimal1, decimal2);
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 确认是否为无限大/小
|
|
178
|
+
export function isInfinity(num: number | string) {
|
|
179
|
+
return [-Infinity, Infinity].includes(Number(num));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 确认是否是大数
|
|
183
|
+
export function isSafeNumber(num: string | number) {
|
|
184
|
+
return Number(num) < Number.MAX_SAFE_INTEGER && Number(num) > Number.MIN_SAFE_INTEGER;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 比较两个数的大小
|
|
189
|
+
*/
|
|
190
|
+
export function compareNumber(num1: string | number, num2: string | number, largeNumber?: boolean) {
|
|
191
|
+
const isSafeNumberCompare = isSafeNumber(num1) && isSafeNumber(num2) && !largeNumber;
|
|
192
|
+
const isInfinityCompare = isInfinity(num1) || isInfinity(num2);
|
|
193
|
+
if (isSafeNumberCompare || isInfinityCompare) {
|
|
194
|
+
// 比较两个非大数或涉及无穷的大小
|
|
195
|
+
if (Number(num1) === Number(num2)) return 0;
|
|
196
|
+
return Number(num1) > Number(num2) ? 1 : -1;
|
|
197
|
+
}
|
|
198
|
+
// 比较两个大数的大小
|
|
199
|
+
return compareLargeNumber(String(num1), String(num2));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 大数减法,仅支持整数
|
|
204
|
+
* @param num1 被减数
|
|
205
|
+
* @param num2 减数
|
|
206
|
+
* @param decimal 是否为小数位相减
|
|
207
|
+
*/
|
|
208
|
+
export function largeIntegerNumberSubtract(
|
|
209
|
+
num1: string,
|
|
210
|
+
num2: string,
|
|
211
|
+
p?: { decimal?: boolean; stayZero?: boolean }
|
|
212
|
+
): string {
|
|
213
|
+
if (num1 === num2) return "0";
|
|
214
|
+
const { decimal, stayZero } = p || {};
|
|
215
|
+
const number1 = removeInvalidZero(num1);
|
|
216
|
+
const number2 = removeInvalidZero(num2);
|
|
217
|
+
const isFirstLarger = compareLargeIntegerNumber(number1, number2) > 0;
|
|
218
|
+
const maxNumber = isFirstLarger ? number1 : number2;
|
|
219
|
+
const minNumber = isFirstLarger ? number2 : number1;
|
|
220
|
+
const newNumber: string[] = [];
|
|
221
|
+
// step 存储借位信息
|
|
222
|
+
const step = [];
|
|
223
|
+
const diff = decimal ? 0 : maxNumber.length - minNumber.length;
|
|
224
|
+
const len = decimal ? minNumber.length : maxNumber.length;
|
|
225
|
+
for (let i = len - 1; i >= 0; i--) {
|
|
226
|
+
const minIndex = i - diff;
|
|
227
|
+
// 第一个数,减第二个数,减借位
|
|
228
|
+
let count = Number(maxNumber[i]) - (Number(minNumber[minIndex]) || 0) - (step[i] || 0);
|
|
229
|
+
if (count < 0) {
|
|
230
|
+
step[i - 1] = 1;
|
|
231
|
+
count += 10;
|
|
232
|
+
}
|
|
233
|
+
newNumber.unshift(String(count));
|
|
234
|
+
}
|
|
235
|
+
if (decimal) {
|
|
236
|
+
return newNumber.concat(maxNumber.slice(len, maxNumber.length)).join("");
|
|
237
|
+
}
|
|
238
|
+
let finalNumber = newNumber.join("");
|
|
239
|
+
if (!stayZero) {
|
|
240
|
+
finalNumber = finalNumber.replace(/^0+/, "");
|
|
241
|
+
}
|
|
242
|
+
return removeInvalidZero(isFirstLarger ? finalNumber : `-${finalNumber}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* 大数减法,支持整数和小数(无精度问题)
|
|
247
|
+
* @param num1 被减数
|
|
248
|
+
* @param num2 减数
|
|
249
|
+
* @param decimal 是否为小数位相减
|
|
250
|
+
*/
|
|
251
|
+
export function largePositiveNumberSubtract(num1: string, num2: string): string {
|
|
252
|
+
if (num1 === num2) return "0";
|
|
253
|
+
const isFirstLarger = compareNumber(num1, num2, true) > 0;
|
|
254
|
+
const maxNumber = isFirstLarger ? num1 : num2;
|
|
255
|
+
const minNumber = isFirstLarger ? num2 : num1;
|
|
256
|
+
// 整数部分和小数部分分开处理
|
|
257
|
+
const [intNumber1, decimalNumber1 = "0"] = maxNumber.split(".");
|
|
258
|
+
const [intNumber2, decimalNumber2 = "0"] = minNumber.split(".");
|
|
259
|
+
let integerNumber = largeIntegerNumberSubtract(intNumber1, intNumber2);
|
|
260
|
+
// 如果不存在小数,则直接返回整数相加结果
|
|
261
|
+
if (decimalNumber1 === "0" && decimalNumber2 === "0") {
|
|
262
|
+
return isFirstLarger ? integerNumber : `-${integerNumber}`;
|
|
263
|
+
}
|
|
264
|
+
// 小数点相减
|
|
265
|
+
let decimalNumber = "";
|
|
266
|
+
let addOneNumber = decimalNumber1;
|
|
267
|
+
// 第一个数字的小数位数比第二个少,需补足 0
|
|
268
|
+
if (decimalNumber1.length < decimalNumber2.length) {
|
|
269
|
+
addOneNumber = `${decimalNumber1}${fillZero(decimalNumber2.length - decimalNumber1.length)}`;
|
|
270
|
+
}
|
|
271
|
+
// 第一个小数位更小,是否需要借位
|
|
272
|
+
if (compareLargeDecimalNumber(addOneNumber, decimalNumber2) >= 0) {
|
|
273
|
+
decimalNumber = largeIntegerNumberSubtract(addOneNumber, decimalNumber2, { decimal: true });
|
|
274
|
+
} else {
|
|
275
|
+
if (decimalNumber1.length < decimalNumber2.length || decimalNumber1 === "0") {
|
|
276
|
+
decimalNumber = largeIntegerNumberSubtract(`1${addOneNumber}`, decimalNumber2, { stayZero: true });
|
|
277
|
+
decimalNumber = fillZero(decimalNumber2.length - decimalNumber.length) + decimalNumber;
|
|
278
|
+
} else {
|
|
279
|
+
decimalNumber = largeIntegerNumberSubtract(decimalNumber1, decimalNumber2, { decimal: true });
|
|
280
|
+
}
|
|
281
|
+
integerNumber = largeIntegerNumberSubtract(integerNumber, "1");
|
|
282
|
+
}
|
|
283
|
+
const finalNumber = decimalNumber ? [integerNumber, decimalNumber].join(".") : integerNumber;
|
|
284
|
+
return isFirstLarger ? finalNumber : `-${finalNumber}`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* -0.6 - 0.8 => -(0.6 + 0.8)
|
|
289
|
+
* -0.6 - (-0.8) => 0.8 - 0.6
|
|
290
|
+
* 0.6 - (-0.8) => 0.6 + 0.8
|
|
291
|
+
* 0.6 - 0.8 => 0.6 - 0.8
|
|
292
|
+
*/
|
|
293
|
+
export function largeNumberSubtract(num1: string, num2: string): string {
|
|
294
|
+
const isFirstNegative = num1[0] === "-";
|
|
295
|
+
const isSecondNegative = num2[0] === "-";
|
|
296
|
+
if (isFirstNegative && !isSecondNegative) {
|
|
297
|
+
const r = largePositiveNumberAdd(num1.slice(1), num2);
|
|
298
|
+
return `-${r}`;
|
|
299
|
+
}
|
|
300
|
+
if (isFirstNegative && isSecondNegative) {
|
|
301
|
+
return largePositiveNumberSubtract(num2.slice(1), num1.slice(1));
|
|
302
|
+
}
|
|
303
|
+
if (!isFirstNegative && isSecondNegative) {
|
|
304
|
+
return largePositiveNumberAdd(num1, num2.slice(1));
|
|
305
|
+
}
|
|
306
|
+
return largePositiveNumberSubtract(num1, num2);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* -0.6 + 0.8 => 0.8 - 0.6
|
|
311
|
+
* -0.6 + (-0.8) => -(0.6 + 0.8)
|
|
312
|
+
* 0.6 + (-0.8) => 0.6 - 0.8
|
|
313
|
+
* 0.6 + 0.8 => 0.6 + 0.8
|
|
314
|
+
*/
|
|
315
|
+
export function largeNumberAdd(num1: string, num2: string): string {
|
|
316
|
+
const isFirstNegative = num1[0] === "-";
|
|
317
|
+
const isSecondNegative = num2[0] === "-";
|
|
318
|
+
if (isFirstNegative && !isSecondNegative) {
|
|
319
|
+
return largePositiveNumberSubtract(num2, num1.slice(1));
|
|
320
|
+
}
|
|
321
|
+
if (isFirstNegative && isSecondNegative) {
|
|
322
|
+
const r = largePositiveNumberAdd(num2.slice(1), num1.slice(1));
|
|
323
|
+
return `-${r}`;
|
|
324
|
+
}
|
|
325
|
+
if (!isFirstNegative && isSecondNegative) {
|
|
326
|
+
return largePositiveNumberSubtract(num1, num2.slice(1));
|
|
327
|
+
}
|
|
328
|
+
return largePositiveNumberAdd(num1, num2);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* 格式化小数,并且可以控制小数点后的位数和是否进行四舍五入。
|
|
333
|
+
*
|
|
334
|
+
* @param {number} num - 要格式化的数字。
|
|
335
|
+
* @param {number} places - 小数点后的位数。
|
|
336
|
+
* @param {boolean} rounding - 是否进行四舍五入。
|
|
337
|
+
* @returns {string} 格式化后的数字字符串。
|
|
338
|
+
*/
|
|
339
|
+
export function formatDecimal(num: number, places: number, enableRound: boolean = true) {
|
|
340
|
+
// 开启四舍五入 直接用 toFixed
|
|
341
|
+
if (enableRound) {
|
|
342
|
+
return num.toFixed(places);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const [integer, decimal] = num.toString().split(".");
|
|
346
|
+
// 保留 0 位小数
|
|
347
|
+
if (places === 0) {
|
|
348
|
+
return integer;
|
|
349
|
+
}
|
|
350
|
+
// 补足小数位数
|
|
351
|
+
if (decimal) {
|
|
352
|
+
let decimalNumber = decimal.slice(0, places);
|
|
353
|
+
if (decimal.length < places) {
|
|
354
|
+
decimalNumber += fillZero(places - decimal.length);
|
|
355
|
+
}
|
|
356
|
+
return [integer, decimalNumber].join(".");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return [integer, fillZero(places)].join(".");
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function decimalPlacesToFixedNum(num: number, decimalPlaces: InputNumberDecimalPlaces) {
|
|
363
|
+
if (isObject(decimalPlaces)) {
|
|
364
|
+
return formatDecimal(num, decimalPlaces.places, decimalPlaces.enableRound ?? true);
|
|
365
|
+
}
|
|
366
|
+
return formatDecimal(num, decimalPlaces, true);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* 大数保留 N 位小数(没有精度问题)
|
|
371
|
+
* @param {String} number 大数(只能使用字符串表示)
|
|
372
|
+
* @param {Number} decimalPlaces 保留的小数位数
|
|
373
|
+
* @param {Boolean} largeNumber 是否为大数
|
|
374
|
+
*/
|
|
375
|
+
export function largeNumberToFixed(
|
|
376
|
+
number: string | number,
|
|
377
|
+
decimalPlaces: InputNumberDecimalPlaces = 0,
|
|
378
|
+
largeNumber: boolean = true
|
|
379
|
+
): string {
|
|
380
|
+
if (Number.isNaN(Number(number))) return "";
|
|
381
|
+
if (!largeNumber) {
|
|
382
|
+
return decimalPlacesToFixedNum(Number(number), decimalPlaces);
|
|
383
|
+
}
|
|
384
|
+
const places = isObject(decimalPlaces) ? decimalPlaces.places : decimalPlaces;
|
|
385
|
+
const enableRound = isObject(decimalPlaces) ? decimalPlaces.enableRound ?? true : true;
|
|
386
|
+
if (!isString(number)) return String(number);
|
|
387
|
+
|
|
388
|
+
let [num1, num2] = number.split(".");
|
|
389
|
+
// 如果不存在小数点,则补足位数
|
|
390
|
+
if (!num2) {
|
|
391
|
+
return places > 0 && enableRound ? [number, fillZero(places)].join(".") : number;
|
|
392
|
+
}
|
|
393
|
+
// 存在小数点,保留 0 位小数,灵活配置四舍五入
|
|
394
|
+
if (places === 0) {
|
|
395
|
+
return enableRound && Number(num2[0]) >= 5 ? largePositiveNumberAdd(num1, "1") : num1;
|
|
396
|
+
}
|
|
397
|
+
// 存在小数点,保留 > 0 位小数,灵活配置四舍五入
|
|
398
|
+
let decimalNumber = num2.slice(0, places);
|
|
399
|
+
if (num2.length < places) {
|
|
400
|
+
decimalNumber += fillZero(places - num2.length);
|
|
401
|
+
} else if (enableRound) {
|
|
402
|
+
// 用于判断是否处于 1.08 这种小数为0开始的边界情况
|
|
403
|
+
const leadZeroNum = decimalNumber.match(/^0+/)?.[0].length;
|
|
404
|
+
// 用于判断是否处于 0.99/1.99 等需要往非0位进位的场景
|
|
405
|
+
const leadNineNum = decimalNumber.match(/^9+/);
|
|
406
|
+
// 决定是否需要四舍五入
|
|
407
|
+
const needAdded = Number(num2[places]) >= 5;
|
|
408
|
+
|
|
409
|
+
// 四舍五入后的结果
|
|
410
|
+
decimalNumber = needAdded ? largePositiveNumberAdd(decimalNumber, "1") : decimalNumber;
|
|
411
|
+
|
|
412
|
+
// 边界场景1(1.08 这种小数为0开始的边界情况):计算后有误判的可能,如008 +1 误判为 8+1,需要手动补 0
|
|
413
|
+
if (leadZeroNum && needAdded && leadZeroNum + decimalNumber.length >= places) {
|
|
414
|
+
decimalNumber = `${fillZero(places - decimalNumber.length)}${decimalNumber}`;
|
|
415
|
+
}
|
|
416
|
+
// 边界场景2:(0.99 这种可能进位的边界情况):计算后有误判的可能,如995 四舍五入后需进位
|
|
417
|
+
if (leadNineNum && decimalNumber.length > places) {
|
|
418
|
+
num1 = (Number(num1) + 1).toString();
|
|
419
|
+
decimalNumber = fillZero(places);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return [num1, decimalNumber].join(".");
|
|
423
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { isUndefined, isString, isNumber } from "lodash-es";
|
|
2
|
+
/** 普通数相关方法 */
|
|
3
|
+
import {
|
|
4
|
+
compareNumber,
|
|
5
|
+
formatENumber,
|
|
6
|
+
largeNumberToFixed,
|
|
7
|
+
isInputNumber,
|
|
8
|
+
largeNumberAdd,
|
|
9
|
+
largeNumberSubtract
|
|
10
|
+
} from "./large-number";
|
|
11
|
+
import log from "../log";
|
|
12
|
+
import type { InputNumberDecimalPlaces } from "./large-number";
|
|
13
|
+
|
|
14
|
+
export * from "./large-number";
|
|
15
|
+
|
|
16
|
+
export type NumberType = number | string;
|
|
17
|
+
|
|
18
|
+
// 小于最大值,才允许继续添加
|
|
19
|
+
export function canAddNumber(num: NumberType, max: NumberType, largeNumber = false): boolean {
|
|
20
|
+
if (!num && num !== 0) return true;
|
|
21
|
+
if (largeNumber && isString(num)) {
|
|
22
|
+
return compareNumber(num, max, largeNumber) < 0;
|
|
23
|
+
}
|
|
24
|
+
return num < max;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 大于最小值,才允许继续减少
|
|
28
|
+
export function canReduceNumber(num: NumberType, min: NumberType, largeNumber = false): boolean {
|
|
29
|
+
if (!num && num !== 0) return true;
|
|
30
|
+
if (largeNumber && isString(num)) {
|
|
31
|
+
return compareNumber(num, min, largeNumber) > 0;
|
|
32
|
+
}
|
|
33
|
+
return num > min;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 将数字控制在 max 和 min 之间
|
|
38
|
+
*/
|
|
39
|
+
export function putInRangeNumber(
|
|
40
|
+
val: NumberType,
|
|
41
|
+
params: {
|
|
42
|
+
max?: NumberType;
|
|
43
|
+
min?: NumberType;
|
|
44
|
+
lastValue?: NumberType;
|
|
45
|
+
largeNumber?: boolean;
|
|
46
|
+
}
|
|
47
|
+
) {
|
|
48
|
+
if (val === "") return undefined;
|
|
49
|
+
const { max, min, lastValue, largeNumber } = params;
|
|
50
|
+
if (!isInputNumber(val)) return lastValue;
|
|
51
|
+
if (largeNumber && (isString(max) || max === Infinity) && (isString(min) || min === -Infinity)) {
|
|
52
|
+
if (compareNumber(max, val, largeNumber) < 0) return max;
|
|
53
|
+
if (compareNumber(min, val, largeNumber) > 0) return min;
|
|
54
|
+
return val;
|
|
55
|
+
}
|
|
56
|
+
return Math.max(Number(min), Math.min(Number(max), Number(val)));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 仅支持正数,小数加法精度处理,小数部分和整数部分分开处理
|
|
61
|
+
*/
|
|
62
|
+
export function positiveAdd(num1: number, num2: number): number {
|
|
63
|
+
if (!num1 || !num2) return (num1 || 0) + (num2 || 0);
|
|
64
|
+
const r1 = num1.toString().split(".")[1]?.length || 0;
|
|
65
|
+
const r2 = num2.toString().split(".")[1]?.length || 0;
|
|
66
|
+
// 整数不存在精度问题,直接返回
|
|
67
|
+
if (!r1 && !r2) return num1 + num2;
|
|
68
|
+
let newNumber1 = num1;
|
|
69
|
+
let newNumber2 = num2;
|
|
70
|
+
const diff = Math.abs(r1 - r2);
|
|
71
|
+
const digit = 10 ** Math.max(r1, r2);
|
|
72
|
+
if (diff > 0) {
|
|
73
|
+
const cm = 10 ** diff;
|
|
74
|
+
if (r1 > r2) {
|
|
75
|
+
newNumber1 = Number(num1.toString().replace(".", ""));
|
|
76
|
+
newNumber2 = Number(num2.toString().replace(".", "")) * cm;
|
|
77
|
+
} else {
|
|
78
|
+
newNumber1 = Number(num1.toString().replace(".", "")) * cm;
|
|
79
|
+
newNumber2 = Number(num2.toString().replace(".", ""));
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
newNumber1 = Number(num1.toString().replace(".", ""));
|
|
83
|
+
newNumber2 = Number(num2.toString().replace(".", ""));
|
|
84
|
+
}
|
|
85
|
+
return (newNumber1 + newNumber2) / digit;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 正数,小数减法精度处理,小数部分和整数部分分开处理
|
|
90
|
+
*/
|
|
91
|
+
export function positiveSubtract(num1: number, num2: number): number {
|
|
92
|
+
if (!num1 || !num2) return (num1 || 0) - (num2 || 0);
|
|
93
|
+
const r1 = num1.toString().split(".")[1]?.length || 0;
|
|
94
|
+
const r2 = num2.toString().split(".")[1]?.length || 0;
|
|
95
|
+
const digit = 10 ** Math.max(r1, r2);
|
|
96
|
+
const n = r1 >= r2 ? r1 : r2;
|
|
97
|
+
return Number(((num1 * digit - num2 * digit) / digit).toFixed(n));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 支持正数、负数、小数等全部数字的加法
|
|
102
|
+
* -0.766 + 1 => 1 - 0.766
|
|
103
|
+
* -1 + (-0.766) => - (1 + 0.766)
|
|
104
|
+
* 1 + (-0.766) => 1 - 0.766
|
|
105
|
+
* 1 + 0.766 => 1 + 0.766
|
|
106
|
+
*/
|
|
107
|
+
export function add(num1: number, num2: number): number {
|
|
108
|
+
if (num1 < 0 && num2 > 0) return positiveSubtract(num2, Math.abs(num1));
|
|
109
|
+
if (num1 < 0 && num2 < 0) return positiveAdd(Math.abs(num1), Math.abs(num2)) * -1;
|
|
110
|
+
if (num1 > 0 && num2 < 0) return positiveSubtract(num1, Math.abs(num2));
|
|
111
|
+
return positiveAdd(num1, num2);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 支持正数、负数、小数等全部数字的减法
|
|
116
|
+
* -0.766 - 1 => - (1 + 0.766)
|
|
117
|
+
* -1 - (-0.766) => 0.766 - 1
|
|
118
|
+
* 1 - (-0.766) => 1 + 0.766
|
|
119
|
+
* 1 - 0.766 => 1 - 0.766
|
|
120
|
+
*/
|
|
121
|
+
export function subtract(num1: number, num2: number): number {
|
|
122
|
+
if (num1 < 0 && num2 > 0) return positiveAdd(Math.abs(num1), num2) * -1;
|
|
123
|
+
if (num1 < 0 && num2 < 0) return positiveSubtract(Math.abs(num2), Math.abs(num1));
|
|
124
|
+
if (num1 > 0 && num2 < 0) return positiveAdd(num1, Math.abs(num2));
|
|
125
|
+
return positiveSubtract(num1, num2);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function getStepValue(p: {
|
|
129
|
+
op: "add" | "reduce";
|
|
130
|
+
step: NumberType;
|
|
131
|
+
max?: NumberType;
|
|
132
|
+
min?: NumberType;
|
|
133
|
+
lastValue?: NumberType;
|
|
134
|
+
largeNumber?: boolean;
|
|
135
|
+
}) {
|
|
136
|
+
const { op, step, lastValue, max, min, largeNumber } = p;
|
|
137
|
+
if (Number(step) <= 0) {
|
|
138
|
+
log.error("InputNumber", "step must be larger than 0.");
|
|
139
|
+
return lastValue;
|
|
140
|
+
}
|
|
141
|
+
const tStep = isNumber(step) ? String(step) : step;
|
|
142
|
+
let newVal;
|
|
143
|
+
if (op === "add") {
|
|
144
|
+
if (largeNumber && isString(lastValue)) {
|
|
145
|
+
newVal = largeNumberAdd(String(lastValue), String(tStep));
|
|
146
|
+
} else {
|
|
147
|
+
newVal = add(Number(lastValue || 0), Number(step));
|
|
148
|
+
}
|
|
149
|
+
} else if (op === "reduce") {
|
|
150
|
+
if (largeNumber && isString(lastValue)) {
|
|
151
|
+
newVal = largeNumberSubtract(String(lastValue), String(tStep));
|
|
152
|
+
} else {
|
|
153
|
+
newVal = subtract(Number(lastValue || 0), Number(step));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (isUndefined(lastValue)) {
|
|
157
|
+
newVal = putInRangeNumber(newVal, { max, min, lastValue, largeNumber });
|
|
158
|
+
}
|
|
159
|
+
return largeNumber ? newVal : Number(newVal);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type InputNumberErrorType = "exceed-maximum" | "below-minimum" | undefined;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 最大值和最小值校验
|
|
166
|
+
*/
|
|
167
|
+
export function getMaxOrMinValidateResult(p: {
|
|
168
|
+
largeNumber: boolean;
|
|
169
|
+
value: NumberType;
|
|
170
|
+
max: NumberType;
|
|
171
|
+
min: NumberType;
|
|
172
|
+
}): InputNumberErrorType {
|
|
173
|
+
const { largeNumber, value, max, min } = p;
|
|
174
|
+
if (isUndefined(value) || isUndefined(largeNumber)) return undefined;
|
|
175
|
+
if (largeNumber && isNumber(value)) {
|
|
176
|
+
log.warn("InputNumber", "largeNumber value must be a string.");
|
|
177
|
+
}
|
|
178
|
+
let error: InputNumberErrorType;
|
|
179
|
+
if (compareNumber(value, max, largeNumber) > 0) {
|
|
180
|
+
error = "exceed-maximum";
|
|
181
|
+
} else if (compareNumber(value, min, largeNumber) < 0) {
|
|
182
|
+
error = "below-minimum";
|
|
183
|
+
} else {
|
|
184
|
+
error = undefined;
|
|
185
|
+
}
|
|
186
|
+
return error;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const specialCode = ["-", ".", "e", "E", "+"];
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 是否允许输入当前字符,输入字符校验
|
|
193
|
+
* 1.23E+08 就表示 1.23 乘 10 的 8 次方
|
|
194
|
+
* 2e3 表示 2 乘 10 的 3 次方
|
|
195
|
+
*/
|
|
196
|
+
export function canInputNumber(number: string | undefined | null, largeNumber?: boolean) {
|
|
197
|
+
if (["", null, undefined].includes(number)) return true;
|
|
198
|
+
// 数字最前方不允许出现连续的两个 0
|
|
199
|
+
if (number.slice(0, 2) === "00") return false;
|
|
200
|
+
// 不能出现空格
|
|
201
|
+
if (number.match(/\s/g)) return false;
|
|
202
|
+
// 只能出现一个点(.)
|
|
203
|
+
if (number.match(/\./g)?.length > 1) return false;
|
|
204
|
+
// 只能出现一个e(e)
|
|
205
|
+
if (number.match(/e/g)?.length > 1) return false;
|
|
206
|
+
// 只能出现一个负号(-)或 一个正号(+),并且在第一个位置;但允许 3e+10 这种形式
|
|
207
|
+
const tmpNumber = number.slice(1);
|
|
208
|
+
const tmpMatched = tmpNumber.match(/(\+|-)/g);
|
|
209
|
+
if (tmpMatched && (!/e(\+|-)/i.test(tmpNumber) || tmpMatched.length > 1)) return false;
|
|
210
|
+
// 允许输入数字字符
|
|
211
|
+
const isNumber = (largeNumber && isInputNumber(number)) || !Number.isNaN(Number(number));
|
|
212
|
+
if (!isNumber && !specialCode.includes(number.slice(-1))) return false;
|
|
213
|
+
if (/e/i.test(number) && (!/\de/i.test(number) || /e\./.test(number))) return false;
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 是否允许设置组件新值,触发 onChange 事件
|
|
219
|
+
*/
|
|
220
|
+
export function canSetValue(number: string, lastNumber: number) {
|
|
221
|
+
return parseFloat(number) !== lastNumber && !Number.isNaN(Number(number));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 1. 格式化未输入完成的数字,如:如:2e/2+/2.等
|
|
226
|
+
* 2. 处理小数点 decimalPlaces
|
|
227
|
+
* 3. 格式化大数字 formatENumber
|
|
228
|
+
*/
|
|
229
|
+
export function formatUnCompleteNumber(
|
|
230
|
+
number: string,
|
|
231
|
+
extra: {
|
|
232
|
+
decimalPlaces?: InputNumberDecimalPlaces;
|
|
233
|
+
largeNumber?: boolean;
|
|
234
|
+
isToFixed?: boolean;
|
|
235
|
+
} = {}
|
|
236
|
+
): number | string {
|
|
237
|
+
if (["", null, undefined].includes(number) || !/\d+/.test(number)) return undefined;
|
|
238
|
+
const { decimalPlaces, largeNumber, isToFixed } = extra;
|
|
239
|
+
let newNumber = number.replace(/[.|+|\-|e]$/, "");
|
|
240
|
+
if (largeNumber) {
|
|
241
|
+
newNumber = formatENumber(newNumber);
|
|
242
|
+
}
|
|
243
|
+
if (decimalPlaces !== undefined) {
|
|
244
|
+
newNumber = largeNumberToFixed(newNumber, decimalPlaces, largeNumber);
|
|
245
|
+
}
|
|
246
|
+
if (largeNumber) return newNumber;
|
|
247
|
+
return isToFixed ? newNumber : parseFloat(newNumber);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 对千分位进行处理 111,111,222 -> 111111222
|
|
252
|
+
*/
|
|
253
|
+
export function formatThousandths(number: string) {
|
|
254
|
+
const thousandthsRegExp = /^[-+]?\d{1,3}(,\d{3})*(\.(\d*))?$/;
|
|
255
|
+
if (thousandthsRegExp.test(number)) return number.replace(/,/g, "");
|
|
256
|
+
return number;
|
|
257
|
+
}
|
package/utils/isFragment.ts
CHANGED
|
@@ -9,14 +9,14 @@ const REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
|
9
9
|
* Compatible with React 18 or 19 to check if node is a Fragment.
|
|
10
10
|
*/
|
|
11
11
|
export default function isFragment(object: React.ReactElement | null | undefined): boolean {
|
|
12
|
+
if (!object || typeof object !== "object") return false;
|
|
13
|
+
|
|
14
|
+
const obj = object as unknown as { $$typeof?: symbol; type?: symbol | React.ElementType };
|
|
15
|
+
|
|
12
16
|
return (
|
|
13
|
-
// Base object type
|
|
14
|
-
object &&
|
|
15
|
-
typeof object === "object" &&
|
|
16
17
|
// React Element type
|
|
17
|
-
(
|
|
18
|
-
(object as { $$typeof: symbol }).$$typeof === REACT_ELEMENT_TYPE_19) &&
|
|
18
|
+
(obj.$$typeof === REACT_ELEMENT_TYPE_18 || obj.$$typeof === REACT_ELEMENT_TYPE_19) &&
|
|
19
19
|
// React Fragment type
|
|
20
|
-
|
|
20
|
+
obj.type === REACT_FRAGMENT_TYPE
|
|
21
21
|
);
|
|
22
22
|
}
|