UNPKG

gem-panel

Version:

A custom element <gem-panel>, let you easily create layout similar to Adobe After Effects.

184 lines (159 loc) 5.9 kB
import { createStore, updateStore } from '@mantou/gem'; import { DROP_DETECTION_DELAY, WINDOW_HOVER_DETECT_BORDER, WINDOW_HOVER_DETECT_HEADER_HEIGHT } from './const'; import { Layout, Window } from './layout'; import { Panel, PanelContent } from './panel'; import { detectPosition } from './utils'; import { GemPanelWindowElement } from '../elements/window'; import { HoverWindowPosition } from '../elements/window-mask'; import { MoveSideArgs, Side } from '../elements/window-handle'; type AppState = { layout: Layout; panels: { [name: string]: Panel }; windowPanTimer: number; hoverWindow: null | Window; panWindow: null | Window; hoverWindowPosition: HoverWindowPosition; }; export const store = createStore<AppState>({ layout: new Layout(), panels: {}, windowPanTimer: 0, hoverWindow: null, hoverWindowPosition: 'center', panWindow: null, }); export function updateAppState(state: Partial<AppState>) { updateStore(store, state); } export function addHiddenPanel(panel: Panel) { store.panels[panel.name] = panel; } export function deleteHiddenPanel(panelName: string) { delete store.panels[panelName]; } export function deletePanelFromWindow(window: Window, panelName: string) { store.layout.closePanel(window, panelName); deleteHiddenPanel(panelName); updateStore(store); } export function openHiddenPanel(panelName: string) { store.layout.openHiddenPanel(panelName); updateStore(store); } export function activePanel(window: Window, panelName: string) { store.layout.activePanel(window, panelName); updateStore(store); } export function openPanelInWindow(window: Window, panelName: string, side?: Side) { store.layout.openPanelInWindow(window, panelName, side); updateStore(store); } export function loadContentInPanel(panelName: string, content: PanelContent) { const panel = store.panels[panelName]; if (!panel) return; panel.detail.content = content; updateStore(store); } export function independentPanel(window: Window, panelName: string, rect: [number, number, number, number]) { const newWindow = store.layout.createIndependentWindow(window, panelName, rect); updateStore(store); return newWindow; } export function setWindowPanTimeout( ele: GemPanelWindowElement, currentPanWindow: Window, [clientX, clientY]: [number, number], ) { const detectHoverWindow = () => { const gemPanelShadowRoot = (ele.getRootNode() as unknown) as ShadowRoot; const windowEles = gemPanelShadowRoot .elementsFromPoint(clientX, clientY) .filter((e) => 'window' in e) as GemPanelWindowElement[]; const currentWindowEle = windowEles.find((e) => e.window === currentPanWindow); const hoverWindowEle = windowEles.find((e) => e !== currentWindowEle && e.window !== currentWindowEle?.window); if (hoverWindowEle) { const { x, y, width, height } = hoverWindowEle.getBoundingClientRect(); const headerHeight = hoverWindowEle.window.engross ? 0 : WINDOW_HOVER_DETECT_HEADER_HEIGHT; const isCenterPostion = !hoverWindowEle.window.isGridWindow() || width < 4 * WINDOW_HOVER_DETECT_BORDER || height < 3 * WINDOW_HOVER_DETECT_BORDER + 2 * headerHeight; const isHeader = clientY > y && clientY < y + headerHeight; const hoverWindowPosition = isCenterPostion ? 'center' : isHeader ? 'header' : detectPosition( [x, y + headerHeight, width, height - headerHeight], [clientX, clientY], WINDOW_HOVER_DETECT_BORDER, ); if ((hoverWindowPosition === 'center' || hoverWindowPosition === 'header') && hoverWindowEle.window.engross) { cancelHandleWindow(); } else { updateStore(store, { hoverWindow: hoverWindowEle.window, panWindow: currentPanWindow, hoverWindowPosition, }); } } else { cancelHandleWindow(); } }; if (store.hoverWindow) { detectHoverWindow(); } else { updateStore(store, { windowPanTimer: window.setTimeout(detectHoverWindow, DROP_DETECTION_DELAY) }); } } export function cancelHandleWindow() { updateStore(store, { hoverWindow: null, panWindow: null }); } export function dropHandleWindow(window: Window) { clearTimeout(store.windowPanTimer); if (store.hoverWindow) { if (store.hoverWindowPosition === 'center' || store.hoverWindowPosition === 'header') { store.layout.mergeWindow(window, store.hoverWindow); } else { store.layout.convertGridWindow(window, store.hoverWindow, store.hoverWindowPosition); } cancelHandleWindow(); } } export function updateCurrentPanel(window: Window, panelName: string) { window.changeCurrent(window.panels.findIndex((p) => p === panelName)); updateStore(store); } export function updatePanelSort(window: Window, p1: string, p2: string) { window.changePanelSort(p1, p2); updateStore(store); } export function updateWindowPosition(window: Window, movement: [number, number]) { store.layout.moveWindow(window, movement); updateStore(store); } export function updateWindowRect(window: Window, movement: [number, number, number, number]) { store.layout.changeWindowRect(window, movement); updateStore(store); } export function updateWindowZIndex(window: Window) { store.layout.focusWindow(window); updateStore(store); } export function updateWindowType(window: Window, { x, y, width, height }: DOMRect) { store.layout.removeWindow(window, [x, y, width, height]); updateStore(store); } export function closePanel(window: Window, panelName: string) { store.layout.closePanel(window, panelName); updateStore(store); } export function closeWindow(window: Window) { store.layout.removeWindow(window); updateStore(store); } export function moveSide(window: Window, side: Side, args: MoveSideArgs) { store.layout.moveSide(window, side, args); updateStore(store); }