Add popup renderer
This commit is contained in:
		
							parent
							
								
									93e1a8d3ef
								
							
						
					
					
						commit
						90398b593e
					
				@ -68,7 +68,13 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi
 | 
			
		||||
                {this.getRenderButton({ iconName: "Camera", i18NKey: "Command.Bar.Camera.Info" })}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                {this.getRenderButton({ iconName: "Settings", i18NKey: "Command.Bar.Setting.Info" })}
 | 
			
		||||
                {this.getRenderButton({
 | 
			
		||||
                    iconName: "Settings",
 | 
			
		||||
                    i18NKey: "Command.Bar.Setting.Info",
 | 
			
		||||
                    click: () => {
 | 
			
		||||
                        this.props.status ? this.props.status.popup.showPopup() : undefined;
 | 
			
		||||
                    }
 | 
			
		||||
                })}
 | 
			
		||||
            </div>
 | 
			
		||||
        </Theme>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								source/Component/Popup/Popup.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								source/Component/Popup/Popup.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
@import "../Theme/Theme.scss";
 | 
			
		||||
 | 
			
		||||
@keyframes show-scale{
 | 
			
		||||
    from {
 | 
			
		||||
        transform: scale3d(1.15, 1.15, 1);
 | 
			
		||||
    }
 | 
			
		||||
    to {
 | 
			
		||||
        transform: scale3d(1, 1, 1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes show-fade{
 | 
			
		||||
    from {
 | 
			
		||||
        opacity: 0;
 | 
			
		||||
    }
 | 
			
		||||
    to {
 | 
			
		||||
        opacity: 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.popup-mask.show-fade {
 | 
			
		||||
    animation: show-fade .1s cubic-bezier(0, 0, 1, 1) both;
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.popup-layer.show-scale {
 | 
			
		||||
    animation: show-scale .3s cubic-bezier(.1, .9, .2, 1) both,
 | 
			
		||||
    show-fade .1s cubic-bezier(0, 0, 1, 1) both;
 | 
			
		||||
    transform: scale3d(1, 1, 1);
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.popup-mask {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.popup-layer {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
 | 
			
		||||
    div.popup-layer-header {
 | 
			
		||||
        min-height: 32px;
 | 
			
		||||
        max-height: 32px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.popup-layer.dark {
 | 
			
		||||
 | 
			
		||||
    div.popup-layer-header {
 | 
			
		||||
        background-color: $lt-bg-color-lvl3-dark;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.popup-layer.light {
 | 
			
		||||
 | 
			
		||||
    div.popup-layer-header {
 | 
			
		||||
        background-color: $lt-bg-color-lvl3-light;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.dark.popup-mask {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.55);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.light.popup-mask {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.15);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										97
									
								
								source/Component/Popup/Popup.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								source/Component/Popup/Popup.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
			
		||||
import { Component, ReactNode } from "react";
 | 
			
		||||
import { IMixinStatusProps, useStatusWithEvent } from "@Context/Status";
 | 
			
		||||
import { BackgroundLevel, Theme } from "@Component/Theme/Theme";
 | 
			
		||||
import { Popup as PopupModel } from "@Context/Popups";
 | 
			
		||||
import "./Popup.scss";
 | 
			
		||||
 | 
			
		||||
interface IPopupProps {}
 | 
			
		||||
 | 
			
		||||
@useStatusWithEvent("popupChange")
 | 
			
		||||
class Popup extends Component<IPopupProps & IMixinStatusProps> {
 | 
			
		||||
 | 
			
		||||
    public renderMask(index?: number, click?: () => void, key?: string): ReactNode {
 | 
			
		||||
        const classList: string[] = ["popup-mask", "show-fade"];
 | 
			
		||||
        return <Theme
 | 
			
		||||
            key={key}
 | 
			
		||||
            onClick={click}
 | 
			
		||||
            className={classList.join(" ")}
 | 
			
		||||
            style={{
 | 
			
		||||
                zIndex: index,
 | 
			
		||||
            }}
 | 
			
		||||
        />
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public renderRootMask(): ReactNode {
 | 
			
		||||
        if (this.props.status) {
 | 
			
		||||
            const needMask = this.props.status.popup.popups.some(popup => popup.needMask);
 | 
			
		||||
            if (!needMask) return null;
 | 
			
		||||
            return this.renderMask(this.props.status.popup.zIndex,
 | 
			
		||||
                () => {
 | 
			
		||||
                    this.props.status?.popup.popups.forEach(
 | 
			
		||||
                        popup => popup.onClose()
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public renderMaskList(): ReactNode {
 | 
			
		||||
        if (this.props.status) {
 | 
			
		||||
            return this.props.status.popup.popups
 | 
			
		||||
            .filter((popup) => {
 | 
			
		||||
                return popup.needMask && popup.maskForSelf;
 | 
			
		||||
            })
 | 
			
		||||
            .filter((_, index) => {
 | 
			
		||||
                if (index === 0) return false;
 | 
			
		||||
                return true;
 | 
			
		||||
            })
 | 
			
		||||
            .map((popup) => {
 | 
			
		||||
                return this.renderMask(popup.zIndex() - 1,
 | 
			
		||||
                    () => {
 | 
			
		||||
                        popup.onClose();
 | 
			
		||||
                    }, popup.id
 | 
			
		||||
                );
 | 
			
		||||
            })
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public renderLayer(popup: PopupModel) {
 | 
			
		||||
        const pageWidth = document.documentElement.clientWidth;
 | 
			
		||||
        const pageHeight = document.documentElement.clientHeight;
 | 
			
		||||
        const top = (pageHeight - popup.height) / 2;
 | 
			
		||||
        const left = (pageWidth - popup.width) / 2;
 | 
			
		||||
 | 
			
		||||
        return <Theme
 | 
			
		||||
            style={{
 | 
			
		||||
                width: popup.width,
 | 
			
		||||
                height: popup.height,
 | 
			
		||||
                zIndex: popup.zIndex(),
 | 
			
		||||
                top: top,
 | 
			
		||||
                left: left
 | 
			
		||||
            }}
 | 
			
		||||
            key={popup.id}
 | 
			
		||||
            backgroundLevel={BackgroundLevel.Level4}
 | 
			
		||||
            className="popup-layer show-scale"
 | 
			
		||||
        >
 | 
			
		||||
            <div className="popup-layer-header">
 | 
			
		||||
                
 | 
			
		||||
            </div>
 | 
			
		||||
        </Theme>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public render(): ReactNode {
 | 
			
		||||
        return <>
 | 
			
		||||
            {this.renderRootMask()}
 | 
			
		||||
            {this.renderMaskList()}
 | 
			
		||||
            {this.props.status?.popup.popups.map((popup) => {
 | 
			
		||||
                return this.renderLayer(popup);
 | 
			
		||||
            })}
 | 
			
		||||
        </>;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { Popup };
 | 
			
		||||
@ -8,11 +8,33 @@ type IPopupConstructor = new (controller: PopupController, id: string) => Popup;
 | 
			
		||||
 */
 | 
			
		||||
class Popup {
 | 
			
		||||
 | 
			
		||||
    public zIndex() {
 | 
			
		||||
        return this.index * 2 + this.controller.zIndex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public width: number = 300;
 | 
			
		||||
 | 
			
		||||
    public height: number = 200;
 | 
			
		||||
 | 
			
		||||
    public top: number = 0;
 | 
			
		||||
 | 
			
		||||
    public left: number = 0;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否关闭
 | 
			
		||||
     */
 | 
			
		||||
    public isClose: boolean = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 需要蒙版
 | 
			
		||||
     */
 | 
			
		||||
    public needMask: boolean = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 单独遮挡下层的蒙版
 | 
			
		||||
     */
 | 
			
		||||
    public maskForSelf: boolean = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 唯一标识符
 | 
			
		||||
     */
 | 
			
		||||
@ -43,7 +65,9 @@ class Popup {
 | 
			
		||||
    /**
 | 
			
		||||
     * 关闭回调
 | 
			
		||||
     */
 | 
			
		||||
    public onClose(): void {};
 | 
			
		||||
    public onClose(): void {
 | 
			
		||||
        this.close();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 渲染节点
 | 
			
		||||
@ -77,6 +101,11 @@ class PopupController extends Emitter<IPopupControllerEvent> {
 | 
			
		||||
     */
 | 
			
		||||
    private idIndex = 0;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 最小弹窗 Index
 | 
			
		||||
     */
 | 
			
		||||
    public zIndex = 100;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 弹窗列表
 | 
			
		||||
     */
 | 
			
		||||
@ -121,7 +150,6 @@ class PopupController extends Emitter<IPopupControllerEvent> {
 | 
			
		||||
                if (isDelete) {
 | 
			
		||||
                    closePopup = currentPopup;
 | 
			
		||||
                    currentPopup.isClose = true;
 | 
			
		||||
                    currentPopup.onClose();
 | 
			
		||||
                    return false;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return true;
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import { initializeIcons } from '@fluentui/font-icons-mdl2';
 | 
			
		||||
import { RootContainer } from "@Component/Container/RootContainer";
 | 
			
		||||
import { LayoutDirection } from "@Context/Layout";
 | 
			
		||||
import { CommandBar } from "@Component/CommandBar/CommandBar";
 | 
			
		||||
import { Popup } from "@Component/Popup/Popup";
 | 
			
		||||
import "./SimulatorWeb.scss";
 | 
			
		||||
 | 
			
		||||
initializeIcons("https://img.mrkbear.com/fabric-cdn-prod_20210407.001/");
 | 
			
		||||
@ -101,6 +102,7 @@ class SimulatorWeb extends Component {
 | 
			
		||||
            backgroundLevel={BackgroundLevel.Level5}
 | 
			
		||||
            fontLevel={FontLevel.Level3}
 | 
			
		||||
        >
 | 
			
		||||
            <Popup/>
 | 
			
		||||
            <HeaderBar height={45}/>
 | 
			
		||||
            <div className="app-root-space" style={{
 | 
			
		||||
                height: `calc( 100% - ${45}px)`
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user