purify getDefaultAppState by removing name

This commit is contained in:
dwelle 2021-01-03 23:46:18 +01:00
parent ade2565f49
commit fe973e3513
10 changed files with 38 additions and 12 deletions

View File

@ -15,7 +15,7 @@ import { getNormalizedZoom, getSelectedElements } from "../scene";
import { centerScrollOn } from "../scene/scroll"; import { centerScrollOn } from "../scene/scroll";
import { getNewZoom } from "../scene/zoom"; import { getNewZoom } from "../scene/zoom";
import { AppState, NormalizedZoomValue } from "../types"; import { AppState, NormalizedZoomValue } from "../types";
import { getShortcutKey } from "../utils"; import { getNewSceneName, getShortcutKey } from "../utils";
import { register } from "./register"; import { register } from "./register";
export const actionChangeViewBackgroundColor = register({ export const actionChangeViewBackgroundColor = register({
@ -59,6 +59,7 @@ export const actionClearCanvas = register({
), ),
appState: { appState: {
...getDefaultAppState(), ...getDefaultAppState(),
name: getNewSceneName(),
appearance: appState.appearance, appearance: appState.appearance,
elementLocked: appState.elementLocked, elementLocked: appState.elementLocked,
exportBackground: appState.exportBackground, exportBackground: appState.exportBackground,

View File

@ -12,6 +12,7 @@ import { KEYS } from "../keys";
import { muteFSAbortError } from "../utils"; import { muteFSAbortError } from "../utils";
import { register } from "./register"; import { register } from "./register";
import "../components/ToolIcon.scss"; import "../components/ToolIcon.scss";
import { SCENE_NAME_FALLBACK } from "../constants";
export const actionChangeProjectName = register({ export const actionChangeProjectName = register({
name: "changeProjectName", name: "changeProjectName",
@ -22,7 +23,7 @@ export const actionChangeProjectName = register({
PanelComponent: ({ appState, updateData }) => ( PanelComponent: ({ appState, updateData }) => (
<ProjectName <ProjectName
label={t("labels.fileTitle")} label={t("labels.fileTitle")}
value={appState.name || "Unnamed"} value={appState.name || SCENE_NAME_FALLBACK}
onChange={(name: string) => updateData(name)} onChange={(name: string) => updateData(name)}
/> />
), ),

View File

@ -2,16 +2,20 @@ import oc from "open-color";
import { import {
DEFAULT_FONT_FAMILY, DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE,
SCENE_NAME_FALLBACK,
DEFAULT_TEXT_ALIGN, DEFAULT_TEXT_ALIGN,
} from "./constants"; } from "./constants";
import { t } from "./i18n";
import { AppState, FlooredNumber, NormalizedZoomValue } from "./types"; import { AppState, FlooredNumber, NormalizedZoomValue } from "./types";
import { getDateTime } from "./utils";
export const getDefaultAppState = (): Omit< type DefaultAppState = Omit<AppState, "offsetTop" | "offsetLeft" | "name"> & {
AppState, /**
"offsetTop" | "offsetLeft" * You should override this with current appState.name, or whatever is
> => { * applicable at a given place where you get default appState.
*/
name: undefined;
};
export const getDefaultAppState = (): DefaultAppState => {
return { return {
appearance: "light", appearance: "light",
collaborators: new Map(), collaborators: new Map(),
@ -50,7 +54,11 @@ export const getDefaultAppState = (): Omit<
isRotating: false, isRotating: false,
lastPointerDownWith: "mouse", lastPointerDownWith: "mouse",
multiElement: null, multiElement: null,
name: `${t("labels.untitled")}-${getDateTime()}`, // for safety (because TS mostly doesn't distinguish optional types and
// undefined values), we set `name` to the fallback name, but we cast it to
// `undefined` so that TS forces us to explicitly specify it wherever
// possible
name: (SCENE_NAME_FALLBACK as unknown) as undefined,
openMenu: null, openMenu: null,
pasteDialog: { shown: false, data: null }, pasteDialog: { shown: false, data: null },
previousSelectedElementIds: {}, previousSelectedElementIds: {},

View File

@ -148,6 +148,7 @@ import {
import { import {
debounce, debounce,
distance, distance,
getNewSceneName,
isInputLike, isInputLike,
isToolIcon, isToolIcon,
isWritableElement, isWritableElement,
@ -281,6 +282,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
} = props; } = props;
this.state = { this.state = {
...defaultAppState, ...defaultAppState,
name: getNewSceneName(),
isLoading: true, isLoading: true,
width, width,
height, height,
@ -528,6 +530,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this.scene.replaceAllElements([]); this.scene.replaceAllElements([]);
this.setState((state) => ({ this.setState((state) => ({
...getDefaultAppState(), ...getDefaultAppState(),
name: getNewSceneName(),
isLoading: opts?.resetLoadingState ? false : state.isLoading, isLoading: opts?.resetLoadingState ? false : state.isLoading,
appearance: this.state.appearance, appearance: this.state.appearance,
})); }));

View File

@ -88,3 +88,5 @@ export const STORAGE_KEYS = {
export const TAP_TWICE_TIMEOUT = 300; export const TAP_TWICE_TIMEOUT = 300;
export const TOUCH_CTX_MENU_TIMEOUT = 500; export const TOUCH_CTX_MENU_TIMEOUT = 500;
export const TITLE_TIMEOUT = 10000; export const TITLE_TIMEOUT = 10000;
export const SCENE_NAME_FALLBACK = "Untitled";

View File

@ -15,6 +15,7 @@ import {
DEFAULT_VERTICAL_ALIGN, DEFAULT_VERTICAL_ALIGN,
} from "../constants"; } from "../constants";
import { getDefaultAppState } from "../appState"; import { getDefaultAppState } from "../appState";
import { getNewSceneName } from "../utils";
const getFontFamilyByName = (fontFamilyName: string): FontFamily => { const getFontFamilyByName = (fontFamilyName: string): FontFamily => {
for (const [id, fontFamilyString] of Object.entries(FONT_FAMILY)) { for (const [id, fontFamilyString] of Object.entries(FONT_FAMILY)) {
@ -166,6 +167,7 @@ const restoreAppState = (
return { return {
...nextAppState, ...nextAppState,
name: appState.name ?? localAppState?.name ?? getNewSceneName(),
offsetLeft: appState.offsetLeft || 0, offsetLeft: appState.offsetLeft || 0,
offsetTop: appState.offsetTop || 0, offsetTop: appState.offsetTop || 0,
// Migrates from previous version where appState.zoom was a number // Migrates from previous version where appState.zoom was a number

View File

@ -6,6 +6,7 @@ import {
} from "../../appState"; } from "../../appState";
import { clearElementsForLocalStorage } from "../../element"; import { clearElementsForLocalStorage } from "../../element";
import { STORAGE_KEYS as APP_STORAGE_KEYS } from "../../constants"; import { STORAGE_KEYS as APP_STORAGE_KEYS } from "../../constants";
import { ImportedDataState } from "../../data/types";
export const STORAGE_KEYS = { export const STORAGE_KEYS = {
LOCAL_STORAGE_ELEMENTS: "excalidraw", LOCAL_STORAGE_ELEMENTS: "excalidraw",
@ -81,7 +82,7 @@ export const importFromLocalStorage = () => {
} }
} }
let appState = null; let appState: ImportedDataState["appState"] = null;
if (savedState) { if (savedState) {
try { try {
appState = { appState = {

View File

@ -1,5 +1,6 @@
import { exportToCanvas } from "./scene/export"; import { exportToCanvas } from "./scene/export";
import { getDefaultAppState } from "./appState"; import { getDefaultAppState } from "./appState";
import { SCENE_NAME_FALLBACK } from "./constants";
const { registerFont, createCanvas } = require("canvas"); const { registerFont, createCanvas } = require("canvas");
@ -61,6 +62,7 @@ const canvas = exportToCanvas(
elements as any, elements as any,
{ {
...getDefaultAppState(), ...getDefaultAppState(),
name: SCENE_NAME_FALLBACK,
offsetTop: 0, offsetTop: 0,
offsetLeft: 0, offsetLeft: 0,
}, },

View File

@ -6,6 +6,7 @@ import { getDefaultAppState } from "../appState";
import { AppState } from "../types"; import { AppState } from "../types";
import { ExcalidrawElement } from "../element/types"; import { ExcalidrawElement } from "../element/types";
import { getNonDeletedElements } from "../element"; import { getNonDeletedElements } from "../element";
import { SCENE_NAME_FALLBACK } from "../constants";
type ExportOpts = { type ExportOpts = {
elements: readonly ExcalidrawElement[]; elements: readonly ExcalidrawElement[];
@ -18,7 +19,7 @@ type ExportOpts = {
export const exportToCanvas = ({ export const exportToCanvas = ({
elements, elements,
appState = getDefaultAppState(), appState = { ...getDefaultAppState(), name: SCENE_NAME_FALLBACK },
getDimensions = (width, height) => ({ width, height, scale: 1 }), getDimensions = (width, height) => ({ width, height, scale: 1 }),
}: ExportOpts) => { }: ExportOpts) => {
return _exportToCanvas( return _exportToCanvas(
@ -74,7 +75,7 @@ export const exportToBlob = (
export const exportToSvg = ({ export const exportToSvg = ({
elements, elements,
appState = getDefaultAppState(), appState = { ...getDefaultAppState(), name: SCENE_NAME_FALLBACK },
exportPadding, exportPadding,
metadata, metadata,
}: ExportOpts & { }: ExportOpts & {

View File

@ -8,6 +8,7 @@ import { FontFamily, FontString } from "./element/types";
import { Zoom } from "./types"; import { Zoom } from "./types";
import { unstable_batchedUpdates } from "react-dom"; import { unstable_batchedUpdates } from "react-dom";
import { isDarwin } from "./keys"; import { isDarwin } from "./keys";
import { t } from "./i18n";
export const SVG_NS = "http://www.w3.org/2000/svg"; export const SVG_NS = "http://www.w3.org/2000/svg";
@ -32,6 +33,10 @@ export const getDateTime = () => {
return `${year}-${month}-${day}-${hr}${min}`; return `${year}-${month}-${day}-${hr}${min}`;
}; };
export const getNewSceneName = () => {
return `${t("labels.untitled")}-${getDateTime()}`;
};
export const capitalizeString = (str: string) => export const capitalizeString = (str: string) =>
str.charAt(0).toUpperCase() + str.slice(1); str.charAt(0).toUpperCase() + str.slice(1);