@tendaui/components 1.0.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +176 -176
- package/alert/Alert.tsx +3 -2
- package/button/_example/base.tsx +10 -0
- package/button/_example/icon.tsx +20 -0
- package/color-picker/ColorPickPanel.tsx +9 -0
- package/color-picker/ColorPicker.tsx +67 -0
- package/color-picker/components/panel/alpha.tsx +32 -0
- package/color-picker/components/panel/format/index.tsx +47 -0
- package/color-picker/components/panel/format/inputs.tsx +119 -0
- package/color-picker/components/panel/header.tsx +37 -0
- package/color-picker/components/panel/hue.tsx +20 -0
- package/color-picker/components/panel/index.tsx +191 -0
- package/color-picker/components/panel/saturation.tsx +81 -0
- package/color-picker/components/panel/slider.tsx +76 -0
- package/color-picker/components/panel/swatches.tsx +84 -0
- package/color-picker/components/trigger.tsx +49 -0
- package/color-picker/defaultProps.ts +7 -0
- package/color-picker/helpers.ts +53 -0
- package/color-picker/hooks/useClassNames.ts +9 -0
- package/color-picker/hooks/useStyles.ts +39 -0
- package/color-picker/index.ts +12 -0
- package/color-picker/style/css.js +1 -0
- package/color-picker/style/index.js +1 -0
- package/color-picker/type.ts +143 -0
- package/color-picker/utils/color-picker/cmyk.ts +89 -0
- package/color-picker/utils/color-picker/color.ts +467 -0
- package/color-picker/utils/color-picker/constants.ts +187 -0
- package/color-picker/utils/color-picker/draggable.ts +100 -0
- package/color-picker/utils/color-picker/format.ts +95 -0
- package/color-picker/utils/color-picker/gradient.ts +243 -0
- package/color-picker/utils/color-picker/index.ts +7 -0
- package/color-picker/utils/color-picker/types.ts +33 -0
- package/common/observe.ts +33 -0
- package/common.ts +20 -0
- package/config-provider/ConfigContext.tsx +4 -1
- package/config-provider/index.ts +1 -1
- package/dialog/DialogCard.tsx +4 -6
- package/dialog/hooks/useDialogPosition.ts +1 -2
- package/dialog/plugin.tsx +3 -2
- package/drawer/Drawer.tsx +264 -0
- package/drawer/defaultProps.ts +19 -0
- package/drawer/hooks/useDrag.ts +98 -0
- package/drawer/hooks/useLockStyle.ts +36 -0
- package/drawer/index.ts +5 -0
- package/drawer/style/css.js +1 -0
- package/drawer/style/index.js +1 -0
- package/drawer/type.ts +193 -0
- package/drawer/utils/index.ts +76 -0
- package/fireworks/Fireworks.tsx +138 -0
- package/fireworks/index.ts +10 -0
- package/fireworks/style/css.js +0 -0
- package/fireworks/style/index.js +0 -0
- package/fireworks/type.ts +72 -0
- package/form/FormItem.tsx +5 -5
- package/form/easing.ts +10 -0
- package/form/scroll.ts +124 -0
- package/form/type.ts +519 -519
- package/global-config/default-config.ts +95 -0
- package/global-config/locale/ar_KW.ts +270 -0
- package/global-config/locale/en_US.ts +280 -0
- package/global-config/locale/it_IT.ts +287 -0
- package/global-config/locale/ja_JP.ts +279 -0
- package/global-config/locale/ko_KR.ts +279 -0
- package/global-config/locale/ru_RU.ts +288 -0
- package/global-config/locale/zh_CN.ts +279 -0
- package/global-config/locale/zh_TW.ts +279 -0
- package/global-config/mobile/default-config.ts +6 -0
- package/global-config/mobile/locale/ar_KW.ts +113 -0
- package/global-config/mobile/locale/en_US.ts +114 -0
- package/global-config/mobile/locale/it_IT.ts +114 -0
- package/global-config/mobile/locale/ja_JP.ts +101 -0
- package/global-config/mobile/locale/ko_KR.ts +101 -0
- package/global-config/mobile/locale/ru_RU.ts +113 -0
- package/global-config/mobile/locale/zh_CN.ts +101 -0
- package/global-config/mobile/locale/zh_TW.ts +101 -0
- package/global-config/t.ts +111 -0
- package/hooks/useControlled.ts +3 -3
- package/hooks/useDeepEffect.ts +32 -0
- package/hooks/useGlobalIcon.ts +10 -3
- package/hooks/useLastest.ts +2 -6
- package/hooks/useResizeObserve.ts +36 -0
- package/index.ts +10 -7
- package/input/Input.tsx +4 -1
- package/input/defaultProps.ts +0 -2
- package/input/type.ts +1 -6
- package/input-number/InputNumber.tsx +124 -0
- package/input-number/defaultProps.ts +17 -0
- package/input-number/index.ts +9 -0
- package/input-number/style/css.js +1 -0
- package/input-number/style/index.js +1 -0
- package/input-number/type.ts +147 -0
- package/input-number/useInputNumber.tsx +270 -0
- package/ip-input/IPInput.tsx +516 -0
- package/ip-input/defaultProps.ts +11 -0
- package/ip-input/index.ts +3 -0
- package/ip-input/style/css.js +1 -0
- package/ip-input/style/index.js +1 -0
- package/ip-input/type.ts +115 -0
- package/ip-input/utils.ts +112 -0
- package/layout/Aside.tsx +38 -0
- package/layout/Layout.tsx +104 -0
- package/layout/defaultProps.ts +9 -0
- package/layout/index.ts +9 -0
- package/layout/style/css.js +1 -0
- package/layout/style/index.js +1 -0
- package/layout/type.ts +43 -0
- package/list/List.tsx +144 -0
- package/list/ListItem.tsx +36 -0
- package/list/ListItemMeta.tsx +40 -0
- package/list/defaultProps.ts +11 -0
- package/list/hooks/useListVirtualScroll.ts +82 -0
- package/list/index.ts +11 -0
- package/list/style/css.js +1 -0
- package/list/style/index.js +1 -0
- package/list/type.ts +93 -0
- package/locale/LocalReceiver.ts +55 -0
- package/locale/ar_KW.ts +7 -0
- package/locale/en_US.ts +7 -0
- package/locale/it_IT.ts +6 -0
- package/locale/ja_JP.ts +6 -0
- package/locale/ko_KR.ts +6 -0
- package/locale/ru_RU.ts +6 -0
- package/locale/zh_CN.ts +5 -0
- package/locale/zh_TW.ts +7 -0
- package/notification/NotifyContainer.tsx +2 -2
- package/notification/NotifyContext.tsx +1 -0
- package/package.json +6 -3
- package/popup/Popup.tsx +34 -10
- package/radio/Radio.tsx +24 -0
- package/radio/RadioGroup.tsx +159 -0
- package/radio/defaultProps.ts +18 -0
- package/radio/index.ts +12 -0
- package/radio/style/css.js +0 -0
- package/radio/style/index.js +1 -0
- package/radio/type.ts +115 -0
- package/radio/useKeyboard.ts +36 -0
- package/select/hooks/useOptions.ts +10 -7
- package/select/hooks/usePanelVirtualScroll.ts +1 -1
- package/select/type.ts +382 -382
- package/select-input/type.ts +280 -280
- package/slider/Slider.tsx +270 -0
- package/slider/SliderHandleButton.tsx +50 -0
- package/slider/defaultProps.ts +15 -0
- package/slider/index.ts +9 -0
- package/slider/style/css.js +1 -0
- package/slider/style/index.js +1 -0
- package/slider/type.ts +77 -0
- package/style/all.js +26 -0
- package/styles/_global.scss +39 -39
- package/styles/_vars.scss +358 -386
- package/styles/components/alert/_index.scss +175 -175
- package/styles/components/alert/_vars.scss +39 -39
- package/styles/components/badge/_index.scss +70 -70
- package/styles/components/badge/_vars.scss +25 -25
- package/styles/components/button/_index.scss +499 -511
- package/styles/components/button/_mixins.scss +39 -39
- package/styles/components/button/_vars.scss +120 -122
- package/styles/components/checkbox/_index.scss +158 -158
- package/styles/components/checkbox/_var.scss +60 -60
- package/styles/components/color-picker/_index.scss +586 -0
- package/styles/components/color-picker/_mixins.scss +0 -0
- package/styles/components/color-picker/_vars.scss +84 -0
- package/styles/components/dialog/_animate.scss +135 -135
- package/styles/components/dialog/_index.scss +311 -311
- package/styles/components/dialog/_vars.scss +59 -59
- package/styles/components/drawer/_index.scss +205 -0
- package/styles/components/drawer/_mixins.scss +1 -0
- package/styles/components/drawer/_var.scss +53 -0
- package/styles/components/fireworks/_index.scss +86 -0
- package/styles/components/fireworks/_vars.scss +4 -0
- package/styles/components/form/_index.scss +174 -174
- package/styles/components/form/_mixins.scss +76 -76
- package/styles/components/form/_vars.scss +100 -100
- package/styles/components/input/_index.scss +349 -349
- package/styles/components/input/_mixins.scss +116 -116
- package/styles/components/input/_vars.scss +134 -134
- package/styles/components/input-number/_index.scss +353 -0
- package/styles/components/input-number/_mixins.scss +0 -0
- package/styles/components/input-number/_vars.scss +65 -0
- package/styles/components/ip-input/_index.scss +280 -0
- package/styles/components/layout/_index.scss +47 -0
- package/styles/components/layout/_mixin.scss +0 -0
- package/styles/components/layout/_vars.scss +18 -0
- package/styles/components/layout/doc.scss +74 -0
- package/styles/components/list/_index.scss +172 -0
- package/styles/components/list/_mixins.scss +0 -0
- package/styles/components/list/_vars.scss +41 -0
- package/styles/components/loading/_index.scss +112 -112
- package/styles/components/loading/_vars.scss +39 -39
- package/styles/components/notification/_index.scss +160 -160
- package/styles/components/notification/_mixins.scss +12 -12
- package/styles/components/notification/_vars.scss +59 -59
- package/styles/components/popup/_index.scss +82 -82
- package/styles/components/popup/_mixin.scss +149 -149
- package/styles/components/popup/_var.scss +31 -31
- package/styles/components/radio/_index.scss +376 -0
- package/styles/components/radio/_mixins.scss +0 -0
- package/styles/components/radio/_var.scss +92 -0
- package/styles/components/select/_index.scss +290 -290
- package/styles/components/select/_var.scss +65 -65
- package/styles/components/select-input/_index.scss +5 -5
- package/styles/components/select-input/_var.scss +3 -3
- package/styles/components/slider/_index.scss +241 -0
- package/styles/components/slider/_mixins.scss +0 -0
- package/styles/components/slider/_vars.scss +50 -0
- package/styles/components/switch/_index.scss +279 -279
- package/styles/components/switch/_vars.scss +61 -61
- package/styles/components/table/_index.scss +193 -0
- package/styles/components/table/_var.scss +52 -0
- package/styles/components/tabs/_index.scss +165 -0
- package/styles/components/tabs/_mixins.scss +11 -0
- package/styles/components/tabs/_vars.scss +71 -0
- package/styles/components/tag/_index.scss +316 -316
- package/styles/components/tag/_var.scss +85 -85
- package/styles/components/tag-input/_index.scss +163 -163
- package/styles/components/tag-input/_vars.scss +16 -16
- package/styles/globals.css +250 -250
- package/styles/mixins/_focus.scss +7 -7
- package/styles/mixins/_layout.scss +32 -32
- package/styles/mixins/_reset.scss +10 -10
- package/styles/mixins/_scrollbar.scss +31 -31
- package/styles/mixins/_text.scss +48 -48
- package/styles/rillple.css +16 -16
- package/styles/scrollbar.css +41 -41
- package/styles/themes/_dark.scss +191 -191
- package/styles/themes/_font.scss +69 -79
- package/styles/themes/_index.scss +5 -5
- package/styles/themes/_light.scss +190 -190
- package/styles/themes/_radius.scss +9 -9
- package/styles/themes/_size.scss +68 -68
- package/styles/themes.css +66 -66
- package/styles/utilities/_animation.scss +57 -57
- package/styles/utilities/_tips.scss +9 -9
- package/tab/TabBar.tsx +85 -0
- package/tab/TabNav.tsx +103 -0
- package/tab/TabNavItem.tsx +80 -0
- package/tab/TabPanel.tsx +42 -0
- package/tab/Tabs.tsx +71 -0
- package/tab/defaultProps.ts +19 -0
- package/tab/index.ts +7 -0
- package/tab/style/index.js +1 -0
- package/tab/type.ts +125 -0
- package/tab/useTabClass.ts +20 -0
- package/table/Cell.tsx +109 -0
- package/table/TBody.tsx +77 -0
- package/table/THead.tsx +63 -0
- package/table/TR.tsx +78 -0
- package/table/Table.tsx +73 -0
- package/table/defaultProps.ts +14 -0
- package/table/hooks/index.ts +4 -0
- package/table/hooks/useTableClassName.ts +63 -0
- package/table/hooks/useTableStyle.ts +93 -0
- package/table/index.ts +7 -0
- package/table/style/css.js +1 -0
- package/table/style/index.js +1 -0
- package/table/type.ts +192 -0
- package/tag/Tag.tsx +1 -1
- package/tag-input/hooks/useTagList.tsx +1 -1
- package/utils/dom.ts +4 -0
- package/utils/forwardRefWithStatics.ts +1 -4
- package/utils/input-number/large-number.ts +423 -0
- package/utils/input-number/number.ts +257 -0
- package/utils/isFragment.ts +6 -6
- package/utils/log/index.ts +3 -0
- package/utils/log/log.ts +30 -0
- package/utils/log/types.ts +12 -0
- package/utils/number.ts +21 -0
- package/utils/scroll.ts +26 -0
- package/utils/style.ts +2 -4
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import React, { forwardRef, isValidElement, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { CSSTransition } from "react-transition-group";
|
|
3
|
+
import { IconClose as TdCloseIcon } from "@tendaui/icons";
|
|
4
|
+
import classnames from "classnames";
|
|
5
|
+
import { isFunction, isObject, isString, isUndefined } from "lodash-es";
|
|
6
|
+
import parseTNode from "../utils/parentTNode";
|
|
7
|
+
import Button, { type ButtonProps } from "../button";
|
|
8
|
+
import Portal from "../common/Portal";
|
|
9
|
+
import useAttach from "../hooks/useAttach";
|
|
10
|
+
import useConfig from "../hooks/useConfig";
|
|
11
|
+
import useDeepEffect from "../hooks/useDeepEffect";
|
|
12
|
+
import useDefaultProps from "../hooks/useDefaultProps";
|
|
13
|
+
import useGlobalIcon from "../hooks/useGlobalIcon";
|
|
14
|
+
import useSetState from "../hooks/useSetState";
|
|
15
|
+
import { drawerDefaultProps } from "./defaultProps";
|
|
16
|
+
import useDrag from "./hooks/useDrag";
|
|
17
|
+
import { useLockStyle } from "./hooks/useLockStyle";
|
|
18
|
+
import { useLocaleReceiver } from "../locale/LocalReceiver";
|
|
19
|
+
|
|
20
|
+
import type { StyledProps } from "../common";
|
|
21
|
+
import type { DrawerEventSource, DrawerInstance, TdDrawerProps } from "./type";
|
|
22
|
+
|
|
23
|
+
export const CloseTriggerType: { [key: string]: DrawerEventSource } = {
|
|
24
|
+
CLICK_OVERLAY: "overlay",
|
|
25
|
+
CLICK_CLOSE_BTN: "close-btn",
|
|
26
|
+
CLICK_CANCEL_BTN: "cancel",
|
|
27
|
+
KEYDOWN_ESC: "esc"
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export interface DrawerProps extends TdDrawerProps, StyledProps {
|
|
31
|
+
isPlugin?: boolean; // 是否以插件形式调用
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const Drawer = forwardRef<DrawerInstance, DrawerProps>((originalProps, ref) => {
|
|
35
|
+
// 国际化文本初始化
|
|
36
|
+
const [local, t] = useLocaleReceiver("drawer");
|
|
37
|
+
const { CloseIcon } = useGlobalIcon({ CloseIcon: TdCloseIcon });
|
|
38
|
+
const confirmText = t(local.confirm);
|
|
39
|
+
const cancelText = t(local.cancel);
|
|
40
|
+
|
|
41
|
+
const props = useDefaultProps<DrawerProps>(originalProps, drawerDefaultProps);
|
|
42
|
+
const { body, children, header, footer, ...restProps } = props;
|
|
43
|
+
const [state, setState] = useSetState<DrawerProps>({ isPlugin: false, ...restProps });
|
|
44
|
+
const {
|
|
45
|
+
className,
|
|
46
|
+
style,
|
|
47
|
+
visible,
|
|
48
|
+
attach,
|
|
49
|
+
showOverlay,
|
|
50
|
+
size: propsSize,
|
|
51
|
+
placement,
|
|
52
|
+
onBeforeOpen,
|
|
53
|
+
onBeforeClose,
|
|
54
|
+
onCancel,
|
|
55
|
+
onConfirm,
|
|
56
|
+
onClose,
|
|
57
|
+
onCloseBtnClick,
|
|
58
|
+
onOverlayClick,
|
|
59
|
+
onEscKeydown,
|
|
60
|
+
onSizeDragEnd,
|
|
61
|
+
showInAttachedElement,
|
|
62
|
+
closeOnOverlayClick,
|
|
63
|
+
closeOnEscKeydown,
|
|
64
|
+
closeBtn,
|
|
65
|
+
cancelBtn = cancelText,
|
|
66
|
+
confirmBtn = confirmText,
|
|
67
|
+
zIndex,
|
|
68
|
+
destroyOnClose,
|
|
69
|
+
sizeDraggable,
|
|
70
|
+
forceRender,
|
|
71
|
+
isPlugin,
|
|
72
|
+
lazy
|
|
73
|
+
} = state;
|
|
74
|
+
|
|
75
|
+
const size = propsSize;
|
|
76
|
+
const { classPrefix } = useConfig();
|
|
77
|
+
const drawerAttach = useAttach("drawer", attach);
|
|
78
|
+
const maskRef = useRef<HTMLDivElement>(null);
|
|
79
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
80
|
+
const drawerWrapperRef = useRef<HTMLElement>(null); // 即最终的 attach dom,默认为 document.body
|
|
81
|
+
const prefixCls = `${classPrefix}-drawer`;
|
|
82
|
+
|
|
83
|
+
const closeIcon = isValidElement(closeBtn) ? closeBtn : <CloseIcon />;
|
|
84
|
+
const { dragSizeValue, enableDrag, draggableLineStyles, draggingStyles } = useDrag(
|
|
85
|
+
placement,
|
|
86
|
+
sizeDraggable,
|
|
87
|
+
onSizeDragEnd
|
|
88
|
+
);
|
|
89
|
+
const [animationStart, setAnimationStart] = useState(visible);
|
|
90
|
+
|
|
91
|
+
const sizeValue = useMemo(() => {
|
|
92
|
+
const sizeMap = { small: "300px", medium: "500px", large: "760px" };
|
|
93
|
+
return dragSizeValue || sizeMap[size] || size;
|
|
94
|
+
}, [dragSizeValue, size]);
|
|
95
|
+
|
|
96
|
+
useLockStyle({ ...state, sizeValue, drawerWrapper: drawerWrapperRef.current });
|
|
97
|
+
useImperativeHandle(ref, () => ({
|
|
98
|
+
show() {
|
|
99
|
+
setState({ visible: true });
|
|
100
|
+
},
|
|
101
|
+
hide() {
|
|
102
|
+
setState({ visible: false });
|
|
103
|
+
},
|
|
104
|
+
destroy() {
|
|
105
|
+
setState({ visible: false, destroyOnClose: true });
|
|
106
|
+
},
|
|
107
|
+
update(options) {
|
|
108
|
+
setState((prevState) => ({ ...prevState, ...options }));
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (visible) {
|
|
114
|
+
// 聚焦到 Drawer 最外层元素即 containerRef.current,KeyDown 事件才有效。
|
|
115
|
+
containerRef.current?.focus?.();
|
|
116
|
+
}
|
|
117
|
+
}, [visible]);
|
|
118
|
+
|
|
119
|
+
useDeepEffect(() => {
|
|
120
|
+
// 非插件式调用 更新props
|
|
121
|
+
if (isPlugin) return;
|
|
122
|
+
setState((prevState) => ({ ...prevState, ...props }));
|
|
123
|
+
}, [props, setState]);
|
|
124
|
+
|
|
125
|
+
function onMaskClick(e: React.MouseEvent<HTMLDivElement>) {
|
|
126
|
+
onOverlayClick?.({ e });
|
|
127
|
+
closeOnOverlayClick && onClose?.({ e, trigger: CloseTriggerType.CLICK_OVERLAY });
|
|
128
|
+
}
|
|
129
|
+
function onClickCloseBtn(e: React.MouseEvent<HTMLDivElement>) {
|
|
130
|
+
onCloseBtnClick?.({ e });
|
|
131
|
+
onClose?.({ e, trigger: CloseTriggerType.CLICK_CLOSE_BTN });
|
|
132
|
+
}
|
|
133
|
+
function onKeyDownEsc(e: React.KeyboardEvent<HTMLDivElement>) {
|
|
134
|
+
if (e.key !== "Escape") return;
|
|
135
|
+
|
|
136
|
+
onEscKeydown?.({ e });
|
|
137
|
+
closeOnEscKeydown && onClose?.({ e, trigger: CloseTriggerType.KEYDOWN_ESC });
|
|
138
|
+
}
|
|
139
|
+
function onCancelClick(e: React.MouseEvent<HTMLButtonElement>) {
|
|
140
|
+
onCancel?.({ e });
|
|
141
|
+
onClose?.({ e, trigger: CloseTriggerType.CLICK_CANCEL_BTN });
|
|
142
|
+
}
|
|
143
|
+
function onConfirmClick(e: React.MouseEvent<HTMLButtonElement>) {
|
|
144
|
+
onConfirm?.({ e });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const contentWrapperStyle = useMemo(
|
|
148
|
+
() => ({
|
|
149
|
+
transform: visible && animationStart ? "translateX(0)" : undefined,
|
|
150
|
+
width: ["left", "right"].includes(placement) ? sizeValue : "",
|
|
151
|
+
height: ["top", "bottom"].includes(placement) ? sizeValue : ""
|
|
152
|
+
}),
|
|
153
|
+
[visible, placement, sizeValue, animationStart]
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const renderDrawerButton = (btn: DrawerProps["cancelBtn"], defaultProps: ButtonProps) => {
|
|
157
|
+
let result = null;
|
|
158
|
+
|
|
159
|
+
if (isString(btn)) {
|
|
160
|
+
result = <Button {...defaultProps}>{btn}</Button>;
|
|
161
|
+
} else if (isValidElement(btn)) {
|
|
162
|
+
result = btn;
|
|
163
|
+
} else if (isObject(btn)) {
|
|
164
|
+
result = <Button {...defaultProps} {...(btn as {})} />;
|
|
165
|
+
} else if (isFunction(btn)) {
|
|
166
|
+
result = btn();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return result;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const renderFooter = () => {
|
|
173
|
+
const defaultFooter = () => {
|
|
174
|
+
const renderCancelBtn = renderDrawerButton(cancelBtn, {
|
|
175
|
+
theme: "default",
|
|
176
|
+
onClick: (e: React.MouseEvent<HTMLButtonElement>) => onCancelClick?.(e),
|
|
177
|
+
className: `${prefixCls}__cancel`
|
|
178
|
+
});
|
|
179
|
+
const renderConfirmBtn = renderDrawerButton(confirmBtn, {
|
|
180
|
+
theme: "primary",
|
|
181
|
+
onClick: (e: React.MouseEvent<HTMLButtonElement>) => onConfirmClick?.(e),
|
|
182
|
+
className: `${prefixCls}__confirm`
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const footerStyle = {
|
|
186
|
+
display: "flex",
|
|
187
|
+
justifyContent: placement === "right" ? "flex-start" : "flex-end"
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<div style={footerStyle}>
|
|
192
|
+
{placement === "right" ? (
|
|
193
|
+
<>
|
|
194
|
+
{renderConfirmBtn} {renderCancelBtn}
|
|
195
|
+
</>
|
|
196
|
+
) : (
|
|
197
|
+
<>
|
|
198
|
+
{renderCancelBtn} {renderConfirmBtn}
|
|
199
|
+
</>
|
|
200
|
+
)}
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
return <div className={`${prefixCls}__footer`}>{parseTNode(footer, null, defaultFooter())}</div>;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const renderOverlay = showOverlay && (
|
|
209
|
+
<CSSTransition in={visible} timeout={200} classNames={`${prefixCls}-fade`} nodeRef={maskRef}>
|
|
210
|
+
<div ref={maskRef} className={`${prefixCls}__mask`} onClick={onMaskClick} />
|
|
211
|
+
</CSSTransition>
|
|
212
|
+
);
|
|
213
|
+
const renderCloseBtn = closeBtn && (
|
|
214
|
+
<div onClick={onClickCloseBtn} className={`${prefixCls}__close-btn`}>
|
|
215
|
+
{closeIcon}
|
|
216
|
+
</div>
|
|
217
|
+
);
|
|
218
|
+
const renderHeader = header && <div className={`${prefixCls}__header`}>{header}</div>;
|
|
219
|
+
const renderBody = <div className={`${prefixCls}__body`}>{body || children}</div>;
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<CSSTransition
|
|
223
|
+
in={visible}
|
|
224
|
+
nodeRef={drawerWrapperRef}
|
|
225
|
+
mountOnEnter={isUndefined(forceRender) ? lazy : !forceRender}
|
|
226
|
+
unmountOnExit={destroyOnClose}
|
|
227
|
+
timeout={{ appear: 10, enter: 10, exit: 300 }}
|
|
228
|
+
onEnter={() => onBeforeOpen?.()}
|
|
229
|
+
onEntered={() => setAnimationStart(true)}
|
|
230
|
+
onExit={() => onBeforeClose?.()}
|
|
231
|
+
onExited={() => setAnimationStart(false)}
|
|
232
|
+
>
|
|
233
|
+
<Portal attach={drawerAttach} ref={drawerWrapperRef}>
|
|
234
|
+
<div
|
|
235
|
+
ref={containerRef}
|
|
236
|
+
className={classnames(prefixCls, className, `${prefixCls}--${placement}`, {
|
|
237
|
+
[`${prefixCls}--open`]: visible,
|
|
238
|
+
[`${prefixCls}--attach`]: showInAttachedElement,
|
|
239
|
+
[`${prefixCls}--without-mask`]: !showOverlay
|
|
240
|
+
})}
|
|
241
|
+
style={{ zIndex, ...style }}
|
|
242
|
+
tabIndex={-1} // https://stackoverflow.com/questions/43503964/onkeydown-event-not-working-on-divs-in-react
|
|
243
|
+
onKeyDown={onKeyDownEsc}
|
|
244
|
+
>
|
|
245
|
+
{renderOverlay}
|
|
246
|
+
<div
|
|
247
|
+
className={classnames(`${prefixCls}__content-wrapper`, `${prefixCls}__content-wrapper--${placement}`)}
|
|
248
|
+
style={{ ...contentWrapperStyle, ...draggingStyles }}
|
|
249
|
+
>
|
|
250
|
+
{renderCloseBtn}
|
|
251
|
+
{renderHeader}
|
|
252
|
+
{renderBody}
|
|
253
|
+
{!!footer && renderFooter()}
|
|
254
|
+
{sizeDraggable && <div style={draggableLineStyles} onMouseDown={enableDrag}></div>}
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
</Portal>
|
|
258
|
+
</CSSTransition>
|
|
259
|
+
);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
Drawer.displayName = "Drawer";
|
|
263
|
+
|
|
264
|
+
export default Drawer;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TdDrawerProps } from "./type";
|
|
2
|
+
|
|
3
|
+
export const drawerDefaultProps: TdDrawerProps = {
|
|
4
|
+
closeOnEscKeydown: undefined,
|
|
5
|
+
closeOnOverlayClick: undefined,
|
|
6
|
+
closeBtn: true,
|
|
7
|
+
destroyOnClose: false,
|
|
8
|
+
footer: true,
|
|
9
|
+
header: true,
|
|
10
|
+
lazy: true,
|
|
11
|
+
mode: "overlay",
|
|
12
|
+
placement: "right",
|
|
13
|
+
preventScrollThrough: true,
|
|
14
|
+
showInAttachedElement: false,
|
|
15
|
+
showOverlay: true,
|
|
16
|
+
size: undefined,
|
|
17
|
+
sizeDraggable: false,
|
|
18
|
+
visible: false
|
|
19
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { getSizeDraggable, calcMoveSize } from "../utils";
|
|
3
|
+
|
|
4
|
+
import type { TdDrawerProps } from "../type";
|
|
5
|
+
import type { Styles } from "../../common";
|
|
6
|
+
|
|
7
|
+
const useDrag = (
|
|
8
|
+
placement: TdDrawerProps["placement"],
|
|
9
|
+
sizeDraggable: TdDrawerProps["sizeDraggable"],
|
|
10
|
+
onSizeDragEnd: TdDrawerProps["onSizeDragEnd"]
|
|
11
|
+
) => {
|
|
12
|
+
const [dragSizeValue, changeDragSizeValue] = useState<string>(null);
|
|
13
|
+
// 使用 ref 来存储当前拖拽的宽度值
|
|
14
|
+
const dragSizeRef = useRef<number>(0);
|
|
15
|
+
const [isSizeDragging, toggleSizeDragging] = useState(false);
|
|
16
|
+
|
|
17
|
+
const handleMousemove = useCallback(
|
|
18
|
+
(e: MouseEvent) => {
|
|
19
|
+
// 如果 sizeDraggable 是 boolean 值的 false,则不进行后续的计算
|
|
20
|
+
if (sizeDraggable === false) return;
|
|
21
|
+
|
|
22
|
+
// 鼠标移动时计算draggedSizeValue的值
|
|
23
|
+
const { x, y } = e;
|
|
24
|
+
|
|
25
|
+
const maxHeight = document.documentElement.clientHeight;
|
|
26
|
+
const maxWidth = document.documentElement.clientWidth;
|
|
27
|
+
const offsetHeight = 8;
|
|
28
|
+
const offsetWidth = 8;
|
|
29
|
+
// x 轴方向使用最大宽度,y轴方向使用最大高度
|
|
30
|
+
const max = placement === "left" || placement === "right" ? maxWidth : maxHeight;
|
|
31
|
+
// x 轴方向使用默认最小宽度,y轴方向使用默认最小高度
|
|
32
|
+
const min = placement === "left" || placement === "right" ? offsetWidth : offsetHeight;
|
|
33
|
+
|
|
34
|
+
const { max: limitMax, min: limitMin } = getSizeDraggable(sizeDraggable, { max, min });
|
|
35
|
+
|
|
36
|
+
const moveSize = calcMoveSize(placement, {
|
|
37
|
+
x,
|
|
38
|
+
y,
|
|
39
|
+
maxWidth,
|
|
40
|
+
maxHeight,
|
|
41
|
+
max: limitMax,
|
|
42
|
+
min: limitMin
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (typeof moveSize === "undefined") return;
|
|
46
|
+
changeDragSizeValue(`${moveSize}px`);
|
|
47
|
+
dragSizeRef.current = moveSize;
|
|
48
|
+
},
|
|
49
|
+
[placement, sizeDraggable]
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const draggableLineStyles: Styles = useMemo(() => {
|
|
53
|
+
// 设置拖拽control的样式
|
|
54
|
+
const isHorizontal = ["right", "left"].includes(placement);
|
|
55
|
+
const oppositeMap = {
|
|
56
|
+
left: "right",
|
|
57
|
+
right: "left",
|
|
58
|
+
top: "bottom",
|
|
59
|
+
bottom: "top"
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
zIndex: 1,
|
|
63
|
+
position: "absolute",
|
|
64
|
+
background: "transparent",
|
|
65
|
+
[oppositeMap[placement]]: 0,
|
|
66
|
+
width: isHorizontal ? "16px" : "100%",
|
|
67
|
+
height: isHorizontal ? "100%" : "16px",
|
|
68
|
+
cursor: isHorizontal ? "col-resize" : "row-resize"
|
|
69
|
+
};
|
|
70
|
+
}, [placement]);
|
|
71
|
+
|
|
72
|
+
const handleMouseup = useCallback(
|
|
73
|
+
(e: MouseEvent) => {
|
|
74
|
+
document.removeEventListener("mouseup", handleMouseup, true);
|
|
75
|
+
document.removeEventListener("mousemove", handleMousemove, true);
|
|
76
|
+
onSizeDragEnd?.({
|
|
77
|
+
e,
|
|
78
|
+
// 此处不要使用 dragSizeValue,useState 的更新是异步的,在鼠标拖拽的同步操作中取不到最新的值
|
|
79
|
+
size: dragSizeRef.current
|
|
80
|
+
});
|
|
81
|
+
toggleSizeDragging(false);
|
|
82
|
+
},
|
|
83
|
+
[handleMousemove, onSizeDragEnd]
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const enableDrag = useCallback(() => {
|
|
87
|
+
// mousedown 绑定 mousemove 和 mouseup 事件
|
|
88
|
+
document.addEventListener("mouseup", handleMouseup, true);
|
|
89
|
+
document.addEventListener("mousemove", handleMousemove, true);
|
|
90
|
+
toggleSizeDragging(true);
|
|
91
|
+
}, [handleMousemove, handleMouseup]);
|
|
92
|
+
|
|
93
|
+
const draggingStyles: Styles = isSizeDragging ? { userSelect: "none" } : {};
|
|
94
|
+
|
|
95
|
+
return { dragSizeValue, enableDrag, draggableLineStyles, draggingStyles };
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default useDrag;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useRef, useCallback, useLayoutEffect } from "react";
|
|
2
|
+
let key = 1;
|
|
3
|
+
export const useLockStyle = (props) => {
|
|
4
|
+
const { visible } = props;
|
|
5
|
+
const drawerLockStyleRef = useRef<HTMLStyleElement>(null);
|
|
6
|
+
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
7
|
+
const clearStyleFunc = useCallback(() => {
|
|
8
|
+
console.log("clearStyleFunc");
|
|
9
|
+
clearTimeout(timerRef.current);
|
|
10
|
+
timerRef.current = setTimeout(() => {
|
|
11
|
+
drawerLockStyleRef.current.parentNode?.removeChild?.(drawerLockStyleRef.current);
|
|
12
|
+
}, 150);
|
|
13
|
+
}, []);
|
|
14
|
+
|
|
15
|
+
useLayoutEffect(() => {
|
|
16
|
+
if (typeof document === "undefined" || !visible) return;
|
|
17
|
+
if (!drawerLockStyleRef.current) {
|
|
18
|
+
drawerLockStyleRef.current = document.createElement("style");
|
|
19
|
+
}
|
|
20
|
+
drawerLockStyleRef.current.dataset.id = `td_drawer_${+new Date()}_${key++}`;
|
|
21
|
+
drawerLockStyleRef.current.innerHTML = `
|
|
22
|
+
html body {
|
|
23
|
+
overflow-y: hidden;
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
}, [visible]);
|
|
27
|
+
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
if (typeof document === "undefined") return;
|
|
30
|
+
if (visible) {
|
|
31
|
+
if (drawerLockStyleRef.current) document.head.appendChild(drawerLockStyleRef.current);
|
|
32
|
+
} else {
|
|
33
|
+
clearStyleFunc();
|
|
34
|
+
}
|
|
35
|
+
}, [visible, clearStyleFunc]);
|
|
36
|
+
};
|
package/drawer/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./index.css";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../../styles/components/drawer/_index.scss";
|
package/drawer/type.ts
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { ButtonProps } from "../button";
|
|
2
|
+
import { TNode, Styles, AttachNode } from "../common";
|
|
3
|
+
import { MouseEvent, KeyboardEvent } from "react";
|
|
4
|
+
export interface TdDrawerProps {
|
|
5
|
+
/**
|
|
6
|
+
* 抽屉挂载的节点,默认挂在组件本身的位置。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body
|
|
7
|
+
*/
|
|
8
|
+
attach?: AttachNode;
|
|
9
|
+
/**
|
|
10
|
+
* 抽屉内容
|
|
11
|
+
*/
|
|
12
|
+
body?: TNode;
|
|
13
|
+
/**
|
|
14
|
+
* 取消按钮,可自定义。值为 null 则不显示取消按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性。使用 TNode 自定义按钮时,需自行控制取消事件
|
|
15
|
+
*/
|
|
16
|
+
cancelBtn?: FooterButton;
|
|
17
|
+
/**
|
|
18
|
+
* 抽屉内容,同 body
|
|
19
|
+
*/
|
|
20
|
+
children?: TNode;
|
|
21
|
+
/**
|
|
22
|
+
* 关闭按钮,可以自定义。值为 true 显示默认关闭按钮,值为 false 不显示关闭按钮。值类型为 string 则直接显示值,如:“关闭”。值类型为 TNode,则表示呈现自定义按钮示例
|
|
23
|
+
*/
|
|
24
|
+
closeBtn?: TNode;
|
|
25
|
+
/**
|
|
26
|
+
* 按下 ESC 时是否触发抽屉关闭事件
|
|
27
|
+
*/
|
|
28
|
+
closeOnEscKeydown?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 点击蒙层时是否触发抽屉关闭事件
|
|
31
|
+
*/
|
|
32
|
+
closeOnOverlayClick?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 取消按钮,可自定义。值为 null 则不显示确认按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性。使用 TNode 自定义按钮时,需自行控制确认事件
|
|
35
|
+
*/
|
|
36
|
+
confirmBtn?: FooterButton;
|
|
37
|
+
/**
|
|
38
|
+
* 抽屉关闭时是否销毁节点
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
destroyOnClose?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* 底部操作栏,默认会有“确认”和“取消”两个按钮。值为 true 显示默认操作按钮,值为 false 或 null 不显示任何内容,值类型为 TNode 表示自定义底部内容
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
footer?: TNode;
|
|
47
|
+
/**
|
|
48
|
+
* 是否强制渲染Drawer
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
forceRender?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* 头部内容。值为 true 显示空白头部,值为 false 不显示头部,值类型为 string 则直接显示值,值类型为 TNode 表示自定义头部内容
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
header?: TNode;
|
|
57
|
+
/**
|
|
58
|
+
* 是否启用抽屉懒加载,启用时抽屉的内容不渲染
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
lazy?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* 展开方式,有两种:直接展示在内容上方 和 推开内容区域
|
|
64
|
+
* @default overlay
|
|
65
|
+
*/
|
|
66
|
+
mode?: "overlay" | "push";
|
|
67
|
+
/**
|
|
68
|
+
* 抽屉方向
|
|
69
|
+
* @default right
|
|
70
|
+
*/
|
|
71
|
+
placement?: "left" | "right" | "top" | "bottom";
|
|
72
|
+
/**
|
|
73
|
+
* 防止滚动穿透
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
76
|
+
preventScrollThrough?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* 仅在挂载元素中显示抽屉,默认在浏览器可视区域显示。父元素需要有定位属性,如:position: relative
|
|
79
|
+
* @default false
|
|
80
|
+
*/
|
|
81
|
+
showInAttachedElement?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* 是否显示遮罩层
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
showOverlay?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* 尺寸,支持 'small', 'medium', 'large','35px', '30%', '3em' 等。纵向抽屉调整的是抽屉宽度,横向抽屉调整的是抽屉高度
|
|
89
|
+
*/
|
|
90
|
+
size?: string;
|
|
91
|
+
/**
|
|
92
|
+
* 抽屉大小可拖拽调整,横向抽屉调整宽度
|
|
93
|
+
* @default false
|
|
94
|
+
*/
|
|
95
|
+
sizeDraggable?: boolean | SizeDragLimit;
|
|
96
|
+
/**
|
|
97
|
+
* 组件是否可见
|
|
98
|
+
* @default false
|
|
99
|
+
*/
|
|
100
|
+
visible?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* 抽屉层级,样式默认为 1500
|
|
103
|
+
*/
|
|
104
|
+
zIndex?: number;
|
|
105
|
+
/**
|
|
106
|
+
* 对话框执行消失动画效果前触发
|
|
107
|
+
*/
|
|
108
|
+
onBeforeClose?: () => void;
|
|
109
|
+
/**
|
|
110
|
+
* 对话框执行弹出动画效果前触发
|
|
111
|
+
*/
|
|
112
|
+
onBeforeOpen?: () => void;
|
|
113
|
+
/**
|
|
114
|
+
* 如果“取消”按钮存在,点击“取消”按钮时触发,同时触发关闭事件
|
|
115
|
+
*/
|
|
116
|
+
onCancel?: (context: { e: MouseEvent<HTMLDivElement | HTMLButtonElement> }) => void;
|
|
117
|
+
/**
|
|
118
|
+
* 关闭事件,取消按钮点击时、关闭按钮点击时、ESC 按下时、点击蒙层时均会触发
|
|
119
|
+
*/
|
|
120
|
+
onClose?: (context: DrawerCloseContext) => void;
|
|
121
|
+
/**
|
|
122
|
+
* 如果关闭按钮存在,点击关闭按钮时触发该事件,同时触发关闭事件
|
|
123
|
+
*/
|
|
124
|
+
onCloseBtnClick?: (context: { e: MouseEvent<HTMLDivElement> }) => void;
|
|
125
|
+
/**
|
|
126
|
+
* 如果“确认”按钮存在,则点击“确认”按钮时触发
|
|
127
|
+
*/
|
|
128
|
+
onConfirm?: (context: { e: MouseEvent<HTMLDivElement | HTMLButtonElement> }) => void;
|
|
129
|
+
/**
|
|
130
|
+
* 按下 ESC 键时触发
|
|
131
|
+
*/
|
|
132
|
+
onEscKeydown?: (context: { e: KeyboardEvent<HTMLDivElement> }) => void;
|
|
133
|
+
/**
|
|
134
|
+
* 如果蒙层存在,点击蒙层时触发
|
|
135
|
+
*/
|
|
136
|
+
onOverlayClick?: (context: { e: MouseEvent<HTMLDivElement> }) => void;
|
|
137
|
+
/**
|
|
138
|
+
* 抽屉大小调整结束事件
|
|
139
|
+
*/
|
|
140
|
+
onSizeDragEnd?: (context: { e: globalThis.MouseEvent; size: number }) => void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface DrawerOptions extends Omit<TdDrawerProps, "attach"> {
|
|
144
|
+
/**
|
|
145
|
+
* 抽屉挂载的节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body
|
|
146
|
+
* @default 'body'
|
|
147
|
+
*/
|
|
148
|
+
attach?: AttachNode;
|
|
149
|
+
/**
|
|
150
|
+
* 抽屉类名,示例:'t-class-drawer-first t-class-drawer-second'
|
|
151
|
+
* @default ''
|
|
152
|
+
*/
|
|
153
|
+
className?: string;
|
|
154
|
+
/**
|
|
155
|
+
* 弹框 style 属性,输入 [CSSStyleDeclaration.cssText](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration/cssText)
|
|
156
|
+
*/
|
|
157
|
+
style?: Styles;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface DrawerInstance {
|
|
161
|
+
/**
|
|
162
|
+
* 销毁抽屉
|
|
163
|
+
*/
|
|
164
|
+
destroy?: () => void;
|
|
165
|
+
/**
|
|
166
|
+
* 隐藏抽屉
|
|
167
|
+
*/
|
|
168
|
+
hide?: () => void;
|
|
169
|
+
/**
|
|
170
|
+
* 显示抽屉
|
|
171
|
+
*/
|
|
172
|
+
show?: () => void;
|
|
173
|
+
/**
|
|
174
|
+
* 更新抽屉内容
|
|
175
|
+
*/
|
|
176
|
+
update?: (props: DrawerOptions) => void;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export type FooterButton = string | ButtonProps | TNode;
|
|
180
|
+
|
|
181
|
+
export interface SizeDragLimit {
|
|
182
|
+
max: number;
|
|
183
|
+
min: number;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export type DrawerEventSource = "esc" | "close-btn" | "cancel" | "overlay";
|
|
187
|
+
|
|
188
|
+
export interface DrawerCloseContext {
|
|
189
|
+
trigger: DrawerEventSource;
|
|
190
|
+
e: MouseEvent<HTMLDivElement | HTMLButtonElement> | KeyboardEvent<HTMLDivElement>;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export type DrawerMethod = (options?: DrawerOptions) => DrawerInstance;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
type Placement = "left" | "right" | "top" | "bottom";
|
|
2
|
+
|
|
3
|
+
interface SizeDragLimit {
|
|
4
|
+
max: number;
|
|
5
|
+
min: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function getSizeDraggable(sizeDraggable: boolean | SizeDragLimit, limit: { max: number; min: number }) {
|
|
9
|
+
if (typeof sizeDraggable === "boolean") {
|
|
10
|
+
return {
|
|
11
|
+
allowSizeDraggable: sizeDraggable,
|
|
12
|
+
max: limit.max,
|
|
13
|
+
min: limit.min
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
allowSizeDraggable: true,
|
|
19
|
+
max: sizeDraggable.max,
|
|
20
|
+
min: sizeDraggable.min
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type IOptions = {
|
|
25
|
+
x: number;
|
|
26
|
+
y: number;
|
|
27
|
+
maxWidth: number;
|
|
28
|
+
maxHeight: number;
|
|
29
|
+
min: number;
|
|
30
|
+
max: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// > min && < max
|
|
34
|
+
function calcSizeRange(size: number, min: number, max: number) {
|
|
35
|
+
return Math.min(Math.max(size, min), max);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function calcMoveSize(placement: Placement, opts: IOptions) {
|
|
39
|
+
const { x, y, max, min, maxWidth, maxHeight } = opts;
|
|
40
|
+
let moveSize: number | undefined;
|
|
41
|
+
switch (placement) {
|
|
42
|
+
case "right":
|
|
43
|
+
// |<--- x --->| |
|
|
44
|
+
// | maxWidth |
|
|
45
|
+
// | size | > min && < max
|
|
46
|
+
moveSize = calcSizeRange(maxWidth - x, min, max);
|
|
47
|
+
break;
|
|
48
|
+
case "left":
|
|
49
|
+
// |<-- x -->| |
|
|
50
|
+
// x > min && < max
|
|
51
|
+
moveSize = calcSizeRange(x, min, max);
|
|
52
|
+
break;
|
|
53
|
+
case "top":
|
|
54
|
+
// - - - - - - - -
|
|
55
|
+
// | y |
|
|
56
|
+
// | |
|
|
57
|
+
// - - - - - - - -
|
|
58
|
+
// > min && < max
|
|
59
|
+
// moveSize = Math.min(Math.max(y, min), max);
|
|
60
|
+
moveSize = calcSizeRange(y, min, max);
|
|
61
|
+
break;
|
|
62
|
+
case "bottom":
|
|
63
|
+
// - - - - - - - -
|
|
64
|
+
// | y |
|
|
65
|
+
// | | maxHeight
|
|
66
|
+
// - - - - - - - -
|
|
67
|
+
// | size |
|
|
68
|
+
// > min && < max
|
|
69
|
+
moveSize = calcSizeRange(maxHeight - y, min, max);
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
// 参数缺失直接返回
|
|
73
|
+
return moveSize;
|
|
74
|
+
}
|
|
75
|
+
return moveSize;
|
|
76
|
+
}
|