@mi-avalon/libs 0.0.24 → 0.0.26
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/components/MiModal/index.d.ts +15 -0
- package/dist/components/MiModal/index.js +70 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -1
- package/dist/constants/date.d.ts +2 -0
- package/dist/constants/date.js +2 -0
- package/dist/constants/pattern.d.ts +66 -0
- package/dist/constants/pattern.js +66 -22
- package/dist/index.es.js +1647 -1180
- package/dist/index.umd.js +15 -15
- package/dist/utils/calc.d.ts +179 -12
- package/dist/utils/calc.js +355 -81
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -1
- package/dist/utils/openModal.d.ts +15 -0
- package/dist/utils/openModal.js +98 -0
- package/package.json +1 -1
package/dist/utils/calc.js
CHANGED
|
@@ -1,92 +1,366 @@
|
|
|
1
1
|
class CMX {
|
|
2
|
+
static factorialCache = new Map();
|
|
2
3
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
4
|
+
* 获取数字的小数位数长度
|
|
5
|
+
* @private
|
|
6
|
+
* @param num 要检查的数字
|
|
7
|
+
* @returns 小数位数长度
|
|
8
|
+
*/
|
|
9
|
+
static getDecimalLength(num) {
|
|
10
|
+
const str = num.toString();
|
|
11
|
+
const decimalIndex = str.indexOf('.');
|
|
12
|
+
return decimalIndex === -1 ? 0 : str.length - decimalIndex - 1;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 将数字转换为整数(移除小数点)
|
|
16
|
+
* @private
|
|
17
|
+
* @param num 要转换的数字
|
|
18
|
+
* @param decimalPlaces 需要补零的小数位数
|
|
19
|
+
* @returns 转换后的整数值
|
|
20
|
+
*/
|
|
21
|
+
static toInteger(num, decimalPlaces) {
|
|
22
|
+
const str = num.toString().replace('.', '');
|
|
23
|
+
return Number(str) * Math.pow(10, decimalPlaces);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 精确加法运算(支持多个参数)
|
|
27
|
+
* @param args 要相加的数字序列
|
|
28
|
+
* @returns 所有数字的和
|
|
29
|
+
* @example
|
|
30
|
+
* cmx.add(0.1, 0.2) // 返回 0.3
|
|
31
|
+
* cmx.add(1, 2, 3) // 返回 6
|
|
32
|
+
*/
|
|
33
|
+
add(...args) {
|
|
34
|
+
if (args.length < 2)
|
|
35
|
+
return args[0] || 0;
|
|
36
|
+
return args.reduce((acc, current) => {
|
|
37
|
+
// 获取两个数的小数位数
|
|
38
|
+
const r1 = CMX.getDecimalLength(acc);
|
|
39
|
+
const r2 = CMX.getDecimalLength(current);
|
|
40
|
+
// 计算最大小数位数和对应的10的幂
|
|
41
|
+
const maxDecimal = Math.max(r1, r2);
|
|
42
|
+
const m = Math.pow(10, maxDecimal);
|
|
43
|
+
// 将两个数调整为相同小数位数的整数
|
|
44
|
+
const adjusted1 = CMX.toInteger(acc, maxDecimal - r1);
|
|
45
|
+
const adjusted2 = CMX.toInteger(current, maxDecimal - r2);
|
|
46
|
+
// 相加后还原小数位
|
|
47
|
+
return (adjusted1 + adjusted2) / m;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 精确减法运算
|
|
52
|
+
* @param arg1 被减数
|
|
53
|
+
* @param arg2 减数
|
|
54
|
+
* @returns 两数之差
|
|
55
|
+
* @example
|
|
56
|
+
* cmx.sub(0.3, 0.1) // 返回 0.2
|
|
57
|
+
*/
|
|
58
|
+
sub(arg1, arg2) {
|
|
59
|
+
const r1 = CMX.getDecimalLength(arg1);
|
|
60
|
+
const r2 = CMX.getDecimalLength(arg2);
|
|
61
|
+
const maxDecimal = Math.max(r1, r2);
|
|
62
|
+
const m = Math.pow(10, maxDecimal);
|
|
63
|
+
// 先转换为整数运算,再还原小数位
|
|
64
|
+
return Number(((arg1 * m - arg2 * m) / m).toFixed(maxDecimal));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 精确乘法运算(支持多个参数)
|
|
68
|
+
* @param args 要相乘的数字序列
|
|
69
|
+
* @returns 所有数字的乘积
|
|
70
|
+
* @example
|
|
71
|
+
* cmx.mul(0.1, 0.2) // 返回 0.02
|
|
72
|
+
* cmx.mul(2, 3, 4) // 返回 24
|
|
73
|
+
*/
|
|
74
|
+
mul(...args) {
|
|
75
|
+
if (args.length < 2)
|
|
76
|
+
return args[0] || 0;
|
|
77
|
+
return args.reduce((acc, current) => {
|
|
78
|
+
// 计算总小数位数
|
|
79
|
+
const decimalPlaces = CMX.getDecimalLength(acc) + CMX.getDecimalLength(current);
|
|
80
|
+
// 移除小数点转换为整数
|
|
81
|
+
const adjusted1 = Number(acc.toString().replace('.', ''));
|
|
82
|
+
const adjusted2 = Number(current.toString().replace('.', ''));
|
|
83
|
+
// 相乘后还原总小数位
|
|
84
|
+
return (adjusted1 * adjusted2) / Math.pow(10, decimalPlaces);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 精确除法运算
|
|
89
|
+
* @param arg1 被除数
|
|
90
|
+
* @param arg2 除数
|
|
91
|
+
* @returns 两数之商
|
|
92
|
+
* @throws {Error} 除数为零时抛出错误
|
|
93
|
+
* @example
|
|
94
|
+
* cmx.div(0.3, 0.1) // 返回 3
|
|
95
|
+
*/
|
|
96
|
+
div(arg1, arg2) {
|
|
97
|
+
if (arg2 === 0)
|
|
98
|
+
throw new Error('除数不能为零');
|
|
99
|
+
// 添加误差补偿
|
|
100
|
+
const compensation = 1 + Number.EPSILON;
|
|
101
|
+
const t1 = CMX.getDecimalLength(arg1);
|
|
102
|
+
const t2 = CMX.getDecimalLength(arg2);
|
|
103
|
+
const r1 = Number(arg1.toString().replace('.', '')) * compensation;
|
|
104
|
+
const r2 = Number(arg2.toString().replace('.', '')) * compensation;
|
|
105
|
+
return (r1 / r2) * Math.pow(10, t2 - t1);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 精确四舍五入
|
|
109
|
+
* @param num 要舍入的数字
|
|
110
|
+
* @param decimalPlaces 保留的小数位数(默认为0)
|
|
111
|
+
* @returns 舍入后的数字
|
|
112
|
+
* @example
|
|
113
|
+
* cmx.round(1.2345, 2) // 返回 1.23
|
|
114
|
+
*/
|
|
115
|
+
round(num, decimalPlaces = 0) {
|
|
116
|
+
const m = Math.pow(10, decimalPlaces);
|
|
117
|
+
return Math.round(num * m) / m;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 计算百分比值
|
|
121
|
+
* @param value 基础值
|
|
122
|
+
* @param percent 百分比
|
|
123
|
+
* @returns 计算后的百分比值
|
|
124
|
+
* @example
|
|
125
|
+
* cmx.percent(200, 15) // 返回 30(200的15%)
|
|
126
|
+
*/
|
|
127
|
+
percent(value, percent) {
|
|
128
|
+
return this.div(this.mul(value, percent), 100);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 计算平均数
|
|
132
|
+
* @param args 要计算平均数的数字序列
|
|
133
|
+
* @returns 平均数
|
|
134
|
+
* @example
|
|
135
|
+
* cmx.average(1, 2, 3) // 返回 2
|
|
136
|
+
*/
|
|
137
|
+
average(...args) {
|
|
138
|
+
if (args.length === 0)
|
|
139
|
+
return 0;
|
|
140
|
+
return this.div(args.reduce((a, b) => this.add(a, b)), args.length);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 判断两个数是否近似相等(解决浮点数精度问题)
|
|
144
|
+
* @param a 第一个数
|
|
145
|
+
* @param b 第二个数
|
|
146
|
+
* @param tolerance 允许的误差范围(默认为1e-10)
|
|
147
|
+
* @returns 如果差值小于误差范围则返回true
|
|
148
|
+
* @example
|
|
149
|
+
* cmx.approxEqual(0.1 + 0.2, 0.3) // 返回 true
|
|
150
|
+
*/
|
|
151
|
+
approxEqual(a, b, tolerance = 1e-10) {
|
|
152
|
+
return Math.abs(this.sub(a, b)) < tolerance;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 计算自然对数(ln(x))
|
|
156
|
+
* @param num 要计算对数的数字
|
|
157
|
+
* @param decimalPlaces 结果保留的小数位数(默认保留10位)
|
|
158
|
+
* @returns 自然对数值
|
|
159
|
+
* @throws {Error} 当输入小于等于0时抛出错误
|
|
160
|
+
* @example
|
|
161
|
+
* cmx.ln(1) // 返回 0
|
|
162
|
+
* cmx.ln(Math.E) // 返回 1
|
|
163
|
+
*/
|
|
164
|
+
ln(num, decimalPlaces = 10) {
|
|
165
|
+
if (num <= 0)
|
|
166
|
+
throw new Error('对数函数的输入必须为正数');
|
|
167
|
+
if (num === 1)
|
|
168
|
+
return 0;
|
|
169
|
+
// 使用泰勒级数展开计算自然对数
|
|
170
|
+
let result = 0;
|
|
171
|
+
const tolerance = Math.pow(10, -decimalPlaces - 1);
|
|
172
|
+
let term = this.div(this.sub(num, 1), this.add(num, 1));
|
|
173
|
+
const termSquared = this.mul(term, term);
|
|
174
|
+
let currentTerm = term;
|
|
175
|
+
let n = 1;
|
|
176
|
+
do {
|
|
177
|
+
result = this.add(result, this.div(currentTerm, n));
|
|
178
|
+
currentTerm = this.mul(currentTerm, termSquared);
|
|
179
|
+
n += 2;
|
|
180
|
+
} while (Math.abs(currentTerm) > tolerance);
|
|
181
|
+
return this.round(this.mul(2, result), decimalPlaces);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 高精度指数函数(解决Math.exp的精度问题)
|
|
185
|
+
* @param x 指数
|
|
186
|
+
* @param decimalPlaces 精度位数(默认10位)
|
|
187
|
+
* @returns e^x 的精确值
|
|
188
|
+
* @example
|
|
189
|
+
* cmx.exp(1) // 2.7182818285(比Math.exp(1)更可控精度)
|
|
190
|
+
* cmx.exp(-3.5) // 0.0301973834
|
|
191
|
+
*/
|
|
192
|
+
exp(x, decimalPlaces = 10) {
|
|
193
|
+
// 添加提前终止条件
|
|
194
|
+
if (x === 0)
|
|
195
|
+
return 1;
|
|
196
|
+
if (x === 1)
|
|
197
|
+
return Math.E;
|
|
198
|
+
let result = 1;
|
|
199
|
+
let term = 1;
|
|
200
|
+
const tolerance = Math.pow(10, -decimalPlaces - 1);
|
|
201
|
+
let n = 1;
|
|
202
|
+
let prevResult = 0;
|
|
203
|
+
do {
|
|
204
|
+
prevResult = result;
|
|
205
|
+
term = this.div(this.mul(term, x), n);
|
|
206
|
+
result = this.add(result, term);
|
|
207
|
+
n++;
|
|
208
|
+
} while (Math.abs(term) > tolerance &&
|
|
209
|
+
!this.approxEqual(result, prevResult, tolerance) // 新增终止条件
|
|
210
|
+
);
|
|
211
|
+
return this.round(result, decimalPlaces);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* 精确计算平方根(解决Math.sqrt的精度问题)
|
|
215
|
+
* @param num 输入数字(必须 ≥0)
|
|
216
|
+
* @param decimalPlaces 结果精度(默认10位)
|
|
217
|
+
* @returns 精确的平方根值
|
|
218
|
+
* @throws {Error} 输入负数时抛出
|
|
219
|
+
* @example
|
|
220
|
+
* cmx.sqrt(2) // 1.4142135624 (Math.sqrt(2)可能产生微小误差)
|
|
221
|
+
*/
|
|
222
|
+
sqrt(num, decimalPlaces = 10) {
|
|
223
|
+
if (num < 0)
|
|
224
|
+
throw new Error('负数平方根需使用复数计算');
|
|
225
|
+
if (num === 0)
|
|
226
|
+
return 0;
|
|
227
|
+
// 牛顿迭代法+自定义精度控制
|
|
228
|
+
let guess = num / 2;
|
|
229
|
+
const tolerance = Math.pow(10, -decimalPlaces - 1);
|
|
230
|
+
do {
|
|
231
|
+
guess = this.div(this.add(guess, this.div(num, guess)), 2);
|
|
232
|
+
} while (Math.abs(this.sub(this.mul(guess, guess), num)) > tolerance);
|
|
233
|
+
return this.round(guess, decimalPlaces);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 安全对数计算(解决Math.log的边界问题)
|
|
237
|
+
* @param num 输入数字(支持 ≤0 的特殊处理)
|
|
238
|
+
* @param options 配置项:
|
|
239
|
+
* - safe: 是否返回安全值(默认true)
|
|
240
|
+
* - replaceNeg: 负数替换值(默认NaN)
|
|
241
|
+
* - replaceZero: 零替换值(默认-Infinity)
|
|
242
|
+
* @returns 处理后的结果
|
|
243
|
+
* @example
|
|
244
|
+
* cmx.safeLog(-1) // NaN(Math.log直接报错)
|
|
245
|
+
* cmx.safeLog(0) // -Infinity(可配置替换值)
|
|
246
|
+
*/
|
|
247
|
+
safeLog(num, options = {}) {
|
|
248
|
+
const { safe = true, replaceNeg = NaN, replaceZero = -Infinity } = options;
|
|
249
|
+
if (num > 0)
|
|
250
|
+
return Math.log(num);
|
|
251
|
+
if (!safe)
|
|
252
|
+
throw new Error('Invalid input');
|
|
253
|
+
return num === 0 ? replaceZero : replaceNeg;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* 精确阶乘(解决Math无阶乘方法的问题)
|
|
257
|
+
* @param n 输入整数(0≤n≤170)
|
|
258
|
+
* @returns 精确结果(超过170返回Infinity)
|
|
259
|
+
* @example
|
|
260
|
+
* cmx.factorial(20) // 2432902008176640000(JS整数精确范围)
|
|
261
|
+
*/
|
|
262
|
+
factorial(n) {
|
|
263
|
+
if (!Number.isInteger(n) || n < 0)
|
|
264
|
+
return NaN;
|
|
265
|
+
if (n < 0)
|
|
266
|
+
return NaN;
|
|
267
|
+
if (n > Number.MAX_SAFE_INTEGER) {
|
|
268
|
+
// 使用BigInt计算后转换为科学计数法
|
|
269
|
+
let result = BigInt(1);
|
|
270
|
+
for (let i = 2; i <= n; i++) {
|
|
271
|
+
result *= BigInt(i);
|
|
30
272
|
}
|
|
273
|
+
return Number(result.toString());
|
|
31
274
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
r1 = arg1.toString().split('.')[1].length;
|
|
45
|
-
}
|
|
46
|
-
catch (e) {
|
|
47
|
-
r1 = 0;
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
r2 = arg2.toString().split('.')[1].length;
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
r2 = 0;
|
|
275
|
+
if (n > 170)
|
|
276
|
+
return Infinity;
|
|
277
|
+
if (CMX.factorialCache.has(n))
|
|
278
|
+
return CMX.factorialCache.get(n);
|
|
279
|
+
let result = 1;
|
|
280
|
+
for (let i = 2; i <= n; i++) {
|
|
281
|
+
if (CMX.factorialCache.has(i)) {
|
|
282
|
+
result = CMX.factorialCache.get(i);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
result = this.mul(result, i);
|
|
286
|
+
CMX.factorialCache.set(i, result); // 缓存中间结果
|
|
54
287
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* 双曲函数精确计算(解决大数精度问题)
|
|
292
|
+
* @param x 输入值
|
|
293
|
+
* @param type 函数类型:'sinh' | 'cosh' | 'tanh'
|
|
294
|
+
* @param decimalPlaces 精度(默认10位)
|
|
295
|
+
* @returns 计算结果
|
|
296
|
+
* @example
|
|
297
|
+
* cmx.hypFunc(1, 'tanh') // 0.761594156(比Math.tanh更精确)
|
|
298
|
+
*/
|
|
299
|
+
hypFunc(x, type, decimalPlaces = 10) {
|
|
300
|
+
// 使用泰勒展开式避免大数计算误差
|
|
301
|
+
const expX = this.exp(x, decimalPlaces + 2);
|
|
302
|
+
const expNegX = this.exp(-x, decimalPlaces + 2);
|
|
303
|
+
switch (type) {
|
|
304
|
+
case 'sinh':
|
|
305
|
+
return this.round(this.div(this.sub(expX, expNegX), 2), decimalPlaces);
|
|
306
|
+
case 'cosh':
|
|
307
|
+
return this.round(this.div(this.add(expX, expNegX), 2), decimalPlaces);
|
|
308
|
+
case 'tanh':
|
|
309
|
+
return this.round(this.div(this.sub(expX, expNegX), this.add(expX, expNegX)), decimalPlaces);
|
|
310
|
+
default:
|
|
311
|
+
throw new Error('不支持的函数类型');
|
|
66
312
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* 精确排列组合(解决大数计算问题)
|
|
316
|
+
* @param n 总数
|
|
317
|
+
* @param k 选取数
|
|
318
|
+
* @param type 计算类型:'permutation' | 'combination'
|
|
319
|
+
* @returns 精确结果
|
|
320
|
+
* @example
|
|
321
|
+
* cmx.permComb(100, 5, 'combination') // 75287520
|
|
322
|
+
*/
|
|
323
|
+
permComb(n, k, type) {
|
|
324
|
+
if (!Number.isInteger(n) || !Number.isInteger(k) || k > n || k < 0) {
|
|
325
|
+
return NaN;
|
|
70
326
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
div = function (arg1, arg2) {
|
|
78
|
-
let t1 = 0, t2 = 0, r1, r2;
|
|
79
|
-
try {
|
|
80
|
-
t1 = arg1.toString().split('.')[1].length;
|
|
327
|
+
let result = 1;
|
|
328
|
+
for (let i = 0; i < k; i++) {
|
|
329
|
+
result = this.mul(result, n - i);
|
|
330
|
+
if (type === 'combination') {
|
|
331
|
+
result = this.div(result, i + 1);
|
|
332
|
+
}
|
|
81
333
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
334
|
+
return result;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* 计算最大公约数(GCD)
|
|
338
|
+
* @param a 第一个数字
|
|
339
|
+
* @param b 第二个数字
|
|
340
|
+
* @returns 最大公约数
|
|
341
|
+
* @example
|
|
342
|
+
* cmx.gcd(48, 18) // 返回 6
|
|
343
|
+
*/
|
|
344
|
+
gcd(a, b) {
|
|
345
|
+
a = Math.abs(a);
|
|
346
|
+
b = Math.abs(b);
|
|
347
|
+
while (b !== 0) {
|
|
348
|
+
const temp = b;
|
|
349
|
+
b = a % b;
|
|
350
|
+
a = temp;
|
|
85
351
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
352
|
+
return a;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* 计算最小公倍数(LCM)
|
|
356
|
+
* @param a 第一个数字
|
|
357
|
+
* @param b 第二个数字
|
|
358
|
+
* @returns 最小公倍数
|
|
359
|
+
* @example
|
|
360
|
+
* cmx.lcm(12, 15) // 返回 60
|
|
361
|
+
*/
|
|
362
|
+
lcm(a, b) {
|
|
363
|
+
return this.div(this.mul(a, b), this.gcd(a, b));
|
|
364
|
+
}
|
|
91
365
|
}
|
|
92
366
|
export const cmx = new CMX();
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ModalProps } from 'antd';
|
|
2
|
+
import { type ComponentType } from 'react';
|
|
3
|
+
interface IModalBaseClosedParams {
|
|
4
|
+
cancel?: boolean;
|
|
5
|
+
ok?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface IModalBaseProps extends ModalProps {
|
|
8
|
+
onClosed?: (params?: IModalBaseClosedParams) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface IModalControls<T = any> {
|
|
11
|
+
destroy: (params?: IModalBaseClosedParams) => void;
|
|
12
|
+
update: (configUpdate: Partial<T> | ((prevConfig: T) => T)) => void;
|
|
13
|
+
}
|
|
14
|
+
declare function openModal<ITModalProps extends IModalBaseProps = IModalBaseProps>(DialogComponent: ComponentType<ITModalProps>, initialConfig: ITModalProps): IModalControls<ITModalProps>;
|
|
15
|
+
export { openModal };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as ReactDOMClient from 'react-dom/client';
|
|
3
|
+
const { createRoot } = ReactDOMClient;
|
|
4
|
+
const destroyFns = [];
|
|
5
|
+
let modalContainer = null;
|
|
6
|
+
let root = null;
|
|
7
|
+
function getOrCreateContainer() {
|
|
8
|
+
if (!modalContainer) {
|
|
9
|
+
modalContainer = document.createElement('div');
|
|
10
|
+
document.body.appendChild(modalContainer);
|
|
11
|
+
}
|
|
12
|
+
return modalContainer;
|
|
13
|
+
}
|
|
14
|
+
function openModal(DialogComponent, initialConfig) {
|
|
15
|
+
const container = getOrCreateContainer();
|
|
16
|
+
let currentConfig = {
|
|
17
|
+
open: true,
|
|
18
|
+
...initialConfig,
|
|
19
|
+
// 默认自动关闭
|
|
20
|
+
onClosed: initialConfig.onClosed ||
|
|
21
|
+
((params) => {
|
|
22
|
+
unifiedDestroy(params);
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
if (!root) {
|
|
26
|
+
try {
|
|
27
|
+
root = createRoot(container);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('Failed to create root:', error);
|
|
31
|
+
return {
|
|
32
|
+
destroy: () => { },
|
|
33
|
+
update: () => { },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const cleanup = () => {
|
|
38
|
+
if (root) {
|
|
39
|
+
root.unmount();
|
|
40
|
+
root = null;
|
|
41
|
+
}
|
|
42
|
+
if (modalContainer && modalContainer.parentNode) {
|
|
43
|
+
modalContainer.parentNode.removeChild(modalContainer);
|
|
44
|
+
modalContainer = null;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const destroy = (params) => {
|
|
48
|
+
if (typeof currentConfig.onClosed === 'function') {
|
|
49
|
+
currentConfig.onClosed(params);
|
|
50
|
+
}
|
|
51
|
+
// 从 destroyFns 中移除
|
|
52
|
+
const index = destroyFns.indexOf(destroy);
|
|
53
|
+
if (index !== -1) {
|
|
54
|
+
destroyFns.splice(index, 1);
|
|
55
|
+
}
|
|
56
|
+
// 销毁 modal
|
|
57
|
+
cleanup();
|
|
58
|
+
};
|
|
59
|
+
const render = (props) => {
|
|
60
|
+
if (root) {
|
|
61
|
+
root.render(_jsx(DialogComponent, { ...props }));
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const update = (configUpdate) => {
|
|
65
|
+
currentConfig =
|
|
66
|
+
typeof configUpdate === 'function'
|
|
67
|
+
? configUpdate(currentConfig)
|
|
68
|
+
: { ...currentConfig, ...configUpdate };
|
|
69
|
+
render(currentConfig);
|
|
70
|
+
};
|
|
71
|
+
// 统一的销毁函数
|
|
72
|
+
const unifiedDestroy = (params) => {
|
|
73
|
+
// 如果当前配置是打开的,关闭
|
|
74
|
+
if (currentConfig.open) {
|
|
75
|
+
currentConfig = {
|
|
76
|
+
...currentConfig,
|
|
77
|
+
open: false,
|
|
78
|
+
onClosed: (closedParams) => {
|
|
79
|
+
if (initialConfig.onClosed) {
|
|
80
|
+
initialConfig.onClosed(closedParams || params);
|
|
81
|
+
}
|
|
82
|
+
destroy(closedParams || params);
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
render(currentConfig);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.warn('Modal is already closed.');
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
render(currentConfig);
|
|
92
|
+
destroyFns.push(unifiedDestroy);
|
|
93
|
+
return {
|
|
94
|
+
destroy: unifiedDestroy,
|
|
95
|
+
update,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export { openModal };
|