UNPKG

@testbank-inc/excalidraw

Version:
1,344 lines (1,264 loc) 302 kB
import { define_import_meta_env_default } from "./chunk-LDSNT77A.js"; import { __publicField } from "./chunk-XDFCUUT6.js"; // data/image.ts import tEXt from "png-chunk-text"; import encodePng from "png-chunks-encode"; import decodePng from "png-chunks-extract"; import { EXPORT_DATA_TYPES as EXPORT_DATA_TYPES3, MIME_TYPES as MIME_TYPES7 } from "@testbank-inc/common"; // data/blob.ts import { nanoid } from "nanoid"; import { IMAGE_MIME_TYPES, MIME_TYPES as MIME_TYPES6, bytesToHexString, isPromiseLike } from "@testbank-inc/common"; import { clearElementsForExport as clearElementsForExport2 } from "@testbank-inc/element"; // appState.ts import { COLOR_PALETTE, ARROW_TYPE, DEFAULT_ELEMENT_PROPS, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_TEXT_ALIGN, DEFAULT_GRID_SIZE, EXPORT_SCALES, STATS_PANELS, THEME, DEFAULT_GRID_STEP, isTestEnv } from "@testbank-inc/common"; var defaultExportScale = EXPORT_SCALES.includes(devicePixelRatio) ? devicePixelRatio : 1; var getDefaultAppState = () => { return { showWelcomeScreen: false, theme: THEME.LIGHT, collaborators: /* @__PURE__ */ new Map(), currentChartType: "bar", currentItemBackgroundColor: DEFAULT_ELEMENT_PROPS.backgroundColor, currentItemEndArrowhead: "arrow", currentItemFillStyle: DEFAULT_ELEMENT_PROPS.fillStyle, currentItemFontFamily: DEFAULT_FONT_FAMILY, currentItemFontSize: DEFAULT_FONT_SIZE, currentItemOpacity: DEFAULT_ELEMENT_PROPS.opacity, currentItemRoughness: DEFAULT_ELEMENT_PROPS.roughness, currentItemStartArrowhead: null, currentItemStrokeColor: DEFAULT_ELEMENT_PROPS.strokeColor, currentItemRoundness: isTestEnv() ? "sharp" : "round", currentItemArrowType: ARROW_TYPE.round, currentItemStrokeStyle: DEFAULT_ELEMENT_PROPS.strokeStyle, currentItemStrokeWidth: DEFAULT_ELEMENT_PROPS.strokeWidth, currentItemTextAlign: DEFAULT_TEXT_ALIGN, currentHoveredFontFamily: null, cursorButton: "up", activeEmbeddable: null, newElement: null, editingTextElement: null, editingGroupId: null, editingLinearElement: null, activeTool: { type: "selection", customType: null, locked: DEFAULT_ELEMENT_PROPS.locked, fromSelection: false, lastActiveTool: null }, penMode: false, penDetected: false, errorMessage: null, exportBackground: true, exportScale: defaultExportScale, exportEmbedScene: false, exportWithDarkMode: false, fileHandle: null, gridSize: DEFAULT_GRID_SIZE, gridStep: DEFAULT_GRID_STEP, gridModeEnabled: false, isBindingEnabled: true, defaultSidebarDockedPreference: false, isLoading: false, isResizing: false, isRotating: false, lastPointerDownWith: "mouse", multiElement: null, name: null, contextMenu: null, openMenu: null, openPopup: null, openSidebar: null, openDialog: null, pasteDialog: { shown: false, data: null }, previousSelectedElementIds: {}, resizingElement: null, scrolledOutside: false, scrollX: 0, scrollY: 0, selectedElementIds: {}, hoveredElementIds: {}, selectedGroupIds: {}, selectedElementsAreBeingDragged: false, selectionElement: null, shouldCacheIgnoreZoom: false, stats: { open: false, panels: STATS_PANELS.generalStats | STATS_PANELS.elementProperties }, startBoundElement: null, suggestedBindings: [], frameRendering: { enabled: true, clip: true, name: true, outline: true }, frameToHighlight: null, editingFrame: null, elementsToHighlight: null, toast: null, viewBackgroundColor: COLOR_PALETTE.white, zenModeEnabled: false, zoom: { value: 1 }, viewModeEnabled: false, showHyperlinkPopup: false, selectedLinearElement: null, snapLines: [], originSnapOffset: { x: 0, y: 0 }, objectsSnapModeEnabled: false, userToFollow: null, followedBy: /* @__PURE__ */ new Set(), isCropping: false, croppingElementId: null, searchMatches: null, lockedMultiSelections: {}, activeLockedId: null, canvasPageSettings: { enabled: true, width: 794, // A4 width at 96 DPI height: 1123, // A4 height at 96 DPI backgroundColor: "#ffffff", showBorder: true } }; }; var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({ showWelcomeScreen: { browser: true, export: false, server: false }, theme: { browser: true, export: false, server: false }, collaborators: { browser: false, export: false, server: false }, currentChartType: { browser: true, export: false, server: false }, currentItemBackgroundColor: { browser: true, export: false, server: false }, currentItemEndArrowhead: { browser: true, export: false, server: false }, currentItemFillStyle: { browser: true, export: false, server: false }, currentItemFontFamily: { browser: true, export: false, server: false }, currentItemFontSize: { browser: true, export: false, server: false }, currentItemRoundness: { browser: true, export: false, server: false }, currentItemArrowType: { browser: true, export: false, server: false }, currentItemOpacity: { browser: true, export: false, server: false }, currentItemRoughness: { browser: true, export: false, server: false }, currentItemStartArrowhead: { browser: true, export: false, server: false }, currentItemStrokeColor: { browser: true, export: false, server: false }, currentItemStrokeStyle: { browser: true, export: false, server: false }, currentItemStrokeWidth: { browser: true, export: false, server: false }, currentItemTextAlign: { browser: true, export: false, server: false }, currentHoveredFontFamily: { browser: false, export: false, server: false }, cursorButton: { browser: true, export: false, server: false }, activeEmbeddable: { browser: false, export: false, server: false }, newElement: { browser: false, export: false, server: false }, editingTextElement: { browser: false, export: false, server: false }, editingGroupId: { browser: true, export: false, server: false }, editingLinearElement: { browser: false, export: false, server: false }, activeTool: { browser: true, export: false, server: false }, penMode: { browser: true, export: false, server: false }, penDetected: { browser: true, export: false, server: false }, errorMessage: { browser: false, export: false, server: false }, exportBackground: { browser: true, export: false, server: false }, exportEmbedScene: { browser: true, export: false, server: false }, exportScale: { browser: true, export: false, server: false }, exportWithDarkMode: { browser: true, export: false, server: false }, fileHandle: { browser: false, export: false, server: false }, gridSize: { browser: true, export: true, server: true }, gridStep: { browser: true, export: true, server: true }, gridModeEnabled: { browser: true, export: true, server: true }, height: { browser: false, export: false, server: false }, isBindingEnabled: { browser: false, export: false, server: false }, defaultSidebarDockedPreference: { browser: true, export: false, server: false }, isLoading: { browser: false, export: false, server: false }, isResizing: { browser: false, export: false, server: false }, isRotating: { browser: false, export: false, server: false }, lastPointerDownWith: { browser: true, export: false, server: false }, multiElement: { browser: false, export: false, server: false }, name: { browser: true, export: false, server: false }, offsetLeft: { browser: false, export: false, server: false }, offsetTop: { browser: false, export: false, server: false }, contextMenu: { browser: false, export: false, server: false }, openMenu: { browser: true, export: false, server: false }, openPopup: { browser: false, export: false, server: false }, openSidebar: { browser: true, export: false, server: false }, openDialog: { browser: false, export: false, server: false }, pasteDialog: { browser: false, export: false, server: false }, previousSelectedElementIds: { browser: true, export: false, server: false }, resizingElement: { browser: false, export: false, server: false }, scrolledOutside: { browser: true, export: false, server: false }, scrollX: { browser: true, export: false, server: false }, scrollY: { browser: true, export: false, server: false }, selectedElementIds: { browser: true, export: false, server: false }, hoveredElementIds: { browser: false, export: false, server: false }, selectedGroupIds: { browser: true, export: false, server: false }, selectedElementsAreBeingDragged: { browser: false, export: false, server: false }, selectionElement: { browser: false, export: false, server: false }, shouldCacheIgnoreZoom: { browser: true, export: false, server: false }, stats: { browser: true, export: false, server: false }, startBoundElement: { browser: false, export: false, server: false }, suggestedBindings: { browser: false, export: false, server: false }, frameRendering: { browser: false, export: false, server: false }, frameToHighlight: { browser: false, export: false, server: false }, editingFrame: { browser: false, export: false, server: false }, elementsToHighlight: { browser: false, export: false, server: false }, toast: { browser: false, export: false, server: false }, viewBackgroundColor: { browser: true, export: true, server: true }, width: { browser: false, export: false, server: false }, zenModeEnabled: { browser: true, export: false, server: false }, zoom: { browser: true, export: false, server: false }, viewModeEnabled: { browser: false, export: false, server: false }, showHyperlinkPopup: { browser: false, export: false, server: false }, selectedLinearElement: { browser: true, export: false, server: false }, snapLines: { browser: false, export: false, server: false }, originSnapOffset: { browser: false, export: false, server: false }, objectsSnapModeEnabled: { browser: true, export: false, server: false }, userToFollow: { browser: false, export: false, server: false }, followedBy: { browser: false, export: false, server: false }, isCropping: { browser: false, export: false, server: false }, croppingElementId: { browser: false, export: false, server: false }, searchMatches: { browser: false, export: false, server: false }, lockedMultiSelections: { browser: true, export: true, server: true }, activeLockedId: { browser: false, export: false, server: false }, canvasPageSettings: { browser: true, export: true, server: true } }); var _clearAppStateForStorage = (appState, exportType) => { const stateForExport = {}; for (const key of Object.keys(appState)) { const propConfig = APP_STATE_STORAGE_CONF[key]; if (propConfig?.[exportType]) { const nextValue = appState[key]; stateForExport[key] = nextValue; } } return stateForExport; }; var cleanAppStateForExport = (appState) => { return _clearAppStateForStorage(appState, "export"); }; var clearAppStateForDatabase = (appState) => { return _clearAppStateForStorage(appState, "server"); }; var isEraserActive = ({ activeTool }) => activeTool.type === "eraser"; var isHandToolActive = ({ activeTool }) => { return activeTool.type === "hand"; }; // errors.ts var CanvasError = class extends Error { constructor(message = "Couldn't export canvas.", name = "CANVAS_ERROR") { super(); this.name = name; this.message = message; } }; var AbortError = class extends DOMException { constructor(message = "Request Aborted") { super(message, "AbortError"); } }; var ImageSceneDataError = class extends Error { constructor(message = "Image Scene Data Error", code = "IMAGE_SCENE_DATA_ERROR") { super(message); __publicField(this, "code"); this.name = "EncodingError"; this.code = code; } }; var WorkerUrlNotDefinedError = class extends Error { constructor(message = "Worker URL is not defined!", code = "WORKER_URL_NOT_DEFINED") { super(message); __publicField(this, "code"); this.name = "WorkerUrlNotDefinedError"; this.code = code; } }; var WorkerInTheMainChunkError = class extends Error { constructor(message = "Worker has to be in a separate chunk!", code = "WORKER_IN_THE_MAIN_CHUNK") { super(message); __publicField(this, "code"); this.name = "WorkerInTheMainChunkError"; this.code = code; } }; var ExcalidrawError = class extends Error { constructor(message) { super(message); this.name = "ExcalidrawError"; } }; // scene/index.ts import { isSomeElementSelected, getElementsWithinSelection, getSelectedElements, getTargetElements } from "@testbank-inc/element"; // scene/scroll.ts import { getVisibleElements } from "@testbank-inc/element"; import { sceneCoordsToViewportCoords, viewportCoordsToSceneCoords } from "@testbank-inc/common"; import { getClosestElementBounds } from "@testbank-inc/element"; import { getCommonBounds } from "@testbank-inc/element"; var isOutsideViewPort = (appState, cords) => { const [x1, y1, x2, y2] = cords; const { x: viewportX1, y: viewportY1 } = sceneCoordsToViewportCoords( { sceneX: x1, sceneY: y1 }, appState ); const { x: viewportX2, y: viewportY2 } = sceneCoordsToViewportCoords( { sceneX: x2, sceneY: y2 }, appState ); return viewportX2 - viewportX1 > appState.width || viewportY2 - viewportY1 > appState.height; }; var centerScrollOn = ({ scenePoint, viewportDimensions, zoom, offsets }) => { let scrollX = (viewportDimensions.width - (offsets?.right ?? 0)) / 2 / zoom.value - scenePoint.x; scrollX += (offsets?.left ?? 0) / 2 / zoom.value; let scrollY = (viewportDimensions.height - (offsets?.bottom ?? 0)) / 2 / zoom.value - scenePoint.y; scrollY += (offsets?.top ?? 0) / 2 / zoom.value; return { scrollX, scrollY }; }; var calculateScrollCenter = (elements, appState) => { elements = getVisibleElements(elements); if (!elements.length) { return { scrollX: 0, scrollY: 0 }; } let [x1, y1, x2, y2] = getCommonBounds(elements); if (isOutsideViewPort(appState, [x1, y1, x2, y2])) { [x1, y1, x2, y2] = getClosestElementBounds( elements, viewportCoordsToSceneCoords( { clientX: appState.scrollX, clientY: appState.scrollY }, appState ) ); } const centerX = (x1 + x2) / 2; const centerY = (y1 + y2) / 2; return centerScrollOn({ scenePoint: { x: centerX, y: centerY }, viewportDimensions: { width: appState.width, height: appState.height }, zoom: appState.zoom }); }; var constrainScrollToPageBounds = (scrollX, scrollY, appState) => { const { canvasPageSettings, zoom, width, height } = appState; if (!canvasPageSettings?.enabled) { return { scrollX, scrollY }; } const pageWidth = canvasPageSettings.width; const pageHeight = canvasPageSettings.height; const viewportWidth = width / zoom.value; const viewportHeight = height / zoom.value; const maxScrollX = 0; const maxScrollY = 0; const minScrollX = Math.min(0, -(pageWidth - viewportWidth)); const minScrollY = Math.min(0, -(pageHeight - viewportHeight)); return { scrollX: Math.max(minScrollX, Math.min(maxScrollX, scrollX)), scrollY: Math.max(minScrollY, Math.min(maxScrollY, scrollY)) }; }; var constrainZoomForPageBounds = (zoom, appState) => { const { canvasPageSettings, width, height } = appState; if (!canvasPageSettings?.enabled) { return zoom; } const pageWidth = canvasPageSettings.width; const pageHeight = canvasPageSettings.height; const scaleX = width / pageWidth; const scaleY = height / pageHeight; const minZoom = Math.max(scaleX, scaleY); const maxZoom = 5; return Math.max(minZoom, Math.min(maxZoom, zoom)); }; // scene/index.ts import { hasBackground, hasStrokeWidth, hasStrokeStyle, canHaveArrowheads, canChangeRoundness } from "@testbank-inc/element"; // scene/normalize.ts import { MAX_ZOOM, MIN_ZOOM } from "@testbank-inc/common"; import { clamp, round } from "@testbank-inc/math"; var getNormalizedZoom = (zoom) => { return clamp(round(zoom, 6), MIN_ZOOM, MAX_ZOOM); }; var getNormalizedGridSize = (gridStep) => { return clamp(Math.round(gridStep), 1, 100); }; var getNormalizedGridStep = (gridStep) => { return clamp(Math.round(gridStep), 1, 100); }; // scene/export.ts import rough from "roughjs/bin/rough"; import { DEFAULT_EXPORT_PADDING, FRAME_STYLE as FRAME_STYLE3, FONT_FAMILY as FONT_FAMILY2, SVG_NS as SVG_NS2, THEME as THEME3, THEME_FILTER as THEME_FILTER2, MIME_TYPES as MIME_TYPES5, EXPORT_DATA_TYPES as EXPORT_DATA_TYPES2, arrayToMap, distance, getFontString as getFontString2, toBrandedType } from "@testbank-inc/common"; import { getCommonBounds as getCommonBounds2, getElementAbsoluteCoords as getElementAbsoluteCoords4 } from "@testbank-inc/element"; import { getInitializedImageElements, updateImageCache } from "@testbank-inc/element"; import { newElementWith } from "@testbank-inc/element"; import { isFrameLikeElement } from "@testbank-inc/element"; import { getElementsOverlappingFrame, getFrameLikeElements, getFrameLikeTitle, getRootElements } from "@testbank-inc/element"; import { syncInvalidIndices } from "@testbank-inc/element"; import { newTextElement } from "@testbank-inc/element"; // data/encode.ts import { deflate, inflate } from "pako"; // data/encryption.ts import { ENCRYPTION_KEY_BITS } from "@testbank-inc/common"; // data/encode.ts var toByteString = (data) => { const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data instanceof Uint8Array ? data : new Uint8Array(data); let bstring = ""; for (const byte of bytes) { bstring += String.fromCharCode(byte); } return bstring; }; var byteStringToArrayBuffer = (byteString) => { const buffer = new ArrayBuffer(byteString.length); const bufferView = new Uint8Array(buffer); for (let i = 0, len = byteString.length; i < len; i++) { bufferView[i] = byteString.charCodeAt(i); } return buffer; }; var byteStringToString = (byteString) => { return new TextDecoder("utf-8").decode(byteStringToArrayBuffer(byteString)); }; var stringToBase64 = (str, isByteString = false) => { return isByteString ? window.btoa(str) : window.btoa(toByteString(str)); }; var base64ToString = (base64, isByteString = false) => { return isByteString ? window.atob(base64) : byteStringToString(window.atob(base64)); }; var encode = ({ text, compress }) => { let deflated; if (compress !== false) { try { deflated = toByteString(deflate(text)); } catch (error) { console.error("encode: cannot deflate", error); } } return { version: "1", encoding: "bstring", compressed: !!deflated, encoded: deflated || toByteString(text) }; }; var decode = (data) => { let decoded; switch (data.encoding) { case "bstring": decoded = data.compressed ? data.encoded : byteStringToString(data.encoded); break; default: throw new Error(`decode: unknown encoding "${data.encoding}"`); } if (data.compressed) { return inflate(new Uint8Array(byteStringToArrayBuffer(decoded)), { to: "string" }); } return decoded; }; // data/json.ts import { DEFAULT_FILENAME, EXPORT_DATA_TYPES, getExportSource, MIME_TYPES as MIME_TYPES2, VERSIONS } from "@testbank-inc/common"; import { clearElementsForDatabase, clearElementsForExport } from "@testbank-inc/element"; // data/filesystem.ts import { fileOpen as _fileOpen, fileSave as _fileSave, supported as nativeFileSystemSupported } from "browser-fs-access"; import { EVENT, MIME_TYPES, debounce } from "@testbank-inc/common"; var INPUT_CHANGE_INTERVAL_MS = 500; var fileOpen = (opts) => { const mimeTypes = opts.extensions?.reduce((mimeTypes2, type) => { mimeTypes2.push(MIME_TYPES[type]); return mimeTypes2; }, []); const extensions = opts.extensions?.reduce((acc, ext) => { if (ext === "jpg") { return acc.concat(".jpg", ".jpeg"); } return acc.concat(`.${ext}`); }, []); return _fileOpen({ description: opts.description, extensions, mimeTypes, multiple: opts.multiple ?? false, legacySetup: (resolve, reject, input) => { const scheduleRejection = debounce(reject, INPUT_CHANGE_INTERVAL_MS); const focusHandler = () => { checkForFile(); document.addEventListener(EVENT.KEYUP, scheduleRejection); document.addEventListener(EVENT.POINTER_UP, scheduleRejection); scheduleRejection(); }; const checkForFile = () => { if (input.files?.length) { const ret = opts.multiple ? [...input.files] : input.files[0]; resolve(ret); } }; requestAnimationFrame(() => { window.addEventListener(EVENT.FOCUS, focusHandler); }); const interval = window.setInterval(() => { checkForFile(); }, INPUT_CHANGE_INTERVAL_MS); return (rejectPromise) => { clearInterval(interval); scheduleRejection.cancel(); window.removeEventListener(EVENT.FOCUS, focusHandler); document.removeEventListener(EVENT.KEYUP, scheduleRejection); document.removeEventListener(EVENT.POINTER_UP, scheduleRejection); if (rejectPromise) { console.warn("Opening the file was canceled (legacy-fs)."); rejectPromise(new AbortError()); } }; } }); }; var fileSave = (blob, opts) => { return _fileSave( blob, { fileName: `${opts.name}.${opts.extension}`, description: opts.description, extensions: [`.${opts.extension}`], mimeTypes: opts.mimeTypes }, opts.fileHandle ); }; // data/json.ts var filterOutDeletedFiles = (elements, files) => { const nextFiles = {}; for (const element of elements) { if (!element.isDeleted && "fileId" in element && element.fileId && files[element.fileId]) { nextFiles[element.fileId] = files[element.fileId]; } } return nextFiles; }; var serializeAsJSON = (elements, appState, files, type) => { const data = { type: EXPORT_DATA_TYPES.excalidraw, version: VERSIONS.excalidraw, source: getExportSource(), elements: type === "local" ? clearElementsForExport(elements) : clearElementsForDatabase(elements), appState: type === "local" ? cleanAppStateForExport(appState) : clearAppStateForDatabase(appState), files: type === "local" ? filterOutDeletedFiles(elements, files) : ( // will be stripped from JSON void 0 ) }; return JSON.stringify(data, null, 2); }; var saveAsJSON = async (elements, appState, files, name = appState.name || DEFAULT_FILENAME) => { const serialized = serializeAsJSON(elements, appState, files, "local"); const blob = new Blob([serialized], { type: MIME_TYPES2.excalidraw }); const fileHandle = await fileSave(blob, { name, extension: "excalidraw", description: "Excalidraw file", fileHandle: isImageFileHandle(appState.fileHandle) ? null : appState.fileHandle }); return { fileHandle }; }; var loadFromJSON = async (localAppState, localElements) => { const file = await fileOpen({ description: "Excalidraw files" // ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442 // gets resolved. Else, iOS users cannot open `.excalidraw` files. // extensions: ["json", "excalidraw", "png", "svg"], }); return loadFromBlob( await normalizeFile(file), localAppState, localElements, file.handle ); }; var isValidExcalidrawData = (data) => { return data?.type === EXPORT_DATA_TYPES.excalidraw && (!data.elements || Array.isArray(data.elements) && (!data.appState || typeof data.appState === "object")); }; var isValidLibrary = (json) => { return typeof json === "object" && json && json.type === EXPORT_DATA_TYPES.excalidrawLibrary && (json.version === 1 || json.version === 2); }; var serializeLibraryAsJSON = (libraryItems) => { const data = { type: EXPORT_DATA_TYPES.excalidrawLibrary, version: VERSIONS.excalidrawLibrary, source: getExportSource(), libraryItems }; return JSON.stringify(data, null, 2); }; var saveLibraryAsJSON = async (libraryItems) => { const serialized = serializeLibraryAsJSON(libraryItems); await fileSave( new Blob([serialized], { type: MIME_TYPES2.excalidrawlib }), { name: "library", extension: "excalidrawlib", description: "Excalidraw library file" } ); }; // fonts/Fonts.ts import { FONT_FAMILY, FONT_FAMILY_FALLBACKS, CJK_HAND_DRAWN_FALLBACK_FONT, WINDOWS_EMOJI_FALLBACK_FONT, getFontFamilyFallbacks } from "@testbank-inc/common"; import { getContainerElement } from "@testbank-inc/element"; import { charWidth } from "@testbank-inc/element"; import { containsCJK } from "@testbank-inc/element"; import { FONT_METADATA, getFontString, PromisePool, promiseTry as promiseTry3 } from "@testbank-inc/common"; import { ShapeCache } from "@testbank-inc/element"; import { isTextElement } from "@testbank-inc/element"; // fonts/Cascadia/CascadiaCode-Regular.woff2 var CascadiaCode_Regular_default = "./fonts/Cascadia/CascadiaCode-Regular.woff2"; // fonts/Cascadia/index.ts var CascadiaFontFaces = [ { uri: CascadiaCode_Regular_default } ]; // fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 var ComicShanns_Regular_279a7b317d12eb88de06167bd672b4b4_default = "./fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2"; // fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 var ComicShanns_Regular_6e066e8de2ac57ea9283adb9c24d7f0c_default = "./fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2"; // fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 var ComicShanns_Regular_dc6a8806fa96795d7b3be5026f989a17_default = "./fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2"; // fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 var ComicShanns_Regular_fcb0fc02dcbee4c9846b3e2508668039_default = "./fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2"; // fonts/ComicShanns/index.ts var ComicShannsFontFaces = [ { uri: ComicShanns_Regular_279a7b317d12eb88de06167bd672b4b4_default, descriptors: { unicodeRange: "U+20-7e,U+a1-a6,U+a8,U+ab-ac,U+af-b1,U+b4,U+b8,U+bb-bc,U+bf-cf,U+d1-d7,U+d9-de,U+e0-ef,U+f1-f7,U+f9-ff,U+131,U+152-153,U+2c6,U+2da,U+2dc,U+2013-2014,U+2018-201a,U+201c-201d,U+2020-2022,U+2026,U+2039-203a,U+2044,U+20ac,U+2191,U+2193,U+2212" } }, { uri: ComicShanns_Regular_fcb0fc02dcbee4c9846b3e2508668039_default, descriptors: { unicodeRange: "U+100-10f,U+112-125,U+128-130,U+134-137,U+139-13c,U+141-148,U+14c-151,U+154-161,U+164-165,U+168-17f,U+1bf,U+1f7,U+218-21b,U+237,U+1e80-1e85,U+1ef2-1ef3,U+a75b" } }, { uri: ComicShanns_Regular_dc6a8806fa96795d7b3be5026f989a17_default, descriptors: { unicodeRange: "U+2c7,U+2d8-2d9,U+2db,U+2dd,U+315,U+2190,U+2192,U+2200,U+2203-2204,U+2264-2265,U+f6c3" } }, { uri: ComicShanns_Regular_6e066e8de2ac57ea9283adb9c24d7f0c_default, descriptors: { unicodeRange: "U+3bb" } } ]; // fonts/Emoji/index.ts import { LOCAL_FONT_PROTOCOL } from "@testbank-inc/common"; var EmojiFontFaces = [ { uri: LOCAL_FONT_PROTOCOL } ]; // fonts/ExcalidrawFontFace.ts import { promiseTry as promiseTry2, LOCAL_FONT_PROTOCOL as LOCAL_FONT_PROTOCOL2 } from "@testbank-inc/common"; // subset/subset-main.ts import { isServerEnv, promiseTry } from "@testbank-inc/common"; // workers.ts import { debounce as debounce2 } from "@testbank-inc/common"; var IdleWorker = class { constructor(workerUrl) { __publicField(this, "instance"); /** * Use to prolong the worker's life by `workerTTL` or terminate it with a flush immediately. */ __publicField(this, "debounceTerminate"); this.instance = new Worker(workerUrl, { type: "module" }); } }; var WorkerPool = class _WorkerPool { constructor(workerUrl, options) { __publicField(this, "idleWorkers", /* @__PURE__ */ new Set()); __publicField(this, "workerUrl"); __publicField(this, "workerTTL"); this.workerUrl = workerUrl; this.workerTTL = options.ttl || 1e3; } /** * Create a new worker pool. * * @param workerUrl - The URL of the worker file. * @param options - The options for the worker pool. * @throws If the worker is bundled into the main chunk. * @returns A new worker pool instance. */ static create(workerUrl, options = {}) { if (!workerUrl) { throw new WorkerUrlNotDefinedError(); } if (!import.meta.url || workerUrl.toString() === import.meta.url) { throw new WorkerInTheMainChunkError(); } return new _WorkerPool(workerUrl, options); } /** * Take idle worker from the pool or create a new one and post a message to it. */ async postMessage(data, options) { let worker; const idleWorker = Array.from(this.idleWorkers).shift(); if (idleWorker) { this.idleWorkers.delete(idleWorker); worker = idleWorker; } else { worker = await this.createWorker(); } return new Promise((resolve, reject) => { worker.instance.onmessage = this.onMessageHandler(worker, resolve); worker.instance.onerror = this.onErrorHandler(worker, reject); worker.instance.postMessage(data, options); worker.debounceTerminate( () => reject( new Error(`Active worker did not respond for ${this.workerTTL}ms!`) ) ); }); } /** * Terminate the idle workers in the pool. */ async clear() { for (const worker of this.idleWorkers) { worker.debounceTerminate.cancel(); worker.instance.terminate(); } this.idleWorkers.clear(); } /** * Used to get a worker from the pool or create a new one if there is no idle available. */ async createWorker() { const worker = new IdleWorker(this.workerUrl); worker.debounceTerminate = debounce2((reject) => { worker.instance.terminate(); if (this.idleWorkers.has(worker)) { this.idleWorkers.delete(worker); console.debug( "Job finished! Idle worker has been released from the pool." ); } else if (reject) { reject(); } else { console.error("Worker has been terminated!"); } }, this.workerTTL); return worker; } onMessageHandler(worker, resolve) { return (e) => { worker.debounceTerminate(); this.idleWorkers.add(worker); resolve(e.data); }; } onErrorHandler(worker, reject) { return (e) => { worker.debounceTerminate(() => reject(e)); worker.debounceTerminate.flush(); this.clear(); }; } }; // subset/subset-main.ts var shouldUseWorkers = typeof Worker !== "undefined"; var subsetWoff2GlyphsByCodepoints = async (arrayBuffer, codePoints) => { const { Commands, subsetToBase64, toBase64 } = await lazyLoadSharedSubsetChunk(); if (!shouldUseWorkers) { return subsetToBase64(arrayBuffer, codePoints); } return promiseTry(async () => { try { const workerPool2 = await getOrCreateWorkerPool(); const arrayBufferCopy = arrayBuffer.slice(0); const result = await workerPool2.postMessage( { command: Commands.Subset, arrayBuffer: arrayBufferCopy, codePoints }, { transfer: [arrayBufferCopy] } ); return toBase64(result); } catch (e) { shouldUseWorkers = false; if ( // don't log the expected errors server-side !(isServerEnv() && (e instanceof WorkerUrlNotDefinedError || e instanceof WorkerInTheMainChunkError)) ) { console.error( "Failed to use workers for subsetting, falling back to the main thread.", e ); } return subsetToBase64(arrayBuffer, codePoints); } }); }; var subsetWorker = null; var subsetShared = null; var lazyLoadWorkerSubsetChunk = async () => { if (!subsetWorker) { subsetWorker = import("./subset-worker.chunk.js"); } return subsetWorker; }; var lazyLoadSharedSubsetChunk = async () => { if (!subsetShared) { subsetShared = import("./subset-shared.chunk.js"); } return subsetShared; }; var workerPool = null; var getOrCreateWorkerPool = () => { if (!workerPool) { workerPool = promiseTry(async () => { const { WorkerUrl } = await lazyLoadWorkerSubsetChunk(); const pool = WorkerPool.create(WorkerUrl); return pool; }); } return workerPool; }; // fonts/ExcalidrawFontFace.ts var _ExcalidrawFontFace = class _ExcalidrawFontFace { constructor(family, uri, descriptors) { __publicField(this, "urls"); __publicField(this, "fontFace"); this.urls = _ExcalidrawFontFace.createUrls(uri); const sources = this.urls.map((url) => `url(${url}) ${_ExcalidrawFontFace.getFormat(url)}`).join(", "); this.fontFace = new FontFace(family, sources, { display: "swap", style: "normal", weight: "400", ...descriptors }); } /** * Generates CSS `@font-face` definition with the (subsetted) font source as a data url for the characters within the unicode range. * * Retrieves `undefined` otherwise. */ toCSS(characters) { if (!this.getUnicodeRangeRegex().test(characters)) { return; } const codepoints = Array.from(characters).map( (char) => char.codePointAt(0) ); return this.getContent(codepoints).then( (content) => `@font-face { font-family: ${this.fontFace.family}; src: url(${content}); }` ); } /** * Tries to fetch woff2 content, based on the registered urls (from first to last, treated as fallbacks). * * @returns base64 with subsetted glyphs based on the passed codepoint, last defined url otherwise */ async getContent(codePoints) { let i = 0; const errorMessages = []; while (i < this.urls.length) { const url = this.urls[i]; try { const arrayBuffer = await this.fetchFont(url); const base64 = await subsetWoff2GlyphsByCodepoints( arrayBuffer, codePoints ); return base64; } catch (e) { errorMessages.push(`"${url.toString()}" returned error "${e}"`); } i++; } console.error( `Failed to fetch font family "${this.fontFace.family}"`, JSON.stringify(errorMessages, void 0, 2) ); return this.urls.length ? this.urls[this.urls.length - 1].toString() : ""; } fetchFont(url) { return promiseTry2(async () => { const response = await fetch(url, { // always prefer cache (even stale), otherwise it always triggers an unnecessary validation request // which we don't need as we are controlling freshness of the fonts with the stable hash suffix in the url // https://developer.mozilla.org/en-US/docs/Web/API/Request/cache cache: "force-cache", headers: { Accept: "font/woff2" } }); if (!response.ok) { const urlString = url instanceof URL ? url.toString() : "dataurl"; throw new Error( `Failed to fetch "${urlString}": ${response.statusText}` ); } const arrayBuffer = await response.arrayBuffer(); return arrayBuffer; }); } getUnicodeRangeRegex() { const unicodeRangeRegex = this.fontFace.unicodeRange.split(/,\s*/).map((range) => { const [start, end] = range.replace("U+", "").split("-"); if (end) { return `\\u{${start}}-\\u{${end}}`; } return `\\u{${start}}`; }).join(""); return new RegExp(`[${unicodeRangeRegex}]`, "u"); } static createUrls(uri) { if (uri.startsWith("data")) { return [uri]; } if (uri.startsWith(LOCAL_FONT_PROTOCOL2)) { return []; } if (uri.startsWith("http")) { return [new URL(uri)]; } const assetUrl = uri.replace(/^\/+/, ""); const urls = []; if (typeof window.EXCALIDRAW_ASSET_PATH === "string") { const normalizedBaseUrl = this.normalizeBaseUrl( window.EXCALIDRAW_ASSET_PATH ); urls.push(new URL(assetUrl, normalizedBaseUrl)); } else if (Array.isArray(window.EXCALIDRAW_ASSET_PATH)) { window.EXCALIDRAW_ASSET_PATH.forEach((path) => { const normalizedBaseUrl = this.normalizeBaseUrl(path); urls.push(new URL(assetUrl, normalizedBaseUrl)); }); } urls.push(new URL(assetUrl, _ExcalidrawFontFace.ASSETS_FALLBACK_URL)); return urls; } static getFormat(url) { if (!(url instanceof URL)) { return ""; } try { const parts = new URL(url).pathname.split("."); if (parts.length === 1) { return ""; } return `format('${parts.pop()}')`; } catch (error) { return ""; } } static normalizeBaseUrl(baseUrl) { let result = baseUrl; if (/^\.?\//.test(result)) { result = new URL( result.replace(/^\.?\/+/, ""), window?.location?.origin ).toString(); } result = `${result.replace(/\/+$/, "")}/`; return result; } }; __publicField(_ExcalidrawFontFace, "ASSETS_FALLBACK_URL", `https://esm.sh/${define_import_meta_env_default.PKG_NAME ? `${define_import_meta_env_default.PKG_NAME}@${define_import_meta_env_default.PKG_VERSION}` : "@excalidraw/excalidraw"}/dist/prod/`); var ExcalidrawFontFace = _ExcalidrawFontFace; // fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 var Excalifont_Regular_349fac6ca4700ffec595a7150a0d1e1d_default = "./fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2"; // fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 var Excalifont_Regular_3f2c5db56cc93c5a6873b1361d730c16_default = "./fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2"; // fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 var Excalifont_Regular_41b173a47b57366892116a575a43e2b6_default = "./fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2"; // fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 var Excalifont_Regular_623ccf21b21ef6b3a0d87738f77eb071_default = "./fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2"; // fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 var Excalifont_Regular_a88b72a24fb54c9f94e3b5fdaa7481c9_default = "./fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2"; // fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 var Excalifont_Regular_b9dcf9d2e50a1eaf42fc664b50a3fd0d_default = "./fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2"; // fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 var Excalifont_Regular_be310b9bcd4f1a43f571c46df7809174_default = "./fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2"; // fonts/Excalifont/index.ts var ExcalifontFontFaces = [ { uri: Excalifont_Regular_a88b72a24fb54c9f94e3b5fdaa7481c9_default, descriptors: { unicodeRange: "U+20-7e,U+a0-a3,U+a5-a6,U+a8-ab,U+ad-b1,U+b4,U+b6-b8,U+ba-ff,U+131,U+152-153,U+2bc,U+2c6,U+2da,U+2dc,U+304,U+308,U+2013-2014,U+2018-201a,U+201c-201e,U+2020,U+2022,U+2024-2026,U+2030,U+2039-203a,U+20ac,U+2122,U+2212" } }, { uri: Excalifont_Regular_be310b9bcd4f1a43f571c46df7809174_default, descriptors: { unicodeRange: "U+100-130,U+132-137,U+139-149,U+14c-151,U+154-17e,U+192,U+1fc-1ff,U+218-21b,U+237,U+1e80-1e85,U+1ef2-1ef3,U+2113" } }, { uri: Excalifont_Regular_b9dcf9d2e50a1eaf42fc664b50a3fd0d_default, descriptors: { unicodeRange: "U+400-45f,U+490-491,U+2116" } }, { uri: Excalifont_Regular_41b173a47b57366892116a575a43e2b6_default, descriptors: { unicodeRange: "U+37e,U+384-38a,U+38c,U+38e-393,U+395-3a1,U+3a3-3a8,U+3aa-3cf,U+3d7" } }, { uri: Excalifont_Regular_3f2c5db56cc93c5a6873b1361d730c16_default, descriptors: { unicodeRange: "U+2c7,U+2d8-2d9,U+2db,U+2dd,U+302,U+306-307,U+30a-30c,U+326-328,U+212e,U+2211,U+fb01-fb02" } }, { uri: Excalifont_Regular_349fac6ca4700ffec595a7150a0d1e1d_default, descriptors: { unicodeRange: "U+462-463,U+472-475,U+4d8-4d9,U+4e2-4e3,U+4e6-4e9,U+4ee-4ef" } }, { uri: Excalifont_Regular_623ccf21b21ef6b3a0d87738f77eb071_default, descriptors: { unicodeRange: "U+300-301,U+303" } } ]; // fonts/Helvetica/index.ts import { LOCAL_FONT_PROTOCOL as LOCAL_FONT_PROTOCOL3 } from "@testbank-inc/common"; var HelveticaFontFaces = [ { uri: LOCAL_FONT_PROTOCOL3 } ]; // fonts/Liberation/LiberationSans-Regular.woff2 var LiberationSans_Regular_default = "./fonts/Liberation/LiberationSans-Regular.woff2"; // fonts/Liberation/index.ts var LiberationFontFaces = [ { uri: LiberationSans_Regular_default } ]; // fonts/Lilita/index.ts import { GOOGLE_FONTS_RANGES } from "@testbank-inc/common"; // fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 var Lilita_Regular_i7dPIFZ9Zz_WBtRtedDbYE98RXi4EwSsbg_default = "./fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2"; // fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 var Lilita_Regular_i7dPIFZ9Zz_WBtRtedDbYEF8RXi4EwQ_default = "./fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2"; // fonts/Lilita/index.ts var LilitaFontFaces = [ { uri: Lilita_Regular_i7dPIFZ9Zz_WBtRtedDbYE98RXi4EwSsbg_default, descriptors: { unicodeRange: GOOGLE_FONTS_RANGES.LATIN_EXT } }, { uri: Lilita_Regular_i7dPIFZ9Zz_WBtRtedDbYEF8RXi4EwQ_default, descriptors: { unicodeRange: GOOGLE_FONTS_RANGES.LATIN } } ]; // fonts/Nunito/index.ts import { GOOGLE_FONTS_RANGES as GOOGLE_FONTS_RANGES2 } from "@testbank-inc/common"; // fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 var Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5_default = "./fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2"; // fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 var Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg_default = "./fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2"; // fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 var Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5_default = "./fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2"; // fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 var Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5_default = "./fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2"; // fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 var Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5_default = "./fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2"; // fonts/Nunito/index.ts var NunitoFontFaces = [ { uri: Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5_default, descriptors: { unicodeRange: GOOGLE_FONTS_RANGES2.CYRILIC_EXT, weight: "500" } }, { uri: Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5_default, descriptors: { unicodeRange: GOOGLE_FONTS_RANGES2.CYRILIC, weight: "500" } }, { uri: Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5_default, descriptors: { unicodeRange: GOOGLE_FONTS_RANGES2.VIETNAMESE, weight: "500" } }, { uri: Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5_default, descriptors: { unicodeRange: GOOGLE_FONTS_RANGES2.LATIN_EXT, weight: "500" } }, { uri: Nunito_Regular_XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg_default, descriptors: { unicodeRange: GOOGLE_FONTS_RANGES2.LATIN, weight: "500" } } ]; // fonts/Virgil/Virgil-Regular.woff2 var Virgil_Regular_default = "./fonts/Virgil/Virgil-Regular.woff2"; // fonts/Virgil/index.ts var VirgilFontFaces = [ { uri: Virgil_Regular_default } ]; // fonts/Xiaolai/Xiaolai-Regular-019d66dcad46dc156b162d267f981c20.woff2 var Xiaolai_Regular_019d66dcad46dc156b162d267f981c20_default = "./fonts/Xiaolai/Xiaolai-Regular-019d66dcad46dc156b162d267f981c20.woff2"; // fonts/Xiaolai/Xiaolai-Regular-04b718e5623574919c8b0dea5f301444.woff2 var Xiaolai_Regular_04b718e5623574919c8b0dea5f301444_default = "./fonts/Xiaolai/Xiaolai-Regular-04b718e5623574919c8b0dea5f301444.woff2"; // fonts/Xiaolai/Xiaolai-Regular-069e77aac84590e2e991d0a0176d34f2.woff2 var Xiaolai_Regular_069e77aac84590e2e991d0a0176d34f2_default = "./fonts/Xiaolai/Xiaolai-Regular-069e77aac84590e2e991d0a0176d34f2.woff2"; // fonts/Xiaolai/Xiaolai-Regular-06c77b8c66e51ed6c63ccb502dd8b8af.woff2 var Xiaolai_Regular_06c77b8c66e51ed6c63ccb502dd8b8af_default = "./fonts/Xiaolai/Xiaolai-Regular-06c77b8c66e51ed6c63ccb502dd8b8af.woff2"; // fonts/Xiaolai/Xiaolai-Regular-08e0dc436ad0ad61ba5558db0674d762.woff2 var Xiaolai_Regular_08e0dc436ad0ad61ba5558db0674d762_default = "./fonts/Xiaolai/Xiaolai-Regular-08e0dc436ad0ad61ba5558db0674d762.woff2"; // fonts/Xiaolai/Xiaolai-Regular-093b9ef39a46ceae95a1df18a0a3a326.woff2 var Xiaolai_Regular_093b9ef39a46ceae95a1df18a0a3a326_default = "./fonts/Xiaolai/Xiaolai-Regular-093b9ef39a46ceae95a1df18a0a3a326.woff2"; // fonts/Xiaolai/Xiaolai-Regular-095c169f3314805276f603a362766abd.woff2 var Xiaolai_Regular_095c169f3314805276f603a362766abd_default = "./fonts/Xiaolai/Xiaolai-Regular-095c169f3314805276f603a362766abd.woff2"; // fonts/Xiaolai/Xiaolai-Regular-09850c4077f3fffe707905872e0e2460.woff2 var Xiaolai_Regular_09850c4077f3fffe707905872e0e2460_default = "./fonts/Xiaolai/Xiaolai-Regular-09850c4077f3fffe707905872e0e2460.woff2"; // fonts/Xiaolai/Xiaolai-Regular-41521fade99856108931b4768b1b2648.woff2 var Xiaolai_Regular_41521fade99856108931b4768b1b2648_default = "./fonts/Xiaolai/Xiaolai-Regular-41521fade99856108931b4768b1b2648.woff2"; // fonts/Xiaolai/Xiaolai-Regular-544fc28abe2c5c30e62383fd4dac255f.woff2 var Xiaolai_Regular_544fc28abe2c5c30e62383fd4dac255f_default = "./fonts/Xiaolai/Xiaolai-Regular-544fc28abe2c5c30e62383fd4dac255f.woff2"; // fonts/Xiaolai/Xiaolai-Regular-60a3089806700d379f11827ee9843b6b.woff2 var Xiaolai_Regular_60a3089806700d379f11827ee9843b6b_default = "./fonts/Xiaolai/Xiaolai-Regular-60a3089806700d379f11827ee9843b6b.woff2"; // fonts/Xiaolai/Xiaolai-Regular-7eb9fffd1aa890d07d0f88cc82e6cfe4.woff2 var Xiaolai_Regular_7eb9fffd1aa890d07d0f88cc82e6cfe4_default = "./fonts/Xiaolai/Xiaolai-Regular-7eb9fffd1aa890d07d0f88cc82e6cfe4.woff2"; // fonts/Xiaolai/Xiaolai-Regular-6fe5c5973cc06f74b2387a631ea36b88.woff2 var Xiaolai_Regular_6fe5c5973cc06f74b2387a631ea36b88_default = "./fonts/Xiaolai/Xiaolai-Regular-6fe5c5973cc06f74b2387a631ea36b88.woff2"; // fonts/Xiaolai/Xiaolai-Regular-a4c34be6d42152e64b0df90bc4607f64.woff2 var Xiaolai_Regular_a4c34be6d42152e64b0df90bc4607f64_default = "./fonts/Xiaolai/Xiaolai-Regular-a4c34be6d42152e64b0df90bc4607f64.woff2"; // fonts/Xiaolai/Xiaolai-Regular-b96d9226ce77ec94ceca043d712182e6.woff2 var Xiaolai_Regular_b96d9226ce77ec94ceca043d712182e6_default = "./fonts/Xiaolai/Xiaolai-Regular-b96d9226ce77ec94ceca043d712182e6.woff2"; // fonts/Xiaolai/Xiaolai-Regular-6ae5b42180ad70b971c91e7eefb8eba2.woff2 var Xiaolai_Regular_6ae5b42180ad70b971c91e7eefb8eba2_default = "./fonts/Xiaolai/Xiaolai-Regular-6ae5b42180ad70b971c91e7eefb8eba2.woff2"; // fonts/Xiaolai/Xiaolai-Regular-c69f61a4ab18d0488c8d1fc12e7028e8.woff2 var Xiaolai_Regular_c69f61a4ab18d0488c8d1fc12e7028e8_default = "./fonts/Xiaolai/Xiaolai-Regular-c69f61a4ab18d0488c8d1fc12e7028e8.woff2"; // fonts/Xiaolai/Xiaolai-Regular-cb17fc3db95f6d139afc9d31a8e93293.woff2 var Xiaolai_Regular_cb17fc3db95f6d139afc9d31a8e93293_default = "./fonts/Xiaolai/Xiaolai-Regular-cb17fc3db95f6d139afc9d31a8e93293.woff2"; // fonts/Xiaolai/Xiaolai-Regular-e3fcf5180fd466c8915c4e8069491054.woff2 var Xiaolai_Regular_e3fcf5180fd466c8915c4e8069491054_default = "./fonts/Xiaolai/Xiaolai-Regular-e3fcf5180fd466c8915c4e8069491054.woff2"; // fonts/Xiaolai/Xiaolai-Regular-c1f94158256bb1f3bf665b053d895af9.woff2 var Xiaolai_Regular_c1f94158256bb1f3bf665b053d895af9_default = "./fonts/Xiaolai/Xiaolai-Regular-c1f94158256bb1f3bf665b053d895af9.woff2"; // fonts/Xiaolai/Xiaolai-Regular-7197d6fda6cba7c3874c53d6381ca239.woff2 var Xiaolai_Regular_7197d6fda6cba7c3874c53d6381ca239_default = "./fonts/Xiaolai/Xiaolai-Regular-7197d6fda6cba7c3874c53d6381ca239.woff2"; // fonts/Xiaolai/Xiaolai-Regular-70c2eb8d64e71a42a834eb857ea9df51.woff2 var Xiaolai_Regular_70c2eb8d64e71a42a834eb857ea9df51_default = "./fonts/Xiaolai/Xiaolai-Regular-70c2eb8d64e71a42a834eb857ea9df51.woff2"; // fonts/Xiaolai/Xiaolai-Regular-a004ddfcb26e67bd6e678c8ed19e25ce.woff2 var Xiaolai_Regular_a004ddfcb26e67bd6e678c8ed19e25ce_default = "./fonts/Xiaolai/Xiaolai-Regular-a004ddfcb26e67bd6e678c8ed19e25ce.woff2"; // fonts/Xiaolai/Xiaolai-Regular-7e4bde7e9c7f84cd34d8a845e384c746.woff2 var Xiaolai_Regular_7e4bde7e9c7f84cd34d8a845e384c746_default = "./fonts/Xiaolai/Xiaolai-Regular-7e4bde7e9c7f84cd34d8a845e384c746.woff2"; // fonts/Xiaolai/Xiaolai-Regular-23686f7f29da6e8008c36dd3a80c83d6.woff2 var Xiaolai_Regular_23686f7f29da6e8008c36dd3a80c83d6_default = "./fonts/Xiaolai/Xiaolai-Regular-23686f7f29da6e8008c36dd3a80c83d6.woff2"; // fonts/Xiaolai/Xiaolai-Regular-69c09cc5fa3e55c74fc4821f76909cc3.woff2 var Xiaolai_Regular_69c09cc5fa3e55c74fc4821f76909cc3_default = "./fonts/Xiaolai/Xiaolai-Regular-69c09cc5fa3e55c74fc4821f76909cc3.woff2"; // fonts/Xiaolai/Xiaolai-Regular-25b7f38e18f035f96cb5e