UNPKG

@ovine/craft

Version:
169 lines (168 loc) 6.14 kB
/** * 悬浮/或者选中 选中时的高亮 * * TODO: * 1. 完善toolbar 快捷操作 * 2. 针对不同类型不同toolbar操作 * 3. UI美化 * * BUG: * 1. 监听 选中 dom 宽高变化,更新 高亮 UI * 2. 某些类型 --- 选中时禁用点击 * 3. 布局要跟随 preview */ import { debounce, includes, throttle } from 'lodash'; import { observer } from 'mobx-react'; import React, { useEffect, useRef, useState } from 'react'; import { referenceStore } from "../../reference/store"; import { domId } from "../../../constants"; import { onNodeMenus } from "../actions"; import { usePreviewStore } from "../store"; import { StyledAttacher } from "./styled"; const displayNone = { display: 'none' }; export default observer(() => { const { setHoverId, setSelectedId, hoverId, selectedId, selectedInfo, renderSchema, } = usePreviewStore(); const [hover, setHover] = useState({ style: displayNone }); const [selected, setSelected] = useState({ style: displayNone, tipStyle: displayNone, toolbarStyle: displayNone, }); const $wrap = useRef(null); const cancelHover = () => { setHover({ style: displayNone }); setHoverId(''); }; const cancelSelected = () => { setSelected({ style: displayNone, toolbarStyle: displayNone }); setSelectedId(''); }; const onActive = (type, $ele, parentRect) => { var _a; // 没有 data-id 标记的内容,不处理 if (!$ele.length) { return; } const activeId = $ele.data('id'); // 已经选择对象的不能被hover,或者再次选择 if (type !== 'updateSelected' && ((_a = $wrap.current) === null || _a === void 0 ? void 0 : _a.dataset.selected) === activeId) { cancelHover(); return; } // 计算位置 const { width, height, left, right, top } = $ele[0].getBoundingClientRect(); const style = { display: 'block', width, height, left: left - parentRect.left, top: top - parentRect.top, }; if (type === 'hover') { setHover({ style }); return; } if (includes(['selected', 'updateSelected'], type)) { const toolbarStyle = { display: 'block', right: parentRect.right - right, top: top - parentRect.top - 25, }; const tipStyle = { display: width >= 100 ? 'block' : 'none' }; cancelHover(); setSelected({ style, toolbarStyle, tipStyle }); } }; const setActiveById = (type, id) => { if (!id) { return; } const $preview = $(`#${domId.editorPreview}`); const parentRect = $preview[0].getBoundingClientRect(); const $active = $preview.find(`[data-id="${id}"]`); onActive(type, $active, parentRect); }; const updateSelected = debounce(() => { var _a; if (hoverId) { cancelHover(); } setActiveById('updateSelected', (_a = $wrap.current) === null || _a === void 0 ? void 0 : _a.dataset.selected); }, 100); const onSelected = throttle(() => { // 取消选中 if (!selectedId) { referenceStore.setSchema({}); cancelSelected(); return; } // selectedId 改变, 高亮与关联面板 同时更新 referenceStore.setSchema(selectedInfo.schema); updateSelected(); }, 100); const onHover = throttle(() => { if (hoverId) { setActiveById('hover', hoverId); } else { cancelHover(); } }, 100); const onMounted = () => { const $preview = $(`#${domId.editorPreview}>[data-preview]`); const onNodeActive = throttle((type, event) => { var _a; const $ele = $(event.target).closest('[data-id]'); const activeId = $ele.data('id'); if (!activeId) { return; } if (type === 'hover') { setHoverId(activeId); return; } if (type === 'selected') { const isSelected = ((_a = $wrap.current) === null || _a === void 0 ? void 0 : _a.dataset.selected) === activeId; // 左键 点击选择 if (event.button === 0) { setSelectedId(activeId); } if (event.button === 2) { // 已经选中 并且是鼠标右键 if (isSelected && event.button === 2) { onNodeMenus({ position: { x: event.pageX, y: event.pageY, }, }); } } } }, 100); $(window).on('resize', updateSelected); // 当窗口变化时 更新 $preview.parent().scroll(updateSelected); // 当滚动时 更新 $preview .on('contextmenu', () => false) .on('mouseleave', cancelHover) .on('mousedown', (e) => onNodeActive('selected', e)) .on('mouseover', (e) => onNodeActive('hover', e)) .on('click', (e) => { // button 类型的点击一律过滤 if ($(e.target).closest('button')) { e.stopPropagation(); } }); return () => { $preview.off(); }; }; useEffect(onMounted, []); useEffect(onSelected, [selectedId]); useEffect(onHover, [hoverId]); useEffect(updateSelected, [renderSchema]); return (React.createElement(StyledAttacher, { ref: $wrap, "data-selected": selectedId }, React.createElement("div", { className: "attach" }, React.createElement("div", { className: "hlbox selected", style: selected.style }), React.createElement("div", { className: "hlbox hover", style: hover.style })))); });