UNPKG

tandem-front-end

Version:

Visual editor for web components

899 lines 44.2 kB
"use strict"; var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); var path = require("path"); var actions_1 = require("../actions"); var fsbox_1 = require("fsbox"); var state_1 = require("../state"); var paperclip_1 = require("paperclip"); var tandem_common_1 = require("tandem-common"); var lodash_1 = require("lodash"); var DEFAULT_RECT_COLOR = "#CCC"; var INSERT_TEXT_OFFSET = { left: -5, top: -10 }; var PANE_SENSITIVITY = process.platform === "win32" ? 0.1 : 1; var ZOOM_SENSITIVITY = process.platform === "win32" ? 2500 : 250; var MIN_ZOOM = 0.02; var MAX_ZOOM = 6400 / 100; var INITIAL_ZOOM_PADDING = 50; exports.rootReducer = function (state, action) { state = fsbox_1.fsSandboxReducer(state, action); state = paperclip_1.paperclipReducer(state, action); state = exports.canvasReducer(state, action); state = shortcutReducer(state, action); state = clipboardReducer(state, action); switch (action.type) { case actions_1.PROJECT_DIRECTORY_LOADED: { var directory = action.directory; return state_1.updateRootState({ projectDirectory: directory }, state); } case actions_1.FILE_NAVIGATOR_ITEM_CLICKED: { var node = action.node; var uri = node.uri; state = state_1.setSelectedFileNodeIds(state, node.id); state = setFileExpanded(node, true, state); if (!tandem_common_1.isDirectory(node)) { state = maybeEvaluateFile(uri, state); state = state_1.setActiveFilePath(uri, state); return state; } return state; } case actions_1.QUICK_SEARCH_ITEM_CLICKED: { var file = action.file; var uri = file.uri; state = maybeEvaluateFile(uri, state); state = state_1.setSelectedFileNodeIds(state, file.id); state = state_1.setActiveFilePath(uri, state); state = state_1.upsertOpenFile(uri, false, state); state = state_1.updateRootState({ showQuickSearch: false }, state); return state; } case actions_1.QUICK_SEARCH_BACKGROUND_CLICK: { return (state = state_1.updateRootState({ showQuickSearch: false }, state)); } case actions_1.FILE_NAVIGATOR_TOGGLE_DIRECTORY_CLICKED: { var node = action.node; state = setFileExpanded(node, !node.expanded, state); return state; } case actions_1.FILE_NAVIGATOR_ITEM_DOUBLE_CLICKED: { var node = action.node; var uri = node.uri; var file = tandem_common_1.getFileFromUri(uri, state.projectDirectory); if (tandem_common_1.isFile(file)) { state = state_1.upsertOpenFile(uri, false, state); state = state_1.openEditorFileUri(uri, state); } return state; } case actions_1.FILE_NAVIGATOR_NEW_FILE_CLICKED: { return state_1.setInsertFile(state_1.InsertFileType.FILE, state); } case actions_1.FILE_NAVIGATOR_NEW_DIRECTORY_CLICKED: { return state_1.setInsertFile(state_1.InsertFileType.DIRECTORY, state); } case actions_1.CANVAS_MOUNTED: { var _a = action, fileUri = _a.fileUri, element = _a.element; if (!element) { return state; } var _b = element.getBoundingClientRect() || {}, _c = _b.width, width = _c === void 0 ? 400 : _c, _d = _b.height, height = _d === void 0 ? 300 : _d; state = state_1.updateEditorWindow({ container: element }, fileUri, state); return state_1.centerEditorCanvas(state, fileUri); } case actions_1.FILE_NAVIGATOR_DROPPED_ITEM: { var _e = action, node_1 = _e.node, targetNode = _e.targetNode; var parent_1 = tandem_common_1.getParentTreeNode(node_1.id, state.projectDirectory); var parentUri_1 = parent_1.uri; var nodeUri_1 = node_1.uri; state = state_1.updateRootState({ projectDirectory: tandem_common_1.updateNestedNode(parent_1, state.projectDirectory, function (parent) { return tandem_common_1.removeNestedTreeNode(node_1, parent); }) }, state); var targetDir = targetNode.name !== tandem_common_1.FSItemTagNames.FILE ? targetNode : tandem_common_1.getParentTreeNode(targetNode.id, state.projectDirectory); var targetUri_1 = targetDir.uri; state = state_1.updateRootState({ projectDirectory: tandem_common_1.updateNestedNode(targetDir, state.projectDirectory, function (targetNode) { return tandem_common_1.appendChildNode(__assign({}, node_1, { uri: nodeUri_1.replace(parentUri_1, targetUri_1) }), targetNode); }) }, state); return state; } case actions_1.NEW_FILE_ADDED: { var _f = action, uri_1 = _f.uri, fileType_1 = _f.fileType; var directory = tandem_common_1.getFileFromUri(path.dirname(uri_1), state.projectDirectory); state = state_1.updateRootState({ insertFileInfo: null, projectDirectory: tandem_common_1.updateNestedNode(directory, state.projectDirectory, function (dir) { return __assign({}, dir, { children: tandem_common_1.sortFSItems(dir.children.concat([ fileType_1 === tandem_common_1.FSItemTagNames.FILE ? tandem_common_1.createFile(uri_1) : tandem_common_1.createDirectory(uri_1) ])) }); }) }, state); if (fileType_1 === tandem_common_1.FSItemTagNames.FILE) { state = state_1.setActiveFilePath(uri_1, state); state = maybeEvaluateFile(uri_1, state); } return state; } case fsbox_1.FS_SANDBOX_ITEM_LOADED: { var _g = action, uri = _g.uri, mimeType = _g.mimeType; // const pcState = paperclipReducer(state, action); var editor = state_1.getEditorWindowWithFileUri(uri, state); // TODO - move this to paperclip-tandem package if (editor && editor.activeFilePath === uri) { state = maybeEvaluateFile(uri, state); } return state; } case actions_1.OPEN_FILE_ITEM_CLICKED: { var _h = action, uri = _h.uri, sourceEvent = _h.sourceEvent; if (state_1.getEditorWithActiveFileUri(uri, state)) { return state; } state = state_1.setNextOpenFile(state_1.removeTemporaryOpenFiles(sourceEvent.metaKey ? state_1.openSecondEditor(uri, state) : state_1.openEditorFileUri(uri, state))); return state; } case actions_1.SAVED_FILE: { var uri = action.uri; return state_1.updateOpenFile({ newContent: null }, uri, state); } case actions_1.SAVED_ALL_FILES: { return state_1.updateRootState({ openFiles: state.openFiles.map(function (openFile) { return (__assign({}, openFile, { newContent: null })); }) }, state); } case actions_1.ELEMENT_VARIANT_TOGGLED: { // const { newVariants } = action as ElementVariantToggled; // const sourceNode = getSyntheticSourceNode( // state.selectedNodeIds[0], // state.paperclip // ); // state = persistRootState( // browser => // persistSetElementVariants( // newVariants, // sourceNode.id, // state.selectedComponentVariantName, // browser // ), // state // ); return state; } case actions_1.NEW_VARIANT_NAME_ENTERED: { // const { value } = action as NewVariantNameEntered; // const sourceNode = getSyntheticSourceNode( // state.selectedNodeIds[0], // state.paperclip // ) as PCComponentNode; // state = persistRootState( // browser => persistInsertNewComponentVariant(value, sourceNode, browser), // state // ); return state; } case actions_1.COMPONENT_VARIANT_NAME_DEFAULT_TOGGLE_CLICK: { var _j = action, name_1 = _j.name, value = _j.value; // const sourceComponent = getSyntheticVisibleNodeSourceComponent( // state.selectedNodeIds[0], // state.paperclip // ); // state = persistRootState( // browser => // persistComponentVariantChanged( // { [PCSourceNamespaces.CORE]: { isDefault: value } }, // name, // sourceComponent.id, // browser // ), // state // ); return state; } case actions_1.COMPONENT_VARIANT_REMOVED: { var _k = action, name_2 = _k.name, value = _k.value; // const sourceComponent = getSyntheticVisibleNodeSourceComponent( // state.selectedNodeIds[0], // state.paperclip // ); // state = persistRootState( // browser => // persistRemoveComponentVariant(name, sourceComponent.id, browser), // state // ); return state; } case actions_1.COMPONENT_VARIANT_NAME_CLICKED: { var name_3 = action.name; state = state_1.updateRootState({ selectedComponentVariantName: name_3 }, state); return state; } case actions_1.COMPONENT_VARIANT_NAME_CHANGED: { var _l = action, oldName = _l.oldName, newName = _l.newName; // const sourceComponentNode = getSyntheticVisibleNodeSourceComponent( // state.selectedNodeIds[0], // state.paperclip // ); // state = persistRootState( // browser => // persistComponentVariantChanged( // { // [PCSourceNamespaces.CORE]: { name: newName } // }, // oldName, // sourceComponentNode.id, // browser // ), // state // ); return state; } case actions_1.PC_LAYER_MOUSE_OVER: { var node = action.node; state = state_1.setHoveringSyntheticVisibleNodeIds(state, node.id); return state; } case actions_1.PC_LAYER_DOUBLE_CLICK: { var node = action.node; state = state_1.setRootStateSyntheticVisibleNodeLabelEditing(node.id, true, state); return state; } case actions_1.PC_LAYER_EDIT_LABEL_BLUR: { var node = action.node; state = state_1.setRootStateSyntheticVisibleNodeLabelEditing(node.id, false, state); return state; } case actions_1.PC_LAYER_LABEL_CHANGED: { var _m = action, label_1 = _m.label, node_2 = _m.node; state = state_1.setRootStateSyntheticVisibleNodeLabelEditing(node_2.id, false, state); state = state_1.persistRootState(function (browser) { return paperclip_1.persistChangeLabel(label_1, node_2, browser); }, state); return state; } case actions_1.PC_LAYER_DROPPED_NODE: { var _o = action, node_3 = _o.node, targetNode_1 = _o.targetNode, offset_1 = _o.offset; var oldState = state; state = state_1.persistRootState(function (state) { return paperclip_1.persistMoveSyntheticVisibleNode(node_3, targetNode_1, offset_1, state); }, state); var document_1 = paperclip_1.getSyntheticVisibleNodeDocument(targetNode_1.id, state.documents); var mutatedTarget = offset_1 === tandem_common_1.TreeMoveOffset.APPEND || offset_1 === tandem_common_1.TreeMoveOffset.PREPEND ? targetNode_1 : tandem_common_1.getParentTreeNode(targetNode_1.id, document_1); state = state_1.selectInsertedSyntheticVisibleNodes(oldState, state, mutatedTarget); return state; } case actions_1.PC_LAYER_MOUSE_OUT: { var node = action.node; state = state_1.setHoveringSyntheticVisibleNodeIds(state); return state; } case actions_1.PC_LAYER_CLICK: { var _p = action, node = _p.node, sourceEvent = _p.sourceEvent; if (sourceEvent.altKey) { // state = openSyntheticVisibleNodeOriginFile(node.id, state); } else { var doc = paperclip_1.getSyntheticVisibleNodeDocument(node.id, state.documents); var dep = paperclip_1.getSyntheticNodeSourceDependency(doc, state.graph); state = state_1.setActiveFilePath(dep.uri, state); state = state_1.setSelectedSyntheticVisibleNodeIds.apply(void 0, [state].concat((sourceEvent.shiftKey ? state.selectedNodeIds.concat([node.id]) : [node.id]))); } return state; } case actions_1.PC_LAYER_EXPAND_TOGGLE_CLICK: { var node = action.node; state = state_1.setRootStateSyntheticVisibleNodeExpanded(node.id, !node.metadata[state_1.SyntheticVisibleNodeMetadataKeys.EXPANDED], state); return state; } case actions_1.OPEN_FILE_ITEM_CLOSE_CLICKED: { // TODO - flag confirm remove state var uri = action.uri; return state_1.closeFile(uri, state); } case actions_1.EDITOR_TAB_CLICKED: { var uri = action.uri; return state_1.openEditorFileUri(uri, state); } case actions_1.EDITOR_TAB_CLOSE_BUTTON_CLICKED: { var uri = action.uri; return state_1.closeFile(uri, state); } case paperclip_1.PC_DEPENDENCY_GRAPH_LOADED: { var graph = action.graph; state = state_1.centerEditorCanvas(state, state.activeEditorFilePath); return state; } } return state; }; exports.canvasReducer = function (state, action) { var _a; switch (action.type) { case actions_1.RESIZER_MOVED: { var newPoint = action.point; state = state_1.updateEditorWindow({ movingOrResizing: true }, state.activeEditorFilePath, state); if (state_1.isSelectionMovable(state)) { var selectionBounds = state_1.getSelectionBounds(state); var nodeId = state.selectedNodeIds[0]; var movedBounds = tandem_common_1.moveBounds(selectionBounds, newPoint); for (var _i = 0, _b = state.selectedNodeIds; _i < _b.length; _i++) { var nodeId_1 = _b[_i]; var itemBounds = paperclip_1.getSyntheticVisibleNodeRelativeBounds(paperclip_1.getSyntheticNodeById(nodeId_1, state.documents), state.frames); var newBounds = tandem_common_1.roundBounds(tandem_common_1.scaleInnerBounds(itemBounds, selectionBounds, movedBounds)); state = paperclip_1.updateSyntheticVisibleNodePosition(newBounds, paperclip_1.getSyntheticNodeById(nodeId_1, state.documents), state); } } return state; } case actions_1.RESIZER_MOUSE_DOWN: { var sourceEvent = action.sourceEvent; if (sourceEvent.metaKey) { // state = openSyntheticVisibleNodeOriginFile(state.selectedNodeIds[0], state); } return state; } case actions_1.COMPONENT_PICKER_BACKGROUND_CLICK: { return state_1.setTool(null, state); } case actions_1.COMPONENT_PICKER_ITEM_CLICK: { var component = action.component; return __assign({}, state, { selectedComponentId: component.id }); } case actions_1.TOOLBAR_TOOL_CLICKED: { var toolType = action.toolType; if (toolType === state_1.ToolType.POINTER) { state = state_1.setTool(null, state); } else { state = state_1.setTool(toolType, state); } return state; } case actions_1.RESIZER_STOPPED_MOVING: { var point = action.point; var oldGraph = state.graph; if (state_1.isSelectionMovable(state)) { var selectionBounds = state_1.getSelectionBounds(state); state = state_1.persistRootState(function (state) { return state.selectedNodeIds.reduce(function (state, nodeId) { return paperclip_1.persistSyntheticVisibleNodeBounds(paperclip_1.getSyntheticNodeById(nodeId, state.documents), state); }, state); }, state); } state = state_1.updateEditorWindow({ movingOrResizing: false }, state.activeEditorFilePath, state); return state; } case actions_1.CANVAS_WHEEL: { var _c = action, metaKey = _c.metaKey, ctrlKey = _c.ctrlKey, deltaX = _c.deltaX, deltaY = _c.deltaY, canvasHeight = _c.canvasHeight, canvasWidth = _c.canvasWidth; var editorWindow = state_1.getActiveEditorWindow(state); var openFile = state_1.getOpenFile(editorWindow.activeFilePath, state); var translate = openFile.canvas.translate; if (metaKey || ctrlKey) { translate = tandem_common_1.centerTransformZoom(translate, tandem_common_1.boundsFromRect({ width: canvasWidth, height: canvasHeight }), lodash_1.clamp(translate.zoom + translate.zoom * deltaY / ZOOM_SENSITIVITY, MIN_ZOOM, MAX_ZOOM), editorWindow.mousePosition); } else { translate = __assign({}, translate, { left: translate.left - deltaX, top: translate.top - deltaY }); } state = state_1.updateEditorWindow({ smooth: false }, editorWindow.activeFilePath, state); state = state_1.updateOpenFileCanvas({ translate: translate }, editorWindow.activeFilePath, state); return state; } case actions_1.CANVAS_DROPPED_ITEM: { var _d = action, item_1 = _d.item, point = _d.point, editorUri = _d.editorUri; var targetNodeId_1 = state_1.getCanvasMouseTargetNodeIdFromPoint(state, point, getDragFilter(item_1)); var sourceNode_1; if (tandem_common_1.isFile(item_1)) { var src = path.relative(path.dirname(editorUri), item_1.uri); if (src.charAt(0) !== ".") { src = "./" + src; } if (fsbox_1.isImageUri(item_1.uri)) { sourceNode_1 = paperclip_1.createPCElement("img", {}, { src: src }); if (fsbox_1.isSvgUri(item_1.uri)) { sourceNode_1 = paperclip_1.createPCElement("object", {}, { data: src, type: "image/svg+xml" }, [sourceNode_1]); } } else if (isJavaScriptFile(item_1.uri)) { return state_1.persistRootState(function (state) { return paperclip_1.persistAddComponentController(item_1.uri, paperclip_1.getSyntheticNodeById(targetNodeId_1, state.documents), state); }, state); } } else if (paperclip_1.isSyntheticVisibleNode(item_1)) { sourceNode_1 = paperclip_1.getSyntheticSourceNode(item_1, state.graph); } else { sourceNode_1 = tandem_common_1.cloneTreeNode(item_1.template); } if (!sourceNode_1) { console.error("Unrecognized dropped item."); return state; } var targetId = state_1.getCanvasMouseTargetNodeIdFromPoint(state, point, function (node) { return node.name !== paperclip_1.PCSourceTagNames.TEXT; }); var target_1 = targetId ? paperclip_1.getSyntheticNodeById(targetId, state.documents) : paperclip_1.getSyntheticDocumentByDependencyUri(editorUri, state.documents, state.graph); if (target_1.name === paperclip_1.SYNTHETIC_DOCUMENT_NODE_NAME) { sourceNode_1 = paperclip_1.updatePCNodeMetadata((_a = {}, _a[paperclip_1.PCVisibleNodeMetadataKey.BOUNDS] = tandem_common_1.moveBounds(sourceNode_1.metadata[paperclip_1.PCVisibleNodeMetadataKey.BOUNDS] || paperclip_1.DEFAULT_FRAME_BOUNDS, point), _a), sourceNode_1); } return state_1.persistRootState(function (browser) { return paperclip_1.persistInsertNode(sourceNode_1, target_1, tandem_common_1.TreeMoveOffset.APPEND, browser); }, state); } case actions_1.SHORTCUT_ZOOM_IN_KEY_DOWN: { var editor = state_1.getActiveEditorWindow(state); var openFile = state_1.getOpenFile(editor.activeFilePath, state); state = setCanvasZoom(normalizeZoom(openFile.canvas.translate.zoom) * 2, false, editor.activeFilePath, state); return state; } case actions_1.SHORTCUT_ZOOM_OUT_KEY_DOWN: { var editor = state_1.getActiveEditorWindow(state); var openFile = state_1.getOpenFile(editor.activeFilePath, state); state = setCanvasZoom(normalizeZoom(openFile.canvas.translate.zoom) / 2, false, editor.activeFilePath, state); return state; } case actions_1.SHORTCUT_SELECT_NEXT_TAB: { return state_1.shiftActiveEditorTab(1, state); } case actions_1.SHORTCUT_SELECT_PREVIOUS_TAB: { return state_1.shiftActiveEditorTab(-1, state); } case actions_1.SHORTCUT_CLOSE_CURRENT_TAB: { return state_1.closeFile(state.activeEditorFilePath, state); } case actions_1.CANVAS_MOUSE_MOVED: { var _e = action.sourceEvent, pageX = _e.pageX, pageY = _e.pageY; state = state_1.updateEditorWindow({ mousePosition: { left: pageX, top: pageY } }, state.activeEditorFilePath, state); var targetNodeId = void 0; var editorWindow = state_1.getActiveEditorWindow(state); var openFile = state_1.getOpenFile(editorWindow.activeFilePath, state); if (!editorWindow.movingOrResizing) { targetNodeId = state_1.getCanvasMouseTargetNodeId(state, action); } state = state_1.updateRootState({ hoveringNodeIds: targetNodeId ? [targetNodeId] : [] }, state); return state; } case actions_1.CANVAS_DRAGGED_OVER: { var _f = action, item = _f.item, offset = _f.offset; state = state_1.updateEditorWindow({ mousePosition: offset }, state.activeEditorFilePath, state); // remove selection so that hovering state is visible state = state_1.setSelectedSyntheticVisibleNodeIds(state); // TODO - in the future, we'll probably want to be able to highlight hovered nodes as the user is moving an element around to indicate where // they can drop the element. var targetNodeId = void 0; var editor = state_1.getActiveEditorWindow(state); targetNodeId = state_1.getCanvasMouseTargetNodeIdFromPoint(state, offset, getDragFilter(item)); state = state_1.updateRootState({ hoveringNodeIds: targetNodeId ? [targetNodeId] : [] }, state); return state; } // TODO case actions_1.CANVAS_MOUSE_CLICKED: { if (state.toolType != null) { return state; } state = state_1.deselectRootProjectFiles(state); var sourceEvent = action.sourceEvent; if (/textarea|input/i.test(sourceEvent.target.nodeName)) { return state; } // alt key opens up a new link var altKey = sourceEvent.altKey; var editorWindow = state_1.getActiveEditorWindow(state); var openFile = state_1.getOpenFile(editorWindow.activeFilePath, state); // do not allow selection while window is panning (scrolling) if (openFile.canvas.panning || editorWindow.movingOrResizing) return state; var targetNodeId = state_1.getCanvasMouseTargetNodeId(state, action); if (!targetNodeId) { return state_1.setSelectedSyntheticVisibleNodeIds(state); } // if (altKey) { // state = openSyntheticVisibleNodeOriginFile(targetNodeId, state); // return state; // } if (!altKey) { state = handleArtboardSelectionFromAction(state, targetNodeId, action); state = state_1.updateEditorWindow({ secondarySelection: false }, editorWindow.activeFilePath, state); return state; } return state; } case actions_1.RESIZER_PATH_MOUSE_MOVED: { state = state_1.updateEditorWindow({ movingOrResizing: true }, state.activeEditorFilePath, state); // TODO - possibly use BoundsStruct instead of Bounds since there are cases where bounds prop doesn't exist var newBounds = getResizeActionBounds(action); for (var _g = 0, _h = state_1.getBoundedSelection(state); _g < _h.length; _g++) { var nodeId = _h[_g]; state = paperclip_1.updateSyntheticVisibleNodeBounds(getNewSyntheticVisibleNodeBounds(newBounds, paperclip_1.getSyntheticNodeById(nodeId, state.documents), state), paperclip_1.getSyntheticNodeById(nodeId, state.documents), state); } return state; } case actions_1.RESIZER_PATH_MOUSE_STOPPED_MOVING: { state = state_1.updateEditorWindow({ movingOrResizing: false }, state.activeEditorFilePath, state); // TODO - possibly use BoundsStruct instead of Bounds since there are cases where bounds prop doesn't exist var newBounds = getResizeActionBounds(action); state = state_1.persistRootState(function (state) { return state.selectedNodeIds.reduce(function (state, nodeId) { return paperclip_1.persistSyntheticVisibleNodeBounds(paperclip_1.getSyntheticNodeById(nodeId, state.documents), state); }, state); }, state); return state; } case actions_1.RAW_CSS_TEXT_CHANGED: { var cssText_1 = action.value; state = state_1.persistRootState(function (browser) { return state.selectedNodeIds.reduce(function (state, nodeId) { return paperclip_1.persistRawCSSText(cssText_1, paperclip_1.getSyntheticNodeById(nodeId, state.documents), state); }, state); }, state); return state; } case actions_1.CSS_PROPERTY_CHANGED: { var _j = action, name_4 = _j.name, value_1 = _j.value; state = state.selectedNodeIds.reduce(function (state, nodeId) { return paperclip_1.updateSyntheticVisibleNode(paperclip_1.getSyntheticNodeById(nodeId, state.documents), state, function (node) { var _a; return __assign({}, node, { style: __assign({}, node.style, (_a = {}, _a[name_4] = value_1, _a)) }); }); }, state); return state; } case actions_1.FRAME_MODE_CHANGE_COMPLETE: { var _k = action, frame_1 = _k.frame, mode_1 = _k.mode; state = state_1.persistRootState(function (state) { return paperclip_1.persistSyntheticNodeMetadata({ mode: mode_1 }, paperclip_1.getSyntheticNodeById(frame_1.contentNodeId, state.documents), state); }, state); return state; } case actions_1.CSS_PROPERTY_CHANGE_COMPLETED: { var _l = action, name_5 = _l.name, value_2 = _l.value; state = state_1.persistRootState(function (browser) { return state.selectedNodeIds.reduce(function (state, nodeId) { return paperclip_1.persistCSSProperty(name_5, value_2, paperclip_1.getSyntheticNodeById(nodeId, state.documents), state); }, state); }, state); return state; } case actions_1.ATTRIBUTE_CHANGED: { var _m = action, name_6 = _m.name, value_3 = _m.value; state = state_1.persistRootState(function (browser) { return state.selectedNodeIds.reduce(function (state, nodeId) { return paperclip_1.persistAttribute(name_6, value_3, paperclip_1.getSyntheticNodeById(nodeId, state.documents), state); }, state); }, state); return state; } case actions_1.SLOT_TOGGLE_CLICK: { // state = persistRootState(browser => { // return persistToggleSlotContainer( // getSyntheticSourceNode(state.selectedNodeIds[0], state.paperclip).id, // browser // ); // }, state); return state; } case actions_1.NATIVE_NODE_TYPE_CHANGED: { var nativeType = action.nativeType; // state = persistRootState(browser => { // return persistChangeNodeType( // nativeType, // getSyntheticSourceNode( // state.selectedNodeIds[0], // state.paperclip // ) as PCElement, // browser // ); // }, state); return state; } case actions_1.TEXT_VALUE_CHANGED: { var value_4 = action.value; state = state_1.persistRootState(function (state) { return paperclip_1.persistChangeSyntheticTextNodeValue(value_4, paperclip_1.getSyntheticNodeById(state.selectedNodeIds[0], state.documents), state); }, state); return state; } case actions_1.ELEMENT_TYPE_CHANGED: { var value_5 = action.value; state = state_1.persistRootState(function (state) { return paperclip_1.persistChangeElementType(value_5, paperclip_1.getSyntheticNodeById(state.selectedNodeIds[0], state.documents), state); }, state); return state; } case actions_1.CANVAS_TOOL_ARTBOARD_TITLE_CLICKED: { var _o = action, frame = _o.frame, sourceEvent = _o.sourceEvent; sourceEvent.stopPropagation(); var contentNode = paperclip_1.getFrameSyntheticNode(frame, state.documents); state = state_1.updateEditorWindow({ smooth: false }, paperclip_1.getPCNodeDependency(paperclip_1.getSyntheticSourceNode(contentNode, state.graph).id, state.graph).uri, state); return handleArtboardSelectionFromAction(state, frame.contentNodeId, action); } case actions_1.CANVAS_TOOL_WINDOW_BACKGROUND_CLICKED: { return state_1.setSelectedSyntheticVisibleNodeIds(state); } case actions_1.INSERT_TOOL_FINISHED: { var _p = action, point = _p.point, fileUri = _p.fileUri; var editor = state_1.getEditorWithActiveFileUri(fileUri, state); var toolType = state.toolType; switch (toolType) { case state_1.ToolType.COMPONENT: { var componentId = state.selectedComponentId; state = __assign({}, state, { selectedComponentId: null }); var component = paperclip_1.getPCNode(componentId, state.graph); return persistInsertNodeFromPoint(paperclip_1.createPCComponentInstance(componentId, [], null, null, null, component.metadata), fileUri, point, state); } case state_1.ToolType.ELEMENT: { return persistInsertNodeFromPoint(paperclip_1.createPCElement("div", { "box-sizing": "border-box" }, null, null, "Element"), fileUri, point, state); } case state_1.ToolType.TEXT: { return persistInsertNodeFromPoint(paperclip_1.createPCTextNode("Click to edit", "Text"), fileUri, point, state); } } } } return state; }; var isJavaScriptFile = function (file) { return /(ts|js)x?$/.test(file); }; var INSERT_ARTBOARD_WIDTH = 100; var INSERT_ARTBOARD_HEIGHT = 100; var persistInsertNodeFromPoint = function (node, fileUri, point, state) { var _a; var oldState = state; var targetNodeId = state_1.getCanvasMouseTargetNodeIdFromPoint(state, point); var targetNode = targetNodeId && paperclip_1.getSyntheticNodeById(targetNodeId, state.documents); if (!targetNode) { var newPoint = tandem_common_1.shiftPoint(normalizePoint(state_1.getOpenFile(fileUri, state).canvas.translate, point), { left: -(INSERT_ARTBOARD_WIDTH / 2), top: -(INSERT_ARTBOARD_HEIGHT / 2) }); var bounds = __assign({ left: 0, top: 0, right: INSERT_ARTBOARD_WIDTH, bottom: INSERT_ARTBOARD_HEIGHT }, (node.metadata[paperclip_1.PCVisibleNodeMetadataKey.BOUNDS] || {})); bounds = tandem_common_1.moveBounds(bounds, newPoint); node = paperclip_1.updatePCNodeMetadata((_a = {}, _a[paperclip_1.PCVisibleNodeMetadataKey.BOUNDS] = bounds, _a), node); targetNode = paperclip_1.getSyntheticDocumentByDependencyUri(fileUri, state.documents, state.graph); } state = state_1.persistRootState(function (browser) { return paperclip_1.persistInsertNode(node, targetNode, tandem_common_1.TreeMoveOffset.APPEND, state); }, state, targetNode); state = state_1.setTool(null, state); state = state_1.selectInsertedSyntheticVisibleNodes(oldState, state, targetNode); return state; }; var getDragFilter = function (item) { var filter = function (node) { return node.name !== paperclip_1.PCSourceTagNames.TEXT; }; if (tandem_common_1.isFile(item) && isJavaScriptFile(item.uri)) { filter = function (node) { return (node.isContentNode && node.isCreatedFromComponent && !node.isComponentInstance); }; } return filter; }; var setFileExpanded = function (node, value, state) { state = state_1.updateRootState({ projectDirectory: tandem_common_1.updateNestedNode(node, state.projectDirectory, function (node) { return (__assign({}, node, { expanded: value })); }) }, state); return state; }; var getNewSyntheticVisibleNodeBounds = function (newBounds, node, state) { var currentBounds = state_1.getSelectionBounds(state); var innerBounds = paperclip_1.getSyntheticVisibleNodeRelativeBounds(node, state.frames); return tandem_common_1.scaleInnerBounds(innerBounds, currentBounds, newBounds); }; var getResizeActionBounds = function (action) { var _a = action, anchor = _a.anchor, originalBounds = _a.originalBounds, newBounds = _a.newBounds, sourceEvent = _a.sourceEvent; var keepAspectRatio = sourceEvent.shiftKey; var keepCenter = sourceEvent.altKey; if (keepCenter) { // TODO - need to test. this might not work newBounds = tandem_common_1.keepBoundsCenter(newBounds, originalBounds, anchor); } if (keepAspectRatio) { newBounds = tandem_common_1.keepBoundsAspectRatio(newBounds, originalBounds, anchor, keepCenter ? { left: 0.5, top: 0.5 } : anchor); } return newBounds; }; var isInputSelected = function (state) { // ick -- this needs to be moved into a saga return (document.activeElement && /textarea|input|button/i.test(document.activeElement.tagName)); }; var shortcutReducer = function (state, action) { switch (action.type) { case actions_1.SHORTCUT_QUICK_SEARCH_KEY_DOWN: { return isInputSelected(state) ? state : state_1.updateRootState({ showQuickSearch: !state.showQuickSearch }, state); } case actions_1.SHORTCUT_UNDO_KEY_DOWN: { return state_1.undo(state); } case actions_1.SHORTCUT_REDO_KEY_DOWN: { return state_1.redo(state); } case actions_1.SHORTCUT_T_KEY_DOWN: { return isInputSelected(state) ? state : state_1.setTool(state_1.ToolType.TEXT, state); } case actions_1.SHORTCUT_R_KEY_DOWN: { return isInputSelected(state) ? state : state_1.setTool(state_1.ToolType.ELEMENT, state); } case actions_1.SHORTCUT_C_KEY_DOWN: { return isInputSelected(state) ? state : state_1.setTool(state_1.ToolType.COMPONENT, state); } case actions_1.SHORTCUT_CONVERT_TO_COMPONENT_KEY_DOWN: { // TODO - should be able to conver all selected nodes to components if (state.selectedNodeIds.length > 1) { return state; } var oldState = state; state = state_1.persistRootState(function (state) { return paperclip_1.persistConvertNodeToComponent(paperclip_1.getSyntheticNodeById(state.selectedNodeIds[0], state.documents), state); }, state); state = state_1.selectInsertedSyntheticVisibleNodes(oldState, state, paperclip_1.getSyntheticDocumentByDependencyUri(state.activeEditorFilePath, state.documents, state.graph)); return state; } case actions_1.SHORTCUT_ESCAPE_KEY_DOWN: { if (isInputSelected(state)) { return state; } if (state.toolType != null) { return state_1.setTool(null, state); } else { state = state_1.setSelectedSyntheticVisibleNodeIds(state); state = state_1.setSelectedFileNodeIds(state); state = state_1.updateRootState({ insertFileInfo: null }, state); return state; } } case actions_1.SHORTCUT_DELETE_KEY_DOWN: { if (isInputSelected(state)) { return state; } return state_1.persistRootState(function (state) { var firstNode = paperclip_1.getSyntheticNodeById(state.selectedNodeIds[0], state.documents); var document = paperclip_1.getSyntheticVisibleNodeDocument(firstNode.id, state.documents); var parent = tandem_common_1.getParentTreeNode(firstNode.id, document); var index = parent.children.indexOf(firstNode); state = state.selectedNodeIds.reduce(function (state, nodeId) { return paperclip_1.persistRemoveSyntheticVisibleNode(paperclip_1.getSyntheticNodeById(nodeId, state.documents), state); }, state); parent = paperclip_1.getSyntheticNodeById(parent.id, state.documents); state = state_1.setSelectedSyntheticVisibleNodeIds.apply(void 0, [state].concat((parent.children.length ? [parent.children[Math.min(index, parent.children.length - 1)].id] : parent.name !== paperclip_1.SYNTHETIC_DOCUMENT_NODE_NAME ? [parent.id] : []))); return state; }, state); } } return state; }; var clipboardReducer = function (state, action) { switch (action.type) { case actions_1.SYNTHETIC_NODES_PASTED: { var clips_1 = action.clips; var oldState = state; var offset_2 = tandem_common_1.TreeMoveOffset.AFTER; var targetNode_2; var scopeNode = void 0; if (state.selectedNodeIds.length) { var nodeId = state.selectedNodeIds[0]; scopeNode = targetNode_2 = paperclip_1.getSyntheticNodeById(nodeId, state.documents); var clipsContainTarget = clips_1.some(function (clip) { return clip.node.id === targetNode_2.source.nodeId; }); // if selected node is the pasted element, then paste if (!clipsContainTarget) { offset_2 = tandem_common_1.TreeMoveOffset.PREPEND; } else { scopeNode = tandem_common_1.getParentTreeNode(scopeNode.id, paperclip_1.getSyntheticVisibleNodeDocument(scopeNode.id, state.documents)); } } else { offset_2 = tandem_common_1.TreeMoveOffset.PREPEND; scopeNode = targetNode_2 = paperclip_1.getSyntheticDocumentByDependencyUri(state.activeEditorFilePath, state.documents, state.graph); } state = state_1.persistRootState(function (state) { return paperclip_1.persistAppendPCClips(clips_1, targetNode_2, offset_2, state); }, state); if (scopeNode === targetNode_2) { state = state_1.selectInsertedSyntheticVisibleNodes(oldState, state, scopeNode); } return state; } } return state; }; var isDroppableNode = function (node) { return (node.name !== "text" && !/input/.test(String(node.name))); }; var maybeEvaluateFile = function (uri, state) { if (paperclip_1.isPaperclipUri(uri) && fsbox_1.hasFileCacheItem(uri, state)) { return paperclip_1.evaluateDependency(uri, state); } return fsbox_1.queueOpenFile(uri, state); }; var handleArtboardSelectionFromAction = function (state, nodeId, event) { var sourceEvent = event.sourceEvent; state = state_1.setRootStateSyntheticVisibleNodeExpanded(nodeId, true, state); return state_1.setSelectedSyntheticVisibleNodeIds(state, nodeId); }; var setCanvasZoom = function (zoom, smooth, uri, state) { if (smooth === void 0) { smooth = true; } var editorWindow = state_1.getEditorWindowWithFileUri(uri, state); var openFile = state_1.getOpenFile(uri, state); return state_1.updateOpenFileCanvas({ translate: tandem_common_1.centerTransformZoom(openFile.canvas.translate, editorWindow.container.getBoundingClientRect(), lodash_1.clamp(zoom, MIN_ZOOM, MAX_ZOOM), editorWindow.mousePosition) }, uri, state); }; var normalizeBounds = function (translate, bounds) { return tandem_common_1.zoomBounds(tandem_common_1.shiftBounds(bounds, { left: -translate.left, top: -translate.top }), 1 / translate.zoom); }; var normalizePoint = function (translate, point) { return tandem_common_1.zoomPoint(tandem_common_1.shiftPoint(point, { left: -translate.left, top: -translate.top }), 1 / translate.zoom); }; var normalizeZoom = function (zoom) { return zoom < 1 ? 1 / Math.round(1 / zoom) : Math.round(zoom); }; //# sourceMappingURL=index.js.map