tandem-front-end
Version:
Visual editor for web components
899 lines • 44.2 kB
JavaScript
"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