UNPKG

@tomino/dynamic-form-semantic-ui

Version:

Semantic UI form renderer based on dynamic form generation

285 lines (279 loc) 9.45 kB
import { css } from '../common'; const dropZone = ` opacity: 0.3; min-width: 100px; display: block; position: absolute; overflow: hidden; white-space: nowrap; text-wrap: ellipsis; font-size: 10px; `; const horizontalDropZone = ` ${dropZone} display: flex !important; align-items: center !important; height: 100%; top: 0px; `; const placeholder = (size, dropStyle) => css ` transition: margin 0.2s cubic-bezier(0.215, 0.61, 0.355, 1) !important; position: relative; /* padding-top: 5px; */ /* padding-bottom: 5px; */ &.onMiddle { outline: dashed 2px #ccc; } &.onBottom { margin-bottom: ${size}px !important; ::after { ${dropZone} ${dropStyle} content: attr(data-after); bottom: -${size - (size - 20) / 2}px; } } &.onTop { margin-top: ${size}px !important; ::before { ${dropZone} ${dropStyle} content: attr(data-before); top: -${size - (size - 20) / 2}px; } } &.onRight { margin-right: 110px !important; ::after { ${horizontalDropZone} ${dropStyle} content: attr(data-after); right: -105px; } } &.onLeft { margin-left: 110px !important; ::before { ${horizontalDropZone} ${dropStyle} content: attr(data-before); left: -105px; } } label: placeholder; `; function findVerticalIndex(e, rects, i) { return (rects[i].getBoundingClientRect().top + window.scrollY < e.pageY && (!rects[i + 1] || rects[i + 1].getBoundingClientRect().top + window.scrollY > e.pageY)); } function findHorizontalIndex(e, rects, i) { let rect = rects[i].getBoundingClientRect(); return (rect.top + window.scrollY < e.pageY && rect.top + rect.height + window.scrollY > e.pageY && rect.left + window.scrollX < e.pageX && (!rects[i + 1] || rect.left + rect.width + window.scrollX > e.pageX || rects[i + 1].getBoundingClientRect().left + window.scrollX > e.pageX)); } function findVerticalPosition(e, rect, previousEnd) { let offset = 8; return rect.bottom + window.scrollY < e.pageY ? 'bottom' : previousEnd + window.scrollY + offset > e.pageY ? 'top' : 'middle'; } function findHorizontalPosition(e, rect) { let offset = rect.width > 100 ? 20 : rect.width / 2; return rect.left + window.scrollX + offset > e.pageX ? 'top' : rect.left + window.scrollX + rect.width - offset < e.pageX ? 'bottom' : 'middle'; } let config = {}; function clear(id) { for (let el of config[id].active) { el.classList.remove('onBottom', 'onTop', 'onLeft', 'onRight', 'onMiddle'); } config[id].active = []; } function cleanup(id, context, e, endDragHandler) { config[id].currentStacks = []; for (let pad of config[id].padMap) { pad.style.paddingBottom = null; pad.style.paddingTop = null; } config[id].padMap = []; if (endDragHandler) { endDragHandler(e); } if (context) { context.dragItem = null; } } export function clearAll(context) { for (let key of Object.keys(config)) { clear(key); cleanup(key, context); } } export class DragDrop { constructor(layout, owner, processor, dropStyle, uid = 'global', dropHandler, endDragHandler, allowParenting, height = 40, context = null) { this.add = true; this.initialised = false; this.init = (container) => { let items = this.processor.children(this.owner); let nodes = Array.from(container.childNodes); let id = this.processor.id(this.owner); container.setAttribute('data-drag', id); for (let i = 0; i < items.length; i++) { let element = nodes[i]; let item = items[i]; if (!item || !element) { continue; } let id = this.processor.id(item); element.setAttribute('data-drag', id); if (!element.classList.contains(this.placeholderClass)) { element.classList.add(this.placeholderClass); } let name = this.processor.name(item); element.setAttribute('data-after', '🔰 After ' + name); element.setAttribute('data-before', '🔰 Before ' + name); } }; this.onDragOver = (e) => { e.preventDefault(); if (this.processor.disableDrop && this.processor.disableDrop(this.owner, this.context)) { return; } if (this.config.padMap.indexOf(e.currentTarget) === -1) { e.currentTarget.style[this.paddingElement] = '5px'; this.config.padMap.push(e.currentTarget); } if (!this.initialised) { this.init(e.currentTarget); this.initialised = true; } let id = e.currentTarget.getAttribute('data-drag'); if (this.add) { this.config.currentStacks.push(id); this.add = false; } let elements = (e.currentTarget.childNodes || []); if (!elements || elements.length === 0) { return; } const currentIndex = this.config.currentStacks.findIndex(s => s === id); if (currentIndex != 0) { return; } const index = this.findRect(e, elements); if (index === -1) { return; } let element = elements[index]; if (!element || element.getAttribute('data-no-drop')) { return; } let previous = element.previousSibling; let next = element.nextSibling; let previousEnd = (previous ? previous.getBoundingClientRect().bottom : element.parentElement.getBoundingClientRect().top) + window.scrollY; let nextStart = (next ? next.getBoundingClientRect().top : element.parentElement.getBoundingClientRect().bottom) + window.scrollY; let pos = this.findPosition(e, element.getBoundingClientRect(), previousEnd, nextStart); let className; if (index === 0 && pos === 'top') { className = this.startClass; } else if (pos === 'bottom') { className = this.endClass; } else if (index > 0 && pos === 'top') { className = this.endClass; element = element.previousSibling; } else if (this.allowParenting && pos === 'middle') { className = 'onMiddle'; } if (element.classList.contains(className)) { return; } this.config.drops = { index, position: pos }; this.clear(); element.classList.add(className); this.config.active.push(element); }; this.onDragEnd = (e) => { this.dragEnd(e); }; this.onDragLeave = () => { this.config.currentStacks = []; this.add = true; }; this.onDrop = (e) => { let id = e.currentTarget.getAttribute('data-drag'); let currentIndex = this.config.currentStacks.findIndex(s => s === id); if (currentIndex === 0) { if (this.dropHandler) { this.initialised = false; this.dropHandler(this.config.drops.index + (this.config.drops.position === 'bottom' ? 1 : 0), this.config.drops.position); } this.dragEnd(e); } }; this.startClass = layout === 'row' ? 'onLeft' : 'onTop'; this.endClass = layout === 'row' ? 'onRight' : 'onBottom'; this.findIndex = layout === 'row' ? findHorizontalIndex : findVerticalIndex; this.findPosition = layout === 'row' ? findHorizontalPosition : findVerticalPosition; this.paddingElement = layout === 'row' ? 'paddingRight' : 'paddingBottom'; this.processor = processor; this.owner = owner; this.uid = uid; this.dropHandler = dropHandler; this.endDragHandler = endDragHandler; this.context = context; this.allowParenting = allowParenting; this.placeholderClass = placeholder(height, dropStyle); if (!config[this.uid]) { config[this.uid] = { currentStacks: [], active: [], drops: null, padMap: [] }; } } get config() { return config[this.uid]; } findRect(e, elements) { for (let i = 0; i < elements.length; i++) { if (this.findIndex(e, elements, i)) { return i; } } return -1; } clear() { clear(this.uid); } dragEnd(e) { this.add = true; this.clear(); cleanup(this.uid, this.context, e, this.endDragHandler); } props() { return { onDragOver: this.onDragOver, onDragEnd: this.onDragEnd, onDrop: this.onDrop, onDragLeave: this.onDragLeave }; } } //# sourceMappingURL=drag_drop.js.map