@tuya-miniapp/smart-ui 2.12.0-beta-4 → 2.12.0-beta-5

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.
@@ -3,6 +3,7 @@ import { SmartComponent } from '../common/component';
3
3
  import { commonProps, inputProps, textareaProps } from './props';
4
4
  import Xmark from '@tuya-miniapp/icons/dist/svg/Xmark';
5
5
  import tyApi from '../common/ty';
6
+ import { formatNumber, parseFormattedNumber } from './numberFormat';
6
7
  SmartComponent({
7
8
  field: true,
8
9
  classes: ['input-class', 'right-icon-class', 'label-class'],
@@ -29,6 +30,12 @@ SmartComponent({
29
30
  }, extraEventParams: {
30
31
  type: Boolean,
31
32
  value: false,
33
+ }, numberFormat: {
34
+ type: Boolean,
35
+ value: false,
36
+ }, locale: {
37
+ type: String,
38
+ value: '',
32
39
  } }),
33
40
  data: {
34
41
  focused: false,
@@ -38,18 +45,24 @@ SmartComponent({
38
45
  watch: {
39
46
  value(value) {
40
47
  if (value !== this.value) {
41
- this.setData({ innerValue: value });
42
48
  this.value = value;
49
+ this.updateDisplayValue();
43
50
  this.setShowClear();
44
51
  }
45
52
  },
53
+ numberFormat() {
54
+ this.updateDisplayValue();
55
+ },
56
+ locale() {
57
+ this.updateDisplayValue();
58
+ },
46
59
  clearTrigger() {
47
60
  this.setShowClear();
48
61
  },
49
62
  },
50
63
  created() {
51
64
  this.value = this.data.value;
52
- this.setData({ innerValue: this.value });
65
+ this.updateDisplayValue();
53
66
  },
54
67
  methods: {
55
68
  formatValue(value) {
@@ -59,10 +72,29 @@ SmartComponent({
59
72
  }
60
73
  return value;
61
74
  },
75
+ // 更新显示值(根据 numberFormat 决定是否格式化)
76
+ // 聚焦时保留末尾小数点(如 23.)不格式化掉,避免打断用户输入;失焦后再做完整格式化
77
+ updateDisplayValue() {
78
+ const { numberFormat, locale } = this.data;
79
+ let displayValue = this.value || '';
80
+ if (numberFormat && displayValue) {
81
+ const preserveTrailingDecimal = !!this.focused;
82
+ displayValue = formatNumber(displayValue, locale, { preserveTrailingDecimal });
83
+ }
84
+ this.setData({ innerValue: displayValue });
85
+ },
62
86
  onInput(event) {
63
87
  const { value = '' } = event.detail || {};
64
- const formatValue = this.formatValue(value);
88
+ const { numberFormat, locale } = this.data;
89
+ let rawValue = value;
90
+ // 如果启用了数字格式化,需要将格式化后的输入值解析为原始格式
91
+ if (numberFormat) {
92
+ rawValue = parseFormattedNumber(value, locale);
93
+ }
94
+ const formatValue = this.formatValue(rawValue);
65
95
  this.value = formatValue;
96
+ // 更新显示值
97
+ this.updateDisplayValue();
66
98
  this.setShowClear();
67
99
  return this.emitChange(Object.assign(Object.assign({}, event.detail), { value: formatValue }));
68
100
  },
@@ -74,6 +106,23 @@ SmartComponent({
74
106
  },
75
107
  onBlur(event) {
76
108
  this.focused = false;
109
+ const { numberFormat, locale } = this.data;
110
+ // 失焦时再做一次完整格式化,去掉多余的小数点(如 23. -> 23),并同步内部 value
111
+ if (numberFormat && this.value) {
112
+ const displayValue = formatNumber(this.value, locale);
113
+ const normalizedValue = parseFormattedNumber(displayValue, locale);
114
+ if (normalizedValue !== this.value) {
115
+ this.value = normalizedValue;
116
+ this.setData({ innerValue: displayValue });
117
+ this.emitChange({ value: this.value });
118
+ }
119
+ else {
120
+ this.updateDisplayValue();
121
+ }
122
+ }
123
+ else {
124
+ this.updateDisplayValue();
125
+ }
77
126
  this.setShowClear();
78
127
  this.$emit('blur', event.detail);
79
128
  },
@@ -84,8 +133,8 @@ SmartComponent({
84
133
  this.$emit('click-input', event.detail);
85
134
  },
86
135
  onClear() {
87
- this.setData({ innerValue: '' });
88
136
  this.value = '';
137
+ this.updateDisplayValue();
89
138
  this.setShowClear();
90
139
  nextTick(() => {
91
140
  this.emitChange({ value: '' });
@@ -94,16 +143,21 @@ SmartComponent({
94
143
  },
95
144
  onConfirm(event) {
96
145
  const { value = '' } = event.detail || {};
97
- this.value = value;
146
+ const { numberFormat, locale } = this.data;
147
+ let rawValue = value;
148
+ // 如果启用了数字格式化,需要解析为原始格式
149
+ if (numberFormat) {
150
+ rawValue = parseFormattedNumber(value, locale);
151
+ }
152
+ this.value = rawValue;
153
+ this.updateDisplayValue();
98
154
  this.setShowClear();
99
- this.$emit('confirm', value);
155
+ this.$emit('confirm', rawValue);
100
156
  },
101
157
  setValue(value) {
102
158
  this.value = value;
159
+ this.updateDisplayValue();
103
160
  this.setShowClear();
104
- if (value === '') {
105
- this.setData({ innerValue: '' });
106
- }
107
161
  this.emitChange({ value });
108
162
  },
109
163
  onLineChange(event) {
@@ -122,7 +176,8 @@ SmartComponent({
122
176
  const data = extraEventParams
123
177
  ? Object.assign(Object.assign({}, detail), { callback: (data) => {
124
178
  result = data;
125
- this.setData({ innerValue: data.value });
179
+ this.value = data.value;
180
+ this.updateDisplayValue();
126
181
  } }) : detail.value;
127
182
  this.$emit('input', data);
128
183
  this.$emit('change', data);
@@ -0,0 +1,11 @@
1
+ export interface NumberFormatConfig {
2
+ thousandsSeparator: string;
3
+ decimalSeparator: string;
4
+ }
5
+ export declare function getNumberFormatConfig(locale: string): NumberFormatConfig;
6
+ export interface FormatNumberOptions {
7
+ /** 为 true 时保留末尾的小数点(用于聚焦输入中,避免 "23." 被格式成 "23" 打断输入) */
8
+ preserveTrailingDecimal?: boolean;
9
+ }
10
+ export declare function formatNumber(value: string, locale: string, options?: FormatNumberOptions): string;
11
+ export declare function parseFormattedNumber(formattedValue: string, locale: string): string;
@@ -0,0 +1,148 @@
1
+ import { getSystemInfoSync } from '../common/utils';
2
+ // 提取语言代码:从 locale 中提取第一部分(去掉 - 和 _ 后面的所有内容)
3
+ function getLangKey(locale) {
4
+ if (!locale) {
5
+ return '';
6
+ }
7
+ // 转换为小写并去除空格
8
+ const normalized = locale.toLowerCase().trim();
9
+ // 统一将下划线和连字符作为分隔符,取第一部分
10
+ const langKey = normalized.split(/[-_]/)[0];
11
+ return langKey;
12
+ }
13
+ // 根据 locale 获取数字格式化配置
14
+ export function getNumberFormatConfig(locale) {
15
+ // 如果没有指定 locale,尝试从系统获取
16
+ if (!locale) {
17
+ try {
18
+ const systemInfo = getSystemInfoSync();
19
+ // 尝试多个可能的字段名
20
+ locale =
21
+ systemInfo.language ||
22
+ systemInfo.locale ||
23
+ systemInfo.lang ||
24
+ 'zh-CN';
25
+ }
26
+ catch (e) {
27
+ locale = 'zh-CN';
28
+ }
29
+ }
30
+ // 规范化 locale(统一大小写和下划线)
31
+ const normalizedLocale = locale.toLowerCase().trim().replace(/_/g, '-');
32
+ // 只配置非标准格式(非 1,234.56 格式)
33
+ // 默认格式:thousandsSeparator: ',', decimalSeparator: '.' (1,234.56)
34
+ const formatMap = {
35
+ // 德语地区:1.000,1312 (点作为千分位,逗号作为小数)
36
+ de: { thousandsSeparator: '.', decimalSeparator: ',' },
37
+ // 法语地区:1 000,1312 (空格作为千分位,逗号作为小数)
38
+ fr: { thousandsSeparator: ' ', decimalSeparator: ',' },
39
+ // 意大利语:1.000,1312
40
+ it: { thousandsSeparator: '.', decimalSeparator: ',' },
41
+ // 西班牙语:1.000,1312
42
+ es: { thousandsSeparator: '.', decimalSeparator: ',' },
43
+ // 葡萄牙语:1.000,1312
44
+ pt: { thousandsSeparator: '.', decimalSeparator: ',' },
45
+ // 俄语:1 000,1312 (空格作为千分位,逗号作为小数)
46
+ ru: { thousandsSeparator: ' ', decimalSeparator: ',' },
47
+ // 部分阿拉伯国家
48
+ 'es-419': { thousandsSeparator: ',', decimalSeparator: '.' },
49
+ 'pt-br': { thousandsSeparator: '.', decimalSeparator: ',' },
50
+ 'ar-ma': { thousandsSeparator: ' ', decimalSeparator: ',' },
51
+ 'ar-tn': { thousandsSeparator: ' ', decimalSeparator: ',' },
52
+ 'de-ch': { thousandsSeparator: "'", decimalSeparator: '.' },
53
+ 'es-mx': { thousandsSeparator: ',', decimalSeparator: '.' },
54
+ 'fr-ch': { thousandsSeparator: "'", decimalSeparator: '.' }, // 瑞士法语
55
+ };
56
+ // 策略1: 先尝试完整匹配(处理特殊国家,如 'de-ch', 'ar-ma', 'ar-tn')
57
+ if (formatMap[normalizedLocale]) {
58
+ return formatMap[normalizedLocale];
59
+ }
60
+ // 策略2: 提取语言代码进行匹配
61
+ const langKey = getLangKey(locale);
62
+ if (langKey && formatMap[langKey]) {
63
+ return formatMap[langKey];
64
+ }
65
+ // 默认使用标准格式:1,234.56 (千分位逗号,小数点)
66
+ return { thousandsSeparator: ',', decimalSeparator: '.' };
67
+ }
68
+ // 格式化数字:将 "1000.1312" 或 "-1000.1312" 格式化为带分隔符的字符串
69
+ export function formatNumber(value, locale, options) {
70
+ if (!value || value === '') {
71
+ return '';
72
+ }
73
+ // 仅保留数字、小数点、减号;连续前导减号按「负负得正」处理
74
+ const raw = value.replace(/[^-0-9.]/g, '');
75
+ let i = 0;
76
+ while (i < raw.length && raw[i] === '-') {
77
+ i++;
78
+ }
79
+ const negative = i % 2 === 1;
80
+ const cleanValue = raw.slice(i).replace(/-/g, '');
81
+ if (!cleanValue) {
82
+ return negative ? '-' : '';
83
+ }
84
+ // 聚焦输入时可能为 "23.",保留末尾小数点以便用户继续输入小数
85
+ const hasTrailingDecimal = (options === null || options === void 0 ? void 0 : options.preserveTrailingDecimal) && /\.$/.test(cleanValue);
86
+ // 分离整数部分和小数部分(处理多个小数点的情况)
87
+ const valueToFormat = hasTrailingDecimal ? cleanValue.slice(0, -1) : cleanValue;
88
+ const parts = valueToFormat.split('.');
89
+ const integerPart = parts[0] || '';
90
+ const decimalPart = parts.length > 1 ? parts.slice(1).join('') : '';
91
+ const config = getNumberFormatConfig(locale);
92
+ // 格式化整数部分(添加千分位分隔符)
93
+ let formattedInteger = '';
94
+ if (integerPart) {
95
+ for (let j = integerPart.length - 1, count = 0; j >= 0; j--) {
96
+ if (count > 0 && count % 3 === 0) {
97
+ formattedInteger = config.thousandsSeparator + formattedInteger;
98
+ }
99
+ formattedInteger = integerPart[j] + formattedInteger;
100
+ count++;
101
+ }
102
+ }
103
+ const prefix = negative ? '-' : '';
104
+ if (decimalPart) {
105
+ return prefix + formattedInteger + config.decimalSeparator + decimalPart;
106
+ }
107
+ if (hasTrailingDecimal) {
108
+ return prefix + (formattedInteger || '0') + config.decimalSeparator;
109
+ }
110
+ return prefix + (formattedInteger || '0');
111
+ }
112
+ // 解析格式化后的数字:将格式化字符串转换回 "1000.1312" 或 "-1000.1312" 格式
113
+ export function parseFormattedNumber(formattedValue, locale) {
114
+ if (!formattedValue || formattedValue === '') {
115
+ return '';
116
+ }
117
+ let body = formattedValue.trim();
118
+ let negative = false;
119
+ const ch0 = body.charAt(0);
120
+ if (ch0 === '-' || ch0 === '\u2212') {
121
+ negative = true;
122
+ body = body.slice(1).trim();
123
+ }
124
+ if (!body) {
125
+ return negative ? '-' : '';
126
+ }
127
+ const config = getNumberFormatConfig(locale);
128
+ // 移除千分位分隔符(需要转义特殊字符)
129
+ const escapedSeparator = config.thousandsSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
130
+ let cleaned = body.replace(new RegExp(escapedSeparator, 'g'), '');
131
+ // 将小数分隔符转换为标准小数点(只替换第一个,因为可能有多个)
132
+ if (config.decimalSeparator !== '.') {
133
+ const decimalIndex = cleaned.indexOf(config.decimalSeparator);
134
+ if (decimalIndex !== -1) {
135
+ cleaned = cleaned.substring(0, decimalIndex) + '.' + cleaned.substring(decimalIndex + 1);
136
+ }
137
+ }
138
+ // 确保只有一个小数点
139
+ const parts = cleaned.split('.');
140
+ if (parts.length > 2) {
141
+ cleaned = parts[0] + '.' + parts.slice(1).join('');
142
+ }
143
+ const num = cleaned.replace(/[^\d.]/g, '');
144
+ if (!num) {
145
+ return negative ? '-' : '';
146
+ }
147
+ return negative ? '-' + num : num;
148
+ }
@@ -19,6 +19,7 @@ var component_1 = require("../common/component");
19
19
  var props_1 = require("./props");
20
20
  var Xmark_1 = __importDefault(require("@tuya-miniapp/icons/dist/svg/Xmark"));
21
21
  var ty_1 = __importDefault(require("../common/ty"));
22
+ var numberFormat_1 = require("./numberFormat");
22
23
  (0, component_1.SmartComponent)({
23
24
  field: true,
24
25
  classes: ['input-class', 'right-icon-class', 'label-class'],
@@ -45,6 +46,12 @@ var ty_1 = __importDefault(require("../common/ty"));
45
46
  }, extraEventParams: {
46
47
  type: Boolean,
47
48
  value: false,
49
+ }, numberFormat: {
50
+ type: Boolean,
51
+ value: false,
52
+ }, locale: {
53
+ type: String,
54
+ value: '',
48
55
  } }),
49
56
  data: {
50
57
  focused: false,
@@ -54,18 +61,24 @@ var ty_1 = __importDefault(require("../common/ty"));
54
61
  watch: {
55
62
  value: function (value) {
56
63
  if (value !== this.value) {
57
- this.setData({ innerValue: value });
58
64
  this.value = value;
65
+ this.updateDisplayValue();
59
66
  this.setShowClear();
60
67
  }
61
68
  },
69
+ numberFormat: function () {
70
+ this.updateDisplayValue();
71
+ },
72
+ locale: function () {
73
+ this.updateDisplayValue();
74
+ },
62
75
  clearTrigger: function () {
63
76
  this.setShowClear();
64
77
  },
65
78
  },
66
79
  created: function () {
67
80
  this.value = this.data.value;
68
- this.setData({ innerValue: this.value });
81
+ this.updateDisplayValue();
69
82
  },
70
83
  methods: {
71
84
  formatValue: function (value) {
@@ -75,10 +88,29 @@ var ty_1 = __importDefault(require("../common/ty"));
75
88
  }
76
89
  return value;
77
90
  },
91
+ // 更新显示值(根据 numberFormat 决定是否格式化)
92
+ // 聚焦时保留末尾小数点(如 23.)不格式化掉,避免打断用户输入;失焦后再做完整格式化
93
+ updateDisplayValue: function () {
94
+ var _a = this.data, numberFormat = _a.numberFormat, locale = _a.locale;
95
+ var displayValue = this.value || '';
96
+ if (numberFormat && displayValue) {
97
+ var preserveTrailingDecimal = !!this.focused;
98
+ displayValue = (0, numberFormat_1.formatNumber)(displayValue, locale, { preserveTrailingDecimal: preserveTrailingDecimal });
99
+ }
100
+ this.setData({ innerValue: displayValue });
101
+ },
78
102
  onInput: function (event) {
79
103
  var _a = (event.detail || {}).value, value = _a === void 0 ? '' : _a;
80
- var formatValue = this.formatValue(value);
104
+ var _b = this.data, numberFormat = _b.numberFormat, locale = _b.locale;
105
+ var rawValue = value;
106
+ // 如果启用了数字格式化,需要将格式化后的输入值解析为原始格式
107
+ if (numberFormat) {
108
+ rawValue = (0, numberFormat_1.parseFormattedNumber)(value, locale);
109
+ }
110
+ var formatValue = this.formatValue(rawValue);
81
111
  this.value = formatValue;
112
+ // 更新显示值
113
+ this.updateDisplayValue();
82
114
  this.setShowClear();
83
115
  return this.emitChange(__assign(__assign({}, event.detail), { value: formatValue }));
84
116
  },
@@ -90,6 +122,23 @@ var ty_1 = __importDefault(require("../common/ty"));
90
122
  },
91
123
  onBlur: function (event) {
92
124
  this.focused = false;
125
+ var _a = this.data, numberFormat = _a.numberFormat, locale = _a.locale;
126
+ // 失焦时再做一次完整格式化,去掉多余的小数点(如 23. -> 23),并同步内部 value
127
+ if (numberFormat && this.value) {
128
+ var displayValue = (0, numberFormat_1.formatNumber)(this.value, locale);
129
+ var normalizedValue = (0, numberFormat_1.parseFormattedNumber)(displayValue, locale);
130
+ if (normalizedValue !== this.value) {
131
+ this.value = normalizedValue;
132
+ this.setData({ innerValue: displayValue });
133
+ this.emitChange({ value: this.value });
134
+ }
135
+ else {
136
+ this.updateDisplayValue();
137
+ }
138
+ }
139
+ else {
140
+ this.updateDisplayValue();
141
+ }
93
142
  this.setShowClear();
94
143
  this.$emit('blur', event.detail);
95
144
  },
@@ -101,8 +150,8 @@ var ty_1 = __importDefault(require("../common/ty"));
101
150
  },
102
151
  onClear: function () {
103
152
  var _this = this;
104
- this.setData({ innerValue: '' });
105
153
  this.value = '';
154
+ this.updateDisplayValue();
106
155
  this.setShowClear();
107
156
  (0, utils_1.nextTick)(function () {
108
157
  _this.emitChange({ value: '' });
@@ -111,16 +160,21 @@ var ty_1 = __importDefault(require("../common/ty"));
111
160
  },
112
161
  onConfirm: function (event) {
113
162
  var _a = (event.detail || {}).value, value = _a === void 0 ? '' : _a;
114
- this.value = value;
163
+ var _b = this.data, numberFormat = _b.numberFormat, locale = _b.locale;
164
+ var rawValue = value;
165
+ // 如果启用了数字格式化,需要解析为原始格式
166
+ if (numberFormat) {
167
+ rawValue = (0, numberFormat_1.parseFormattedNumber)(value, locale);
168
+ }
169
+ this.value = rawValue;
170
+ this.updateDisplayValue();
115
171
  this.setShowClear();
116
- this.$emit('confirm', value);
172
+ this.$emit('confirm', rawValue);
117
173
  },
118
174
  setValue: function (value) {
119
175
  this.value = value;
176
+ this.updateDisplayValue();
120
177
  this.setShowClear();
121
- if (value === '') {
122
- this.setData({ innerValue: '' });
123
- }
124
178
  this.emitChange({ value: value });
125
179
  },
126
180
  onLineChange: function (event) {
@@ -140,7 +194,8 @@ var ty_1 = __importDefault(require("../common/ty"));
140
194
  var data = extraEventParams
141
195
  ? __assign(__assign({}, detail), { callback: function (data) {
142
196
  result = data;
143
- _this.setData({ innerValue: data.value });
197
+ _this.value = data.value;
198
+ _this.updateDisplayValue();
144
199
  } }) : detail.value;
145
200
  this.$emit('input', data);
146
201
  this.$emit('change', data);
@@ -0,0 +1,11 @@
1
+ export interface NumberFormatConfig {
2
+ thousandsSeparator: string;
3
+ decimalSeparator: string;
4
+ }
5
+ export declare function getNumberFormatConfig(locale: string): NumberFormatConfig;
6
+ export interface FormatNumberOptions {
7
+ /** 为 true 时保留末尾的小数点(用于聚焦输入中,避免 "23." 被格式成 "23" 打断输入) */
8
+ preserveTrailingDecimal?: boolean;
9
+ }
10
+ export declare function formatNumber(value: string, locale: string, options?: FormatNumberOptions): string;
11
+ export declare function parseFormattedNumber(formattedValue: string, locale: string): string;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseFormattedNumber = exports.formatNumber = exports.getNumberFormatConfig = void 0;
4
+ var utils_1 = require("../common/utils");
5
+ // 提取语言代码:从 locale 中提取第一部分(去掉 - 和 _ 后面的所有内容)
6
+ function getLangKey(locale) {
7
+ if (!locale) {
8
+ return '';
9
+ }
10
+ // 转换为小写并去除空格
11
+ var normalized = locale.toLowerCase().trim();
12
+ // 统一将下划线和连字符作为分隔符,取第一部分
13
+ var langKey = normalized.split(/[-_]/)[0];
14
+ return langKey;
15
+ }
16
+ // 根据 locale 获取数字格式化配置
17
+ function getNumberFormatConfig(locale) {
18
+ // 如果没有指定 locale,尝试从系统获取
19
+ if (!locale) {
20
+ try {
21
+ var systemInfo = (0, utils_1.getSystemInfoSync)();
22
+ // 尝试多个可能的字段名
23
+ locale =
24
+ systemInfo.language ||
25
+ systemInfo.locale ||
26
+ systemInfo.lang ||
27
+ 'zh-CN';
28
+ }
29
+ catch (e) {
30
+ locale = 'zh-CN';
31
+ }
32
+ }
33
+ // 规范化 locale(统一大小写和下划线)
34
+ var normalizedLocale = locale.toLowerCase().trim().replace(/_/g, '-');
35
+ // 只配置非标准格式(非 1,234.56 格式)
36
+ // 默认格式:thousandsSeparator: ',', decimalSeparator: '.' (1,234.56)
37
+ var formatMap = {
38
+ // 德语地区:1.000,1312 (点作为千分位,逗号作为小数)
39
+ de: { thousandsSeparator: '.', decimalSeparator: ',' },
40
+ // 法语地区:1 000,1312 (空格作为千分位,逗号作为小数)
41
+ fr: { thousandsSeparator: ' ', decimalSeparator: ',' },
42
+ // 意大利语:1.000,1312
43
+ it: { thousandsSeparator: '.', decimalSeparator: ',' },
44
+ // 西班牙语:1.000,1312
45
+ es: { thousandsSeparator: '.', decimalSeparator: ',' },
46
+ // 葡萄牙语:1.000,1312
47
+ pt: { thousandsSeparator: '.', decimalSeparator: ',' },
48
+ // 俄语:1 000,1312 (空格作为千分位,逗号作为小数)
49
+ ru: { thousandsSeparator: ' ', decimalSeparator: ',' },
50
+ // 部分阿拉伯国家
51
+ 'es-419': { thousandsSeparator: ',', decimalSeparator: '.' },
52
+ 'pt-br': { thousandsSeparator: '.', decimalSeparator: ',' },
53
+ 'ar-ma': { thousandsSeparator: ' ', decimalSeparator: ',' },
54
+ 'ar-tn': { thousandsSeparator: ' ', decimalSeparator: ',' },
55
+ 'de-ch': { thousandsSeparator: "'", decimalSeparator: '.' },
56
+ 'es-mx': { thousandsSeparator: ',', decimalSeparator: '.' },
57
+ 'fr-ch': { thousandsSeparator: "'", decimalSeparator: '.' }, // 瑞士法语
58
+ };
59
+ // 策略1: 先尝试完整匹配(处理特殊国家,如 'de-ch', 'ar-ma', 'ar-tn')
60
+ if (formatMap[normalizedLocale]) {
61
+ return formatMap[normalizedLocale];
62
+ }
63
+ // 策略2: 提取语言代码进行匹配
64
+ var langKey = getLangKey(locale);
65
+ if (langKey && formatMap[langKey]) {
66
+ return formatMap[langKey];
67
+ }
68
+ // 默认使用标准格式:1,234.56 (千分位逗号,小数点)
69
+ return { thousandsSeparator: ',', decimalSeparator: '.' };
70
+ }
71
+ exports.getNumberFormatConfig = getNumberFormatConfig;
72
+ // 格式化数字:将 "1000.1312" 或 "-1000.1312" 格式化为带分隔符的字符串
73
+ function formatNumber(value, locale, options) {
74
+ if (!value || value === '') {
75
+ return '';
76
+ }
77
+ // 仅保留数字、小数点、减号;连续前导减号按「负负得正」处理
78
+ var raw = value.replace(/[^-0-9.]/g, '');
79
+ var i = 0;
80
+ while (i < raw.length && raw[i] === '-') {
81
+ i++;
82
+ }
83
+ var negative = i % 2 === 1;
84
+ var cleanValue = raw.slice(i).replace(/-/g, '');
85
+ if (!cleanValue) {
86
+ return negative ? '-' : '';
87
+ }
88
+ // 聚焦输入时可能为 "23.",保留末尾小数点以便用户继续输入小数
89
+ var hasTrailingDecimal = (options === null || options === void 0 ? void 0 : options.preserveTrailingDecimal) && /\.$/.test(cleanValue);
90
+ // 分离整数部分和小数部分(处理多个小数点的情况)
91
+ var valueToFormat = hasTrailingDecimal ? cleanValue.slice(0, -1) : cleanValue;
92
+ var parts = valueToFormat.split('.');
93
+ var integerPart = parts[0] || '';
94
+ var decimalPart = parts.length > 1 ? parts.slice(1).join('') : '';
95
+ var config = getNumberFormatConfig(locale);
96
+ // 格式化整数部分(添加千分位分隔符)
97
+ var formattedInteger = '';
98
+ if (integerPart) {
99
+ for (var j = integerPart.length - 1, count = 0; j >= 0; j--) {
100
+ if (count > 0 && count % 3 === 0) {
101
+ formattedInteger = config.thousandsSeparator + formattedInteger;
102
+ }
103
+ formattedInteger = integerPart[j] + formattedInteger;
104
+ count++;
105
+ }
106
+ }
107
+ var prefix = negative ? '-' : '';
108
+ if (decimalPart) {
109
+ return prefix + formattedInteger + config.decimalSeparator + decimalPart;
110
+ }
111
+ if (hasTrailingDecimal) {
112
+ return prefix + (formattedInteger || '0') + config.decimalSeparator;
113
+ }
114
+ return prefix + (formattedInteger || '0');
115
+ }
116
+ exports.formatNumber = formatNumber;
117
+ // 解析格式化后的数字:将格式化字符串转换回 "1000.1312" 或 "-1000.1312" 格式
118
+ function parseFormattedNumber(formattedValue, locale) {
119
+ if (!formattedValue || formattedValue === '') {
120
+ return '';
121
+ }
122
+ var body = formattedValue.trim();
123
+ var negative = false;
124
+ var ch0 = body.charAt(0);
125
+ if (ch0 === '-' || ch0 === '\u2212') {
126
+ negative = true;
127
+ body = body.slice(1).trim();
128
+ }
129
+ if (!body) {
130
+ return negative ? '-' : '';
131
+ }
132
+ var config = getNumberFormatConfig(locale);
133
+ // 移除千分位分隔符(需要转义特殊字符)
134
+ var escapedSeparator = config.thousandsSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
135
+ var cleaned = body.replace(new RegExp(escapedSeparator, 'g'), '');
136
+ // 将小数分隔符转换为标准小数点(只替换第一个,因为可能有多个)
137
+ if (config.decimalSeparator !== '.') {
138
+ var decimalIndex = cleaned.indexOf(config.decimalSeparator);
139
+ if (decimalIndex !== -1) {
140
+ cleaned = cleaned.substring(0, decimalIndex) + '.' + cleaned.substring(decimalIndex + 1);
141
+ }
142
+ }
143
+ // 确保只有一个小数点
144
+ var parts = cleaned.split('.');
145
+ if (parts.length > 2) {
146
+ cleaned = parts[0] + '.' + parts.slice(1).join('');
147
+ }
148
+ var num = cleaned.replace(/[^\d.]/g, '');
149
+ if (!num) {
150
+ return negative ? '-' : '';
151
+ }
152
+ return negative ? '-' + num : num;
153
+ }
154
+ exports.parseFormattedNumber = parseFormattedNumber;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuya-miniapp/smart-ui",
3
- "version": "2.12.0-beta-4",
3
+ "version": "2.12.0-beta-5",
4
4
  "author": "MiniApp Team",
5
5
  "license": "MIT",
6
6
  "miniprogram": "lib",