diff --git a/source/Component/Popup/Popup.scss b/source/Component/Popup/Popup.scss index e37d254..39de7c4 100644 --- a/source/Component/Popup/Popup.scss +++ b/source/Component/Popup/Popup.scss @@ -46,11 +46,21 @@ div.focus.popup-layer { div.popup-layer { position: absolute; border-radius: 3px; - overflow: hidden; transition: none; box-sizing: border-box; border: 0.8px solid transparent; + div.popup-layer-container { + width: 100%; + height: 100%; + display: flex; + } + + div.popup-layer-root-content { + width: 100%; + height: 100%; + } + div.popup-layer-header { min-height: $header-height; max-height: $header-height; @@ -68,7 +78,7 @@ div.popup-layer { span { padding-left: 10px; display: inline-block; - vertical-align: middle; + vertical-align: bottom; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; @@ -92,6 +102,44 @@ div.popup-layer { width: 100%; overflow: hidden; } + + div.drag-line-root.drag-line-y { + flex-direction: column; + } + + div.drag-line-root { + display: flex; + justify-content: center; + align-items: center; + position: relative; + + div.drag-line { + transition: all 300ms ease-in-out; + display: flex; + } + + div.render-drag-block-root { + height: 0; + width: 0; + display: flex; + justify-content: center; + align-items: center; + + div.render-drag-block { + min-width: 5px; + min-height: 5px; + position: relative; + } + } + + div.drag-line:hover { + background-color: $lt-blue; + } + + div.drag-line.hover { + background-color: $lt-blue; + } + } } div.popup-layer.dark { diff --git a/source/Component/Popup/Popup.tsx b/source/Component/Popup/Popup.tsx index f37224a..8d9e0c5 100644 --- a/source/Component/Popup/Popup.tsx +++ b/source/Component/Popup/Popup.tsx @@ -2,7 +2,7 @@ import { Component, ReactNode } from "react"; import { IMixinStatusProps, useStatusWithEvent } from "@Context/Status"; import { IMixinSettingProps, useSettingWithEvent } from "@Context/Setting"; import { BackgroundLevel, FontLevel, getClassList, Theme } from "@Component/Theme/Theme"; -import { Popup as PopupModel } from "@Context/Popups"; +import { Popup as PopupModel, ResizeDragDirection } from "@Context/Popups"; import { Icon } from "@fluentui/react"; import "./Popup.scss"; @@ -79,9 +79,6 @@ class Popup extends Component { - popup.isOnMouseDown = false; - }} > {popup.onRenderHeader()} @@ -108,6 +105,129 @@ class Popup extends Component } + private renderDragBlock(dir: ResizeDragDirection, popup: PopupModel) { + return
+
{ + popup.lastMouseLeft = e.clientX; + popup.lastMouseTop = e.clientY; + popup.resizeDragDirection = dir; + popup.isResizeMouseDown = true; + }} + onMouseEnter={() => { + popup.resizeHoverDirection = dir; + this.forceUpdate(); + }} + onMouseLeave={() => { + popup.resizeHoverDirection = undefined; + this.forceUpdate(); + }} + /> +
+ } + + private mapDirToCursor = new Map([ + [ResizeDragDirection.rightTop, "sw-resize"], + [ResizeDragDirection.rightBottom, "nw-resize"], + [ResizeDragDirection.leftBottom, "sw-resize"], + [ResizeDragDirection.LeftTop, "nw-resize"] + ]); + + private renderDragLine(dir: ResizeDragDirection, popup: PopupModel) { + let xy: boolean = false; + const dragLineCList: string[] = ["drag-line"]; + + if (dir === ResizeDragDirection.top || dir === ResizeDragDirection.bottom) { + xy = false; + } + if (dir === ResizeDragDirection.left || dir === ResizeDragDirection.right) { + xy = true; + } + if ( + ( + dir === ResizeDragDirection.top && + ( + popup.resizeHoverDirection === ResizeDragDirection.LeftTop || + popup.resizeHoverDirection === ResizeDragDirection.rightTop + ) + ) || + ( + dir === ResizeDragDirection.bottom && + ( + popup.resizeHoverDirection === ResizeDragDirection.leftBottom || + popup.resizeHoverDirection === ResizeDragDirection.rightBottom + ) + ) || + ( + dir === ResizeDragDirection.right && + ( + popup.resizeHoverDirection === ResizeDragDirection.rightTop || + popup.resizeHoverDirection === ResizeDragDirection.rightBottom + ) + ) || + ( + dir === ResizeDragDirection.left && + ( + popup.resizeHoverDirection === ResizeDragDirection.leftBottom || + popup.resizeHoverDirection === ResizeDragDirection.LeftTop + ) + ) + ) { + dragLineCList.push("hover") + } + + return
+ { + xy && dir === ResizeDragDirection.left ? this.renderDragBlock( + ResizeDragDirection.LeftTop, popup + ) : null + } + { + xy && dir === ResizeDragDirection.right ? this.renderDragBlock( + ResizeDragDirection.rightTop, popup + ) : null + } + { + !xy && dir === ResizeDragDirection.bottom ? this.renderDragBlock( + ResizeDragDirection.leftBottom, popup + ) : null + } +
{ + popup.lastMouseLeft = e.clientX; + popup.lastMouseTop = e.clientY; + popup.resizeDragDirection = dir; + popup.isResizeMouseDown = true; + }} + /> + { + !xy && dir === ResizeDragDirection.bottom ? this.renderDragBlock( + ResizeDragDirection.rightBottom, popup + ) : null + } +
+ } + private renderLayer(popup: PopupModel) { const pageWidth = document.documentElement.clientWidth; const pageHeight = document.documentElement.clientHeight; @@ -132,8 +252,16 @@ class Popup extends Component - {this.renderHeader(popup)} - {this.renderContent(popup)} + {this.renderDragLine(ResizeDragDirection.top, popup)} +
+ {this.renderDragLine(ResizeDragDirection.left, popup)} +
+ {this.renderHeader(popup)} + {this.renderContent(popup)} +
+ {this.renderDragLine(ResizeDragDirection.right, popup)} +
+ {this.renderDragLine(ResizeDragDirection.bottom, popup)} } @@ -145,9 +273,54 @@ class Popup extends Component { this.isMouseDown = false; + if (this.props.status) { + this.props.status.popup.popups.forEach((popup) => { + popup.isOnMouseDown = false; + popup.resizeDragDirection = undefined; + popup.isResizeMouseDown = false; + }); + } + } + + private resize(popup: PopupModel, dis: number, dir: boolean, lsk: boolean) { + + if (dir) { + // Y + popup.isResizeOverFlowY = false; + const heightBackup = popup.height + const topBackup = popup.top; + if (lsk) { + popup.height += dis; + } else { + popup.top += dis; + popup.height -= dis; + } + if (popup.height < popup.minHeight) { + popup.height = heightBackup; + popup.top = topBackup; + popup.isResizeOverFlowY = true; + } + } else { + // X + popup.isResizeOverFlowX = false; + const leftBackup = popup.left + const widthBackup = popup.width; + if (lsk) { + popup.width += dis; + } else { + popup.left += dis; + popup.width -= dis; + } + if (popup.width < popup.minWidth) { + popup.width = widthBackup; + popup.left = leftBackup; + popup.isResizeOverFlowX = true; + } + } } private handelMouseMove = (e: MouseEvent) => { + let isActionSuccess: boolean = false; if ( this.isMouseDown && this.props.status && @@ -159,10 +332,69 @@ class Popup extends Component { + if (popup.resizeDragDirection) { + + let moveX = e.clientX - popup.lastMouseLeft; + let moveY = e.clientY - popup.lastMouseTop; + switch (popup.resizeDragDirection) { + + case ResizeDragDirection.LeftTop: + this.resize(popup, moveX, false, false); + this.resize(popup, moveY, true, false); + break; + + case ResizeDragDirection.leftBottom: + this.resize(popup, moveX, false, false); + this.resize(popup, moveY, true, true); + break; + + case ResizeDragDirection.rightTop: + this.resize(popup, moveX, false, true); + this.resize(popup, moveY, true, false); + break; + + case ResizeDragDirection.rightBottom: + this.resize(popup, moveX, false, true); + this.resize(popup, moveY, true, true); + break; + + case ResizeDragDirection.top: + this.resize(popup, moveY, true, false); + break; + + case ResizeDragDirection.left: + this.resize(popup, moveX, false, false); + break; + + case ResizeDragDirection.bottom: + this.resize(popup, moveY, true, true); + break; + + case ResizeDragDirection.right: + this.resize(popup, moveX, false, true); + break; + } + if (!popup.isResizeOverFlowX) { + popup.lastMouseLeft = e.clientX; + } + if (!popup.isResizeOverFlowY) { + popup.lastMouseTop = e.clientY; + } + isActionSuccess = true; + this.forceUpdate(); + } + }); + } + if (isActionSuccess) { + e.preventDefault(); + } } public componentDidMount() { diff --git a/source/Context/Popups.ts b/source/Context/Popups.ts index 963d74b..075498c 100644 --- a/source/Context/Popups.ts +++ b/source/Context/Popups.ts @@ -3,6 +3,17 @@ import { Emitter } from "@Model/Emitter"; import { Localization } from "@Component/Localization/Localization"; import { IAnyObject } from "@Model/Renderer"; +enum ResizeDragDirection { + top = 1, + rightTop = 2, + right = 3, + rightBottom = 4, + bottom = 5, + leftBottom = 6, + left = 7, + LeftTop = 8 +} + /** * 弹窗类型 */ @@ -15,22 +26,23 @@ class Popup

{ } public zIndex() { - return this.index * 2 + this.controller.zIndex; + return this.index * 5 + this.controller.zIndex; } public width: number = 300; - public height: number = 200; - + public minWidth: number = 300; + public minHeight: number = 200; public top: number = NaN; - public left: number = NaN; - public lastMouseTop: number = 0; - public lastMouseLeft: number = 0; - public isOnMouseDown: boolean = false; + public resizeHoverDirection?: ResizeDragDirection; + public resizeDragDirection?: ResizeDragDirection; + public isResizeMouseDown: boolean = false; + public isResizeOverFlowX: boolean = false; + public isResizeOverFlowY: boolean = false; /** * 是否关闭 @@ -178,4 +190,4 @@ class PopupController extends Emitter { } } -export { Popup, PopupController } \ No newline at end of file +export { Popup, PopupController, ResizeDragDirection } \ No newline at end of file