Add confirm popup component
This commit is contained in:
parent
8b44ae953e
commit
89ae499d4b
0
source/Component/ConfirmPopup/ConfirmPopup.scss
Normal file
0
source/Component/ConfirmPopup/ConfirmPopup.scss
Normal file
8
source/Component/ConfirmPopup/ConfirmPopup.tsx
Normal file
8
source/Component/ConfirmPopup/ConfirmPopup.tsx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Popup } from "@Context/Popups";
|
||||||
|
import "./ConfirmPopup.scss";
|
||||||
|
|
||||||
|
class ConfirmPopup extends Popup {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ConfirmPopup }
|
@ -39,10 +39,17 @@ div.popup-mask {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.focus.popup-layer {
|
||||||
|
border: 0.8px solid #514feb;
|
||||||
|
}
|
||||||
|
|
||||||
div.popup-layer {
|
div.popup-layer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
transition: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 0.8px solid transparent;
|
||||||
|
|
||||||
div.popup-layer-header {
|
div.popup-layer-header {
|
||||||
min-height: $header-height;
|
min-height: $header-height;
|
||||||
@ -79,9 +86,16 @@ div.popup-layer {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.popup-layer-content {
|
||||||
|
height: calc( 100% - 32px );
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.popup-layer.dark {
|
div.popup-layer.dark {
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
div.popup-layer-header {
|
div.popup-layer-header {
|
||||||
background-color: $lt-bg-color-lvl3-dark;
|
background-color: $lt-bg-color-lvl3-dark;
|
||||||
@ -94,6 +108,7 @@ div.popup-layer.dark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.popup-layer.light {
|
div.popup-layer.light {
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.15);
|
||||||
|
|
||||||
div.popup-layer-header {
|
div.popup-layer-header {
|
||||||
background-color: $lt-bg-color-lvl3-light;
|
background-color: $lt-bg-color-lvl3-light;
|
||||||
|
@ -10,7 +10,7 @@ interface IPopupProps {}
|
|||||||
@useStatusWithEvent("popupChange")
|
@useStatusWithEvent("popupChange")
|
||||||
class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
||||||
|
|
||||||
public renderMask(index?: number, click?: () => void, key?: string): ReactNode {
|
private renderMask(index?: number, click?: () => void, key?: string): ReactNode {
|
||||||
const classList: string[] = ["popup-mask", "show-fade"];
|
const classList: string[] = ["popup-mask", "show-fade"];
|
||||||
return <Theme
|
return <Theme
|
||||||
key={key}
|
key={key}
|
||||||
@ -22,7 +22,7 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderRootMask(): ReactNode {
|
private renderRootMask(): ReactNode {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
const needMask = this.props.status.popup.popups.some(popup => popup.needMask);
|
const needMask = this.props.status.popup.popups.some(popup => popup.needMask);
|
||||||
if (!needMask) return null;
|
if (!needMask) return null;
|
||||||
@ -38,7 +38,7 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderMaskList(): ReactNode {
|
private renderMaskList(): ReactNode {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
return this.props.status.popup.popups
|
return this.props.status.popup.popups
|
||||||
.filter((popup) => {
|
.filter((popup) => {
|
||||||
@ -60,9 +60,19 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderHeader(popup: PopupModel): ReactNode {
|
private renderHeader(popup: PopupModel): ReactNode {
|
||||||
return <div className="popup-layer-header">
|
return <div className="popup-layer-header">
|
||||||
<div className="header-text">
|
<div
|
||||||
|
className="header-text"
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
popup.isOnMouseDown = true;
|
||||||
|
popup.lastMouseLeft = e.clientX;
|
||||||
|
popup.lastMouseTop = e.clientY;
|
||||||
|
}}
|
||||||
|
onMouseUp={() => {
|
||||||
|
popup.isOnMouseDown = false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
{popup.onRenderHeader()}
|
{popup.onRenderHeader()}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -76,28 +86,79 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderLayer(popup: PopupModel) {
|
private renderContent(popup: PopupModel) {
|
||||||
|
return <div className="popup-layer-content">
|
||||||
|
{popup.render()}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderLayer(popup: PopupModel) {
|
||||||
const pageWidth = document.documentElement.clientWidth;
|
const pageWidth = document.documentElement.clientWidth;
|
||||||
const pageHeight = document.documentElement.clientHeight;
|
const pageHeight = document.documentElement.clientHeight;
|
||||||
const top = (pageHeight - popup.height) / 2;
|
if (isNaN(popup.top)) {
|
||||||
const left = (pageWidth - popup.width) / 2;
|
popup.top = (pageHeight - popup.height) / 2;
|
||||||
|
}
|
||||||
|
if (isNaN(popup.left)) {
|
||||||
|
popup.left = (pageWidth - popup.width) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
return <Theme
|
return <Theme
|
||||||
style={{
|
style={{
|
||||||
width: popup.width,
|
width: popup.width,
|
||||||
height: popup.height,
|
height: popup.height,
|
||||||
zIndex: popup.zIndex(),
|
zIndex: popup.zIndex(),
|
||||||
top: top,
|
top: popup.top,
|
||||||
left: left
|
left: popup.left
|
||||||
}}
|
}}
|
||||||
key={popup.id}
|
key={popup.id}
|
||||||
backgroundLevel={BackgroundLevel.Level4}
|
backgroundLevel={BackgroundLevel.Level4}
|
||||||
className="popup-layer show-scale"
|
className="popup-layer show-scale"
|
||||||
>
|
>
|
||||||
{this.renderHeader(popup)}
|
{this.renderHeader(popup)}
|
||||||
|
{this.renderContent(popup)}
|
||||||
</Theme>
|
</Theme>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isMouseDown: boolean = false;
|
||||||
|
|
||||||
|
private handelMouseDown = () => {
|
||||||
|
this.isMouseDown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handelMouseUp = () => {
|
||||||
|
this.isMouseDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handelMouseMove = (e: MouseEvent) => {
|
||||||
|
if (
|
||||||
|
this.isMouseDown &&
|
||||||
|
this.props.status &&
|
||||||
|
this.props.status.popup.popups.some(popup => popup.isOnMouseDown)
|
||||||
|
) {
|
||||||
|
this.props.status.popup.popups.forEach((popup) => {
|
||||||
|
if (popup.isOnMouseDown) {
|
||||||
|
popup.top += e.clientY - popup.lastMouseTop;
|
||||||
|
popup.left += e.clientX - popup.lastMouseLeft;
|
||||||
|
popup.lastMouseLeft = e.clientX;
|
||||||
|
popup.lastMouseTop = e.clientY;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
window.addEventListener("mousemove", this.handelMouseMove);
|
||||||
|
window.addEventListener("mousedown", this.handelMouseDown);
|
||||||
|
window.addEventListener("mouseup", this.handelMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
window.removeEventListener("mousemove", this.handelMouseMove);
|
||||||
|
window.removeEventListener("mousedown", this.handelMouseDown);
|
||||||
|
window.removeEventListener("mouseup", this.handelMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
return <>
|
return <>
|
||||||
{this.renderRootMask()}
|
{this.renderRootMask()}
|
||||||
|
@ -2,12 +2,16 @@ import { ReactNode, createElement } from "react";
|
|||||||
import { Emitter } from "@Model/Emitter";
|
import { Emitter } from "@Model/Emitter";
|
||||||
import { Localization } from "@Component/Localization/Localization";
|
import { Localization } from "@Component/Localization/Localization";
|
||||||
|
|
||||||
type IPopupConstructor = new (controller: PopupController, id: string) => Popup;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 弹窗类型
|
* 弹窗类型
|
||||||
*/
|
*/
|
||||||
class Popup {
|
class Popup<P extends any = any> {
|
||||||
|
|
||||||
|
public props: P;
|
||||||
|
|
||||||
|
public constructor(props: P) {
|
||||||
|
this.props = props;
|
||||||
|
}
|
||||||
|
|
||||||
public zIndex() {
|
public zIndex() {
|
||||||
return this.index * 2 + this.controller.zIndex;
|
return this.index * 2 + this.controller.zIndex;
|
||||||
@ -17,9 +21,15 @@ class Popup {
|
|||||||
|
|
||||||
public height: number = 200;
|
public height: number = 200;
|
||||||
|
|
||||||
public top: number = 0;
|
public top: number = NaN;
|
||||||
|
|
||||||
public left: number = 0;
|
public left: number = NaN;
|
||||||
|
|
||||||
|
public lastMouseTop: number = 0;
|
||||||
|
|
||||||
|
public lastMouseLeft: number = 0;
|
||||||
|
|
||||||
|
public isOnMouseDown: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否关闭
|
* 是否关闭
|
||||||
@ -39,12 +49,12 @@ class Popup {
|
|||||||
/**
|
/**
|
||||||
* 唯一标识符
|
* 唯一标识符
|
||||||
*/
|
*/
|
||||||
public id: string;
|
public id: string = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制器
|
* 控制器
|
||||||
*/
|
*/
|
||||||
public controller: PopupController;
|
public controller: PopupController = undefined as any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染层级
|
* 渲染层级
|
||||||
@ -67,7 +77,7 @@ class Popup {
|
|||||||
* 渲染函数
|
* 渲染函数
|
||||||
*/
|
*/
|
||||||
public onRender(p: Popup): ReactNode {
|
public onRender(p: Popup): ReactNode {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,15 +91,15 @@ class Popup {
|
|||||||
* 渲染节点
|
* 渲染节点
|
||||||
*/
|
*/
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
this.reactNode = this.onRender(this);
|
this.reactNode = this.onRender(this) ?? this.reactNode;
|
||||||
return this.reactNode;
|
return this.reactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
public close() {
|
public close(): Popup | undefined {
|
||||||
return this.controller.closePopup(this);
|
return this.controller.closePopup(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(controller: PopupController, id: string) {
|
public init(controller: PopupController, id: string) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
@ -134,8 +144,16 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
|||||||
/**
|
/**
|
||||||
* 实例化并开启一个弹窗
|
* 实例化并开启一个弹窗
|
||||||
*/
|
*/
|
||||||
public showPopup<P extends IPopupConstructor>(popup?: P): Popup {
|
public showPopup<P extends any, T extends Popup<P>>(
|
||||||
let newPopup = new (popup ?? Popup)(this, `P-${this.idIndex ++}`);
|
popup?: (new () => T) | Popup<P>, props?: P
|
||||||
|
): Popup<P> {
|
||||||
|
let newPopup: Popup;
|
||||||
|
if (popup instanceof Popup) {
|
||||||
|
newPopup = popup;
|
||||||
|
} else {
|
||||||
|
newPopup = new (popup ?? Popup)(props);
|
||||||
|
}
|
||||||
|
newPopup.init(this, `P-${this.idIndex ++}`);
|
||||||
this.popups.push(newPopup);
|
this.popups.push(newPopup);
|
||||||
this.sortPopup();
|
this.sortPopup();
|
||||||
return newPopup;
|
return newPopup;
|
||||||
|
Loading…
Reference in New Issue
Block a user