From 022f349dc67b35169d4815cff724331e8476b5bc Mon Sep 17 00:00:00 2001 From: Lipis Date: Sun, 27 Dec 2020 18:26:30 +0200 Subject: [PATCH] feat: Add line chart and paste dialog selection (#2670) Co-authored-by: dwelle Co-authored-by: Jed Fox --- src/actions/actionCanvas.tsx | 28 +- src/appState.ts | 117 ++--- src/charts.ts | 431 +++++++++++++----- src/components/App.tsx | 331 +++++++------- src/components/Dialog.tsx | 14 +- src/components/LayerUI.tsx | 58 ++- src/components/LibraryUnit.tsx | 12 +- src/components/MobileMenu.tsx | 2 - src/components/PasteChartDialog.scss | 46 ++ src/components/PasteChartDialog.tsx | 121 +++++ src/components/Stats.tsx | 1 - src/element/types.ts | 1 + src/locales/en.json | 6 +- .../regressionTests.test.tsx.snap | 335 ++++++++++++++ src/types.ts | 12 + 15 files changed, 1122 insertions(+), 393 deletions(-) create mode 100644 src/components/PasteChartDialog.scss create mode 100644 src/components/PasteChartDialog.tsx diff --git a/src/actions/actionCanvas.tsx b/src/actions/actionCanvas.tsx index 5435aab3..aff1a7f6 100644 --- a/src/actions/actionCanvas.tsx +++ b/src/actions/actionCanvas.tsx @@ -1,23 +1,22 @@ import React from "react"; -import { ColorPicker } from "../components/ColorPicker"; +import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics"; import { getDefaultAppState } from "../appState"; -import { trash, zoomIn, zoomOut, resetZoom } from "../components/icons"; +import colors from "../colors"; +import { ColorPicker } from "../components/ColorPicker"; +import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons"; import { ToolButton } from "../components/ToolButton"; -import { t } from "../i18n"; -import { getNormalizedZoom, getSelectedElements } from "../scene"; -import { getNonDeletedElements } from "../element"; -import { CODES, KEYS } from "../keys"; -import { getShortcutKey } from "../utils"; -import useIsMobile from "../is-mobile"; -import { register } from "./register"; +import { getCommonBounds, getNonDeletedElements } from "../element"; import { newElementWith } from "../element/mutateElement"; import { ExcalidrawElement } from "../element/types"; -import { AppState, NormalizedZoomValue } from "../types"; -import { getCommonBounds } from "../element"; -import { getNewZoom } from "../scene/zoom"; +import { t } from "../i18n"; +import useIsMobile from "../is-mobile"; +import { CODES, KEYS } from "../keys"; +import { getNormalizedZoom, getSelectedElements } from "../scene"; import { centerScrollOn } from "../scene/scroll"; -import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics"; -import colors from "../colors"; +import { getNewZoom } from "../scene/zoom"; +import { AppState, NormalizedZoomValue } from "../types"; +import { getShortcutKey } from "../utils"; +import { register } from "./register"; export const actionChangeViewBackgroundColor = register({ name: "changeViewBackgroundColor", @@ -67,6 +66,7 @@ export const actionClearCanvas = register({ gridSize: appState.gridSize, shouldAddWatermark: appState.shouldAddWatermark, showStats: appState.showStats, + pasteDialog: appState.pasteDialog, }, commitToHistory: true, }; diff --git a/src/appState.ts b/src/appState.ts index 7b8eba03..02036a43 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -1,12 +1,12 @@ import oc from "open-color"; -import { AppState, FlooredNumber, NormalizedZoomValue } from "./types"; -import { getDateTime } from "./utils"; -import { t } from "./i18n"; import { - DEFAULT_FONT_SIZE, DEFAULT_FONT_FAMILY, + DEFAULT_FONT_SIZE, DEFAULT_TEXT_ALIGN, } from "./constants"; +import { t } from "./i18n"; +import { AppState, FlooredNumber, NormalizedZoomValue } from "./types"; +import { getDateTime } from "./utils"; export const getDefaultAppState = (): Omit< AppState, @@ -14,64 +14,63 @@ export const getDefaultAppState = (): Omit< > => { return { appearance: "light", - isLoading: false, - errorMessage: null, + collaborators: new Map(), + currentChartType: "bar", + currentItemBackgroundColor: "transparent", + currentItemEndArrowhead: "arrow", + currentItemFillStyle: "hachure", + currentItemFontFamily: DEFAULT_FONT_FAMILY, + currentItemFontSize: DEFAULT_FONT_SIZE, + currentItemLinearStrokeSharpness: "round", + currentItemOpacity: 100, + currentItemRoughness: 1, + currentItemStartArrowhead: null, + currentItemStrokeColor: oc.black, + currentItemStrokeSharpness: "sharp", + currentItemStrokeStyle: "solid", + currentItemStrokeWidth: 1, + currentItemTextAlign: DEFAULT_TEXT_ALIGN, + cursorButton: "up", draggingElement: null, - resizingElement: null, - multiElement: null, editingElement: null, - startBoundElement: null, + editingGroupId: null, editingLinearElement: null, - elementType: "selection", elementLocked: false, + elementType: "selection", + errorMessage: null, exportBackground: true, exportEmbedScene: false, - shouldAddWatermark: false, - currentItemStrokeColor: oc.black, - currentItemBackgroundColor: "transparent", - currentItemFillStyle: "hachure", - currentItemStrokeWidth: 1, - currentItemStrokeStyle: "solid", - currentItemRoughness: 1, - currentItemOpacity: 100, - currentItemFontSize: DEFAULT_FONT_SIZE, - currentItemFontFamily: DEFAULT_FONT_FAMILY, - currentItemTextAlign: DEFAULT_TEXT_ALIGN, - currentItemStrokeSharpness: "sharp", - currentItemLinearStrokeSharpness: "round", - currentItemStartArrowhead: null, - currentItemEndArrowhead: "arrow", - viewBackgroundColor: oc.white, - scrollX: 0 as FlooredNumber, - scrollY: 0 as FlooredNumber, - cursorButton: "up", - scrolledOutside: false, - name: `${t("labels.untitled")}-${getDateTime()}`, + fileHandle: null, + gridSize: null, + height: window.innerHeight, isBindingEnabled: true, + isLibraryOpen: false, + isLoading: false, isResizing: false, isRotating: false, - selectionElement: null, - zoom: { - value: 1 as NormalizedZoomValue, - translation: { x: 0, y: 0 }, - }, - openMenu: null, lastPointerDownWith: "mouse", - selectedElementIds: {}, + multiElement: null, + name: `${t("labels.untitled")}-${getDateTime()}`, + openMenu: null, + pasteDialog: { shown: false, data: null }, previousSelectedElementIds: {}, + resizingElement: null, + scrolledOutside: false, + scrollX: 0 as FlooredNumber, + scrollY: 0 as FlooredNumber, + selectedElementIds: {}, + selectedGroupIds: {}, + selectionElement: null, + shouldAddWatermark: false, shouldCacheIgnoreZoom: false, showShortcutsDialog: false, - suggestedBindings: [], - zenModeEnabled: false, - gridSize: null, - editingGroupId: null, - selectedGroupIds: {}, - width: window.innerWidth, - height: window.innerHeight, - isLibraryOpen: false, - fileHandle: null, - collaborators: new Map(), showStats: false, + startBoundElement: null, + suggestedBindings: [], + viewBackgroundColor: oc.white, + width: window.innerWidth, + zenModeEnabled: false, + zoom: { value: 1 as NormalizedZoomValue, translation: { x: 0, y: 0 } }, }; }; @@ -91,24 +90,25 @@ const APP_STATE_STORAGE_CONF = (< config: { [K in keyof T]: K extends keyof AppState ? T[K] : never }, ) => config)({ appearance: { browser: true, export: false }, + collaborators: { browser: false, export: false }, + currentChartType: { browser: true, export: false }, currentItemBackgroundColor: { browser: true, export: false }, + currentItemEndArrowhead: { browser: true, export: false }, currentItemFillStyle: { browser: true, export: false }, currentItemFontFamily: { browser: true, export: false }, currentItemFontSize: { browser: true, export: false }, + currentItemLinearStrokeSharpness: { browser: true, export: false }, currentItemOpacity: { browser: true, export: false }, currentItemRoughness: { browser: true, export: false }, + currentItemStartArrowhead: { browser: true, export: false }, currentItemStrokeColor: { browser: true, export: false }, + currentItemStrokeSharpness: { browser: true, export: false }, currentItemStrokeStyle: { browser: true, export: false }, currentItemStrokeWidth: { browser: true, export: false }, currentItemTextAlign: { browser: true, export: false }, - currentItemStrokeSharpness: { browser: true, export: false }, - currentItemLinearStrokeSharpness: { browser: true, export: false }, - currentItemStartArrowhead: { browser: true, export: false }, - currentItemEndArrowhead: { browser: true, export: false }, cursorButton: { browser: true, export: false }, draggingElement: { browser: false, export: false }, editingElement: { browser: false, export: false }, - startBoundElement: { browser: false, export: false }, editingGroupId: { browser: true, export: false }, editingLinearElement: { browser: false, export: false }, elementLocked: { browser: true, export: false }, @@ -116,6 +116,7 @@ const APP_STATE_STORAGE_CONF = (< errorMessage: { browser: false, export: false }, exportBackground: { browser: true, export: false }, exportEmbedScene: { browser: true, export: false }, + fileHandle: { browser: false, export: false }, gridSize: { browser: true, export: true }, height: { browser: false, export: false }, isBindingEnabled: { browser: false, export: false }, @@ -126,7 +127,10 @@ const APP_STATE_STORAGE_CONF = (< lastPointerDownWith: { browser: true, export: false }, multiElement: { browser: false, export: false }, name: { browser: true, export: false }, + offsetLeft: { browser: false, export: false }, + offsetTop: { browser: false, export: false }, openMenu: { browser: true, export: false }, + pasteDialog: { browser: false, export: false }, previousSelectedElementIds: { browser: true, export: false }, resizingElement: { browser: false, export: false }, scrolledOutside: { browser: true, export: false }, @@ -138,16 +142,13 @@ const APP_STATE_STORAGE_CONF = (< shouldAddWatermark: { browser: true, export: false }, shouldCacheIgnoreZoom: { browser: true, export: false }, showShortcutsDialog: { browser: false, export: false }, + showStats: { browser: true, export: false }, + startBoundElement: { browser: false, export: false }, suggestedBindings: { browser: false, export: false }, viewBackgroundColor: { browser: true, export: true }, width: { browser: false, export: false }, zenModeEnabled: { browser: true, export: false }, zoom: { browser: true, export: false }, - offsetTop: { browser: false, export: false }, - offsetLeft: { browser: false, export: false }, - fileHandle: { browser: false, export: false }, - collaborators: { browser: false, export: false }, - showStats: { browser: true, export: false }, }); const _clearAppStateForStorage = ( diff --git a/src/charts.ts b/src/charts.ts index 5e49e936..81d27f31 100644 --- a/src/charts.ts +++ b/src/charts.ts @@ -1,13 +1,21 @@ import { EVENT_MAGIC, trackEvent } from "./analytics"; import colors from "./colors"; -import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "./constants"; -import { newElement, newTextElement, newLinearElement } from "./element"; -import { ExcalidrawElement } from "./element/types"; +import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, ENV } from "./constants"; +import { newElement, newLinearElement, newTextElement } from "./element"; +import { NonDeletedExcalidrawElement } from "./element/types"; import { randomId } from "./random"; +export type ChartElements = readonly NonDeletedExcalidrawElement[]; + const BAR_WIDTH = 32; const BAR_GAP = 12; const BAR_HEIGHT = 256; +const GRID_OPACITY = 50; + +export const CHART_LABELS = { + bar: "labels.chartTypeBar", + line: "labels.chartTypeLine", +}; export interface Spreadsheet { title: string | null; @@ -139,114 +147,48 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => { return transposedResults; } } - return result; }; -// For the maths behind it https://excalidraw.com/#json=6320864370884608,O_5xfD-Agh32tytHpRJx1g -export const renderSpreadsheet = ( +const bgColors = colors.elementBackground.slice( + 2, + colors.elementBackground.length, +); + +// Put all the common properties here so when the whole chart is selected +// the properties dialog shows the correct selected values +const commonProps = { + fillStyle: "hachure", + fontFamily: DEFAULT_FONT_FAMILY, + fontSize: DEFAULT_FONT_SIZE, + opacity: 100, + roughness: 1, + strokeColor: colors.elementStroke[0], + strokeSharpness: "sharp", + strokeStyle: "solid", + strokeWidth: 1, + verticalAlign: "middle", +} as const; + +const getChartDimentions = (spreadsheet: Spreadsheet) => { + const chartWidth = + (BAR_WIDTH + BAR_GAP) * spreadsheet.values.length + BAR_GAP; + const chartHeight = BAR_HEIGHT + BAR_GAP * 2; + return { chartWidth, chartHeight }; +}; + +const chartXLabels = ( spreadsheet: Spreadsheet, x: number, y: number, -): ExcalidrawElement[] => { - const values = spreadsheet.values; - const max = Math.max(...values); - const chartHeight = BAR_HEIGHT + BAR_GAP * 2; - const chartWidth = (BAR_WIDTH + BAR_GAP) * values.length + BAR_GAP; - const maxColors = colors.elementBackground.length; - const bgColors = colors.elementBackground.slice(2, maxColors); - - // Put all the common properties here so when the whole chart is selected - // the properties dialog shows the correct selected values - const commonProps = { - backgroundColor: bgColors[Math.floor(Math.random() * bgColors.length)], - fillStyle: "hachure", - fontFamily: DEFAULT_FONT_FAMILY, - fontSize: DEFAULT_FONT_SIZE, - groupIds: [randomId()], - opacity: 100, - roughness: 1, - strokeColor: colors.elementStroke[0], - strokeSharpness: "sharp", - strokeStyle: "solid", - strokeWidth: 1, - verticalAlign: "middle", - } as const; - - const minYLabel = newTextElement({ - ...commonProps, - x: x - BAR_GAP, - y: y - BAR_GAP, - text: "0", - textAlign: "right", - }); - - const maxYLabel = newTextElement({ - ...commonProps, - x: x - BAR_GAP, - y: y - BAR_HEIGHT - minYLabel.height / 2, - text: max.toLocaleString(), - textAlign: "right", - }); - - const xAxisLine = newLinearElement({ - type: "line", - x, - y, - startArrowhead: null, - endArrowhead: null, - width: chartWidth, - points: [ - [0, 0], - [chartWidth, 0], - ], - ...commonProps, - }); - - const yAxisLine = newLinearElement({ - type: "line", - x, - y, - startArrowhead: null, - endArrowhead: null, - height: chartHeight, - points: [ - [0, 0], - [0, -chartHeight], - ], - ...commonProps, - }); - - const maxValueLine = newLinearElement({ - type: "line", - x, - y: y - BAR_HEIGHT - BAR_GAP, - startArrowhead: null, - endArrowhead: null, - ...commonProps, - strokeStyle: "dotted", - width: chartWidth, - points: [ - [0, 0], - [chartWidth, 0], - ], - }); - - const bars = values.map((value, index) => { - const barHeight = (value / max) * BAR_HEIGHT; - return newElement({ - ...commonProps, - type: "rectangle", - x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP, - y: y - barHeight - BAR_GAP, - width: BAR_WIDTH, - height: barHeight, - }); - }); - - const xLabels = + groupId: string, + backgroundColor: string, +): ChartElements => { + return ( spreadsheet.labels?.map((label, index) => { return newTextElement({ + groupIds: [groupId], + backgroundColor, ...commonProps, text: label.length > 8 ? `${label.slice(0, 5)}...` : label, x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP * 2, @@ -257,29 +199,288 @@ export const renderSpreadsheet = ( textAlign: "center", verticalAlign: "top", }); - }) || []; + }) || [] + ); +}; + +const chartYLabels = ( + spreadsheet: Spreadsheet, + x: number, + y: number, + groupId: string, + backgroundColor: string, +): ChartElements => { + const minYLabel = newTextElement({ + groupIds: [groupId], + backgroundColor, + ...commonProps, + x: x - BAR_GAP, + y: y - BAR_GAP, + text: "0", + textAlign: "right", + }); + + const maxYLabel = newTextElement({ + groupIds: [groupId], + backgroundColor, + ...commonProps, + x: x - BAR_GAP, + y: y - BAR_HEIGHT - minYLabel.height / 2, + text: Math.max(...spreadsheet.values).toLocaleString(), + textAlign: "right", + }); + + return [minYLabel, maxYLabel]; +}; + +const chartLines = ( + spreadsheet: Spreadsheet, + x: number, + y: number, + groupId: string, + backgroundColor: string, +): ChartElements => { + const { chartWidth, chartHeight } = getChartDimentions(spreadsheet); + const xLine = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x, + y, + startArrowhead: null, + endArrowhead: null, + width: chartWidth, + points: [ + [0, 0], + [chartWidth, 0], + ], + }); + + const yLine = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x, + y, + startArrowhead: null, + endArrowhead: null, + height: chartHeight, + points: [ + [0, 0], + [0, -chartHeight], + ], + }); + + const maxLine = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x, + y: y - BAR_HEIGHT - BAR_GAP, + startArrowhead: null, + endArrowhead: null, + strokeStyle: "dotted", + width: chartWidth, + opacity: GRID_OPACITY, + points: [ + [0, 0], + [chartWidth, 0], + ], + }); + + return [xLine, yLine, maxLine]; +}; + +// For the maths behind it https://excalidraw.com/#json=6320864370884608,O_5xfD-Agh32tytHpRJx1g +const chartBaseElements = ( + spreadsheet: Spreadsheet, + x: number, + y: number, + groupId: string, + backgroundColor: string, + debug?: boolean, +): ChartElements => { + const { chartWidth, chartHeight } = getChartDimentions(spreadsheet); const title = spreadsheet.title ? newTextElement({ + backgroundColor, + groupIds: [groupId], ...commonProps, text: spreadsheet.title, x: x + chartWidth / 2, - y: y - BAR_HEIGHT - BAR_GAP * 2 - maxYLabel.height, + y: y - BAR_HEIGHT - BAR_GAP * 2 - DEFAULT_FONT_SIZE, strokeSharpness: "sharp", strokeStyle: "solid", textAlign: "center", }) : null; - trackEvent(EVENT_MAGIC, "chart", "bars", bars.length); + const debugRect = debug + ? newElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "rectangle", + x, + y: y - chartHeight, + width: chartWidth, + height: chartHeight, + strokeColor: colors.elementStroke[0], + fillStyle: "solid", + opacity: 6, + }) + : null; + return [ - title, - ...bars, - ...xLabels, - xAxisLine, - yAxisLine, - maxValueLine, - minYLabel, - maxYLabel, - ].filter((element) => element !== null) as ExcalidrawElement[]; + ...(debugRect ? [debugRect] : []), + ...(title ? [title] : []), + ...chartXLabels(spreadsheet, x, y, groupId, backgroundColor), + ...chartYLabels(spreadsheet, x, y, groupId, backgroundColor), + ...chartLines(spreadsheet, x, y, groupId, backgroundColor), + ]; +}; + +const chartTypeBar = ( + spreadsheet: Spreadsheet, + x: number, + y: number, +): ChartElements => { + const max = Math.max(...spreadsheet.values); + const groupId = randomId(); + const backgroundColor = bgColors[Math.floor(Math.random() * bgColors.length)]; + + const bars = spreadsheet.values.map((value, index) => { + const barHeight = (value / max) * BAR_HEIGHT; + return newElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "rectangle", + x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP, + y: y - barHeight - BAR_GAP, + width: BAR_WIDTH, + height: barHeight, + }); + }); + + return [ + ...bars, + ...chartBaseElements( + spreadsheet, + x, + y, + groupId, + backgroundColor, + process.env.NODE_ENV === ENV.DEVELOPMENT, + ), + ]; +}; + +const chartTypeLine = ( + spreadsheet: Spreadsheet, + x: number, + y: number, +): ChartElements => { + const max = Math.max(...spreadsheet.values); + const groupId = randomId(); + const backgroundColor = bgColors[Math.floor(Math.random() * bgColors.length)]; + + let index = 0; + const points = []; + for (const value of spreadsheet.values) { + const cx = index * (BAR_WIDTH + BAR_GAP); + const cy = -(value / max) * BAR_HEIGHT; + points.push([cx, cy]); + index++; + } + + const maxX = Math.max(...points.map((element) => element[0])); + const maxY = Math.max(...points.map((element) => element[1])); + const minX = Math.min(...points.map((element) => element[0])); + const minY = Math.min(...points.map((element) => element[1])); + + const line = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x: x + BAR_GAP + BAR_WIDTH / 2, + y: y - BAR_GAP, + startArrowhead: null, + endArrowhead: null, + height: maxY - minY, + width: maxX - minX, + strokeWidth: 2, + points: points as any, + }); + + const dots = spreadsheet.values.map((value, index) => { + const cx = index * (BAR_WIDTH + BAR_GAP) + BAR_GAP / 2; + const cy = -(value / max) * BAR_HEIGHT + BAR_GAP / 2; + return newElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + fillStyle: "solid", + strokeWidth: 2, + type: "ellipse", + x: x + cx + BAR_WIDTH / 2, + y: y + cy - BAR_GAP * 2, + width: BAR_GAP, + height: BAR_GAP, + }); + }); + + const lines = spreadsheet.values.map((value, index) => { + const cx = index * (BAR_WIDTH + BAR_GAP) + BAR_GAP / 2; + const cy = (value / max) * BAR_HEIGHT + BAR_GAP / 2 + BAR_GAP; + return newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x: x + cx + BAR_WIDTH / 2 + BAR_GAP / 2, + y: y - cy, + startArrowhead: null, + endArrowhead: null, + height: cy, + strokeStyle: "dotted", + opacity: GRID_OPACITY, + points: [ + [0, 0], + [0, cy], + ], + }); + }); + + return [ + ...chartBaseElements( + spreadsheet, + x, + y, + groupId, + backgroundColor, + process.env.NODE_ENV === ENV.DEVELOPMENT, + ), + line, + ...lines, + ...dots, + ]; +}; + +export const renderSpreadsheet = ( + chartType: string, + spreadsheet: Spreadsheet, + x: number, + y: number, +): ChartElements => { + trackEvent(EVENT_MAGIC, "chart", chartType, spreadsheet.values.length); + if (chartType === "line") { + return chartTypeLine(spreadsheet, x, y); + } + return chartTypeBar(spreadsheet, x, y); }; diff --git a/src/components/App.tsx b/src/components/App.tsx index 5599b951..e60c27bf 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,181 +1,167 @@ +import { Point, simplify } from "points-on-curve"; import React from "react"; - -import rough from "roughjs/bin/rough"; import { RoughCanvas } from "roughjs/bin/canvas"; -import { simplify, Point } from "points-on-curve"; - -import { - newElement, - newTextElement, - duplicateElement, - isInvisiblySmallElement, - isTextElement, - textWysiwyg, - getCommonBounds, - getCursorForResizingElement, - getPerfectElementSize, - getNormalizedDimensions, - newLinearElement, - transformElements, - getElementWithTransformHandleType, - getResizeOffsetXY, - getResizeArrowDirection, - getTransformHandleTypeFromCoords, - isNonDeletedElement, - updateTextElement, - dragSelectedElements, - getDragOffsetXY, - dragNewElement, - hitTest, - isHittingElementBoundingBoxWithoutHittingElement, - getNonDeletedElements, -} from "../element"; -import { - getElementsWithinSelection, - isOverScrollBars, - getElementsAtPosition, - getElementContainingPosition, - getNormalizedZoom, - getSelectedElements, - isSomeElementSelected, - calculateScrollCenter, -} from "../scene"; -import { loadFromBlob, exportCanvas } from "../data"; - -import { renderScene } from "../renderer"; -import { - AppState, - GestureEvent, - Gesture, - ExcalidrawProps, - SceneData, -} from "../types"; -import { - ExcalidrawElement, - ExcalidrawTextElement, - NonDeleted, - ExcalidrawGenericElement, - ExcalidrawLinearElement, - ExcalidrawBindableElement, -} from "../element/types"; - -import { distance2d, isPathALoop, getGridPoint } from "../math"; - -import { - isWritableElement, - isInputLike, - isToolIcon, - debounce, - distance, - resetCursor, - viewportCoordsToSceneCoords, - sceneCoordsToViewportCoords, - setCursorForShape, - tupleToCoors, - ResolvablePromise, - resolvablePromise, - withBatchedUpdates, -} from "../utils"; -import { - KEYS, - isArrowKey, - getResizeCenterPointKey, - getResizeWithSidesSameLengthKey, - getRotateWithDiscreteAngleKey, - CODES, -} from "../keys"; - -import { findShapeByKey } from "../shapes"; -import { createHistory, SceneHistory } from "../history"; - -import ContextMenu from "./ContextMenu"; - -import { ActionManager } from "../actions/manager"; +import rough from "roughjs/bin/rough"; import "../actions"; +import { actionDeleteSelected, actionFinalize } from "../actions"; +import { createRedoAction, createUndoAction } from "../actions/actionHistory"; +import { ActionManager } from "../actions/manager"; import { actions } from "../actions/register"; - import { ActionResult } from "../actions/types"; -import { getDefaultAppState } from "../appState"; -import { t, getLanguage } from "../i18n"; - -import { - copyToClipboard, - parseClipboard, - probablySupportsClipboardBlob, - probablySupportsClipboardWriteText, -} from "../clipboard"; -import { normalizeScroll } from "../scene"; -import { getCenter, getDistance } from "../gesture"; -import { createUndoAction, createRedoAction } from "../actions/actionHistory"; - -import { - CURSOR_TYPE, - ELEMENT_SHIFT_TRANSLATE_AMOUNT, - ELEMENT_TRANSLATE_AMOUNT, - POINTER_BUTTON, - DRAGGING_THRESHOLD, - TEXT_TO_CENTER_SNAP_THRESHOLD, - LINE_CONFIRM_THRESHOLD, - EVENT, - ENV, - CANVAS_ONLY_ACTIONS, - DEFAULT_VERTICAL_ALIGN, - GRID_SIZE, - MIME_TYPES, - TAP_TWICE_TIMEOUT, - TOUCH_CTX_MENU_TIMEOUT, - APP_NAME, -} from "../constants"; - -import LayerUI from "./LayerUI"; -import { ScrollBars, SceneState } from "../scene/types"; -import { mutateElement } from "../element/mutateElement"; -import { invalidateShapeForElement } from "../renderer/renderElement"; -import { - isLinearElement, - isLinearElementType, - isBindingElement, - isBindingElementType, -} from "../element/typeChecks"; -import { actionFinalize, actionDeleteSelected } from "../actions"; - -import { LinearElementEditor } from "../element/linearElementEditor"; -import { - getSelectedGroupIds, - isSelectedViaGroup, - selectGroupsForSelectedElements, - isElementInGroup, - getSelectedGroupIdForElement, - getElementsInGroup, - editGroupForSelectedElement, -} from "../groups"; -import { Library } from "../data/library"; -import Scene from "../scene/Scene"; -import { - getHoveredElementForBinding, - maybeBindLinearElement, - getEligibleElementsForBinding, - bindOrUnbindSelectedElements, - unbindLinearElements, - fixBindingsAfterDuplication, - fixBindingsAfterDeletion, - isLinearElementSimpleAndAlreadyBound, - isBindingEnabled, - updateBoundElements, - shouldEnableBindingForPointerEvent, -} from "../element/binding"; -import { MaybeTransformHandleType } from "../element/transformHandles"; -import { deepCopyElement } from "../element/newElement"; -import { renderSpreadsheet } from "../charts"; -import { isValidLibrary } from "../data/json"; -import { getNewZoom } from "../scene/zoom"; -import { restore } from "../data/restore"; import { EVENT_DIALOG, EVENT_LIBRARY, EVENT_SHAPE, trackEvent, } from "../analytics"; +import { getDefaultAppState } from "../appState"; +import { + copyToClipboard, + parseClipboard, + probablySupportsClipboardBlob, + probablySupportsClipboardWriteText, +} from "../clipboard"; +import { + APP_NAME, + CANVAS_ONLY_ACTIONS, + CURSOR_TYPE, + DEFAULT_VERTICAL_ALIGN, + DRAGGING_THRESHOLD, + ELEMENT_SHIFT_TRANSLATE_AMOUNT, + ELEMENT_TRANSLATE_AMOUNT, + ENV, + EVENT, + GRID_SIZE, + LINE_CONFIRM_THRESHOLD, + MIME_TYPES, + POINTER_BUTTON, + TAP_TWICE_TIMEOUT, + TEXT_TO_CENTER_SNAP_THRESHOLD, + TOUCH_CTX_MENU_TIMEOUT, +} from "../constants"; +import { exportCanvas, loadFromBlob } from "../data"; +import { isValidLibrary } from "../data/json"; +import { Library } from "../data/library"; +import { restore } from "../data/restore"; +import { + dragNewElement, + dragSelectedElements, + duplicateElement, + getCommonBounds, + getCursorForResizingElement, + getDragOffsetXY, + getElementWithTransformHandleType, + getNonDeletedElements, + getNormalizedDimensions, + getPerfectElementSize, + getResizeArrowDirection, + getResizeOffsetXY, + getTransformHandleTypeFromCoords, + hitTest, + isHittingElementBoundingBoxWithoutHittingElement, + isInvisiblySmallElement, + isNonDeletedElement, + isTextElement, + newElement, + newLinearElement, + newTextElement, + textWysiwyg, + transformElements, + updateTextElement, +} from "../element"; +import { + bindOrUnbindSelectedElements, + fixBindingsAfterDeletion, + fixBindingsAfterDuplication, + getEligibleElementsForBinding, + getHoveredElementForBinding, + isBindingEnabled, + isLinearElementSimpleAndAlreadyBound, + maybeBindLinearElement, + shouldEnableBindingForPointerEvent, + unbindLinearElements, + updateBoundElements, +} from "../element/binding"; +import { LinearElementEditor } from "../element/linearElementEditor"; +import { mutateElement } from "../element/mutateElement"; +import { deepCopyElement } from "../element/newElement"; +import { MaybeTransformHandleType } from "../element/transformHandles"; +import { + isBindingElement, + isBindingElementType, + isLinearElement, + isLinearElementType, +} from "../element/typeChecks"; +import { + ExcalidrawBindableElement, + ExcalidrawElement, + ExcalidrawGenericElement, + ExcalidrawLinearElement, + ExcalidrawTextElement, + NonDeleted, +} from "../element/types"; +import { getCenter, getDistance } from "../gesture"; +import { + editGroupForSelectedElement, + getElementsInGroup, + getSelectedGroupIdForElement, + getSelectedGroupIds, + isElementInGroup, + isSelectedViaGroup, + selectGroupsForSelectedElements, +} from "../groups"; +import { createHistory, SceneHistory } from "../history"; +import { getLanguage, t } from "../i18n"; +import { + CODES, + getResizeCenterPointKey, + getResizeWithSidesSameLengthKey, + getRotateWithDiscreteAngleKey, + isArrowKey, + KEYS, +} from "../keys"; +import { distance2d, getGridPoint, isPathALoop } from "../math"; +import { renderScene } from "../renderer"; +import { invalidateShapeForElement } from "../renderer/renderElement"; +import { + calculateScrollCenter, + getElementContainingPosition, + getElementsAtPosition, + getElementsWithinSelection, + getNormalizedZoom, + getSelectedElements, + isOverScrollBars, + isSomeElementSelected, + normalizeScroll, +} from "../scene"; +import Scene from "../scene/Scene"; +import { SceneState, ScrollBars } from "../scene/types"; +import { getNewZoom } from "../scene/zoom"; +import { findShapeByKey } from "../shapes"; +import { + AppState, + ExcalidrawProps, + Gesture, + GestureEvent, + SceneData, +} from "../types"; +import { + debounce, + distance, + isInputLike, + isToolIcon, + isWritableElement, + resetCursor, + ResolvablePromise, + resolvablePromise, + sceneCoordsToViewportCoords, + setCursorForShape, + tupleToCoors, + viewportCoordsToSceneCoords, + withBatchedUpdates, +} from "../utils"; +import ContextMenu from "./ContextMenu"; +import LayerUI from "./LayerUI"; import { Stats } from "./Stats"; const { history } = createHistory(); @@ -374,7 +360,7 @@ class App extends React.Component { elements={this.scene.getElements()} onCollabButtonClick={onCollabButtonClick} onLockToggle={this.toggleLock} - onInsertShape={(elements) => + onInsertElements={(elements) => this.addElementsFromPasteOrLibrary( elements, DEFAULT_PASTE_X, @@ -1004,9 +990,12 @@ class App extends React.Component { if (data.errorMessage) { this.setState({ errorMessage: data.errorMessage }); } else if (data.spreadsheet) { - this.addElementsFromPasteOrLibrary( - renderSpreadsheet(data.spreadsheet, cursorX, cursorY), - ); + this.setState({ + pasteDialog: { + data: data.spreadsheet, + shown: true, + }, + }); } else if (data.elements) { this.addElementsFromPasteOrLibrary(data.elements); } else if (data.text) { diff --git a/src/components/Dialog.tsx b/src/components/Dialog.tsx index f1b83b4e..90c3d030 100644 --- a/src/components/Dialog.tsx +++ b/src/components/Dialog.tsx @@ -1,13 +1,12 @@ -import React, { useCallback, useEffect, useState } from "react"; import clsx from "clsx"; -import { Modal } from "./Modal"; -import { Island } from "./Island"; +import React, { useCallback, useEffect, useState } from "react"; import { t } from "../i18n"; import useIsMobile from "../is-mobile"; -import { back, close } from "./icons"; import { KEYS } from "../keys"; - import "./Dialog.scss"; +import { back, close } from "./icons"; +import { Island } from "./Island"; +import { Modal } from "./Modal"; const useRefState = () => { const [refValue, setRefValue] = useState(null); @@ -23,6 +22,7 @@ export const Dialog = (props: { maxWidth?: number; onCloseRequest(): void; title: React.ReactNode; + autofocus?: boolean; }) => { const [islandNode, setIslandNode] = useRefState(); @@ -33,7 +33,7 @@ export const Dialog = (props: { const focusableElements = queryFocusableElements(islandNode); - if (focusableElements.length > 0) { + if (focusableElements.length > 0 && props.autofocus !== false) { // If there's an element other than close, focus it. (focusableElements[1] || focusableElements[0]).focus(); } @@ -62,7 +62,7 @@ export const Dialog = (props: { islandNode.addEventListener("keydown", handleKeyDown); return () => islandNode.removeEventListener("keydown", handleKeyDown); - }, [islandNode]); + }, [islandNode, props.autofocus]); const queryFocusableElements = (node: HTMLElement) => { const focusableElements = node.querySelectorAll( diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index 767b3e8f..ec3b17e9 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -51,6 +51,7 @@ import { EVENT_LIBRARY, trackEvent, } from "../analytics"; +import { PasteChartDialog } from "./PasteChartDialog"; interface LayerUIProps { actionManager: ActionManager; @@ -60,7 +61,7 @@ interface LayerUIProps { elements: readonly NonDeletedExcalidrawElement[]; onCollabButtonClick?: () => void; onLockToggle: () => void; - onInsertShape: (elements: LibraryItem) => void; + onInsertElements: (elements: readonly NonDeletedExcalidrawElement[]) => void; zenModeEnabled: boolean; toggleZenMode: () => void; lng: string; @@ -318,7 +319,7 @@ const LayerUI = ({ elements, onCollabButtonClick, onLockToggle, - onInsertShape, + onInsertElements, zenModeEnabled, toggleZenMode, isCollaborating, @@ -456,7 +457,7 @@ const LayerUI = ({ @@ -592,21 +593,8 @@ const LayerUI = ({ ); - return isMobile ? ( - - ) : ( -
+ const dialogs = ( + <> {appState.isLoading && } {appState.errorMessage && ( setAppState({ showShortcutsDialog: false })} /> )} + {appState.pasteDialog.shown && ( + + setAppState({ + pasteDialog: { shown: false, data: null }, + }) + } + /> + )} + + ); + + return isMobile ? ( + <> + {dialogs} + + + ) : ( +
+ {dialogs} {renderFixedSideContainer()} {renderBottomAppMenu()} { diff --git a/src/components/LibraryUnit.tsx b/src/components/LibraryUnit.tsx index 397eecfe..c4dd280a 100644 --- a/src/components/LibraryUnit.tsx +++ b/src/components/LibraryUnit.tsx @@ -1,13 +1,13 @@ -import React, { useRef, useEffect, useState } from "react"; import clsx from "clsx"; -import { exportToSvg } from "../scene/export"; +import oc from "open-color"; +import React, { useEffect, useRef, useState } from "react"; import { close } from "../components/icons"; - -import "./LibraryUnit.scss"; +import { MIME_TYPES } from "../constants"; import { t } from "../i18n"; import useIsMobile from "../is-mobile"; +import { exportToSvg } from "../scene/export"; import { LibraryItem } from "../types"; -import { MIME_TYPES } from "../constants"; +import "./LibraryUnit.scss"; // fa-plus const PLUS_ICON = ( @@ -38,7 +38,7 @@ export const LibraryUnit = ({ } const svg = exportToSvg(elementsToRender, { exportBackground: false, - viewBackgroundColor: "#fff", + viewBackgroundColor: oc.white, shouldAddWatermark: false, }); for (const child of ref.current!.children) { diff --git a/src/components/MobileMenu.tsx b/src/components/MobileMenu.tsx index bf6b2093..bf5425ff 100644 --- a/src/components/MobileMenu.tsx +++ b/src/components/MobileMenu.tsx @@ -15,7 +15,6 @@ import { Section } from "./Section"; import CollabButton from "./CollabButton"; import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars"; import { LockIcon } from "./LockIcon"; -import { LoadingMessage } from "./LoadingMessage"; import { UserList } from "./UserList"; import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle"; import { EVENT_ACTION, trackEvent } from "../analytics"; @@ -46,7 +45,6 @@ export const MobileMenu = ({ isCollaborating, }: MobileMenuProps) => ( <> - {appState.isLoading && }
{(heading) => ( diff --git a/src/components/PasteChartDialog.scss b/src/components/PasteChartDialog.scss new file mode 100644 index 00000000..6d28f8a3 --- /dev/null +++ b/src/components/PasteChartDialog.scss @@ -0,0 +1,46 @@ +@import "../css/_variables"; + +.excalidraw { + .PasteChartDialog { + @media #{$media-query} { + .Island { + display: flex; + flex-direction: column; + } + } + .container { + display: flex; + align-items: center; + justify-content: space-around; + flex-wrap: wrap; + @media #{$media-query} { + flex-direction: column; + justify-content: center; + } + } + .ChartPreview { + margin: 8px; + text-align: center; + width: 192px; + height: 128px; + border-radius: 2px; + padding: 1px; + border: 1px solid $oc-gray-4; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + div { + display: inline-block; + } + svg { + max-height: 120px; + max-width: 186px; + } + &:hover { + padding: 0; + border: 2px solid $oc-blue-5; + } + } + } +} diff --git a/src/components/PasteChartDialog.tsx b/src/components/PasteChartDialog.tsx new file mode 100644 index 00000000..5b82e4d4 --- /dev/null +++ b/src/components/PasteChartDialog.tsx @@ -0,0 +1,121 @@ +import oc from "open-color"; +import React, { useLayoutEffect, useRef, useState } from "react"; +import { ChartElements, renderSpreadsheet, Spreadsheet } from "../charts"; +import { ChartType } from "../element/types"; +import { exportToSvg } from "../scene/export"; +import { AppState, LibraryItem } from "../types"; +import { Dialog } from "./Dialog"; +import "./PasteChartDialog.scss"; + +type OnInsertChart = (chartType: ChartType, elements: ChartElements) => void; + +const ChartPreviewBtn = (props: { + spreadsheet: Spreadsheet | null; + chartType: ChartType; + selected: boolean; + onClick: OnInsertChart; +}) => { + const previewRef = useRef(null); + const [chartElements, setChartElements] = useState( + null, + ); + + useLayoutEffect(() => { + if (!props.spreadsheet) { + return; + } + + const elements = renderSpreadsheet( + props.chartType, + props.spreadsheet, + 0, + 0, + ); + setChartElements(elements); + + const svg = exportToSvg(elements, { + exportBackground: false, + viewBackgroundColor: oc.white, + shouldAddWatermark: false, + }); + + const previewNode = previewRef.current!; + + previewNode.appendChild(svg); + + if (props.selected) { + (previewNode.parentNode as HTMLDivElement).focus(); + } + + return () => { + previewNode.removeChild(svg); + }; + }, [props.spreadsheet, props.chartType, props.selected]); + + return ( + + ); +}; + +export const PasteChartDialog = ({ + setAppState, + appState, + onClose, + onInsertChart, +}: { + appState: AppState; + onClose: () => void; + setAppState: React.Component["setState"]; + onInsertChart: (elements: LibraryItem) => void; +}) => { + const handleClose = React.useCallback(() => { + if (onClose) { + onClose(); + } + }, [onClose]); + + const handleChartClick = (chartType: ChartType, elements: ChartElements) => { + onInsertChart(elements); + setAppState({ + currentChartType: chartType, + pasteDialog: { + shown: false, + data: null, + }, + }); + }; + + return ( + +
+ + +
+
+ ); +}; diff --git a/src/components/Stats.tsx b/src/components/Stats.tsx index c8acdd07..3780691e 100644 --- a/src/components/Stats.tsx +++ b/src/components/Stats.tsx @@ -85,7 +85,6 @@ export const Stats = (props: { {t("stats.total")} {nFormatter(storageSizes.total, 1)} - {selectedElements.length === 1 && ( {t("stats.element")} diff --git a/src/element/types.ts b/src/element/types.ts index 2980263b..8a7b26ec 100644 --- a/src/element/types.ts +++ b/src/element/types.ts @@ -1,6 +1,7 @@ import { Point } from "../types"; import { FONT_FAMILY } from "../constants"; +export type ChartType = "bar" | "line"; export type FillStyle = "hachure" | "cross-hatch" | "solid"; export type FontFamily = keyof typeof FONT_FAMILY; export type FontString = string & { _brand: "fontString" }; diff --git a/src/locales/en.json b/src/locales/en.json index 6f16fc98..49711314 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -90,7 +90,9 @@ "centerVertically": "Center vertically", "centerHorizontally": "Center horizontally", "distributeHorizontally": "Distribute horizontally", - "distributeVertically": "Distribute vertically" + "distributeVertically": "Distribute vertically", + "chartTypeBar": "Bar", + "chartTypeLine": "Line" }, "buttons": { "clearReset": "Reset the canvas", @@ -222,6 +224,8 @@ }, "stats": { "angle": "Angle", + "charts": "Charts", + "current": "Current", "element": "Element", "elements": "Elements", "height": "Height", diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index 0f5db1c9..8513b0e4 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -4,6 +4,7 @@ exports[`given element A and group of elements B and given both are selected whe Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -42,6 +43,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -457,6 +462,7 @@ exports[`given element A and group of elements B and given both are selected whe Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -495,6 +501,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -916,6 +926,7 @@ exports[`regression tests Cmd/Ctrl-click exclusively select element under pointe Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -954,6 +965,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -1684,6 +1699,7 @@ exports[`regression tests Drags selected element when hitting only bounding box Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -1722,6 +1738,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -1880,6 +1900,7 @@ exports[`regression tests adjusts z order when grouping: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -1918,6 +1939,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id3": true, @@ -2330,6 +2355,7 @@ exports[`regression tests alt-drag duplicates an element: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -2368,6 +2394,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -2575,6 +2605,7 @@ exports[`regression tests arrow keys: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -2613,6 +2644,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -2731,6 +2766,7 @@ exports[`regression tests can drag element that covers another element, while an Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -2769,6 +2805,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id2": true, }, @@ -3200,6 +3240,7 @@ exports[`regression tests change the properties of a shape: [end of test] appSta Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3238,6 +3279,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -3500,6 +3545,7 @@ exports[`regression tests click on an element and drag it: [dragged] appState 1` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3538,6 +3584,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -3696,6 +3746,7 @@ exports[`regression tests click on an element and drag it: [end of test] appStat Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3734,6 +3785,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -3932,6 +3987,7 @@ exports[`regression tests click to select a shape: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3970,6 +4026,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -4176,6 +4236,7 @@ exports[`regression tests click-drag to select a group: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -4214,6 +4275,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id2": true, }, @@ -4529,6 +4594,7 @@ exports[`regression tests deselects group of selected elements on pointer down w Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -4589,6 +4655,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -4816,6 +4886,7 @@ exports[`regression tests deselects group of selected elements on pointer up whe Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -4876,6 +4947,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -5115,6 +5190,7 @@ exports[`regression tests deselects selected element on pointer down when pointe Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -5175,6 +5251,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -5315,6 +5395,7 @@ exports[`regression tests deselects selected element, on pointer up, when click Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -5375,6 +5456,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -5493,6 +5578,7 @@ exports[`regression tests double click to edit a group: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -5531,6 +5617,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -5938,6 +6028,7 @@ exports[`regression tests drags selected elements from point inside common bound Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -5976,6 +6067,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -6248,6 +6343,7 @@ exports[`regression tests draw every type of shape: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -6286,6 +6382,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -8274,6 +8374,7 @@ exports[`regression tests given a group of selected elements with an element tha Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -8312,6 +8413,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -8628,6 +8733,7 @@ exports[`regression tests given a selected element A and a not selected element Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -8666,6 +8772,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -8875,6 +8985,7 @@ exports[`regression tests given selected element A with lower z-index than unsel Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -8913,6 +9024,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -9120,6 +9235,7 @@ exports[`regression tests given selected element A with lower z-index than unsel Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9158,6 +9274,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -9427,6 +9547,7 @@ exports[`regression tests key 2 selects rectangle tool: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9465,6 +9586,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -9583,6 +9708,7 @@ exports[`regression tests key 3 selects diamond tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9621,6 +9747,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -9739,6 +9869,7 @@ exports[`regression tests key 4 selects ellipse tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9777,6 +9908,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -9895,6 +10030,7 @@ exports[`regression tests key 5 selects arrow tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9933,6 +10069,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10081,6 +10221,7 @@ exports[`regression tests key 6 selects line tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10119,6 +10260,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10267,6 +10412,7 @@ exports[`regression tests key 7 selects draw tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10305,6 +10451,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10453,6 +10603,7 @@ exports[`regression tests key a selects arrow tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10491,6 +10642,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10639,6 +10794,7 @@ exports[`regression tests key d selects diamond tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10677,6 +10833,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10795,6 +10955,7 @@ exports[`regression tests key e selects ellipse tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10833,6 +10994,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10951,6 +11116,7 @@ exports[`regression tests key l selects line tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10989,6 +11155,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -11137,6 +11307,7 @@ exports[`regression tests key r selects rectangle tool: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -11175,6 +11346,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -11293,6 +11468,7 @@ exports[`regression tests key x selects draw tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -11331,6 +11507,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -11479,6 +11659,7 @@ exports[`regression tests make a group and duplicate it: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -11517,6 +11698,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -12187,6 +12372,7 @@ exports[`regression tests noop interaction after undo shouldn't create history e Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12225,6 +12411,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id3": true, @@ -12432,6 +12622,7 @@ exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12470,6 +12661,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": -6, @@ -12526,6 +12721,7 @@ exports[`regression tests rerenders UI on language change: [end of test] appStat Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12564,6 +12760,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -12618,6 +12818,7 @@ exports[`regression tests selecting 'Add to library' in context menu adds elemen Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12656,6 +12857,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -12774,6 +12979,7 @@ exports[`regression tests selecting 'Bring forward' in context menu brings eleme Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12812,6 +13018,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13074,6 +13284,7 @@ exports[`regression tests selecting 'Bring to front' in context menu brings elem Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13112,6 +13323,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13374,6 +13589,7 @@ exports[`regression tests selecting 'Copy styles' in context menu copies styles: Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13412,6 +13628,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13530,6 +13750,7 @@ exports[`regression tests selecting 'Delete' in context menu deletes element: [e Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13568,6 +13789,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13718,6 +13943,7 @@ exports[`regression tests selecting 'Duplicate' in context menu duplicates eleme Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13756,6 +13982,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13959,6 +14189,7 @@ exports[`regression tests selecting 'Group selection' in context menu groups sel Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13997,6 +14228,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -14275,6 +14510,7 @@ exports[`regression tests selecting 'Paste styles' in context menu pastes styles Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#e64980", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "cross-hatch", @@ -14313,6 +14549,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -15106,6 +15346,7 @@ exports[`regression tests selecting 'Send backward' in context menu sends elemen Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -15144,6 +15385,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -15406,6 +15651,7 @@ exports[`regression tests selecting 'Send to back' in context menu sends element Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -15444,6 +15690,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -15706,6 +15956,7 @@ exports[`regression tests selecting 'Ungroup selection' in context menu ungroups Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -15744,6 +15995,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -16077,6 +16332,7 @@ exports[`regression tests shift click on selected element should deselect it on Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16115,6 +16371,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -16236,6 +16496,7 @@ exports[`regression tests shift-click to multiselect, then drag: [end of test] a Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16274,6 +16535,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -16549,6 +16814,7 @@ exports[`regression tests should show fill icons when element has non transparen Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16587,6 +16853,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -16780,6 +17050,7 @@ exports[`regression tests shows 'Group selection' in context menu for multiple s Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16818,6 +17089,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -17027,6 +17302,7 @@ exports[`regression tests shows 'Ungroup selection' in context menu for group in Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17065,6 +17341,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -17346,6 +17626,7 @@ exports[`regression tests shows context menu for canvas: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17384,6 +17665,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -17438,6 +17723,7 @@ exports[`regression tests shows context menu for element: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17476,6 +17762,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -17594,6 +17884,7 @@ exports[`regression tests single-clicking on a subgroup of a selected group shou Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17632,6 +17923,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -18407,6 +18702,7 @@ exports[`regression tests spacebar + drag scrolls the canvas: [end of test] appS Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -18445,6 +18741,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 60, @@ -18499,6 +18799,7 @@ exports[`regression tests supports nested groups: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -18537,6 +18838,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -19223,6 +19528,7 @@ exports[`regression tests switches from group of selected elements to another el Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -19283,6 +19589,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, "id2": true, @@ -19620,6 +19930,7 @@ exports[`regression tests switches selected element on pointer down: [end of tes Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -19680,6 +19991,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -19907,6 +20222,7 @@ exports[`regression tests two-finger scroll works: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -19945,6 +20261,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 11, @@ -20001,6 +20321,7 @@ exports[`regression tests undo/redo drawing an element: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -20039,6 +20360,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -20491,6 +20816,7 @@ exports[`regression tests updates fontSize & fontFamily appState: [end of test] Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -20529,6 +20855,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -20583,6 +20913,7 @@ exports[`regression tests zoom hotkeys: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -20621,6 +20952,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, diff --git a/src/types.ts b/src/types.ts index 6161bf88..5d4485bc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,6 +9,7 @@ import { GroupId, ExcalidrawBindableElement, Arrowhead, + ChartType, } from "./element/types"; import { SHAPES } from "./shapes"; import { Point as RoughPoint } from "roughjs/bin/geometry"; @@ -17,6 +18,7 @@ import { SuggestedBinding } from "./element/binding"; import { ImportedDataState } from "./data/types"; import { ExcalidrawImperativeAPI } from "./components/App"; import type { ResolvablePromise } from "./utils"; +import { Spreadsheet } from "./charts"; export type FlooredNumber = number & { _brand: "FlooredNumber" }; export type Point = Readonly; @@ -97,6 +99,16 @@ export type AppState = { fileHandle: import("browser-nativefs").FileSystemHandle | null; collaborators: Map; showStats: boolean; + currentChartType: ChartType; + pasteDialog: + | { + shown: false; + data: null; + } + | { + shown: true; + data: Spreadsheet; + }; }; export type NormalizedZoomValue = number & { _brand: "normalizedZoom" };