UNPKG

nitropage

Version:

A free and open source, extensible visual page builder based on SolidStart.

139 lines (116 loc) 3.98 kB
import { Config, State } from "#../types"; import { EditorUiContext } from "#lib/context/admin"; import { ConfigContext, StateContext } from "#lib/context/page"; import { spliceValue } from "#utils/array"; import { startTransition, useContext } from "solid-js"; import { MoveEvent, SortableEvent, SortableOptions } from "sortablejs"; import { blueprintAllowed } from "./blueprint"; import { addSlotToState, createSlot, slotHasSpace } from "./slot"; export const useSortableElementMove = function () { const [state, setState] = useContext(StateContext)!; const [_, setEditorUi] = useContext(EditorUiContext)!; const [declaration] = useContext(ConfigContext)!; return function (childProduce: any, evt: SortableEvent) { const builderInfo = getBuilderInfoFromSortableEvent(evt, state); const { fromElementId, targetElementId, element } = builderInfo; if (!element || !fromElementId || !targetElementId) return false; const fromSlot = evt.from.dataset.slot || "default"; const targetSlot = evt.to.dataset.slot || "default"; let fromSlotId = state.elements[fromElementId].slots[fromSlot]; let targetSlotId = state.elements[targetElementId].slots[targetSlot]; const sameList = fromSlotId === targetSlotId; setEditorUi((d) => (d.movingElementId = false)); if (sameList) { startTransition(() => { setState((d) => { childProduce(d.slots[targetSlotId].elements); }); }); return true; } if (!canMoveToOtherSlot(state, declaration, builderInfo)) { return false; } if (!targetSlotId) { const newSlot = createSlot(targetSlot, targetElementId); targetSlotId = newSlot.id; setState((d) => addSlotToState(d, newSlot)); } startTransition(() => { setState((d) => { // Remove element from old list spliceValue(element.id, d.slots[fromSlotId].elements); // Add element to new list d.slots[targetSlotId].elements.splice(evt.newIndex!, 0, element.id); d.elements[element.id].parentSlotId = targetSlotId; }); }); }; }; export const getBuilderInfoFromSortableEvent = function ( evt: MoveEvent | SortableEvent, state: State, ) { const domElement = (evt as SortableEvent).item || (evt as MoveEvent).dragged; const elementId = domElement.dataset.element; const fromElementId = evt.from.dataset.elementId; const targetElementId = evt.to.dataset.elementId; const element = elementId ? state.elements[elementId] : undefined; const fromElement = fromElementId ? state.elements[fromElementId] : undefined; const targetElement = targetElementId ? state.elements[targetElementId] : undefined; const fromSlotKey = evt.from.dataset.slot || "default"; const targetSlotKey = evt.to.dataset.slot || "default"; const fromSlotId = fromElement?.slots[fromSlotKey]; const targetSlotId = targetElement?.slots[targetSlotKey]; return { element, elementId, elementBlueprint: element?.blueprintId, fromElementId, fromElement, fromBlueprint: fromElement?.blueprintId, fromSlotKey, fromSlotId, targetElement, targetElementId, targetBlueprint: targetElement?.blueprintId, targetSlotKey, targetSlotId, }; }; export const canMoveToOtherSlot = function ( state: State, declaration: Config, builderInfo: ReturnType<typeof getBuilderInfoFromSortableEvent>, ) { if ( !slotHasSpace( state, declaration, builderInfo.targetElement, builderInfo.targetSlotKey, ) ) { return false; } if ( !blueprintAllowed( declaration, builderInfo.element?.blueprintId, builderInfo.targetElement?.blueprintId, builderInfo.targetSlotKey, ) ) { return false; } return true; }; export const nestedSortableConfig: Partial<SortableOptions> = { forceFallback: true, fallbackOnBody: true, swapThreshold: 1, emptyInsertThreshold: 1, invertSwap: true, };