schema: add payload schemaVersion plumbing

This commit is contained in:
Ryan Di
2026-03-20 00:26:08 +11:00
parent d1cbab855d
commit 7b51a6ac54
5 changed files with 20 additions and 2 deletions
+10 -1
View File
@@ -40,9 +40,11 @@ import type { FileSystemHandle } from "./data/filesystem";
import type { Spreadsheet } from "./charts";
import type { BinaryFiles } from "./types";
import { SCHEMA_VERSIONS } from "./data/schema";
type ElementsClipboard = {
type: typeof EXPORT_DATA_TYPES.excalidrawClipboard;
schemaVersion: number;
elements: readonly NonDeletedExcalidrawElement[];
files: BinaryFiles | undefined;
};
@@ -53,6 +55,7 @@ export interface ClipboardData {
spreadsheet?: Spreadsheet;
elements?: readonly ExcalidrawElement[];
files?: BinaryFiles;
schemaVersion?: number;
text?: string;
mixedContent?: PastedMixedContent;
errorMessage?: string;
@@ -79,7 +82,11 @@ export const probablySupportsClipboardBlob =
const clipboardContainsElements = (
contents: any,
): contents is { elements: ExcalidrawElement[]; files?: BinaryFiles } => {
): contents is {
elements: ExcalidrawElement[];
files?: BinaryFiles;
schemaVersion?: number;
} => {
if (
[
EXPORT_DATA_TYPES.excalidraw,
@@ -178,6 +185,7 @@ export const serializeAsClipboardJSON = ({
// select bound text elements when copying
const contents: ElementsClipboard = {
type: EXPORT_DATA_TYPES.excalidrawClipboard,
schemaVersion: SCHEMA_VERSIONS.latest,
elements: elements.map((element) => {
if (
getContainingFrame(element, elementsMap) &&
@@ -572,6 +580,7 @@ export const parseClipboard = async (
return {
elements: systemClipboardData.elements,
files: systemClipboardData.files,
schemaVersion: systemClipboardData.schemaVersion,
text: isPlainPaste
? JSON.stringify(systemClipboardData.elements, null, 2)
: undefined,
+2
View File
@@ -12,6 +12,7 @@ import { cleanAppStateForExport, clearAppStateForDatabase } from "../appState";
import { isImageFileHandle, loadFromBlob } from "./blob";
import { fileOpen, fileSave } from "./filesystem";
import { SCHEMA_VERSIONS } from "./schema";
import type { AppState, BinaryFiles, LibraryItems } from "../types";
import type {
@@ -51,6 +52,7 @@ export const serializeAsJSON = (
const data: ExportedDataState = {
type: EXPORT_DATA_TYPES.excalidraw,
version: VERSIONS.excalidraw,
schemaVersion: SCHEMA_VERSIONS.latest,
source: getExportSource(),
elements,
appState:
+5
View File
@@ -0,0 +1,5 @@
export const SCHEMA_VERSIONS = {
initial: 1,
latest: 2,
} as const;
+2
View File
@@ -14,6 +14,7 @@ import type {
export interface ExportedDataState {
type: string;
version: number;
schemaVersion: number;
source: string;
elements: readonly ExcalidrawElement[];
appState: ReturnType<typeof cleanAppStateForExport>;
@@ -35,6 +36,7 @@ export type LegacyAppState = {
export interface ImportedDataState {
type?: string;
version?: number;
schemaVersion?: number;
source?: string;
elements?: readonly ExcalidrawElement[] | null;
appState?: Readonly<
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`export > export svg-embedded scene > svg-embdedded scene export output 1`] = `
"<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="36" height="36"><!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nHVTS27bMFx1MDAxMN33XHUwMDE0grItXHUwMDEy2UW68C7NXHUwMDA3zVwiXdRcdTAwMDW6KLpgxLE0ME1cdTAwMTLkKLZrXHUwMDE4yDG661x1MDAxNXOEXGZpVTTlRFx1MDAwMlxi8M3vzZvh7kNRlLS1UM6KXHUwMDEyNrVQKJ1Yl1x1MDAxZlx1MDAwM/5cdTAwMDTOo9Fsmsa7N52ro2dLZGdcdTAwMTdcdTAwMTfKcEBrPM0+VVV1XGJcdTAwMDJcdTAwMDUr0OTZ7Vx1MDAxN9+LYlx1MDAxN0+2oFxmoVfRLVx1MDAwMv/rXHUwMDEybCihXHUwMDFihqrhts1ua5TUMjL5PEAtYNNSjlx03SjIXHUwMDAyPTmzhGujjFx1MDAwYlx1MDAxNc8mXHUwMDEw/lT0UdTLxplOy8GHnNDeXG7HzSS/XHUwMDA1KjWnbczOerBa5ajGz57idIS/XHUwMDE3xUWbVoNcdTAwMGaCTVx1MDAwNtRYUSOF5idV6lwiMLT3Mmr7O3FyYlx1MDAwNfdBXFzdKTXAqCVsxmBssa+WXHUwMDE5PIDMXHUwMDE4pOGfYN+MrnN50d/w3CmmWFxi5SFcdFx1MDAxYlxu3qadyIp2VlxuXHUwMDFh1VWol2M/3rPlXHUwMDFiuePesKIv//4+XHUwMDFmjchomuOfQHBaZeidWKFcbppeZimuXHUwMDE0NqHPUsHiaNTcLCHv92AmY5O15nxcdTAwMDI1uFPhjcNcdTAwMDa1UD/epCc6Mt/BXHUwMDFmXGKS6+C4c/g6bPP59DJcdTAwMWH2fMZZl8LaObFebD28Kd5cdTAwMDeUo1ZcdTAwMGZcdTAwMTiBTW1G6MFIuNXiUY11LJ9cdTAwMTDWX07X/2xcdTAwMTG/nng/godOXHUwMDExznnUNfFcdTAwMWWEee5cdTAwMDK/feTHb1x1MDAwM3po/1xua2IoWiJ9<!-- payload-end --></metadata><defs><style class="style-fonts">
"<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="36" height="36"><!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nHVTTW/bMFxmve9XXHUwMDE47rVYnVx1MDAxNN0ht35ccuuhOyzDdlx1MDAxOHZQLcYmokiCRDfJglx1MDAwMPtcdTAwMTm77S/uJ4xSXFwrclpcdTAwMWIwoEeKfHx83r0ripK2XHUwMDE2yllRwqZcdTAwMTZcbqVcdTAwMTPr8jzgz+A8XHUwMDFhzaFpPPu6hZX4NkZN5+p4vyWys4tcdTAwMGJluExrPM0uq6o6lFx1MDAwMlx1MDAwNSvQ5DntXHUwMDA3n4tiXHUwMDE3v1x1MDAxY0FcdTAwMTmuXse0XGK8sCHYUEI3XGZVw2mbndYoqWVk8mGAWsCmpVx1MDAxY1x1MDAxM7pRkF305MxcdTAwMTJujTIudDybQHhT0ydRL1x1MDAxYmc6LYdcdTAwMWNyQnsrXHUwMDFjXHUwMDBmk/JcdTAwMTao1Jy2sTrrwVx1MDAxYZajXHUwMDFl33uK01x1MDAxMf7WLW7atFx1MDAxYXxcdTAwMTBsMqDGilx1MDAxYSlcZj+p0lx1MDAxNIGhfZBR25+Jk1x1MDAxMyt4XGLi6k6pXHUwMDAxRi1hM1x1MDAwNuOIfbcs4Fx1MDAwMWTGIFniXHUwMDA0+2x0ncuL/o73TrHEQihcdTAwMGZJ2NDwPnlcImvaWSlo1FehXo7z2GfLV2pH37Ci//7++X20XCKjaY6/XHUwMDAywWmVoVx1MDAxZsVcblXQ9Corca2wXHRzllxuXHUwMDE2R6vmYVx02d9DmIxN0ZrrXHTU4E6FN1x1MDAwZVx1MDAxYtRCfX2VnujIfFx1MDAwMX8gSK6D48nh0+Dm99OrXHUwMDE42PM37rpcdTAwMTTWzon14ujhn2I/oFx1MDAxY416wFxibFx1MDAxYTNCj0bCvVx1MDAxNk9qrGP5jLC+ObX/2VwiPj3xflx1MDAwNY+dXCKc86prYlx1MDAxZoR97lx1MDAwMr995Mf/XHUwMDA29ND+P2sqLvcifQ==<!-- payload-end --></metadata><defs><style class="style-fonts">
</style></defs><rect x="0" y="0" width="36" height="36" fill="#ffffff"></rect><g transform="translate(10 10) rotate(0 8 8)" data-id="A"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">😀</text></g></svg>"
`;