@tendaui/components 1.0.0 → 1.2.3
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,101 @@
|
|
|
1
|
+
/* eslint-disable no-template-curly-in-string */
|
|
2
|
+
// 文件有效,为国际化做准备
|
|
3
|
+
import 'dayjs/locale/zh-tw';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
actionSheet: {
|
|
7
|
+
cancel: '取消',
|
|
8
|
+
},
|
|
9
|
+
calendar: {
|
|
10
|
+
title: '請選擇日期',
|
|
11
|
+
confirm: '確認',
|
|
12
|
+
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
|
|
13
|
+
monthTitle: '{year} 年 {month}',
|
|
14
|
+
months: ['1 月', '2 月', '3 月', '4 月', '5 月', '6 月', '7 月', '8 月', '9 月', '10 月', '11 月', '12 月'],
|
|
15
|
+
},
|
|
16
|
+
cascader: {
|
|
17
|
+
title: '標題',
|
|
18
|
+
placeholder: '選擇選項',
|
|
19
|
+
},
|
|
20
|
+
dropdownMenu: {
|
|
21
|
+
reset: '重置',
|
|
22
|
+
confirm: '確定',
|
|
23
|
+
},
|
|
24
|
+
dateTimePicker: {
|
|
25
|
+
title: '選擇時間',
|
|
26
|
+
cancel: '取消',
|
|
27
|
+
confirm: '確定',
|
|
28
|
+
format: 'YYYY-MM-DD',
|
|
29
|
+
yearLabel: '年',
|
|
30
|
+
monthLabel: '月',
|
|
31
|
+
dateLabel: '日',
|
|
32
|
+
hourLabel: '時',
|
|
33
|
+
minuteLabel: '分',
|
|
34
|
+
secondLabel: '秒',
|
|
35
|
+
},
|
|
36
|
+
form: {
|
|
37
|
+
errorMessage: {
|
|
38
|
+
date: '請輸入正確的${name}',
|
|
39
|
+
url: '請輸入正確的${name}',
|
|
40
|
+
whitespace: '${name}不能為空',
|
|
41
|
+
required: '${name}必填',
|
|
42
|
+
max: '${name}字符長度不能超過 ${validate} 個字符,一個中文等於兩個字符',
|
|
43
|
+
min: '${name}字符長度不能少於 ${validate} 個字符,一個中文等於兩個字符',
|
|
44
|
+
len: '${name}字符長度必須是 ${validate}',
|
|
45
|
+
enum: '${name}只能是${validate}等',
|
|
46
|
+
idcard: '請輸入正確的${name}',
|
|
47
|
+
telnumber: '請輸入正確的${name}',
|
|
48
|
+
pattern: '請輸入正確的${name}',
|
|
49
|
+
validator: '${name}不符合要求',
|
|
50
|
+
boolean: '${name}數據類型必須是布林類型',
|
|
51
|
+
number: '${name}必須是數字',
|
|
52
|
+
},
|
|
53
|
+
colonText: ':',
|
|
54
|
+
},
|
|
55
|
+
picker: {
|
|
56
|
+
cancel: '取消',
|
|
57
|
+
confirm: '確認',
|
|
58
|
+
},
|
|
59
|
+
pullDownRefresh: {
|
|
60
|
+
loadingTexts: ['下拉刷新', '鬆手刷新', '正在刷新', '刷新完成'],
|
|
61
|
+
},
|
|
62
|
+
rate: {
|
|
63
|
+
valueText: '{value} 分',
|
|
64
|
+
noValueText: '未評分',
|
|
65
|
+
},
|
|
66
|
+
tabBar: {
|
|
67
|
+
newsAriaLabel: '有新消息',
|
|
68
|
+
moreNewsAriaLabel: '有很多消息',
|
|
69
|
+
haveMoreNewsAriaLabel: '有 {value}+ 條消息',
|
|
70
|
+
haveNewsAriaLabel: '有 {value} 條消息',
|
|
71
|
+
},
|
|
72
|
+
table: {
|
|
73
|
+
empty: '暫無數據',
|
|
74
|
+
},
|
|
75
|
+
list: {
|
|
76
|
+
loading: '加載中...',
|
|
77
|
+
loadingMoreText: '點擊加載更多',
|
|
78
|
+
pulling: '下拉即可刷新...',
|
|
79
|
+
loosing: '釋放即可刷新...',
|
|
80
|
+
success: '刷新成功',
|
|
81
|
+
},
|
|
82
|
+
upload: {
|
|
83
|
+
progress: {
|
|
84
|
+
uploadingText: '上傳中...',
|
|
85
|
+
waitingText: '待上傳',
|
|
86
|
+
failText: '上傳失敗',
|
|
87
|
+
successText: '上傳成功',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
guide: {
|
|
91
|
+
next: '下一步',
|
|
92
|
+
skip: '跳過',
|
|
93
|
+
finish: '完成',
|
|
94
|
+
back: '返回',
|
|
95
|
+
},
|
|
96
|
+
qrcode: {
|
|
97
|
+
expiredText: '二維碼過期',
|
|
98
|
+
refreshText: '點擊刷新',
|
|
99
|
+
scannedText: '已掃描',
|
|
100
|
+
},
|
|
101
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { isString } from 'lodash-es';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 复数规则判断函数
|
|
5
|
+
* @param count 数量
|
|
6
|
+
* @returns 返回复数形式的索引 (0: zero/none, 1: one, 2: other/many)
|
|
7
|
+
*/
|
|
8
|
+
function getPluralIndex(count: number): number {
|
|
9
|
+
if (count === 0) return 0; // no items
|
|
10
|
+
if (count === 1) return 1; // one item
|
|
11
|
+
return 2; // multiple items
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @see https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/config-provider/hooks/useConfig.ts#L48
|
|
16
|
+
* 自定义 t function 可能依赖特定库函数,例如 tdesign-vue-next 中使用了 vue 的 h 函数
|
|
17
|
+
* 因此交由各个类库自行实现
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 国际化函数,支持复数处理和变量替换
|
|
22
|
+
*
|
|
23
|
+
* 示例用法:
|
|
24
|
+
* 1. 基本变量替换:
|
|
25
|
+
* t('Hello {name}', { name: 'World' }) // => 'Hello World'
|
|
26
|
+
*
|
|
27
|
+
* 2. 复数处理(传入数字):
|
|
28
|
+
* t('no apples | one apple | {count} apples', 0) // => 'no apples'
|
|
29
|
+
* t('no apples | one apple | {count} apples', 1) // => 'one apple'
|
|
30
|
+
* t('no apples | one apple | {count} apples', 5) // => '5 apples'
|
|
31
|
+
*
|
|
32
|
+
* 3. 复合使用:
|
|
33
|
+
* t('no items found | found {count} item | found {count} items', 3, { count: 3 }) // => 'found 3 items'
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
// 类型重载定义
|
|
37
|
+
export function t(pattern: string): string;
|
|
38
|
+
export function t(pattern: string, data: Record<string, any>): string;
|
|
39
|
+
export function t(pattern: string, count: number): string;
|
|
40
|
+
export function t(pattern: string, count: number, data: Record<string, any>): string;
|
|
41
|
+
export function t<T>(pattern: T): string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param pattern 文本模式,可以是字符串、函数或其他类型
|
|
45
|
+
* @param args 参数列表,支持 (count: number) 或 (count: number, data: object) 或 (data: object)
|
|
46
|
+
* @returns 处理后的文本
|
|
47
|
+
*/
|
|
48
|
+
export function t<T>(pattern: T, ...args: any[]): string {
|
|
49
|
+
if (isString(pattern)) {
|
|
50
|
+
let text = pattern as string;
|
|
51
|
+
let count: number | undefined;
|
|
52
|
+
let data: Record<string, any> = {};
|
|
53
|
+
|
|
54
|
+
// 解析参数
|
|
55
|
+
if (args.length > 0) {
|
|
56
|
+
const [firstArg, secondArg] = args;
|
|
57
|
+
|
|
58
|
+
if (typeof firstArg === 'number') {
|
|
59
|
+
// 第一个参数是数字,表示 count
|
|
60
|
+
count = firstArg;
|
|
61
|
+
if (secondArg && typeof secondArg === 'object') {
|
|
62
|
+
// 第二个参数是对象,表示额外的数据
|
|
63
|
+
data = secondArg;
|
|
64
|
+
} else {
|
|
65
|
+
data.count = count; // 若没有提供第二个参数,则将 count 添加到数据中
|
|
66
|
+
}
|
|
67
|
+
} else if (typeof firstArg === 'object' && firstArg !== null) {
|
|
68
|
+
// 第一个参数是对象,表示数据
|
|
69
|
+
data = firstArg;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 处理复数形式:支持 "no items | one item | {count} items" 格式
|
|
74
|
+
if (text.includes('|')) {
|
|
75
|
+
const pluralParts = text.split('|').map((part) => part.trim());
|
|
76
|
+
|
|
77
|
+
if (typeof count === 'number') {
|
|
78
|
+
// 使用 count 进行复数处理
|
|
79
|
+
const pluralIndex = getPluralIndex(count);
|
|
80
|
+
|
|
81
|
+
// 根据复数索引选择对应的文本
|
|
82
|
+
if (pluralIndex < pluralParts.length) {
|
|
83
|
+
text = pluralParts[pluralIndex];
|
|
84
|
+
} else {
|
|
85
|
+
// 如果索引超出范围,使用最后一个选项
|
|
86
|
+
text = pluralParts[pluralParts.length - 1];
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
// 如果没有 count,默认使用第一个选项
|
|
90
|
+
const [firstPart] = pluralParts;
|
|
91
|
+
text = firstPart;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 处理变量替换:{key} 格式
|
|
96
|
+
if (data && Object.keys(data).length > 0) {
|
|
97
|
+
const regular = /\{\s*([\w-]+)\s*\}/g;
|
|
98
|
+
text = text.replace(regular, (match, key) => {
|
|
99
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
100
|
+
return String(data[key]);
|
|
101
|
+
}
|
|
102
|
+
return match; // 如果找不到对应的键,保留原始占位符
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return text as any;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 如果不是字符串或函数,返回空字符串
|
|
110
|
+
return '';
|
|
111
|
+
}
|
package/hooks/useControlled.ts
CHANGED
|
@@ -29,10 +29,10 @@ const useControlled: <P extends unknown[], R extends object, K extends keyof R>(
|
|
|
29
29
|
if (isControlled) return [value, onChange || (() => {})];
|
|
30
30
|
return [
|
|
31
31
|
internalValue,
|
|
32
|
-
(newValue, ...args) => {
|
|
32
|
+
((newValue: any, ...args: any[]) => {
|
|
33
33
|
setInternalValue(newValue);
|
|
34
|
-
onChange?.(newValue, ...args);
|
|
35
|
-
}
|
|
34
|
+
onChange?.(newValue, ...(args as any));
|
|
35
|
+
}) as any
|
|
36
36
|
];
|
|
37
37
|
};
|
|
38
38
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { isEqualWith } from "lodash-es";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 与 useEffect 用法一致,但对依赖数组进行深比较
|
|
6
|
+
* - 只在依赖真正变化时才会触发副作用函数
|
|
7
|
+
* - 适用于依赖为复杂对象的场景
|
|
8
|
+
*/
|
|
9
|
+
function useDeepEffect(effect: React.EffectCallback, deps: React.DependencyList) {
|
|
10
|
+
const isInitial = useRef(true);
|
|
11
|
+
const prevDeps = useRef(deps);
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const isSame = isEqualWith(prevDeps.current, deps, (value1, value2) => {
|
|
15
|
+
// 函数类型比较字符串表示
|
|
16
|
+
if (typeof value1 === "function" && typeof value2 === "function") {
|
|
17
|
+
return value1.toString() === value2.toString();
|
|
18
|
+
}
|
|
19
|
+
// 其他类型使用默认比较
|
|
20
|
+
return undefined;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (isInitial.current || !isSame) {
|
|
24
|
+
effect();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
isInitial.current = false;
|
|
28
|
+
prevDeps.current = deps;
|
|
29
|
+
}, [effect, deps]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default useDeepEffect;
|
package/hooks/useGlobalIcon.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import useConfig from "./useConfig";
|
|
2
|
-
import Icon from "@tendaui/icons";
|
|
2
|
+
import Icon, { IconProps } from "@tendaui/icons";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
// 通过 convertIcon 创建的图标组件类型,不需要 svg 和 type 属性
|
|
6
|
+
type ConvertedIconComponent = React.ForwardRefExoticComponent<
|
|
7
|
+
Omit<IconProps, "svg" | "type"> & React.RefAttributes<HTMLSpanElement>
|
|
8
|
+
>;
|
|
9
|
+
|
|
3
10
|
// 从 globalConfig 获取 icon 配置用于覆盖组件内置 icon
|
|
4
|
-
export default function useGlobalIcon(tdIcon: Record<string,
|
|
11
|
+
export default function useGlobalIcon(tdIcon: Record<string, ConvertedIconComponent>) {
|
|
5
12
|
const { icon: globalIcon } = useConfig();
|
|
6
13
|
|
|
7
|
-
const resultIcon: Record<string,
|
|
14
|
+
const resultIcon: Record<string, ConvertedIconComponent> = {};
|
|
8
15
|
|
|
9
16
|
Object.keys(tdIcon).forEach((key) => {
|
|
10
17
|
resultIcon[key] = globalIcon?.[key] || tdIcon[key];
|
package/hooks/useLastest.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import useIsomorphicLayoutEffect from "./useLayoutEffect";
|
|
2
|
+
import { canUseDocument } from "../utils/dom";
|
|
3
|
+
import useLatest from "./useLastest";
|
|
4
|
+
|
|
5
|
+
export default function useResizeObserver(
|
|
6
|
+
container: React.MutableRefObject<HTMLElement | null>,
|
|
7
|
+
callback: (data: ResizeObserverEntry[]) => void,
|
|
8
|
+
enabled = true
|
|
9
|
+
) {
|
|
10
|
+
const callbackRef = useLatest(callback);
|
|
11
|
+
|
|
12
|
+
useIsomorphicLayoutEffect(() => {
|
|
13
|
+
const isSupport = canUseDocument && window.ResizeObserver;
|
|
14
|
+
const element = container.current;
|
|
15
|
+
let observer: ResizeObserver = null;
|
|
16
|
+
|
|
17
|
+
if (!enabled) return;
|
|
18
|
+
|
|
19
|
+
if (isSupport && element) {
|
|
20
|
+
const resizeCallback: ResizeObserverCallback = (entries) => {
|
|
21
|
+
callbackRef.current(entries);
|
|
22
|
+
};
|
|
23
|
+
observer = new ResizeObserver(resizeCallback);
|
|
24
|
+
observer.observe(element);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return () => {
|
|
28
|
+
if (observer && element) {
|
|
29
|
+
observer.unobserve(element);
|
|
30
|
+
observer.disconnect?.();
|
|
31
|
+
observer = null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
// eslint-disable-next-line
|
|
35
|
+
}, [container, enabled]);
|
|
36
|
+
}
|
package/index.ts
CHANGED
|
@@ -6,10 +6,11 @@ export * from "./input";
|
|
|
6
6
|
// export * from './input-adornment';
|
|
7
7
|
export * from "./alert";
|
|
8
8
|
export * from "./badge";
|
|
9
|
-
|
|
9
|
+
export * from "./radio";
|
|
10
10
|
export * from "./checkbox";
|
|
11
|
-
|
|
11
|
+
export * from "./input-number";
|
|
12
12
|
export * from "./config-provider";
|
|
13
|
+
export * from "./layout";
|
|
13
14
|
// export * from './steps';
|
|
14
15
|
// export * from './sticky-tool';
|
|
15
16
|
// export * from './message';
|
|
@@ -18,7 +19,7 @@ export * from "./tag";
|
|
|
18
19
|
export * from "./tag-input";
|
|
19
20
|
export * from "./select";
|
|
20
21
|
export * from "./select-input";
|
|
21
|
-
|
|
22
|
+
export * from "./list";
|
|
22
23
|
// export * from './tabs';
|
|
23
24
|
export * from "./notification";
|
|
24
25
|
// export * from './pagination';
|
|
@@ -26,20 +27,22 @@ export * from "./notification";
|
|
|
26
27
|
export * from "./dialog";
|
|
27
28
|
// export * from './tree';
|
|
28
29
|
// export * from './tree-select';
|
|
29
|
-
// export * from
|
|
30
|
+
// export * from "./divider";
|
|
30
31
|
export * from "./switch";
|
|
31
32
|
// export * from './anchor';
|
|
32
33
|
// export * from './calendar';
|
|
33
34
|
export * from "./form";
|
|
35
|
+
export * from "./ip-input";
|
|
36
|
+
export * from "./fireworks";
|
|
34
37
|
// export * from './tooltip';
|
|
35
|
-
|
|
38
|
+
export * from "./drawer";
|
|
36
39
|
// export * from './progress';
|
|
37
40
|
// export * from './popconfirm';
|
|
38
41
|
// export * from './textarea';
|
|
39
42
|
// export * from './breadcrumb';
|
|
40
43
|
// export * from './affix';
|
|
41
44
|
// export * from './dropdown';
|
|
42
|
-
|
|
45
|
+
export * from "./slider";
|
|
43
46
|
// export * from './auto-complete';
|
|
44
47
|
// export * from './cascader';
|
|
45
48
|
// export * from './time-picker';
|
|
@@ -50,7 +53,7 @@ export * from "./form";
|
|
|
50
53
|
// export * from './transfer';
|
|
51
54
|
// export * from './avatar';
|
|
52
55
|
// export * from './skeleton';
|
|
53
|
-
|
|
56
|
+
export * from "./color-picker";
|
|
54
57
|
// export * from './card';
|
|
55
58
|
// export * from './collapse';
|
|
56
59
|
// export * from './range-input';
|
package/input/Input.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import useDefaultProps from "../hooks/useDefaultProps";
|
|
|
10
10
|
import { StyledProps, TNode, TElement } from "../common";
|
|
11
11
|
import { isFunction } from "lodash-es";
|
|
12
12
|
import useConfig from "../hooks/useConfig";
|
|
13
|
+
import { useLocaleReceiver } from "../locale/LocalReceiver";
|
|
13
14
|
export interface InputProps extends TdInputProps, StyledProps {
|
|
14
15
|
showInput?: boolean; // 控制透传readonly同时是否展示input 默认保留 因为正常Input需要撑开宽度
|
|
15
16
|
keepWrapperWidth?: boolean; // 控制透传autoWidth之后是否容器宽度也自适应 多选等组件需要用到自适应但也需要保留宽度
|
|
@@ -36,12 +37,14 @@ const renderIcon = (classPrefix: string, type: "prefix" | "suffix", icon: TNode
|
|
|
36
37
|
const Input = forwardRef<HTMLInputElement, InputProps>((originalProps, ref) => {
|
|
37
38
|
const props = useDefaultProps<InputProps>(originalProps, inputDefaultProps as Partial<InputProps>);
|
|
38
39
|
const { classPrefix } = useConfig();
|
|
40
|
+
const [local, t] = useLocaleReceiver("input");
|
|
41
|
+
const placeholderText = t(local.placeholder);
|
|
39
42
|
|
|
40
43
|
const {
|
|
41
44
|
type,
|
|
42
45
|
autoWidth,
|
|
43
46
|
borderless,
|
|
44
|
-
placeholder =
|
|
47
|
+
placeholder = placeholderText,
|
|
45
48
|
disabled,
|
|
46
49
|
size,
|
|
47
50
|
className,
|
package/input/defaultProps.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export const inputDefaultProps = {
|
|
2
2
|
align: "left" as "left" | "center" | "right",
|
|
3
|
-
allowInputOverMax: false,
|
|
4
3
|
autoWidth: false,
|
|
5
4
|
autocomplete: undefined,
|
|
6
5
|
autofocus: false,
|
|
@@ -13,7 +12,6 @@ export const inputDefaultProps = {
|
|
|
13
12
|
// 是否只读,在只读模式下,输入框不能输入,且没有清除按钮,优先级高于 allowInput、clearable
|
|
14
13
|
readonly: false,
|
|
15
14
|
showClearIconOnEmpty: false,
|
|
16
|
-
showLimitNumber: false,
|
|
17
15
|
size: "medium",
|
|
18
16
|
spellCheck: false,
|
|
19
17
|
status: "default",
|
package/input/type.ts
CHANGED
|
@@ -16,7 +16,6 @@ export interface TdInputProps {
|
|
|
16
16
|
* 超出 `maxlength` 或 `maxcharacter` 之后是否允许继续输入
|
|
17
17
|
* @default false
|
|
18
18
|
*/
|
|
19
|
-
allowInputOverMax?: boolean;
|
|
20
19
|
/**
|
|
21
20
|
* 宽度随内容自适应
|
|
22
21
|
* @default false
|
|
@@ -88,11 +87,7 @@ export interface TdInputProps {
|
|
|
88
87
|
* @default false
|
|
89
88
|
*/
|
|
90
89
|
showClearIconOnEmpty?: boolean;
|
|
91
|
-
|
|
92
|
-
* 是否在输入框右侧显示字数统计
|
|
93
|
-
* @default false
|
|
94
|
-
*/
|
|
95
|
-
showLimitNumber?: boolean;
|
|
90
|
+
|
|
96
91
|
/**
|
|
97
92
|
* 输入框尺寸
|
|
98
93
|
* @default medium
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React, { forwardRef, useImperativeHandle, useRef, ForwardedRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
IconChevronDown as TdChevronDownIcon,
|
|
4
|
+
IconMinusStroked as TdRemoveIcon,
|
|
5
|
+
IconChevronUp as TdChevronUpIcon,
|
|
6
|
+
IconPlus as TdAddIcon
|
|
7
|
+
} from "@tendaui/icons";
|
|
8
|
+
import classNames from "classnames";
|
|
9
|
+
import Input from "../input";
|
|
10
|
+
import Button from "../button";
|
|
11
|
+
import useInputNumber from "./useInputNumber";
|
|
12
|
+
import useGlobalIcon from "../hooks/useGlobalIcon";
|
|
13
|
+
import { inputNumberDefaultProps } from "./defaultProps";
|
|
14
|
+
import { InputNumberValue, TdInputNumberProps } from "./type";
|
|
15
|
+
import { StyledProps } from "../common";
|
|
16
|
+
import useDefaultProps from "../hooks/useDefaultProps";
|
|
17
|
+
|
|
18
|
+
export interface InputNumberProps<T = InputNumberValue> extends TdInputNumberProps<T>, StyledProps {}
|
|
19
|
+
|
|
20
|
+
export interface InputNumberRef {
|
|
21
|
+
currentElement: ForwardedRef<HTMLDivElement>;
|
|
22
|
+
inputElement: ForwardedRef<HTMLDivElement>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// https://fettblog.eu/typescript-react-generic-forward-refs/
|
|
26
|
+
function TdInputNumber<T extends InputNumberValue = InputNumberValue>(
|
|
27
|
+
originalProps: InputNumberProps<T>,
|
|
28
|
+
ref: ForwardedRef<InputNumberRef>
|
|
29
|
+
) {
|
|
30
|
+
const { ChevronDownIcon, RemoveIcon, ChevronUpIcon, AddIcon } = useGlobalIcon({
|
|
31
|
+
ChevronDownIcon: TdChevronDownIcon,
|
|
32
|
+
RemoveIcon: TdRemoveIcon,
|
|
33
|
+
ChevronUpIcon: TdChevronUpIcon,
|
|
34
|
+
AddIcon: TdAddIcon
|
|
35
|
+
});
|
|
36
|
+
const props = useDefaultProps<InputNumberProps<T>>(
|
|
37
|
+
originalProps,
|
|
38
|
+
inputNumberDefaultProps as Partial<InputNumberProps<T>>
|
|
39
|
+
);
|
|
40
|
+
const {
|
|
41
|
+
classPrefix,
|
|
42
|
+
wrapClasses,
|
|
43
|
+
addClasses,
|
|
44
|
+
reduceClasses,
|
|
45
|
+
listeners,
|
|
46
|
+
isError,
|
|
47
|
+
inputRef,
|
|
48
|
+
userInput,
|
|
49
|
+
handleAdd,
|
|
50
|
+
handleReduce,
|
|
51
|
+
onInnerInputChange
|
|
52
|
+
} = useInputNumber(props);
|
|
53
|
+
|
|
54
|
+
const wrapRef = useRef(null);
|
|
55
|
+
|
|
56
|
+
const status = isError ? "error" : props.status;
|
|
57
|
+
const iconSize = props.size === "medium" ? "default" : props.size;
|
|
58
|
+
const addIcon =
|
|
59
|
+
props.theme === "column" ? <ChevronUpIcon size={iconSize as any} /> : <AddIcon size={iconSize as any} />;
|
|
60
|
+
const reduceIcon =
|
|
61
|
+
props.theme === "column" ? <ChevronDownIcon size={iconSize as any} /> : <RemoveIcon size={iconSize as any} />;
|
|
62
|
+
|
|
63
|
+
useImperativeHandle(ref, () => ({
|
|
64
|
+
currentElement: wrapRef.current,
|
|
65
|
+
inputElement: inputRef.current
|
|
66
|
+
}));
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div className={classNames(wrapClasses, props.className)} style={props.style} ref={wrapRef}>
|
|
70
|
+
{props.theme !== "normal" && (
|
|
71
|
+
<Button
|
|
72
|
+
className={reduceClasses}
|
|
73
|
+
disabled={props.disabled}
|
|
74
|
+
onClick={handleReduce}
|
|
75
|
+
variant="outline"
|
|
76
|
+
shape="square"
|
|
77
|
+
icon={reduceIcon}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
<Input
|
|
81
|
+
ref={inputRef}
|
|
82
|
+
autocomplete="off"
|
|
83
|
+
disabled={props.disabled}
|
|
84
|
+
readonly={props.readonly}
|
|
85
|
+
placeholder={props.placeholder}
|
|
86
|
+
autoWidth={props.autoWidth}
|
|
87
|
+
align={props.align || (props.theme === "row" ? "center" : undefined)}
|
|
88
|
+
status={status}
|
|
89
|
+
label={props.label}
|
|
90
|
+
suffix={props.suffix}
|
|
91
|
+
value={userInput}
|
|
92
|
+
onChange={onInnerInputChange}
|
|
93
|
+
size={props.size}
|
|
94
|
+
{...listeners}
|
|
95
|
+
{...(props.inputProps || {})}
|
|
96
|
+
/>
|
|
97
|
+
{props.theme !== "normal" && (
|
|
98
|
+
<Button
|
|
99
|
+
className={addClasses}
|
|
100
|
+
disabled={props.disabled}
|
|
101
|
+
onClick={handleAdd}
|
|
102
|
+
variant="outline"
|
|
103
|
+
shape="square"
|
|
104
|
+
icon={addIcon}
|
|
105
|
+
/>
|
|
106
|
+
)}
|
|
107
|
+
{props.tips && (
|
|
108
|
+
<div className={classNames(`${classPrefix}-input__tips`, `${classPrefix}-input__tips--${status}`)}>
|
|
109
|
+
{props.tips}
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export type InputNumberOuterForwardRef = {
|
|
117
|
+
<T>(props: InputNumberProps<T> & { ref?: ForwardedRef<InputNumberRef> }): ReturnType<typeof TdInputNumber>;
|
|
118
|
+
} & React.ForwardRefExoticComponent<InputNumberProps>;
|
|
119
|
+
|
|
120
|
+
const InputNumber = forwardRef<InputNumberRef, InputNumberProps<InputNumberValue>>(TdInputNumber);
|
|
121
|
+
|
|
122
|
+
InputNumber.displayName = "InputNumber";
|
|
123
|
+
|
|
124
|
+
export default InputNumber;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TdInputNumberProps } from "./type";
|
|
2
|
+
|
|
3
|
+
export const inputNumberDefaultProps: TdInputNumberProps = {
|
|
4
|
+
allowInputOverLimit: true,
|
|
5
|
+
autoWidth: false,
|
|
6
|
+
decimalPlaces: undefined,
|
|
7
|
+
disabled: undefined,
|
|
8
|
+
largeNumber: false,
|
|
9
|
+
max: Infinity,
|
|
10
|
+
min: -Infinity,
|
|
11
|
+
placeholder: undefined,
|
|
12
|
+
readonly: undefined,
|
|
13
|
+
size: "medium",
|
|
14
|
+
status: "default",
|
|
15
|
+
step: 1,
|
|
16
|
+
theme: "row"
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./index.css";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../../styles/components/input-number/_index.scss";
|