@excalidraw/excalidraw 0.17.1-a38e82f → 0.17.1-b7babe5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-IM4WTX2M.js → chunk-6NMK7JTV.js} +2 -1
- package/dist/browser/dev/excalidraw-assets-dev/chunk-6NMK7JTV.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-5VWQDKDR.js → chunk-CX3RATXT.js} +50 -5
- package/dist/browser/dev/excalidraw-assets-dev/chunk-CX3RATXT.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-IOBA4CS2.js → en-BZY7JRTM.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-VKDAL6BQ.js → image-CVN3YKRW.js} +2 -2
- package/dist/browser/dev/index.js +332 -76
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/{chunk-N2C5DK3B.js → chunk-VJAIK3AX.js} +15 -15
- package/dist/browser/prod/excalidraw-assets/{chunk-LIG3S5TN.js → chunk-YYO5DFUW.js} +3 -3
- package/dist/browser/prod/excalidraw-assets/{en-WFZVQ7I6.js → en-O2YCQM2W.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/image-6FKY54X5.js +1 -0
- package/dist/browser/prod/index.js +16 -16
- package/dist/{prod/en-TDNWCAOT.json → dev/en-EY7E2L5O.json} +1 -0
- package/dist/dev/index.js +372 -77
- package/dist/dev/index.js.map +3 -3
- package/dist/excalidraw/data/library.d.ts +60 -8
- package/dist/excalidraw/data/library.js +302 -33
- package/dist/excalidraw/element/index.d.ts +8 -0
- package/dist/excalidraw/element/index.js +23 -0
- package/dist/excalidraw/element/textElement.d.ts +16 -1
- package/dist/excalidraw/element/textElement.js +10 -3
- package/dist/excalidraw/index.d.ts +2 -2
- package/dist/excalidraw/index.js +2 -2
- package/dist/excalidraw/locales/en.json +1 -0
- package/dist/excalidraw/queue.d.ts +9 -0
- package/dist/excalidraw/queue.js +27 -0
- package/dist/excalidraw/types.d.ts +6 -6
- package/dist/excalidraw/utility-types.d.ts +2 -0
- package/dist/excalidraw/utils.d.ts +3 -1
- package/dist/excalidraw/utils.js +6 -0
- package/dist/{dev/en-TDNWCAOT.json → prod/en-EY7E2L5O.json} +1 -0
- package/dist/prod/index.js +26 -26
- package/package.json +1 -1
- package/dist/browser/dev/excalidraw-assets-dev/chunk-5VWQDKDR.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-IM4WTX2M.js.map +0 -7
- package/dist/browser/prod/excalidraw-assets/image-4AT7LYMR.js +0 -1
- /package/dist/browser/dev/excalidraw-assets-dev/{en-IOBA4CS2.js.map → en-BZY7JRTM.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-VKDAL6BQ.js.map → image-CVN3YKRW.js.map} +0 -0
|
@@ -216,6 +216,7 @@
|
|
|
216
216
|
"failedToFetchImage": "Failed to fetch image.",
|
|
217
217
|
"cannotResolveCollabServer": "Couldn't connect to the collab server. Please reload the page and try again.",
|
|
218
218
|
"importLibraryError": "Couldn't load library",
|
|
219
|
+
"saveLibraryError": "Couldn't save library to storage. Please save your library to a file locally to make sure you don't lose changes.",
|
|
219
220
|
"collabSaveFailed": "Couldn't save to the backend database. If problems persist, you should save your file locally to ensure you don't lose your work.",
|
|
220
221
|
"collabSaveFailed_sizeExceeded": "Couldn't save to the backend database, the canvas seems to be too big. You should save the file locally to ensure you don't lose your work.",
|
|
221
222
|
"imageToolNotSupported": "Images are disabled.",
|
package/dist/dev/index.js
CHANGED
|
@@ -448,7 +448,7 @@ function getSvgPathFromStroke(points, closed = true) {
|
|
|
448
448
|
}
|
|
449
449
|
return result;
|
|
450
450
|
}
|
|
451
|
-
var mockDateTime, getDateTime, capitalizeString, isToolIcon, isInputLike, isInteractive, isWritableElement, getFontFamilyString, getFontString, debounce, throttleRAF, easeOut, easeOutInterpolate, easeToValuesRAF, chunk, distance, updateActiveTool, getShortcutKey, viewportCoordsToSceneCoords, sceneCoordsToViewportCoords, getGlobalCSSVariable, RS_LTR_CHARS, RS_RTL_CHARS, RE_RTL_CHECK, isRTL, tupleToCoors, muteFSAbortError, findIndex, findLastIndex, isTransparent, getNearestScrollableContainer, focusNearestParent, bytesToHexString, getUpdatedTimestamp, arrayToMap, arrayToMapWithIndex, isTestEnv, wrapEvent, updateObject, getFrame, isPromiseLike, queryFocusableElements, _defaultIsShallowComparatorFallback, isShallowEqual, composeEventHandlers, assertNever, memoize, isMemberOf, cloneJSON, isFiniteNumber, updateStable, average, normalizeEOL, toBrandedType;
|
|
451
|
+
var mockDateTime, getDateTime, capitalizeString, isToolIcon, isInputLike, isInteractive, isWritableElement, getFontFamilyString, getFontString, debounce, throttleRAF, easeOut, easeOutInterpolate, easeToValuesRAF, chunk, distance, updateActiveTool, getShortcutKey, viewportCoordsToSceneCoords, sceneCoordsToViewportCoords, getGlobalCSSVariable, RS_LTR_CHARS, RS_RTL_CHARS, RE_RTL_CHECK, isRTL, tupleToCoors, muteFSAbortError, findIndex, findLastIndex, isTransparent, resolvablePromise, getNearestScrollableContainer, focusNearestParent, preventUnload, bytesToHexString, getUpdatedTimestamp, arrayToMap, arrayToMapWithIndex, isTestEnv, wrapEvent, updateObject, getFrame, isPromiseLike, queryFocusableElements, _defaultIsShallowComparatorFallback, isShallowEqual, composeEventHandlers, assertNever, memoize, isMemberOf, cloneJSON, isFiniteNumber, updateStable, average, normalizeEOL, toBrandedType, promiseTry;
|
|
452
452
|
var init_utils = __esm({
|
|
453
453
|
"utils.ts"() {
|
|
454
454
|
"use strict";
|
|
@@ -735,6 +735,17 @@ var init_utils = __esm({
|
|
|
735
735
|
const isRRGGBBTransparent = color.length === 9 && color.substr(7, 2) === "00";
|
|
736
736
|
return isRGBTransparent || isRRGGBBTransparent || color === COLOR_PALETTE.transparent;
|
|
737
737
|
};
|
|
738
|
+
resolvablePromise = () => {
|
|
739
|
+
let resolve;
|
|
740
|
+
let reject;
|
|
741
|
+
const promise = new Promise((_resolve, _reject) => {
|
|
742
|
+
resolve = _resolve;
|
|
743
|
+
reject = _reject;
|
|
744
|
+
});
|
|
745
|
+
promise.resolve = resolve;
|
|
746
|
+
promise.reject = reject;
|
|
747
|
+
return promise;
|
|
748
|
+
};
|
|
738
749
|
getNearestScrollableContainer = (element) => {
|
|
739
750
|
let parent = element.parentElement;
|
|
740
751
|
while (parent) {
|
|
@@ -760,6 +771,10 @@ var init_utils = __esm({
|
|
|
760
771
|
parent = parent.parentElement;
|
|
761
772
|
}
|
|
762
773
|
};
|
|
774
|
+
preventUnload = (event) => {
|
|
775
|
+
event.preventDefault();
|
|
776
|
+
event.returnValue = "";
|
|
777
|
+
};
|
|
763
778
|
bytesToHexString = (bytes) => {
|
|
764
779
|
return Array.from(bytes).map((byte) => `0${byte.toString(16)}`.slice(-2)).join("");
|
|
765
780
|
};
|
|
@@ -933,6 +948,11 @@ var init_utils = __esm({
|
|
|
933
948
|
toBrandedType = (value) => {
|
|
934
949
|
return value;
|
|
935
950
|
};
|
|
951
|
+
promiseTry = async (fn, ...args) => {
|
|
952
|
+
return new Promise((resolve) => {
|
|
953
|
+
resolve(fn(...args));
|
|
954
|
+
});
|
|
955
|
+
};
|
|
936
956
|
}
|
|
937
957
|
});
|
|
938
958
|
|
|
@@ -5224,7 +5244,7 @@ var init_textElement = __esm({
|
|
|
5224
5244
|
return fontSize * lineHeight;
|
|
5225
5245
|
};
|
|
5226
5246
|
getVerticalOffset = (fontFamily, fontSize, lineHeightPx) => {
|
|
5227
|
-
const { unitsPerEm, ascender, descender } = FONT_METRICS[fontFamily];
|
|
5247
|
+
const { unitsPerEm, ascender, descender } = FONT_METRICS[fontFamily] || FONT_METRICS[FONT_FAMILY.Helvetica];
|
|
5228
5248
|
const fontSizeEm = fontSize / unitsPerEm;
|
|
5229
5249
|
const lineGap = lineHeightPx - fontSizeEm * ascender + fontSizeEm * descender;
|
|
5230
5250
|
const verticalOffset = fontSizeEm * ascender + lineGap;
|
|
@@ -5618,6 +5638,11 @@ var init_textElement = __esm({
|
|
|
5618
5638
|
unitsPerEm: 2048,
|
|
5619
5639
|
ascender: 1977,
|
|
5620
5640
|
descender: -480
|
|
5641
|
+
},
|
|
5642
|
+
[FONT_FAMILY.Assistant]: {
|
|
5643
|
+
unitsPerEm: 1e3,
|
|
5644
|
+
ascender: 1021,
|
|
5645
|
+
descender: -287
|
|
5621
5646
|
}
|
|
5622
5647
|
};
|
|
5623
5648
|
getDefaultLineHeight = (fontFamily) => {
|
|
@@ -13096,7 +13121,7 @@ var init_showSelectedShapeActions = __esm({
|
|
|
13096
13121
|
});
|
|
13097
13122
|
|
|
13098
13123
|
// element/index.ts
|
|
13099
|
-
var getSceneVersion, getVisibleElements, getNonDeletedElements3, isNonDeletedElement, _clearElements, clearElementsForDatabase, clearElementsForExport;
|
|
13124
|
+
var getSceneVersion, hashElementsVersion, hashString, getVisibleElements, getNonDeletedElements3, isNonDeletedElement, _clearElements, clearElementsForDatabase, clearElementsForExport;
|
|
13100
13125
|
var init_element = __esm({
|
|
13101
13126
|
"element/index.ts"() {
|
|
13102
13127
|
"use strict";
|
|
@@ -13115,6 +13140,21 @@ var init_element = __esm({
|
|
|
13115
13140
|
init_sizeHelpers();
|
|
13116
13141
|
init_showSelectedShapeActions();
|
|
13117
13142
|
getSceneVersion = (elements) => elements.reduce((acc, el) => acc + el.version, 0);
|
|
13143
|
+
hashElementsVersion = (elements) => {
|
|
13144
|
+
let hash = 5381;
|
|
13145
|
+
for (let i = 0; i < elements.length; i++) {
|
|
13146
|
+
hash = (hash << 5) + hash + elements[i].versionNonce;
|
|
13147
|
+
}
|
|
13148
|
+
return hash >>> 0;
|
|
13149
|
+
};
|
|
13150
|
+
hashString = (s) => {
|
|
13151
|
+
let hash = 5381;
|
|
13152
|
+
for (let i = 0; i < s.length; i++) {
|
|
13153
|
+
const char = s.charCodeAt(i);
|
|
13154
|
+
hash = (hash << 5) + hash + char;
|
|
13155
|
+
}
|
|
13156
|
+
return hash >>> 0;
|
|
13157
|
+
};
|
|
13118
13158
|
getVisibleElements = (elements) => elements.filter(
|
|
13119
13159
|
(el) => !el.isDeleted && !isInvisiblySmallElement(el)
|
|
13120
13160
|
);
|
|
@@ -13385,7 +13425,7 @@ init_define_import_meta_env();
|
|
|
13385
13425
|
|
|
13386
13426
|
// i18n.ts
|
|
13387
13427
|
init_define_import_meta_env();
|
|
13388
|
-
import fallbackLangData from "./en-
|
|
13428
|
+
import fallbackLangData from "./en-EY7E2L5O.json";
|
|
13389
13429
|
import percentages from "./percentages-UCQDHIQF.json";
|
|
13390
13430
|
|
|
13391
13431
|
// jotai.ts
|
|
@@ -13409,7 +13449,7 @@ var globImport_locales_json = __glob({
|
|
|
13409
13449
|
"./locales/da-DK.json": () => import("./da-DK-WBEQB3CJ.json"),
|
|
13410
13450
|
"./locales/de-DE.json": () => import("./de-DE-VEIMCP7R.json"),
|
|
13411
13451
|
"./locales/el-GR.json": () => import("./el-GR-TKRKG5GQ.json"),
|
|
13412
|
-
"./locales/en.json": () => import("./en-
|
|
13452
|
+
"./locales/en.json": () => import("./en-EY7E2L5O.json"),
|
|
13413
13453
|
"./locales/es-ES.json": () => import("./es-ES-TOLWEZNW.json"),
|
|
13414
13454
|
"./locales/eu-ES.json": () => import("./eu-ES-7CDRJQWJ.json"),
|
|
13415
13455
|
"./locales/fa-IR.json": () => import("./fa-IR-527E2XGU.json"),
|
|
@@ -22878,7 +22918,79 @@ var useLibraryCache = () => {
|
|
|
22878
22918
|
|
|
22879
22919
|
// data/library.ts
|
|
22880
22920
|
init_utils();
|
|
22881
|
-
|
|
22921
|
+
|
|
22922
|
+
// emitter.ts
|
|
22923
|
+
init_define_import_meta_env();
|
|
22924
|
+
var Emitter = class {
|
|
22925
|
+
subscribers = [];
|
|
22926
|
+
/**
|
|
22927
|
+
* Attaches subscriber
|
|
22928
|
+
*
|
|
22929
|
+
* @returns unsubscribe function
|
|
22930
|
+
*/
|
|
22931
|
+
on(...handlers) {
|
|
22932
|
+
const _handlers = handlers.flat().filter((item) => typeof item === "function");
|
|
22933
|
+
this.subscribers.push(..._handlers);
|
|
22934
|
+
return () => this.off(_handlers);
|
|
22935
|
+
}
|
|
22936
|
+
once(...handlers) {
|
|
22937
|
+
const _handlers = handlers.flat().filter((item) => typeof item === "function");
|
|
22938
|
+
_handlers.push(() => detach());
|
|
22939
|
+
const detach = this.on(..._handlers);
|
|
22940
|
+
return detach;
|
|
22941
|
+
}
|
|
22942
|
+
off(...handlers) {
|
|
22943
|
+
const _handlers = handlers.flat();
|
|
22944
|
+
this.subscribers = this.subscribers.filter(
|
|
22945
|
+
(handler) => !_handlers.includes(handler)
|
|
22946
|
+
);
|
|
22947
|
+
}
|
|
22948
|
+
trigger(...payload) {
|
|
22949
|
+
for (const handler of this.subscribers) {
|
|
22950
|
+
handler(...payload);
|
|
22951
|
+
}
|
|
22952
|
+
return this;
|
|
22953
|
+
}
|
|
22954
|
+
clear() {
|
|
22955
|
+
this.subscribers = [];
|
|
22956
|
+
}
|
|
22957
|
+
};
|
|
22958
|
+
|
|
22959
|
+
// queue.ts
|
|
22960
|
+
init_define_import_meta_env();
|
|
22961
|
+
init_utils();
|
|
22962
|
+
var Queue = class {
|
|
22963
|
+
jobs = [];
|
|
22964
|
+
running = false;
|
|
22965
|
+
tick() {
|
|
22966
|
+
if (this.running) {
|
|
22967
|
+
return;
|
|
22968
|
+
}
|
|
22969
|
+
const job = this.jobs.shift();
|
|
22970
|
+
if (job) {
|
|
22971
|
+
this.running = true;
|
|
22972
|
+
job.promise.resolve(
|
|
22973
|
+
promiseTry(job.jobFactory, ...job.args).finally(() => {
|
|
22974
|
+
this.running = false;
|
|
22975
|
+
this.tick();
|
|
22976
|
+
})
|
|
22977
|
+
);
|
|
22978
|
+
} else {
|
|
22979
|
+
this.running = false;
|
|
22980
|
+
}
|
|
22981
|
+
}
|
|
22982
|
+
push(jobFactory, ...args) {
|
|
22983
|
+
const promise = resolvablePromise();
|
|
22984
|
+
this.jobs.push({ jobFactory, promise, args });
|
|
22985
|
+
this.tick();
|
|
22986
|
+
return promise;
|
|
22987
|
+
}
|
|
22988
|
+
};
|
|
22989
|
+
|
|
22990
|
+
// data/library.ts
|
|
22991
|
+
init_element();
|
|
22992
|
+
var onLibraryUpdateEmitter = new Emitter();
|
|
22993
|
+
var libraryItemsAtom = atom5({ status: "loaded", isInitialized: false, libraryItems: [] });
|
|
22882
22994
|
var cloneLibraryItems = (libraryItems) => cloneJSON(libraryItems);
|
|
22883
22995
|
var isUniqueItem = (existingLibraryItems, targetLibraryItem) => {
|
|
22884
22996
|
return !existingLibraryItems.find((libraryItem) => {
|
|
@@ -22899,12 +23011,30 @@ var mergeLibraryItems = (localItems, otherItems) => {
|
|
|
22899
23011
|
}
|
|
22900
23012
|
return [...newItems, ...localItems];
|
|
22901
23013
|
};
|
|
23014
|
+
var createLibraryUpdate = (prevLibraryItems, nextLibraryItems) => {
|
|
23015
|
+
const nextItemsMap = arrayToMap(nextLibraryItems);
|
|
23016
|
+
const update = {
|
|
23017
|
+
deletedItems: /* @__PURE__ */ new Map(),
|
|
23018
|
+
addedItems: /* @__PURE__ */ new Map()
|
|
23019
|
+
};
|
|
23020
|
+
for (const item of prevLibraryItems) {
|
|
23021
|
+
if (!nextItemsMap.has(item.id)) {
|
|
23022
|
+
update.deletedItems.set(item.id, item);
|
|
23023
|
+
}
|
|
23024
|
+
}
|
|
23025
|
+
const prevItemsMap = arrayToMap(prevLibraryItems);
|
|
23026
|
+
for (const item of nextLibraryItems) {
|
|
23027
|
+
if (!prevItemsMap.has(item.id)) {
|
|
23028
|
+
update.addedItems.set(item.id, item);
|
|
23029
|
+
}
|
|
23030
|
+
}
|
|
23031
|
+
return update;
|
|
23032
|
+
};
|
|
22902
23033
|
var Library = class {
|
|
22903
23034
|
/** latest libraryItems */
|
|
22904
|
-
|
|
22905
|
-
/**
|
|
22906
|
-
|
|
22907
|
-
isInitialized = false;
|
|
23035
|
+
currLibraryItems = [];
|
|
23036
|
+
/** snapshot of library items since last onLibraryChange call */
|
|
23037
|
+
prevLibraryItems = cloneLibraryItems(this.currLibraryItems);
|
|
22908
23038
|
app;
|
|
22909
23039
|
constructor(app) {
|
|
22910
23040
|
this.app = app;
|
|
@@ -22915,21 +23045,25 @@ var Library = class {
|
|
|
22915
23045
|
};
|
|
22916
23046
|
notifyListeners = () => {
|
|
22917
23047
|
if (this.updateQueue.length > 0) {
|
|
22918
|
-
jotaiStore.set(libraryItemsAtom, {
|
|
23048
|
+
jotaiStore.set(libraryItemsAtom, (s) => ({
|
|
22919
23049
|
status: "loading",
|
|
22920
|
-
libraryItems: this.
|
|
22921
|
-
isInitialized:
|
|
22922
|
-
});
|
|
23050
|
+
libraryItems: this.currLibraryItems,
|
|
23051
|
+
isInitialized: s.isInitialized
|
|
23052
|
+
}));
|
|
22923
23053
|
} else {
|
|
22924
|
-
this.isInitialized = true;
|
|
22925
23054
|
jotaiStore.set(libraryItemsAtom, {
|
|
22926
23055
|
status: "loaded",
|
|
22927
|
-
libraryItems: this.
|
|
22928
|
-
isInitialized:
|
|
23056
|
+
libraryItems: this.currLibraryItems,
|
|
23057
|
+
isInitialized: true
|
|
22929
23058
|
});
|
|
22930
23059
|
try {
|
|
22931
|
-
this.
|
|
22932
|
-
|
|
23060
|
+
const prevLibraryItems = this.prevLibraryItems;
|
|
23061
|
+
this.prevLibraryItems = cloneLibraryItems(this.currLibraryItems);
|
|
23062
|
+
const nextLibraryItems = cloneLibraryItems(this.currLibraryItems);
|
|
23063
|
+
this.app.props.onLibraryChange?.(nextLibraryItems);
|
|
23064
|
+
onLibraryUpdateEmitter.trigger(
|
|
23065
|
+
createLibraryUpdate(prevLibraryItems, nextLibraryItems),
|
|
23066
|
+
nextLibraryItems
|
|
22933
23067
|
);
|
|
22934
23068
|
} catch (error) {
|
|
22935
23069
|
console.error(error);
|
|
@@ -22938,9 +23072,8 @@ var Library = class {
|
|
|
22938
23072
|
};
|
|
22939
23073
|
/** call on excalidraw instance unmount */
|
|
22940
23074
|
destroy = () => {
|
|
22941
|
-
this.isInitialized = false;
|
|
22942
23075
|
this.updateQueue = [];
|
|
22943
|
-
this.
|
|
23076
|
+
this.currLibraryItems = [];
|
|
22944
23077
|
jotaiStore.set(libraryItemSvgsCache, /* @__PURE__ */ new Map());
|
|
22945
23078
|
};
|
|
22946
23079
|
resetLibrary = () => {
|
|
@@ -22952,14 +23085,14 @@ var Library = class {
|
|
|
22952
23085
|
getLatestLibrary = () => {
|
|
22953
23086
|
return new Promise(async (resolve) => {
|
|
22954
23087
|
try {
|
|
22955
|
-
const libraryItems = await (this.getLastUpdateTask() || this.
|
|
23088
|
+
const libraryItems = await (this.getLastUpdateTask() || this.currLibraryItems);
|
|
22956
23089
|
if (this.updateQueue.length > 0) {
|
|
22957
23090
|
resolve(this.getLatestLibrary());
|
|
22958
23091
|
} else {
|
|
22959
23092
|
resolve(cloneLibraryItems(libraryItems));
|
|
22960
23093
|
}
|
|
22961
23094
|
} catch (error) {
|
|
22962
|
-
return resolve(this.
|
|
23095
|
+
return resolve(this.currLibraryItems);
|
|
22963
23096
|
}
|
|
22964
23097
|
});
|
|
22965
23098
|
};
|
|
@@ -22981,7 +23114,7 @@ var Library = class {
|
|
|
22981
23114
|
return this.setLibrary(() => {
|
|
22982
23115
|
return new Promise(async (resolve, reject) => {
|
|
22983
23116
|
try {
|
|
22984
|
-
const source = await (typeof libraryItems === "function" && !(libraryItems instanceof Blob) ? libraryItems(this.
|
|
23117
|
+
const source = await (typeof libraryItems === "function" && !(libraryItems instanceof Blob) ? libraryItems(this.currLibraryItems) : libraryItems);
|
|
22985
23118
|
let nextItems;
|
|
22986
23119
|
if (source instanceof Blob) {
|
|
22987
23120
|
nextItems = await loadLibraryFromBlob(source, defaultStatus);
|
|
@@ -22997,7 +23130,7 @@ var Library = class {
|
|
|
22997
23130
|
this.app.focusContainer();
|
|
22998
23131
|
}
|
|
22999
23132
|
if (merge) {
|
|
23000
|
-
resolve(mergeLibraryItems(this.
|
|
23133
|
+
resolve(mergeLibraryItems(this.currLibraryItems, nextItems));
|
|
23001
23134
|
} else {
|
|
23002
23135
|
resolve(nextItems);
|
|
23003
23136
|
}
|
|
@@ -23015,17 +23148,17 @@ var Library = class {
|
|
|
23015
23148
|
try {
|
|
23016
23149
|
await this.getLastUpdateTask();
|
|
23017
23150
|
if (typeof libraryItems === "function") {
|
|
23018
|
-
libraryItems = libraryItems(this.
|
|
23151
|
+
libraryItems = libraryItems(this.currLibraryItems);
|
|
23019
23152
|
}
|
|
23020
|
-
this.
|
|
23021
|
-
resolve(this.
|
|
23153
|
+
this.currLibraryItems = cloneLibraryItems(await libraryItems);
|
|
23154
|
+
resolve(this.currLibraryItems);
|
|
23022
23155
|
} catch (error) {
|
|
23023
23156
|
reject(error);
|
|
23024
23157
|
}
|
|
23025
23158
|
}).catch((error) => {
|
|
23026
23159
|
if (error.name === "AbortError") {
|
|
23027
23160
|
console.warn("Library update aborted by user");
|
|
23028
|
-
return this.
|
|
23161
|
+
return this.currLibraryItems;
|
|
23029
23162
|
}
|
|
23030
23163
|
throw error;
|
|
23031
23164
|
}).finally(() => {
|
|
@@ -23117,15 +23250,86 @@ var parseLibraryTokensFromUrl = () => {
|
|
|
23117
23250
|
const idToken = libraryUrl ? new URLSearchParams(window.location.hash.slice(1)).get("token") : null;
|
|
23118
23251
|
return libraryUrl ? { libraryUrl, idToken } : null;
|
|
23119
23252
|
};
|
|
23120
|
-
var
|
|
23121
|
-
|
|
23122
|
-
|
|
23123
|
-
|
|
23124
|
-
|
|
23253
|
+
var AdapterTransaction = class _AdapterTransaction {
|
|
23254
|
+
static queue = new Queue();
|
|
23255
|
+
static async getLibraryItems(adapter, source, _queue = true) {
|
|
23256
|
+
const task = () => new Promise(async (resolve, reject) => {
|
|
23257
|
+
try {
|
|
23258
|
+
const data = await adapter.load({ source });
|
|
23259
|
+
resolve(restoreLibraryItems(data?.libraryItems || [], "published"));
|
|
23260
|
+
} catch (error) {
|
|
23261
|
+
reject(error);
|
|
23262
|
+
}
|
|
23263
|
+
});
|
|
23264
|
+
if (_queue) {
|
|
23265
|
+
return _AdapterTransaction.queue.push(task);
|
|
23266
|
+
}
|
|
23267
|
+
return task();
|
|
23268
|
+
}
|
|
23269
|
+
static run = async (adapter, fn) => {
|
|
23270
|
+
const transaction = new _AdapterTransaction(adapter);
|
|
23271
|
+
return _AdapterTransaction.queue.push(() => fn(transaction));
|
|
23272
|
+
};
|
|
23273
|
+
// ------------------
|
|
23274
|
+
adapter;
|
|
23275
|
+
constructor(adapter) {
|
|
23276
|
+
this.adapter = adapter;
|
|
23277
|
+
}
|
|
23278
|
+
getLibraryItems(source) {
|
|
23279
|
+
return _AdapterTransaction.getLibraryItems(this.adapter, source, false);
|
|
23280
|
+
}
|
|
23281
|
+
};
|
|
23282
|
+
var lastSavedLibraryItemsHash = 0;
|
|
23283
|
+
var librarySaveCounter = 0;
|
|
23284
|
+
var getLibraryItemsHash = (items) => {
|
|
23285
|
+
return hashString(
|
|
23286
|
+
items.map((item) => {
|
|
23287
|
+
return `${item.id}:${hashElementsVersion(item.elements)}`;
|
|
23288
|
+
}).sort().join()
|
|
23289
|
+
);
|
|
23290
|
+
};
|
|
23291
|
+
var persistLibraryUpdate = async (adapter, update) => {
|
|
23292
|
+
try {
|
|
23293
|
+
librarySaveCounter++;
|
|
23294
|
+
return await AdapterTransaction.run(adapter, async (transaction) => {
|
|
23295
|
+
const nextLibraryItemsMap = arrayToMap(
|
|
23296
|
+
await transaction.getLibraryItems("save")
|
|
23297
|
+
);
|
|
23298
|
+
for (const [id] of update.deletedItems) {
|
|
23299
|
+
nextLibraryItemsMap.delete(id);
|
|
23300
|
+
}
|
|
23301
|
+
const addedItems = [];
|
|
23302
|
+
for (const [id, item] of update.addedItems) {
|
|
23303
|
+
if (nextLibraryItemsMap.has(id)) {
|
|
23304
|
+
nextLibraryItemsMap.set(id, item);
|
|
23305
|
+
} else {
|
|
23306
|
+
addedItems.push(item);
|
|
23307
|
+
}
|
|
23308
|
+
}
|
|
23309
|
+
const nextLibraryItems = addedItems.concat(
|
|
23310
|
+
Array.from(nextLibraryItemsMap.values())
|
|
23311
|
+
);
|
|
23312
|
+
const version = getLibraryItemsHash(nextLibraryItems);
|
|
23313
|
+
if (version !== lastSavedLibraryItemsHash) {
|
|
23314
|
+
await adapter.save({ libraryItems: nextLibraryItems });
|
|
23315
|
+
}
|
|
23316
|
+
lastSavedLibraryItemsHash = version;
|
|
23317
|
+
return nextLibraryItems;
|
|
23318
|
+
});
|
|
23319
|
+
} finally {
|
|
23320
|
+
librarySaveCounter--;
|
|
23321
|
+
}
|
|
23322
|
+
};
|
|
23323
|
+
var useHandleLibrary = (opts) => {
|
|
23324
|
+
const { excalidrawAPI } = opts;
|
|
23325
|
+
const optsRef = useRef11(opts);
|
|
23326
|
+
optsRef.current = opts;
|
|
23327
|
+
const isLibraryLoadedRef = useRef11(false);
|
|
23125
23328
|
useEffect15(() => {
|
|
23126
23329
|
if (!excalidrawAPI) {
|
|
23127
23330
|
return;
|
|
23128
23331
|
}
|
|
23332
|
+
isLibraryLoadedRef.current = false;
|
|
23129
23333
|
const importLibraryFromURL = async ({
|
|
23130
23334
|
libraryUrl,
|
|
23131
23335
|
idToken
|
|
@@ -23176,20 +23380,145 @@ var useHandleLibrary = ({
|
|
|
23176
23380
|
importLibraryFromURL(libraryUrlTokens2);
|
|
23177
23381
|
}
|
|
23178
23382
|
};
|
|
23179
|
-
if (getInitialLibraryRef.current) {
|
|
23180
|
-
excalidrawAPI.updateLibrary({
|
|
23181
|
-
libraryItems: getInitialLibraryRef.current()
|
|
23182
|
-
});
|
|
23183
|
-
}
|
|
23184
23383
|
const libraryUrlTokens = parseLibraryTokensFromUrl();
|
|
23185
23384
|
if (libraryUrlTokens) {
|
|
23186
23385
|
importLibraryFromURL(libraryUrlTokens);
|
|
23187
23386
|
}
|
|
23387
|
+
if ("getInitialLibraryItems" in optsRef.current && optsRef.current.getInitialLibraryItems) {
|
|
23388
|
+
console.warn(
|
|
23389
|
+
"useHandleLibrar `opts.getInitialLibraryItems` is deprecated. Use `opts.adapter` instead."
|
|
23390
|
+
);
|
|
23391
|
+
Promise.resolve(optsRef.current.getInitialLibraryItems()).then((libraryItems) => {
|
|
23392
|
+
excalidrawAPI.updateLibrary({
|
|
23393
|
+
libraryItems,
|
|
23394
|
+
// merge with current library items because we may have already
|
|
23395
|
+
// populated it (e.g. by installing 3rd party library which can
|
|
23396
|
+
// happen before the DB data is loaded)
|
|
23397
|
+
merge: true
|
|
23398
|
+
});
|
|
23399
|
+
}).catch((error) => {
|
|
23400
|
+
console.error(
|
|
23401
|
+
`UseHandeLibrary getInitialLibraryItems failed: ${error?.message}`
|
|
23402
|
+
);
|
|
23403
|
+
});
|
|
23404
|
+
}
|
|
23405
|
+
if ("adapter" in optsRef.current && optsRef.current.adapter) {
|
|
23406
|
+
const adapter = optsRef.current.adapter;
|
|
23407
|
+
const migrationAdapter = optsRef.current.migrationAdapter;
|
|
23408
|
+
const initDataPromise = resolvablePromise();
|
|
23409
|
+
if (migrationAdapter) {
|
|
23410
|
+
initDataPromise.resolve(
|
|
23411
|
+
promiseTry(migrationAdapter.load).then(async (libraryData) => {
|
|
23412
|
+
let restoredData = null;
|
|
23413
|
+
try {
|
|
23414
|
+
if (!libraryData) {
|
|
23415
|
+
return AdapterTransaction.getLibraryItems(adapter, "load");
|
|
23416
|
+
}
|
|
23417
|
+
restoredData = restoreLibraryItems(
|
|
23418
|
+
libraryData.libraryItems || [],
|
|
23419
|
+
"published"
|
|
23420
|
+
);
|
|
23421
|
+
const nextItems = await persistLibraryUpdate(
|
|
23422
|
+
adapter,
|
|
23423
|
+
createLibraryUpdate([], restoredData)
|
|
23424
|
+
);
|
|
23425
|
+
try {
|
|
23426
|
+
await migrationAdapter.clear();
|
|
23427
|
+
} catch (error) {
|
|
23428
|
+
console.error(
|
|
23429
|
+
`couldn't delete legacy library data: ${error.message}`
|
|
23430
|
+
);
|
|
23431
|
+
}
|
|
23432
|
+
return nextItems;
|
|
23433
|
+
} catch (error) {
|
|
23434
|
+
console.error(
|
|
23435
|
+
`couldn't migrate legacy library data: ${error.message}`
|
|
23436
|
+
);
|
|
23437
|
+
return restoredData;
|
|
23438
|
+
}
|
|
23439
|
+
}).catch((error) => {
|
|
23440
|
+
console.error(`error during library migration: ${error.message}`);
|
|
23441
|
+
return AdapterTransaction.getLibraryItems(adapter, "load");
|
|
23442
|
+
})
|
|
23443
|
+
);
|
|
23444
|
+
} else {
|
|
23445
|
+
initDataPromise.resolve(
|
|
23446
|
+
promiseTry(AdapterTransaction.getLibraryItems, adapter, "load")
|
|
23447
|
+
);
|
|
23448
|
+
}
|
|
23449
|
+
excalidrawAPI.updateLibrary({
|
|
23450
|
+
libraryItems: initDataPromise.then((libraryItems) => {
|
|
23451
|
+
const _libraryItems = libraryItems || [];
|
|
23452
|
+
lastSavedLibraryItemsHash = getLibraryItemsHash(_libraryItems);
|
|
23453
|
+
return _libraryItems;
|
|
23454
|
+
}),
|
|
23455
|
+
// merge with current library items because we may have already
|
|
23456
|
+
// populated it (e.g. by installing 3rd party library which can
|
|
23457
|
+
// happen before the DB data is loaded)
|
|
23458
|
+
merge: true
|
|
23459
|
+
}).finally(() => {
|
|
23460
|
+
isLibraryLoadedRef.current = true;
|
|
23461
|
+
});
|
|
23462
|
+
}
|
|
23188
23463
|
window.addEventListener("hashchange" /* HASHCHANGE */, onHashChange);
|
|
23189
23464
|
return () => {
|
|
23190
23465
|
window.removeEventListener("hashchange" /* HASHCHANGE */, onHashChange);
|
|
23191
23466
|
};
|
|
23192
|
-
}, [
|
|
23467
|
+
}, [
|
|
23468
|
+
// important this useEffect only depends on excalidrawAPI so it only reruns
|
|
23469
|
+
// on editor remounts (the excalidrawAPI changes)
|
|
23470
|
+
excalidrawAPI
|
|
23471
|
+
]);
|
|
23472
|
+
useEffect15(
|
|
23473
|
+
() => {
|
|
23474
|
+
const unsubOnLibraryUpdate = onLibraryUpdateEmitter.on(
|
|
23475
|
+
async (update, nextLibraryItems) => {
|
|
23476
|
+
const isLoaded = isLibraryLoadedRef.current;
|
|
23477
|
+
const adapter = "adapter" in optsRef.current && optsRef.current.adapter || null;
|
|
23478
|
+
try {
|
|
23479
|
+
if (adapter) {
|
|
23480
|
+
if (
|
|
23481
|
+
// if nextLibraryItems hash identical to previously saved hash,
|
|
23482
|
+
// exit early, even if actual upstream state ends up being
|
|
23483
|
+
// different (e.g. has more data than we have locally), as it'd
|
|
23484
|
+
// be low-impact scenario.
|
|
23485
|
+
lastSavedLibraryItemsHash !== getLibraryItemsHash(nextLibraryItems)
|
|
23486
|
+
) {
|
|
23487
|
+
await persistLibraryUpdate(adapter, update);
|
|
23488
|
+
}
|
|
23489
|
+
}
|
|
23490
|
+
} catch (error) {
|
|
23491
|
+
console.error(
|
|
23492
|
+
`couldn't persist library update: ${error.message}`,
|
|
23493
|
+
update
|
|
23494
|
+
);
|
|
23495
|
+
if (isLoaded && optsRef.current.excalidrawAPI) {
|
|
23496
|
+
optsRef.current.excalidrawAPI.updateScene({
|
|
23497
|
+
appState: {
|
|
23498
|
+
errorMessage: t("errors.saveLibraryError")
|
|
23499
|
+
}
|
|
23500
|
+
});
|
|
23501
|
+
}
|
|
23502
|
+
}
|
|
23503
|
+
}
|
|
23504
|
+
);
|
|
23505
|
+
const onUnload = (event) => {
|
|
23506
|
+
if (librarySaveCounter) {
|
|
23507
|
+
preventUnload(event);
|
|
23508
|
+
}
|
|
23509
|
+
};
|
|
23510
|
+
window.addEventListener("beforeunload" /* BEFORE_UNLOAD */, onUnload);
|
|
23511
|
+
return () => {
|
|
23512
|
+
window.removeEventListener("beforeunload" /* BEFORE_UNLOAD */, onUnload);
|
|
23513
|
+
unsubOnLibraryUpdate();
|
|
23514
|
+
lastSavedLibraryItemsHash = 0;
|
|
23515
|
+
librarySaveCounter = 0;
|
|
23516
|
+
};
|
|
23517
|
+
},
|
|
23518
|
+
[
|
|
23519
|
+
// this effect must not have any deps so it doesn't rerun
|
|
23520
|
+
]
|
|
23521
|
+
);
|
|
23193
23522
|
};
|
|
23194
23523
|
|
|
23195
23524
|
// components/App.tsx
|
|
@@ -33785,43 +34114,6 @@ var SVGLayer = ({ trails }) => {
|
|
|
33785
34114
|
// components/App.tsx
|
|
33786
34115
|
init_cursor();
|
|
33787
34116
|
|
|
33788
|
-
// emitter.ts
|
|
33789
|
-
init_define_import_meta_env();
|
|
33790
|
-
var Emitter = class {
|
|
33791
|
-
subscribers = [];
|
|
33792
|
-
/**
|
|
33793
|
-
* Attaches subscriber
|
|
33794
|
-
*
|
|
33795
|
-
* @returns unsubscribe function
|
|
33796
|
-
*/
|
|
33797
|
-
on(...handlers) {
|
|
33798
|
-
const _handlers = handlers.flat().filter((item) => typeof item === "function");
|
|
33799
|
-
this.subscribers.push(..._handlers);
|
|
33800
|
-
return () => this.off(_handlers);
|
|
33801
|
-
}
|
|
33802
|
-
once(...handlers) {
|
|
33803
|
-
const _handlers = handlers.flat().filter((item) => typeof item === "function");
|
|
33804
|
-
_handlers.push(() => detach());
|
|
33805
|
-
const detach = this.on(..._handlers);
|
|
33806
|
-
return detach;
|
|
33807
|
-
}
|
|
33808
|
-
off(...handlers) {
|
|
33809
|
-
const _handlers = handlers.flat();
|
|
33810
|
-
this.subscribers = this.subscribers.filter(
|
|
33811
|
-
(handler) => !_handlers.includes(handler)
|
|
33812
|
-
);
|
|
33813
|
-
}
|
|
33814
|
-
trigger(...payload) {
|
|
33815
|
-
for (const handler of this.subscribers) {
|
|
33816
|
-
handler(...payload);
|
|
33817
|
-
}
|
|
33818
|
-
return this;
|
|
33819
|
-
}
|
|
33820
|
-
clear() {
|
|
33821
|
-
this.subscribers = [];
|
|
33822
|
-
}
|
|
33823
|
-
};
|
|
33824
|
-
|
|
33825
34117
|
// element/ElementCanvasButtons.tsx
|
|
33826
34118
|
init_define_import_meta_env();
|
|
33827
34119
|
init_utils();
|
|
@@ -42142,9 +42434,12 @@ export {
|
|
|
42142
42434
|
exportToSvg2 as exportToSvg,
|
|
42143
42435
|
getCommonBounds,
|
|
42144
42436
|
getFreeDrawSvgPath,
|
|
42437
|
+
getLibraryItemsHash,
|
|
42145
42438
|
getNonDeletedElements3 as getNonDeletedElements,
|
|
42146
42439
|
getSceneVersion,
|
|
42147
42440
|
getVisibleSceneBounds,
|
|
42441
|
+
hashElementsVersion,
|
|
42442
|
+
hashString,
|
|
42148
42443
|
isElementInsideBBox,
|
|
42149
42444
|
isInvisiblySmallElement,
|
|
42150
42445
|
isLinearElement,
|