@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.
Files changed (270) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +176 -176
  3. package/alert/Alert.tsx +3 -2
  4. package/button/_example/base.tsx +10 -0
  5. package/button/_example/icon.tsx +20 -0
  6. package/color-picker/ColorPickPanel.tsx +9 -0
  7. package/color-picker/ColorPicker.tsx +67 -0
  8. package/color-picker/components/panel/alpha.tsx +32 -0
  9. package/color-picker/components/panel/format/index.tsx +47 -0
  10. package/color-picker/components/panel/format/inputs.tsx +119 -0
  11. package/color-picker/components/panel/header.tsx +37 -0
  12. package/color-picker/components/panel/hue.tsx +20 -0
  13. package/color-picker/components/panel/index.tsx +191 -0
  14. package/color-picker/components/panel/saturation.tsx +81 -0
  15. package/color-picker/components/panel/slider.tsx +76 -0
  16. package/color-picker/components/panel/swatches.tsx +84 -0
  17. package/color-picker/components/trigger.tsx +49 -0
  18. package/color-picker/defaultProps.ts +7 -0
  19. package/color-picker/helpers.ts +53 -0
  20. package/color-picker/hooks/useClassNames.ts +9 -0
  21. package/color-picker/hooks/useStyles.ts +39 -0
  22. package/color-picker/index.ts +12 -0
  23. package/color-picker/style/css.js +1 -0
  24. package/color-picker/style/index.js +1 -0
  25. package/color-picker/type.ts +143 -0
  26. package/color-picker/utils/color-picker/cmyk.ts +89 -0
  27. package/color-picker/utils/color-picker/color.ts +467 -0
  28. package/color-picker/utils/color-picker/constants.ts +187 -0
  29. package/color-picker/utils/color-picker/draggable.ts +100 -0
  30. package/color-picker/utils/color-picker/format.ts +95 -0
  31. package/color-picker/utils/color-picker/gradient.ts +243 -0
  32. package/color-picker/utils/color-picker/index.ts +7 -0
  33. package/color-picker/utils/color-picker/types.ts +33 -0
  34. package/common/observe.ts +33 -0
  35. package/common.ts +20 -0
  36. package/config-provider/ConfigContext.tsx +4 -1
  37. package/config-provider/index.ts +1 -1
  38. package/dialog/DialogCard.tsx +4 -6
  39. package/dialog/hooks/useDialogPosition.ts +1 -2
  40. package/dialog/plugin.tsx +3 -2
  41. package/drawer/Drawer.tsx +264 -0
  42. package/drawer/defaultProps.ts +19 -0
  43. package/drawer/hooks/useDrag.ts +98 -0
  44. package/drawer/hooks/useLockStyle.ts +36 -0
  45. package/drawer/index.ts +5 -0
  46. package/drawer/style/css.js +1 -0
  47. package/drawer/style/index.js +1 -0
  48. package/drawer/type.ts +193 -0
  49. package/drawer/utils/index.ts +76 -0
  50. package/fireworks/Fireworks.tsx +138 -0
  51. package/fireworks/index.ts +10 -0
  52. package/fireworks/style/css.js +0 -0
  53. package/fireworks/style/index.js +0 -0
  54. package/fireworks/type.ts +72 -0
  55. package/form/FormItem.tsx +5 -5
  56. package/form/easing.ts +10 -0
  57. package/form/scroll.ts +124 -0
  58. package/form/type.ts +519 -519
  59. package/global-config/default-config.ts +95 -0
  60. package/global-config/locale/ar_KW.ts +270 -0
  61. package/global-config/locale/en_US.ts +280 -0
  62. package/global-config/locale/it_IT.ts +287 -0
  63. package/global-config/locale/ja_JP.ts +279 -0
  64. package/global-config/locale/ko_KR.ts +279 -0
  65. package/global-config/locale/ru_RU.ts +288 -0
  66. package/global-config/locale/zh_CN.ts +279 -0
  67. package/global-config/locale/zh_TW.ts +279 -0
  68. package/global-config/mobile/default-config.ts +6 -0
  69. package/global-config/mobile/locale/ar_KW.ts +113 -0
  70. package/global-config/mobile/locale/en_US.ts +114 -0
  71. package/global-config/mobile/locale/it_IT.ts +114 -0
  72. package/global-config/mobile/locale/ja_JP.ts +101 -0
  73. package/global-config/mobile/locale/ko_KR.ts +101 -0
  74. package/global-config/mobile/locale/ru_RU.ts +113 -0
  75. package/global-config/mobile/locale/zh_CN.ts +101 -0
  76. package/global-config/mobile/locale/zh_TW.ts +101 -0
  77. package/global-config/t.ts +111 -0
  78. package/hooks/useControlled.ts +3 -3
  79. package/hooks/useDeepEffect.ts +32 -0
  80. package/hooks/useGlobalIcon.ts +10 -3
  81. package/hooks/useLastest.ts +2 -6
  82. package/hooks/useResizeObserve.ts +36 -0
  83. package/index.ts +10 -7
  84. package/input/Input.tsx +4 -1
  85. package/input/defaultProps.ts +0 -2
  86. package/input/type.ts +1 -6
  87. package/input-number/InputNumber.tsx +124 -0
  88. package/input-number/defaultProps.ts +17 -0
  89. package/input-number/index.ts +9 -0
  90. package/input-number/style/css.js +1 -0
  91. package/input-number/style/index.js +1 -0
  92. package/input-number/type.ts +147 -0
  93. package/input-number/useInputNumber.tsx +270 -0
  94. package/ip-input/IPInput.tsx +516 -0
  95. package/ip-input/defaultProps.ts +11 -0
  96. package/ip-input/index.ts +3 -0
  97. package/ip-input/style/css.js +1 -0
  98. package/ip-input/style/index.js +1 -0
  99. package/ip-input/type.ts +115 -0
  100. package/ip-input/utils.ts +112 -0
  101. package/layout/Aside.tsx +38 -0
  102. package/layout/Layout.tsx +104 -0
  103. package/layout/defaultProps.ts +9 -0
  104. package/layout/index.ts +9 -0
  105. package/layout/style/css.js +1 -0
  106. package/layout/style/index.js +1 -0
  107. package/layout/type.ts +43 -0
  108. package/list/List.tsx +144 -0
  109. package/list/ListItem.tsx +36 -0
  110. package/list/ListItemMeta.tsx +40 -0
  111. package/list/defaultProps.ts +11 -0
  112. package/list/hooks/useListVirtualScroll.ts +82 -0
  113. package/list/index.ts +11 -0
  114. package/list/style/css.js +1 -0
  115. package/list/style/index.js +1 -0
  116. package/list/type.ts +93 -0
  117. package/locale/LocalReceiver.ts +55 -0
  118. package/locale/ar_KW.ts +7 -0
  119. package/locale/en_US.ts +7 -0
  120. package/locale/it_IT.ts +6 -0
  121. package/locale/ja_JP.ts +6 -0
  122. package/locale/ko_KR.ts +6 -0
  123. package/locale/ru_RU.ts +6 -0
  124. package/locale/zh_CN.ts +5 -0
  125. package/locale/zh_TW.ts +7 -0
  126. package/notification/NotifyContainer.tsx +2 -2
  127. package/notification/NotifyContext.tsx +1 -0
  128. package/package.json +6 -3
  129. package/popup/Popup.tsx +34 -10
  130. package/radio/Radio.tsx +24 -0
  131. package/radio/RadioGroup.tsx +159 -0
  132. package/radio/defaultProps.ts +18 -0
  133. package/radio/index.ts +12 -0
  134. package/radio/style/css.js +0 -0
  135. package/radio/style/index.js +1 -0
  136. package/radio/type.ts +115 -0
  137. package/radio/useKeyboard.ts +36 -0
  138. package/select/hooks/useOptions.ts +10 -7
  139. package/select/hooks/usePanelVirtualScroll.ts +1 -1
  140. package/select/type.ts +382 -382
  141. package/select-input/type.ts +280 -280
  142. package/slider/Slider.tsx +270 -0
  143. package/slider/SliderHandleButton.tsx +50 -0
  144. package/slider/defaultProps.ts +15 -0
  145. package/slider/index.ts +9 -0
  146. package/slider/style/css.js +1 -0
  147. package/slider/style/index.js +1 -0
  148. package/slider/type.ts +77 -0
  149. package/style/all.js +26 -0
  150. package/styles/_global.scss +39 -39
  151. package/styles/_vars.scss +358 -386
  152. package/styles/components/alert/_index.scss +175 -175
  153. package/styles/components/alert/_vars.scss +39 -39
  154. package/styles/components/badge/_index.scss +70 -70
  155. package/styles/components/badge/_vars.scss +25 -25
  156. package/styles/components/button/_index.scss +499 -511
  157. package/styles/components/button/_mixins.scss +39 -39
  158. package/styles/components/button/_vars.scss +120 -122
  159. package/styles/components/checkbox/_index.scss +158 -158
  160. package/styles/components/checkbox/_var.scss +60 -60
  161. package/styles/components/color-picker/_index.scss +586 -0
  162. package/styles/components/color-picker/_mixins.scss +0 -0
  163. package/styles/components/color-picker/_vars.scss +84 -0
  164. package/styles/components/dialog/_animate.scss +135 -135
  165. package/styles/components/dialog/_index.scss +311 -311
  166. package/styles/components/dialog/_vars.scss +59 -59
  167. package/styles/components/drawer/_index.scss +205 -0
  168. package/styles/components/drawer/_mixins.scss +1 -0
  169. package/styles/components/drawer/_var.scss +53 -0
  170. package/styles/components/fireworks/_index.scss +86 -0
  171. package/styles/components/fireworks/_vars.scss +4 -0
  172. package/styles/components/form/_index.scss +174 -174
  173. package/styles/components/form/_mixins.scss +76 -76
  174. package/styles/components/form/_vars.scss +100 -100
  175. package/styles/components/input/_index.scss +349 -349
  176. package/styles/components/input/_mixins.scss +116 -116
  177. package/styles/components/input/_vars.scss +134 -134
  178. package/styles/components/input-number/_index.scss +353 -0
  179. package/styles/components/input-number/_mixins.scss +0 -0
  180. package/styles/components/input-number/_vars.scss +65 -0
  181. package/styles/components/ip-input/_index.scss +280 -0
  182. package/styles/components/layout/_index.scss +47 -0
  183. package/styles/components/layout/_mixin.scss +0 -0
  184. package/styles/components/layout/_vars.scss +18 -0
  185. package/styles/components/layout/doc.scss +74 -0
  186. package/styles/components/list/_index.scss +172 -0
  187. package/styles/components/list/_mixins.scss +0 -0
  188. package/styles/components/list/_vars.scss +41 -0
  189. package/styles/components/loading/_index.scss +112 -112
  190. package/styles/components/loading/_vars.scss +39 -39
  191. package/styles/components/notification/_index.scss +160 -160
  192. package/styles/components/notification/_mixins.scss +12 -12
  193. package/styles/components/notification/_vars.scss +59 -59
  194. package/styles/components/popup/_index.scss +82 -82
  195. package/styles/components/popup/_mixin.scss +149 -149
  196. package/styles/components/popup/_var.scss +31 -31
  197. package/styles/components/radio/_index.scss +376 -0
  198. package/styles/components/radio/_mixins.scss +0 -0
  199. package/styles/components/radio/_var.scss +92 -0
  200. package/styles/components/select/_index.scss +290 -290
  201. package/styles/components/select/_var.scss +65 -65
  202. package/styles/components/select-input/_index.scss +5 -5
  203. package/styles/components/select-input/_var.scss +3 -3
  204. package/styles/components/slider/_index.scss +241 -0
  205. package/styles/components/slider/_mixins.scss +0 -0
  206. package/styles/components/slider/_vars.scss +50 -0
  207. package/styles/components/switch/_index.scss +279 -279
  208. package/styles/components/switch/_vars.scss +61 -61
  209. package/styles/components/table/_index.scss +193 -0
  210. package/styles/components/table/_var.scss +52 -0
  211. package/styles/components/tabs/_index.scss +165 -0
  212. package/styles/components/tabs/_mixins.scss +11 -0
  213. package/styles/components/tabs/_vars.scss +71 -0
  214. package/styles/components/tag/_index.scss +316 -316
  215. package/styles/components/tag/_var.scss +85 -85
  216. package/styles/components/tag-input/_index.scss +163 -163
  217. package/styles/components/tag-input/_vars.scss +16 -16
  218. package/styles/globals.css +250 -250
  219. package/styles/mixins/_focus.scss +7 -7
  220. package/styles/mixins/_layout.scss +32 -32
  221. package/styles/mixins/_reset.scss +10 -10
  222. package/styles/mixins/_scrollbar.scss +31 -31
  223. package/styles/mixins/_text.scss +48 -48
  224. package/styles/rillple.css +16 -16
  225. package/styles/scrollbar.css +41 -41
  226. package/styles/themes/_dark.scss +191 -191
  227. package/styles/themes/_font.scss +69 -79
  228. package/styles/themes/_index.scss +5 -5
  229. package/styles/themes/_light.scss +190 -190
  230. package/styles/themes/_radius.scss +9 -9
  231. package/styles/themes/_size.scss +68 -68
  232. package/styles/themes.css +66 -66
  233. package/styles/utilities/_animation.scss +57 -57
  234. package/styles/utilities/_tips.scss +9 -9
  235. package/tab/TabBar.tsx +85 -0
  236. package/tab/TabNav.tsx +103 -0
  237. package/tab/TabNavItem.tsx +80 -0
  238. package/tab/TabPanel.tsx +42 -0
  239. package/tab/Tabs.tsx +71 -0
  240. package/tab/defaultProps.ts +19 -0
  241. package/tab/index.ts +7 -0
  242. package/tab/style/index.js +1 -0
  243. package/tab/type.ts +125 -0
  244. package/tab/useTabClass.ts +20 -0
  245. package/table/Cell.tsx +109 -0
  246. package/table/TBody.tsx +77 -0
  247. package/table/THead.tsx +63 -0
  248. package/table/TR.tsx +78 -0
  249. package/table/Table.tsx +73 -0
  250. package/table/defaultProps.ts +14 -0
  251. package/table/hooks/index.ts +4 -0
  252. package/table/hooks/useTableClassName.ts +63 -0
  253. package/table/hooks/useTableStyle.ts +93 -0
  254. package/table/index.ts +7 -0
  255. package/table/style/css.js +1 -0
  256. package/table/style/index.js +1 -0
  257. package/table/type.ts +192 -0
  258. package/tag/Tag.tsx +1 -1
  259. package/tag-input/hooks/useTagList.tsx +1 -1
  260. package/utils/dom.ts +4 -0
  261. package/utils/forwardRefWithStatics.ts +1 -4
  262. package/utils/input-number/large-number.ts +423 -0
  263. package/utils/input-number/number.ts +257 -0
  264. package/utils/isFragment.ts +6 -6
  265. package/utils/log/index.ts +3 -0
  266. package/utils/log/log.ts +30 -0
  267. package/utils/log/types.ts +12 -0
  268. package/utils/number.ts +21 -0
  269. package/utils/scroll.ts +26 -0
  270. 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
+ }
@@ -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;
@@ -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, typeof Icon>) {
11
+ export default function useGlobalIcon(tdIcon: Record<string, ConvertedIconComponent>) {
5
12
  const { icon: globalIcon } = useConfig();
6
13
 
7
- const resultIcon: Record<string, typeof Icon> = {};
14
+ const resultIcon: Record<string, ConvertedIconComponent> = {};
8
15
 
9
16
  Object.keys(tdIcon).forEach((key) => {
10
17
  resultIcon[key] = globalIcon?.[key] || tdIcon[key];
@@ -1,12 +1,8 @@
1
- import { useRef, useEffect } from "react";
1
+ import { useRef } from "react";
2
2
 
3
3
  const useLatest = <T>(value: T) => {
4
4
  const ref = useRef(value);
5
-
6
- useEffect(() => {
7
- ref.current = value;
8
- });
9
-
5
+ ref.current = value;
10
6
  return ref;
11
7
  };
12
8
 
@@ -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
- // export * from './radio';
9
+ export * from "./radio";
10
10
  export * from "./checkbox";
11
- // export * from './input-number';
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
- // export * from './list';
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 './divider';
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
- // export * from './drawer';
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
- // export * from './slider';
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
- // export * from './color-picker';
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,
@@ -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,9 @@
1
+ import _InputNumber from "./InputNumber";
2
+
3
+ import "./style/index.js";
4
+
5
+ export type { InputNumberProps } from "./InputNumber";
6
+ export * from "./type";
7
+
8
+ export const InputNumber = _InputNumber;
9
+ export default InputNumber;
@@ -0,0 +1 @@
1
+ import "./index.css";
@@ -0,0 +1 @@
1
+ import "../../styles/components/input-number/_index.scss";