@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.
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,100 @@
1
+ /* eslint-disable no-use-before-define */
2
+ export interface Coordinate {
3
+ x: number;
4
+ y: number;
5
+ }
6
+
7
+ export type DraggableEvent = MouseEvent;
8
+
9
+ interface DraggableCallback {
10
+ (coordinate: Coordinate, event?: DraggableEvent): void;
11
+ }
12
+
13
+ export interface DraggableProps {
14
+ start?: DraggableCallback;
15
+ drag?: DraggableCallback;
16
+ end?: DraggableCallback;
17
+ }
18
+
19
+ interface DraggableHandles {
20
+ start: (event: DraggableEvent) => void;
21
+ drag: (event: DraggableEvent) => void;
22
+ end: (event: DraggableEvent) => void;
23
+ }
24
+
25
+ // 配置项
26
+ const defaultsOptions: DraggableProps = {
27
+ start: (coordinate: Coordinate, event: DraggableEvent) => {},
28
+ drag: (coordinate: Coordinate, event: DraggableEvent) => {},
29
+ end: (coordinate: Coordinate, event: DraggableEvent) => {},
30
+ };
31
+
32
+ export class Draggable {
33
+ private dragging = false;
34
+
35
+ private $el: HTMLElement;
36
+
37
+ private props: DraggableProps;
38
+
39
+ private handles: DraggableHandles;
40
+
41
+ constructor(el: HTMLElement, options?: DraggableProps) {
42
+ this.$el = el;
43
+ this.props = { ...defaultsOptions, ...options };
44
+ this.handles = {
45
+ start: this.#dragStart.bind(this),
46
+ drag: this.#drag.bind(this),
47
+ end: this.#dragEnd.bind(this),
48
+ };
49
+ this.$el.addEventListener('mousedown', this.handles.start, false);
50
+ }
51
+
52
+ #dragStart(event: DraggableEvent) {
53
+ if (this.dragging) {
54
+ return;
55
+ }
56
+ // event.preventDefault();
57
+ window.addEventListener('mousemove', this.handles.drag, false);
58
+ window.addEventListener('mouseup', this.handles.end, false);
59
+ window.addEventListener('contextmenu', this.handles.end, false);
60
+ this.dragging = true;
61
+ this.props.start(this.#getCoordinate(event), event);
62
+ }
63
+
64
+ #drag(event: DraggableEvent) {
65
+ if (!this.dragging) {
66
+ return;
67
+ }
68
+ this.props.drag(this.#getCoordinate(event), event);
69
+ }
70
+
71
+ #dragEnd(event: DraggableEvent) {
72
+ setTimeout(() => {
73
+ this.dragging = false;
74
+ this.props.end(this.#getCoordinate(event), event);
75
+ }, 0);
76
+ window.removeEventListener('mousemove', this.handles.drag, false);
77
+ window.removeEventListener('mouseup', this.handles.end, false);
78
+ window.removeEventListener('contextmenu', this.handles.end, false);
79
+ }
80
+
81
+ #getCoordinate(event: DraggableEvent) {
82
+ const rect = this.$el.getBoundingClientRect();
83
+ const mouseEvent = event;
84
+ const left = mouseEvent.clientX - rect.left;
85
+ const top = mouseEvent.clientY - rect.top;
86
+ return {
87
+ y: Math.min(Math.max(0, top), rect.height),
88
+ x: Math.min(Math.max(0, left), rect.width),
89
+ };
90
+ }
91
+
92
+ destroy() {
93
+ this.$el.removeEventListener('mousedown', this.handles.start, false);
94
+ window.removeEventListener('mousemove', this.handles.drag, false);
95
+ window.removeEventListener('mouseup', this.handles.end, false);
96
+ window.removeEventListener('contextmenu', this.handles.end, false);
97
+ }
98
+ }
99
+
100
+ export default Draggable;
@@ -0,0 +1,95 @@
1
+ import Color from './color';
2
+ import { ALPHA_FORMAT_MAP, COLOR_FORMAT_INPUTS, FORMATS } from './constants';
3
+ import type { AlphaConvertibleFormat, BasicColorFormat, ColorFormat } from './types';
4
+
5
+ /**
6
+ * 兜底处理用户传入的格式,例如:
7
+ * - 传入 `RGB`, 但 `enableAlpha` ,则返回 `RGBA`
8
+ */
9
+ export const initColorFormat = (format: ColorFormat, enableAlpha: boolean) => {
10
+ if (enableAlpha && format in ALPHA_FORMAT_MAP) {
11
+ return format in ALPHA_FORMAT_MAP ? ALPHA_FORMAT_MAP[format as AlphaConvertibleFormat] : format;
12
+ }
13
+ return format as BasicColorFormat;
14
+ };
15
+
16
+ /**
17
+ * 获取不同格式的输入输出值
18
+ * - encode:将字符串转换为单独的颜色值,例如 `{r: 255, g: 255, b: 255}`
19
+ * - decode:获取完整的颜色字符串,例如 `rgb(255, 255, 255)`
20
+ */
21
+ export const getColorFormatMap = (color: Color, type: 'encode' | 'decode') => {
22
+ if (type === 'encode') {
23
+ return {
24
+ HSV: color.getHsva(),
25
+ HSVA: color.getHsva(),
26
+ HSL: color.getHsla(),
27
+ HSLA: color.getHsla(),
28
+ RGB: color.getRgba(),
29
+ RGBA: color.getRgba(),
30
+ CMYK: color.getCmyk(),
31
+ CSS: {
32
+ css: color.css,
33
+ },
34
+ HEX: {
35
+ hex: color.hex,
36
+ },
37
+ HEX8: {
38
+ hex: color.hex8, // 为了减少转换 hex8 的 key 也对应 hex
39
+ },
40
+ };
41
+ }
42
+
43
+ // decode
44
+ return color.getFormatsColorMap();
45
+ };
46
+
47
+ /**
48
+ * 获取下拉框的格式选项
49
+ */
50
+ export const getColorFormatOptions = (enableAlpha: boolean) => (
51
+ enableAlpha
52
+ ? FORMATS.map((item) => (item in ALPHA_FORMAT_MAP ? ALPHA_FORMAT_MAP[item as AlphaConvertibleFormat] : item))
53
+ : FORMATS
54
+ );
55
+
56
+ /**
57
+ * 获取当前格式的输入框配置
58
+ */
59
+ export const getColorFormatInputs = (
60
+ format: ColorFormat = 'RGB',
61
+ enableAlpha: boolean
62
+ ) => {
63
+ let finalFormat;
64
+
65
+ /* 为了减少 `ALPHA_FORMAT_MAP` 中的重复代码
66
+ `RGBA/HEX8/HSLA/HSVA` 会被转换为 `RGB/HEX/HSL/HSV` 后再匹配
67
+ 但在下一步会 push 一个代表透明度的输入框 */
68
+ if (enableAlpha) {
69
+ finalFormat = Object.keys(ALPHA_FORMAT_MAP).find(
70
+ (key) => key in ALPHA_FORMAT_MAP && ALPHA_FORMAT_MAP[key as AlphaConvertibleFormat] === format
71
+ ) || format;
72
+ } else {
73
+ finalFormat = format;
74
+ }
75
+
76
+ if (!COLOR_FORMAT_INPUTS[finalFormat as BasicColorFormat]) return [];
77
+
78
+ const configs = [
79
+ ...(COLOR_FORMAT_INPUTS[finalFormat as BasicColorFormat]),
80
+ ];
81
+
82
+ // CMYK 格式不支持透明度
83
+ if (enableAlpha && format !== 'CMYK') {
84
+ configs.push({
85
+ type: 'inputNumber',
86
+ key: 'a',
87
+ min: 0,
88
+ max: 100,
89
+ format: (value: number) => `${value}%`,
90
+ flex: 1.15,
91
+ });
92
+ }
93
+
94
+ return configs;
95
+ };
@@ -0,0 +1,243 @@
1
+ import { isString, isNull } from 'lodash-es';
2
+ /* eslint-disable no-param-reassign */
3
+ /**
4
+ * 用于反解析渐变字符串为对象
5
+ * https://stackoverflow.com/questions/20215440/parse-css-gradient-rule-with-javascript-regex
6
+ */
7
+ import tinyColor from 'tinycolor2';
8
+
9
+ /**
10
+ * Utility combine multiple regular expressions.
11
+ *
12
+ * @param {RegExp[]|string[]} regexpList List of regular expressions or strings.
13
+ * @param {string} flags Normal RegExp flags.
14
+ */
15
+ const combineRegExp = (regexpList: (string | RegExp)[], flags: string): RegExp => {
16
+ let source = '';
17
+ for (let i = 0; i < regexpList.length; i++) {
18
+ if (isString(regexpList[i])) {
19
+ source += regexpList[i];
20
+ } else {
21
+ source += (regexpList[i] as RegExp).source;
22
+ }
23
+ }
24
+ return new RegExp(source, flags);
25
+ };
26
+
27
+ interface RegExpLib {
28
+ gradientSearch: RegExp;
29
+ colorStopSearch: RegExp;
30
+ }
31
+
32
+ interface ColorStop {
33
+ color: string;
34
+ position?: string;
35
+ }
36
+
37
+ interface ParseGradientResult {
38
+ original: string;
39
+ colorStopList?: ColorStop[];
40
+ line?: string;
41
+ angle?: string;
42
+ sideCorner?: string;
43
+ }
44
+
45
+ /**
46
+ * Generate the required regular expressions once.
47
+ *
48
+ * Regular Expressions are easier to manage this way and can be well described.
49
+ *
50
+ * @result {object} Object containing regular expressions.
51
+ */
52
+ const generateRegExp = (): RegExpLib => {
53
+ // Note any variables with "Capture" in name include capturing bracket set(s).
54
+ const searchFlags = 'gi'; // ignore case for angles, "rgb" etc
55
+ const rAngle = /(?:[+-]?\d*\.?\d+)(?:deg|grad|rad|turn)/; // Angle +ive, -ive and angle types
56
+ // optional 2nd part
57
+ const rSideCornerCapture = /to\s+((?:(?:left|right|top|bottom)(?:\s+(?:top|bottom|left|right))?))/;
58
+ const rComma = /\s*,\s*/; // Allow space around comma.
59
+ const rColorHex = /#(?:[a-f0-9]{6}|[a-f0-9]{3})/; // 3 or 6 character form
60
+ const rDigits3 = /\(\s*(?:\d{1,3}\s*,\s*){2}\d{1,3}\s*\)/;
61
+ const // "(1, 2, 3)"
62
+ rDigits4 = /\(\s*(?:\d{1,3}\s*,\s*){2}\d{1,3}\s*,\s*\d*\.?\d+\)/;
63
+ const // "(1, 2, 3, 4)"
64
+ rValue = /(?:[+-]?\d*\.?\d+)(?:%|[a-z]+)?/;
65
+ const // ".9", "-5px", "100%".
66
+ rKeyword = /[_a-z-][_a-z0-9-]*/;
67
+ const // "red", "transparent".
68
+ rColor = combineRegExp(
69
+ ['(?:', rColorHex, '|', '(?:rgb|hsl)', rDigits3, '|', '(?:rgba|hsla)', rDigits4, '|', rKeyword, ')'],
70
+ '',
71
+ );
72
+ const rColorStop = combineRegExp([rColor, '(?:\\s+', rValue, '(?:\\s+', rValue, ')?)?'], '');
73
+ const // Single Color Stop, optional %, optional length.
74
+ rColorStopList = combineRegExp(['(?:', rColorStop, rComma, ')*', rColorStop], '');
75
+ const // List of color stops min 1.
76
+ rLineCapture = combineRegExp(['(?:(', rAngle, ')|', rSideCornerCapture, ')'], '');
77
+ const // Angle or SideCorner
78
+ rGradientSearch = combineRegExp(['(?:(', rLineCapture, ')', rComma, ')?(', rColorStopList, ')'], searchFlags);
79
+ const // Capture 1:"line", 2:"angle" (optional), 3:"side corner" (optional) and 4:"stop list".
80
+ rColorStopSearch = combineRegExp(
81
+ ['\\s*(', rColor, ')', '(?:\\s+', '(', rValue, '))?', '(?:', rComma, '\\s*)?'],
82
+ searchFlags,
83
+ ); // Capture 1:"color" and 2:"position" (optional).
84
+
85
+ return {
86
+ gradientSearch: rGradientSearch,
87
+ colorStopSearch: rColorStopSearch,
88
+ };
89
+ };
90
+
91
+ /**
92
+ * Actually parse the input gradient parameters string into an object for reusability.
93
+ *
94
+ *
95
+ * @note Really this only supports the standard syntax not historical versions, see MDN for details
96
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient
97
+ *
98
+ * @param regExpLib
99
+ * @param {string} input
100
+ * @returns {object|undefined}
101
+ */
102
+ const parseGradient = (regExpLib: RegExpLib, input: string) => {
103
+ let result: ParseGradientResult;
104
+ let matchColorStop: any;
105
+ let stopResult: ColorStop;
106
+
107
+ // reset search position, because we reuse regex.
108
+ regExpLib.gradientSearch.lastIndex = 0;
109
+
110
+ const matchGradient = regExpLib.gradientSearch.exec(input);
111
+ if (!isNull(matchGradient)) {
112
+ result = {
113
+ original: matchGradient[0],
114
+ colorStopList: [],
115
+ };
116
+
117
+ // Line (Angle or Side-Corner).
118
+ if (matchGradient[1]) {
119
+ // eslint-disable-next-line prefer-destructuring
120
+ result.line = matchGradient[1];
121
+ }
122
+ // Angle or undefined if side-corner.
123
+ if (matchGradient[2]) {
124
+ // eslint-disable-next-line prefer-destructuring
125
+ result.angle = matchGradient[2];
126
+ }
127
+ // Side-corner or undefined if angle.
128
+ if (matchGradient[3]) {
129
+ // eslint-disable-next-line prefer-destructuring
130
+ result.sideCorner = matchGradient[3];
131
+ }
132
+
133
+ // reset search position, because we reuse regex.
134
+ regExpLib.colorStopSearch.lastIndex = 0;
135
+
136
+ // Loop though all the color-stops.
137
+ matchColorStop = regExpLib.colorStopSearch.exec(matchGradient[4]);
138
+ while (!isNull(matchColorStop)) {
139
+ stopResult = {
140
+ color: matchColorStop[1],
141
+ };
142
+
143
+ // Position (optional).
144
+ if (matchColorStop[2]) {
145
+ // eslint-disable-next-line prefer-destructuring
146
+ stopResult.position = matchColorStop[2];
147
+ }
148
+ result.colorStopList.push(stopResult);
149
+
150
+ // Continue searching from previous position.
151
+ matchColorStop = regExpLib.colorStopSearch.exec(matchGradient[4]);
152
+ }
153
+ }
154
+
155
+ // Can be undefined if match not found.
156
+ return result;
157
+ };
158
+
159
+ export interface GradientColorPoint {
160
+ id?: string;
161
+ color?: string;
162
+ left?: number;
163
+ }
164
+
165
+ export interface GradientColors {
166
+ points: GradientColorPoint[];
167
+ degree: number;
168
+ }
169
+
170
+ const REGEXP_LIB = generateRegExp();
171
+ const REG_GRADIENT = /.*gradient\s*\(((?:\([^)]*\)|[^)(]*)*)\)/gim;
172
+
173
+ /**
174
+ * 验证是否是渐变字符串
175
+ * @param input
176
+ * @returns
177
+ */
178
+ export const isGradientColor = (input: string): null | RegExpExecArray => {
179
+ REG_GRADIENT.lastIndex = 0;
180
+ return REG_GRADIENT.exec(input);
181
+ };
182
+
183
+ // 边界字符串和角度关系
184
+ const sideCornerDegreeMap = {
185
+ top: 0,
186
+ right: 90,
187
+ bottom: 180,
188
+ left: 270,
189
+ 'top left': 315,
190
+ 'left top': 315,
191
+ 'top right': 45,
192
+ 'right top': 45,
193
+ 'bottom left': 225,
194
+ 'left bottom': 225,
195
+ 'bottom right': 135,
196
+ 'right bottom': 135,
197
+ };
198
+
199
+ /**
200
+ * 解析渐变字符串为 GradientColors 对象
201
+ * @param input
202
+ * @returns
203
+ */
204
+ export const parseGradientString = (input: string): GradientColors | false => {
205
+ const match = isGradientColor(input);
206
+ if (!match) return false;
207
+
208
+ const gradientColors: GradientColors = {
209
+ points: [],
210
+ degree: 0,
211
+ };
212
+
213
+ const result: ParseGradientResult = parseGradient(REGEXP_LIB, match[1]);
214
+ if (result.original.trim() !== match[1].trim()) return false;
215
+
216
+ const points: GradientColorPoint[] = result.colorStopList.map(
217
+ ({ color, position }, index, array) => {
218
+ const point = Object.create(null);
219
+ point.color = tinyColor(color).toRgbString();
220
+
221
+ let left = parseFloat(position);
222
+ if (Number.isNaN(left)) {
223
+ left = (index / (array.length - 1)) * 100;
224
+ }
225
+
226
+ point.left = left;
227
+ return point;
228
+ }
229
+ );
230
+ gradientColors.points = points;
231
+
232
+ let degree = parseInt(result.angle, 10);
233
+ if (Number.isNaN(degree)) {
234
+ /* 如果角度不存在,使用 CSS 渐变的默认逻辑(180 deg)
235
+ https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_images/Using_CSS_gradients */
236
+ degree = sideCornerDegreeMap[result.sideCorner as keyof typeof sideCornerDegreeMap] || 180;
237
+ }
238
+ gradientColors.degree = degree;
239
+
240
+ return gradientColors;
241
+ };
242
+
243
+ export default parseGradientString;
@@ -0,0 +1,7 @@
1
+ export * from "./cmyk";
2
+ export * from "./color";
3
+ export * from "./constants";
4
+ export * from "./draggable";
5
+ export * from "./format";
6
+ export * from "./gradient";
7
+ export * from "./types";
@@ -0,0 +1,33 @@
1
+ import { ALPHA_FORMAT_MAP, FORMATS } from './constants';
2
+
3
+ /**
4
+ * 非透明色类型
5
+ */
6
+ export type BasicColorFormat = typeof FORMATS[number];
7
+
8
+ /**
9
+ * 支持转为透明格式的非透明色类型
10
+ */
11
+ export type AlphaConvertibleFormat = keyof typeof ALPHA_FORMAT_MAP;
12
+
13
+ /**
14
+ * 透明色类型
15
+ */
16
+ export type AlphaColorFormat = typeof ALPHA_FORMAT_MAP[AlphaConvertibleFormat];
17
+
18
+ /**
19
+ * 完整的颜色格式类型
20
+ */
21
+ export type ColorFormat = BasicColorFormat | AlphaColorFormat;
22
+
23
+ /**
24
+ * 不同颜色格式对应的输入框配置
25
+ */
26
+ export interface ColorInputProp {
27
+ key: string;
28
+ min?: number;
29
+ max?: number;
30
+ type: 'input' | 'inputNumber';
31
+ flex?: number;
32
+ format?: Function;
33
+ }
@@ -0,0 +1,33 @@
1
+ export default function observe(
2
+ element: HTMLElement,
3
+ root: HTMLElement,
4
+ callback: Function,
5
+ marginBottom: number
6
+ ): IntersectionObserver {
7
+ if (typeof window === "undefined") return null;
8
+ if (!window || !window.IntersectionObserver) {
9
+ callback();
10
+ return null;
11
+ }
12
+ let io: IntersectionObserver = null;
13
+ try {
14
+ io = new window.IntersectionObserver(
15
+ (entries) => {
16
+ const entry = entries[0];
17
+ if (entry.isIntersecting) {
18
+ callback();
19
+ io.unobserve(element);
20
+ }
21
+ },
22
+ {
23
+ rootMargin: `0px 0px ${marginBottom}px 0px`,
24
+ root
25
+ }
26
+ );
27
+ io.observe(element);
28
+ } catch (e) {
29
+ console.error(e);
30
+ callback();
31
+ }
32
+ return io;
33
+ }
package/common.ts CHANGED
@@ -27,6 +27,7 @@ export type HorizontalAlignEnum = "left" | "center" | "right";
27
27
  export type VerticalAlignEnum = "top" | "middle" | "bottom";
28
28
 
29
29
  export type LayoutEnum = "vertical" | "horizontal";
30
+
30
31
  // TElement 表示 API 只接受传入组件
31
32
  export type TElement<T = undefined> = T extends undefined ? ReactElement : (props: T) => ReactElement;
32
33
 
@@ -63,6 +64,8 @@ export interface ScrollToElementParams {
63
64
  /** 单个元素高度非固定场景下,即 isFixedRowHeight = false。延迟设置元素位置,一般用于依赖不同高度异步渲染等场景,单位:毫秒 */
64
65
  time?: number;
65
66
  behavior?: "auto" | "smooth";
67
+ /** 跳转元素的 key */
68
+ key?: string | number;
66
69
  }
67
70
 
68
71
  /**
@@ -74,3 +77,20 @@ export type PlainObject = { [key: string]: unknown };
74
77
  * @deprecated use TScroll instead
75
78
  */
76
79
  export type InfinityScroll = TScroll;
80
+
81
+ export const ARROW_DOWN_REG = /^ArrowDown$/i;
82
+ export const ARROW_UP_REG = /^ArrowUp$/i;
83
+ export const ARROW_LEFT_REG = /^ArrowLeft$/i;
84
+ export const ARROW_RIGHT_REG = /^ArrowRight$/i;
85
+ export const ESCAPE_REG = /^Escape$/i;
86
+ export const SPACE_REG = /^Space$/i;
87
+ export const ENTER_REG = /^Enter$/i;
88
+ export const SHIFT_REG = /^(Shift|ShiftLeft|ShiftRight)$/i;
89
+ export const CLEAR_REG = /^KeyC$/i;
90
+ export const ALL_REG = /^(KeyA|KeyL)$/i;
91
+ export const CHECKED_CODE_REG = /^(Enter|Space)$/i;
92
+
93
+ export const THEME_MODE = "theme-mode";
94
+
95
+ export type ScrollContainer = string | (() => HTMLElement | Window) | HTMLElement | Window | null;
96
+ export type ScrollContainerElement = HTMLElement | Window;
@@ -2,13 +2,15 @@ import { createContext } from "react";
2
2
  import { GlobalConfigProvider } from "./type";
3
3
  import Icon from "@tendaui/icons";
4
4
  export const defaultClassPrefix = "t";
5
+ import defaultLocale from "../locale/zh_CN";
5
6
 
6
7
  export const defaultGlobalConfig: GlobalConfigProvider = {
7
8
  classPrefix: defaultClassPrefix,
8
9
  attach: null,
9
10
  form: {},
10
11
  icon: {} as Record<string, typeof Icon>,
11
- isContextEffectPlugin: false
12
+ isContextEffectPlugin: false,
13
+ ...defaultLocale
12
14
  };
13
15
 
14
16
  export const defaultContext = {
@@ -19,3 +21,4 @@ export type Config = typeof defaultContext;
19
21
 
20
22
  const ConfigContext = createContext(defaultContext);
21
23
  export default ConfigContext;
24
+ export type Locale = typeof defaultLocale;
@@ -1,7 +1,7 @@
1
1
  import ConfigProvider, { merge } from "./ConfigProvider";
2
2
  import ConfigContext from "./ConfigContext";
3
3
 
4
- export type { Config } from "./ConfigContext";
4
+ export type { Config, Locale } from "./ConfigContext";
5
5
  export type { ConfigProviderProps } from "./ConfigProvider";
6
6
  export * from "./type";
7
7
 
@@ -12,7 +12,7 @@ import { StyledProps, TNode } from "../common";
12
12
  import parseTNode from "../utils/parseTNode";
13
13
  import useConfig from "../hooks/useConfig";
14
14
  import useGlobalIcon from "../hooks/useGlobalIcon";
15
- // import { useLocaleReceiver } from '../locale/LocalReceiver';
15
+ import { useLocaleReceiver } from "../locale/LocalReceiver";
16
16
  import { dialogCardDefaultProps } from "./defaultProps";
17
17
  import useDefaultProps from "../hooks/useDefaultProps";
18
18
 
@@ -44,11 +44,9 @@ const DialogCard = forwardRef<HTMLDivElement, DialogCardProps>((props, ref) => {
44
44
  InfoCircleFilledIcon: TdInfoCircleFilledIcon,
45
45
  CheckCircleFilledIcon: TdCheckCircleFilledIcon
46
46
  });
47
- // const [local, t] = useLocaleReceiver('dialog');
48
- // const confirmText = t(local.confirm);
49
- // const cancelText = t(local.cancel);
50
- const confirmText = "确认";
51
- const cancelText = "取消";
47
+ const [local, t] = useLocaleReceiver("dialog");
48
+ const confirmText = t(local.confirm);
49
+ const cancelText = t(local.cancel);
52
50
  const {
53
51
  theme,
54
52
  header,
@@ -27,8 +27,7 @@ export default function useDialogPosition(visible: boolean | undefined, dialogCa
27
27
  if (!visible) return;
28
28
  // 动画渲染初始位置
29
29
  if (mousePosRef.current && dialogCardRef.current) {
30
- // eslint-disable-next-line
31
- dialogCardRef.current.style.transformOrigin = `${mousePosRef.current.x - dialogCardRef.current.offsetLeft}px ${
30
+ dialogCardRef.current.style.transformOrigin = `${mousePosRef.current.x - dialogCardRef.current.offsetLeft}px ${
32
31
  mousePosRef.current.y - dialogCardRef.current.offsetTop
33
32
  }px`;
34
33
  }
package/dialog/plugin.tsx CHANGED
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { render } from "../utils/react-render";
3
3
  import DialogComponent, { DialogProps } from "./Dialog";
4
- import { getAttach } from "../utils/dom";
4
+ import { getAttach } from "../common/Portal";
5
5
  import { DialogOptions, DialogMethod, DialogConfirmMethod, DialogAlertMethod, DialogInstance } from "./type";
6
6
  import PluginContainer from "../common/PluginContainer";
7
7
  import ConfigProvider from "../config-provider";
@@ -25,7 +25,8 @@ const createDialog: DialogPluginType = (props: DialogOptions): DialogInstance =>
25
25
  </PluginContainer>,
26
26
  fragment
27
27
  );
28
- const container = getAttach(options.attach);
28
+ const attachResult = getAttach(options.attach);
29
+ const container = (attachResult && attachResult instanceof HTMLElement ? attachResult : null) || document.body;
29
30
 
30
31
  if (container) {
31
32
  container.appendChild(fragment);