Compare commits
3 Commits
04060902e0
...
90398b593e
Author | SHA1 | Date | |
---|---|---|---|
90398b593e | |||
93e1a8d3ef | |||
3357960f61 |
@ -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>
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ import { Component, ReactNode, DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { useSetting, IMixinSettingProps, Language } from "@Context/Setting";
|
||||
import "./Localization.scss";
|
||||
|
||||
import EN_US from "../../Localization/EN-US";
|
||||
import ZH_CN from "../../Localization/ZH-CN";
|
||||
import EN_US from "@Localization/EN-US";
|
||||
import ZH_CN from "@Localization/ZH-CN";
|
||||
|
||||
const LanguageDataBase = {
|
||||
EN_US, ZH_CN
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { AllI18nKeys, I18N } from "@Component/Localization/Localization";
|
||||
import { useStatusWithEvent, IMixinSettingProps, Themes, Language } from "@Context/Setting";
|
||||
import { useSettingWithEvent, IMixinSettingProps, Themes, Language } from "@Context/Setting";
|
||||
import { FunctionComponent } from "react";
|
||||
import "./Message.scss";
|
||||
|
||||
@ -38,5 +38,5 @@ const MessageView: FunctionComponent<IMessageProps & IMixinSettingProps> = (prop
|
||||
</div>
|
||||
}
|
||||
|
||||
const Message = useStatusWithEvent("language", "themes")(MessageView);
|
||||
const Message = useSettingWithEvent("language", "themes")(MessageView);
|
||||
export { Message };
|
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;
|
||||
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@ -36,18 +58,29 @@ class Popup {
|
||||
/**
|
||||
* 渲染函数
|
||||
*/
|
||||
public rendererFunction: undefined | ((p: Popup) => ReactNode);
|
||||
public onRender(p: Popup): ReactNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭回调
|
||||
*/
|
||||
public onClose(): void {
|
||||
this.close();
|
||||
};
|
||||
|
||||
/**
|
||||
* 渲染节点
|
||||
*/
|
||||
public render(): ReactNode {
|
||||
if (this.rendererFunction) {
|
||||
this.reactNode = this.rendererFunction(this);
|
||||
}
|
||||
this.reactNode = this.onRender(this);
|
||||
return this.reactNode;
|
||||
};
|
||||
|
||||
public close() {
|
||||
return this.controller.closePopup(this);
|
||||
}
|
||||
|
||||
public constructor(controller: PopupController, id: string) {
|
||||
this.controller = controller;
|
||||
this.id = id;
|
||||
@ -68,6 +101,11 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
||||
*/
|
||||
private idIndex = 0;
|
||||
|
||||
/**
|
||||
* 最小弹窗 Index
|
||||
*/
|
||||
public zIndex = 100;
|
||||
|
||||
/**
|
||||
* 弹窗列表
|
||||
*/
|
||||
@ -82,6 +120,7 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
||||
popup.index = (index + 1);
|
||||
return popup;
|
||||
});
|
||||
this.emit("popupChange");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,7 +129,7 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
||||
public showPopup<P extends IPopupConstructor>(popup?: P): Popup {
|
||||
let newPopup = new (popup ?? Popup)(this, `P-${this.idIndex ++}`);
|
||||
this.popups.push(newPopup);
|
||||
this.emit("popupChange");
|
||||
this.sortPopup();
|
||||
return newPopup;
|
||||
}
|
||||
|
||||
@ -110,6 +149,7 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
||||
let isDelete = currentPopup.id === id;
|
||||
if (isDelete) {
|
||||
closePopup = currentPopup;
|
||||
currentPopup.isClose = true;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@ -117,6 +157,7 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
||||
}
|
||||
);
|
||||
if (closePopup) {
|
||||
this.sortPopup();
|
||||
this.emit("popupChange");
|
||||
}
|
||||
return closePopup;
|
||||
|
@ -14,7 +14,7 @@ enum Themes {
|
||||
type Language = "ZH_CN" | "EN_US";
|
||||
|
||||
interface ISettingEvents extends Setting {
|
||||
change: keyof Setting;
|
||||
attrChange: keyof Setting;
|
||||
}
|
||||
|
||||
class Setting extends Emitter<ISettingEvents> {
|
||||
@ -39,7 +39,7 @@ class Setting extends Emitter<ISettingEvents> {
|
||||
*/
|
||||
public setProps<P extends keyof Setting>(key: P, value: Setting[P]) {
|
||||
this[key] = value as any;
|
||||
this.emit("change", key);
|
||||
this.emit("attrChange", key);
|
||||
this.emit(key as any, value as any);
|
||||
}
|
||||
}
|
||||
@ -59,9 +59,9 @@ const SettingConsumer = SettingContext.Consumer;
|
||||
*/
|
||||
const useSetting = superConnect<Setting>(SettingConsumer, "setting");
|
||||
|
||||
const useStatusWithEvent = superConnectWithEvent<Setting, ISettingEvents>(SettingConsumer, "setting");
|
||||
const useSettingWithEvent = superConnectWithEvent<Setting, ISettingEvents>(SettingConsumer, "setting");
|
||||
|
||||
export {
|
||||
Themes, Setting, SettingContext, useSetting, Language, useStatusWithEvent,
|
||||
Themes, Setting, SettingContext, useSetting, Language, useSettingWithEvent,
|
||||
IMixinSettingProps, SettingProvider, SettingConsumer
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import { createContext, Component, FunctionComponent, ReactNode } from "react";
|
||||
import { createContext } from "react";
|
||||
import { Emitter } from "@Model/Emitter";
|
||||
import { Model, ObjectID } from "@Model/Model";
|
||||
import { Label } from "@Model/Label";
|
||||
@ -10,6 +10,7 @@ import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer";
|
||||
import { Setting } from "./Setting";
|
||||
import { I18N } from "@Component/Localization/Localization";
|
||||
import { superConnectWithEvent, superConnect } from "./Context";
|
||||
import { PopupController } from "./Popups";
|
||||
|
||||
function randomColor(unNormal: boolean = false) {
|
||||
const color = [
|
||||
@ -39,6 +40,7 @@ interface IStatusEvent {
|
||||
labelAttrChange: void;
|
||||
groupAttrChange: void;
|
||||
individualChange: void;
|
||||
popupChange: void;
|
||||
}
|
||||
|
||||
class Status extends Emitter<IStatusEvent> {
|
||||
@ -66,6 +68,11 @@ class Status extends Emitter<IStatusEvent> {
|
||||
*/
|
||||
public model: Model = new Model();
|
||||
|
||||
/**
|
||||
* 弹窗
|
||||
*/
|
||||
public popup: PopupController = new PopupController();
|
||||
|
||||
/**
|
||||
* 焦点对象
|
||||
*/
|
||||
@ -96,6 +103,9 @@ class Status extends Emitter<IStatusEvent> {
|
||||
this.model.on("objectChange", () => this.emit("objectChange"));
|
||||
this.model.on("labelChange", () => this.emit("labelChange"));
|
||||
|
||||
// 弹窗事件
|
||||
this.popup.on("popupChange", () => this.emit("popupChange"));
|
||||
|
||||
// 对象变换时执行渲染,更新渲染器数据
|
||||
this.on("objectChange", this.delayDraw);
|
||||
this.model.on("individualChange", this.delayDraw);
|
||||
|
@ -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)`
|
||||
|
@ -31,6 +31,12 @@
|
||||
],
|
||||
"@Component/*": [
|
||||
"./source/Component/*"
|
||||
],
|
||||
"@Localization/*": [
|
||||
"./source/Localization/*"
|
||||
],
|
||||
"@Panel/*": [
|
||||
"./source/Panel/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user