@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.
- 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,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,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;
|
package/config-provider/index.ts
CHANGED
|
@@ -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
|
|
package/dialog/DialogCard.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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 "../
|
|
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
|
|
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);
|