kritzel-stencil 0.4.0 → 0.4.2
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/dist/cjs/index.cjs.js +2 -1
- package/dist/cjs/kritzel-active-users_47.cjs.entry.js +365 -80
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{schema.constants-fuAsi56H.js → schema.constants-C8hqt--r.js} +274 -33
- package/dist/cjs/stencil.cjs.js +1 -1
- package/dist/collection/classes/core/workspace.class.js +1 -1
- package/dist/collection/classes/handlers/context-menu.handler.js +2 -3
- package/dist/collection/classes/managers/clipboard.manager.js +9 -3
- package/dist/collection/classes/objects/base-object.class.js +0 -1
- package/dist/collection/classes/objects/text.class.js +2 -1
- package/dist/collection/classes/registries/font-registry.class.js +161 -0
- package/dist/collection/classes/structures/object-map.structure.js +9 -0
- package/dist/collection/classes/tools/image-tool.class.js +19 -3
- package/dist/collection/classes/tools/text-tool.class.js +2 -0
- package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +22 -7
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +138 -9
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +186 -25
- package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.js +31 -22
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +10 -11
- package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +40 -5
- package/dist/collection/configs/default-text-tool.config.js +2 -0
- package/dist/collection/constants/text-tool-fonts.constants.js +18 -0
- package/dist/collection/constants/version.js +1 -1
- package/dist/collection/helpers/image-file.helper.js +6 -0
- package/dist/collection/index.js +2 -0
- package/dist/collection/interfaces/font.interface.js +1 -0
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-awareness-cursors.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-cursor-trail.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-font-family.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/kritzel-workspace-manager.js +1 -1
- package/dist/components/p--Oazz-BP.js +9 -0
- package/dist/components/p-C38P-Vd0.js +1 -0
- package/dist/components/{p-zhjb97WN.js → p-C3UQ-Zrg.js} +1 -1
- package/dist/components/{p-9692OaI_.js → p-ClFprFvz.js} +1 -1
- package/dist/components/p-Cm33td2O.js +1 -0
- package/dist/components/{p-DhMlShij.js → p-DAwPPDMS.js} +1 -1
- package/dist/components/p-DJkKlUyZ.js +1 -0
- package/dist/components/p-JYj3Facr.js +1 -0
- package/dist/components/p-Ka7OWbnk.js +1 -0
- package/dist/components/p-djJSnjAX.js +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-active-users_47.entry.js +365 -80
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{schema.constants-Cv5-yM39.js → schema.constants-uC7_X6yr.js} +272 -34
- package/dist/esm/stencil.js +1 -1
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-b64c3584.entry.js +9 -0
- package/dist/stencil/p-uC7_X6yr.js +1 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/workspace.class.d.ts +1 -1
- package/dist/types/classes/managers/clipboard.manager.d.ts +1 -0
- package/dist/types/classes/objects/base-object.class.d.ts +0 -1
- package/dist/types/classes/registries/font-registry.class.d.ts +19 -0
- package/dist/types/classes/structures/object-map.structure.d.ts +2 -2
- package/dist/types/classes/tools/image-tool.class.d.ts +9 -2
- package/dist/types/classes/tools/text-tool.class.d.ts +3 -0
- package/dist/types/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.d.ts +2 -0
- package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +22 -0
- package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +17 -0
- package/dist/types/components/shared/kritzel-font-family/kritzel-font-family.d.ts +4 -0
- package/dist/types/components/ui/kritzel-tool-config/kritzel-tool-config.d.ts +1 -0
- package/dist/types/components.d.ts +20 -2
- package/dist/types/constants/text-tool-fonts.constants.d.ts +3 -0
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/helpers/image-file.helper.d.ts +3 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/interfaces/font.interface.d.ts +15 -0
- package/dist/types/interfaces/toolbar-control.interface.d.ts +2 -0
- package/package.json +1 -1
- package/dist/components/p-B4b6TDxp.js +0 -1
- package/dist/components/p-C2ocjA6D.js +0 -1
- package/dist/components/p-CwbZCXKh.js +0 -1
- package/dist/components/p-D2q_wTyG.js +0 -1
- package/dist/components/p-D8NvNMcU.js +0 -1
- package/dist/components/p-D8W6LE-c.js +0 -1
- package/dist/components/p-G9G9y5VE.js +0 -9
- package/dist/components/p-JhOYwUOj.js +0 -1
- package/dist/components/p-UEf2EN23.js +0 -1
- package/dist/stencil/p-2c489187.entry.js +0 -9
- package/dist/stencil/p-Cv5-yM39.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-Dhio9uis.js';
|
|
2
|
-
import { c as KritzelPath, e as KritzelLine,
|
|
2
|
+
import { c as KritzelPath, e as KritzelLine, T as KritzelColorHelper, U as KritzelDevicesHelper, V as KritzelMouseButton, X as KritzelHTMLHelper, Y as DEFAULT_STROKE_SIZES, Z as DEFAULT_COLOR_PALETTE, S as ShapeType, q as KritzelSelectionTool, D as DEFAULT_BRUSH_CONFIG, j as KritzelBrushTool, l as KritzelEraserTool, B as DEFAULT_LINE_TOOL_CONFIG, k as KritzelLineTool, o as KritzelShapeTool, z as DEFAULT_TEXT_CONFIG, n as KritzelTextTool, m as KritzelImageTool, M as KritzelAlignment, C as DEFAULT_ASSET_STORAGE_CONFIG, _ as ObjectHelper, $ as resolveTextToolAvailableFonts, a0 as ThemeHelper, F as darkTheme, E as lightTheme, a1 as KritzelSelectionGroup, a2 as KritzelSelectionBox, a3 as KritzelIconRegistry, y as KritzelFontRegistry, a4 as KritzelKeyboardHelper, a5 as KritzelBaseHandler, s as KritzelWorkspace, f as KritzelGroup, h as KritzelCustomElement, d as KritzelImage, g as KritzelShape, b as KritzelText, N as runMigrations, R as CURRENT_WORKSPACE_SCHEMA_VERSION, P as WORKSPACE_MIGRATIONS, a6 as KritzelClassHelper, Q as CURRENT_APP_STATE_SCHEMA_VERSION, O as APP_STATE_MIGRATIONS, p as KritzelCursorHelper, a7 as KritzelImageFileHelper, a8 as imageCompression, t as KritzelAnchorManager, u as KritzelThemeManager, v as KritzelLocalizationManager, w as KritzelLicenseManager, r as KritzelAssetResolver, a9 as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION, i as KritzelBaseTool } from './schema.constants-uC7_X6yr.js';
|
|
3
3
|
import * as Y from 'yjs';
|
|
4
4
|
import 'y-indexeddb';
|
|
5
5
|
import 'y-websocket';
|
|
@@ -174,23 +174,38 @@ const KritzelAwarenessCursors = class {
|
|
|
174
174
|
objectVersion = 0;
|
|
175
175
|
cleanupIntervalId;
|
|
176
176
|
objectChangeRafId = null;
|
|
177
|
+
removeAwarenessChangeListener;
|
|
178
|
+
removeObjectsChangeListener;
|
|
177
179
|
componentDidLoad() {
|
|
178
|
-
this.core.store.objects?.onAwarenessChange(states => {
|
|
180
|
+
this.removeAwarenessChangeListener = this.core.store.objects?.onAwarenessChange(states => {
|
|
179
181
|
this.handleAwarenessChange(states);
|
|
180
182
|
});
|
|
181
|
-
this.core.store.objects?.onObjectsChange(() => {
|
|
183
|
+
this.removeObjectsChangeListener = this.core.store.objects?.onObjectsChange(() => {
|
|
182
184
|
this.handleRemoteObjectChange();
|
|
183
185
|
});
|
|
184
186
|
this.cleanupIntervalId = setInterval(() => {
|
|
185
187
|
this.cleanupStaleCursors();
|
|
186
188
|
}, CLEANUP_INTERVAL_MS);
|
|
189
|
+
if (this.cleanupIntervalId && typeof this.cleanupIntervalId.unref === 'function') {
|
|
190
|
+
this.cleanupIntervalId.unref();
|
|
191
|
+
}
|
|
187
192
|
}
|
|
188
193
|
disconnectedCallback() {
|
|
189
|
-
if (this.
|
|
190
|
-
|
|
194
|
+
if (this.removeAwarenessChangeListener) {
|
|
195
|
+
this.removeAwarenessChangeListener();
|
|
196
|
+
this.removeAwarenessChangeListener = undefined;
|
|
197
|
+
}
|
|
198
|
+
if (this.removeObjectsChangeListener) {
|
|
199
|
+
this.removeObjectsChangeListener();
|
|
200
|
+
this.removeObjectsChangeListener = undefined;
|
|
191
201
|
}
|
|
192
|
-
if (this.
|
|
193
|
-
|
|
202
|
+
if (this.cleanupIntervalId && typeof globalThis.clearInterval === 'function') {
|
|
203
|
+
globalThis.clearInterval(this.cleanupIntervalId);
|
|
204
|
+
this.cleanupIntervalId = undefined;
|
|
205
|
+
}
|
|
206
|
+
if (this.objectChangeRafId !== null && typeof globalThis.cancelAnimationFrame === 'function') {
|
|
207
|
+
globalThis.cancelAnimationFrame(this.objectChangeRafId);
|
|
208
|
+
this.objectChangeRafId = null;
|
|
194
209
|
}
|
|
195
210
|
}
|
|
196
211
|
handleAwarenessChange(states) {
|
|
@@ -348,7 +363,7 @@ const KritzelAwarenessCursors = class {
|
|
|
348
363
|
}
|
|
349
364
|
render() {
|
|
350
365
|
const cursors = Array.from(this.remoteCursors.values());
|
|
351
|
-
return (h(Host, { key: '
|
|
366
|
+
return (h(Host, { key: '9be6694250bafe011be27301d1c7a53fc7957657' }, cursors.map(remoteCursor => {
|
|
352
367
|
if (!remoteCursor.cursor)
|
|
353
368
|
return null;
|
|
354
369
|
// When a remote user is actively drawing, derive cursor position from
|
|
@@ -971,8 +986,9 @@ const KritzelControls = class {
|
|
|
971
986
|
this.closeTooltip();
|
|
972
987
|
}
|
|
973
988
|
handleSelectionChange() {
|
|
974
|
-
|
|
975
|
-
|
|
989
|
+
const tool = this.activeControl?.tool;
|
|
990
|
+
if (tool && typeof tool !== 'function' && tool.toolType === 'selection') {
|
|
991
|
+
this.updateDisplayValues(tool);
|
|
976
992
|
}
|
|
977
993
|
}
|
|
978
994
|
async onControlsChange() {
|
|
@@ -1023,7 +1039,7 @@ const KritzelControls = class {
|
|
|
1023
1039
|
color: KritzelColorHelper.applyOpacity(color, opacity, this.theme),
|
|
1024
1040
|
size,
|
|
1025
1041
|
};
|
|
1026
|
-
if (tool
|
|
1042
|
+
if (tool.toolType === 'text') {
|
|
1027
1043
|
displayValues.fontFamily = tool.fontFamily;
|
|
1028
1044
|
}
|
|
1029
1045
|
// Check for equality implementation to prevent unnecessary re-renders
|
|
@@ -1164,13 +1180,13 @@ const KritzelControls = class {
|
|
|
1164
1180
|
// Separate tool controls from config control
|
|
1165
1181
|
const toolControls = this.internalControls.filter(c => c.type === 'tool' || c.type === 'separator');
|
|
1166
1182
|
const configControl = this.internalControls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
|
|
1167
|
-
return (h(Host, { key: '
|
|
1183
|
+
return (h(Host, { key: 'a526bd337a6b75933ec4be89c3edded0a9c39e7c', style: { display: this.visible ? '' : 'none' }, class: {
|
|
1168
1184
|
mobile: this.isTouchDevice,
|
|
1169
|
-
} }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '
|
|
1185
|
+
} }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '5314f067c5a22425690e3b6f26c836962ac528a2', style: {
|
|
1170
1186
|
position: 'absolute',
|
|
1171
1187
|
bottom: '56px',
|
|
1172
1188
|
left: '12px',
|
|
1173
|
-
}, undoState: this.undoState, terms: this.terms, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '
|
|
1189
|
+
}, undoState: this.undoState, terms: this.terms, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '7cf0cd164d723b5901f54a6671395f63dd8bad29', class: "kritzel-controls" }, h("div", { key: 'b7169122686a0a67c37d96751291fc43f4c45e4a', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), h("div", { key: '6e3c4f30900e4722abdfaf3cfdc68cf1a07b9292', class: "kritzel-tools-scroll", ref: el => (this.toolsScrollRef = el), onScroll: this.handleToolsScroll }, toolControls.map(control => {
|
|
1174
1190
|
// Check if this control has sub-options (split-button)
|
|
1175
1191
|
if (control.subOptions?.length) {
|
|
1176
1192
|
const selectedSubOption = this.getSelectedSubOption(control);
|
|
@@ -1200,10 +1216,10 @@ const KritzelControls = class {
|
|
|
1200
1216
|
'kritzel-control': true,
|
|
1201
1217
|
'selected': this.activeControl?.name === control?.name,
|
|
1202
1218
|
}, key: control.name, "data-testid": `tool-${control.name}`, onClick: _event => this.handleControlClick?.(control), "aria-label": control.name.charAt(0).toUpperCase() + control.name.slice(1) }, h("kritzel-icon", { name: control.icon })));
|
|
1203
|
-
})), h("div", { key: '
|
|
1219
|
+
})), h("div", { key: 'bc8d79e0512f30fe150c6d2ac7f81206fc47c1a5', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (h("div", { class: {
|
|
1204
1220
|
'kritzel-config-container': true,
|
|
1205
1221
|
'visible': hasConfigUI,
|
|
1206
|
-
}, key: configControl.name }, h("div", { key: '
|
|
1222
|
+
}, key: configControl.name }, h("div", { key: '671431a9c388080fb917d4e8c596d17e92eaba08', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), h("kritzel-tooltip", { key: '394e8e2c07b191b3fb93645d68d7eae67761167a', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, h("kritzel-tool-config", { key: 'b8479fba2afdb51fe0ef965e18b1ae45ba8a7da6', tool: this.activeControl.tool, theme: this.theme, engine: this.kritzelEngine, terms: this.terms, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), h("div", { key: '8fac81d682dbdec6b5247154fd20d553dfe6f1a7', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
|
|
1207
1223
|
if (el)
|
|
1208
1224
|
this.configTriggerRef = el;
|
|
1209
1225
|
}, onKeyDown: event => {
|
|
@@ -1212,7 +1228,7 @@ const KritzelControls = class {
|
|
|
1212
1228
|
}
|
|
1213
1229
|
}, style: {
|
|
1214
1230
|
cursor: 'pointer',
|
|
1215
|
-
} }, this.displayValues && (h("div", { key: '
|
|
1231
|
+
} }, this.displayValues && (h("div", { key: '6aa1daed9425d069c7d0405a04e65b4c4e88291f', class: "color-container" }, h("kritzel-color", { key: '7b54461769bf4aec3e39d1fbe21c015b7d7a85bb', value: this.displayValues.color, theme: this.theme, size: 18, style: {
|
|
1216
1232
|
borderRadius: '50%',
|
|
1217
1233
|
border: 'none',
|
|
1218
1234
|
} })))))))));
|
|
@@ -2290,6 +2306,11 @@ const KritzelEditor = class {
|
|
|
2290
2306
|
/** The locale used to resolve terms missing from the active locale. */
|
|
2291
2307
|
fallbackLocale = 'en';
|
|
2292
2308
|
customSvgIcons = {};
|
|
2309
|
+
/**
|
|
2310
|
+
* Registers fonts for runtime usage (for example custom object rendering).
|
|
2311
|
+
* Text-tool config tooltip options are controlled via controls[].config.availableFonts.
|
|
2312
|
+
*/
|
|
2313
|
+
customFonts = {};
|
|
2293
2314
|
isPanningEnabled = true;
|
|
2294
2315
|
isZoomingEnabled = true;
|
|
2295
2316
|
isControlsVisible = true;
|
|
@@ -2342,11 +2363,14 @@ const KritzelEditor = class {
|
|
|
2342
2363
|
isEditorVisible = false;
|
|
2343
2364
|
activeNotification;
|
|
2344
2365
|
isNotificationDismissing = false;
|
|
2366
|
+
normalizedControls = [];
|
|
2345
2367
|
notificationDismissTimeout;
|
|
2346
2368
|
notificationDismissAnimationTimeout;
|
|
2347
2369
|
notificationDisplayDurationMs = 5000;
|
|
2348
2370
|
notificationDismissAnimationDurationMs = 180;
|
|
2349
2371
|
isNotificationHovered = false;
|
|
2372
|
+
customFontsLoadVersion = 0;
|
|
2373
|
+
customFontsReady = Promise.resolve();
|
|
2350
2374
|
onIsEngineReady(newValue) {
|
|
2351
2375
|
if (newValue && this.isControlsReady) {
|
|
2352
2376
|
this.checkIsReady();
|
|
@@ -2376,6 +2400,12 @@ const KritzelEditor = class {
|
|
|
2376
2400
|
onActiveWorkspaceChange() {
|
|
2377
2401
|
this.updateCurrentIsPublic();
|
|
2378
2402
|
}
|
|
2403
|
+
onCustomFontsChange(newValue) {
|
|
2404
|
+
void this.registerCustomFonts(newValue);
|
|
2405
|
+
}
|
|
2406
|
+
onControlsChange(newValue) {
|
|
2407
|
+
this.normalizedControls = this.normalizeControls(newValue);
|
|
2408
|
+
}
|
|
2379
2409
|
onActiveWorkspaceIdChange(newId) {
|
|
2380
2410
|
// If no ID is provided, do nothing (allows other logic to control activeWorkspace)
|
|
2381
2411
|
if (!newId) {
|
|
@@ -2649,9 +2679,27 @@ const KritzelEditor = class {
|
|
|
2649
2679
|
loginDialogRef;
|
|
2650
2680
|
currentUserDialogRef;
|
|
2651
2681
|
componentWillLoad() {
|
|
2682
|
+
this.normalizedControls = this.normalizeControls(this.controls);
|
|
2652
2683
|
this.loadSettingsFromStorage();
|
|
2653
2684
|
this.applyTheme();
|
|
2654
2685
|
}
|
|
2686
|
+
isTextToolConfig(config) {
|
|
2687
|
+
return !!config && 'fontFamily' in config && 'size' in config && 'color' in config;
|
|
2688
|
+
}
|
|
2689
|
+
normalizeControls(controls) {
|
|
2690
|
+
return controls.map(control => {
|
|
2691
|
+
if (!this.isTextToolConfig(control.config)) {
|
|
2692
|
+
return control;
|
|
2693
|
+
}
|
|
2694
|
+
return {
|
|
2695
|
+
...control,
|
|
2696
|
+
config: {
|
|
2697
|
+
...control.config,
|
|
2698
|
+
availableFonts: resolveTextToolAvailableFonts(control.config.availableFonts),
|
|
2699
|
+
},
|
|
2700
|
+
};
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2655
2703
|
applyTheme() {
|
|
2656
2704
|
const themeObj = this.resolveThemeObject();
|
|
2657
2705
|
ThemeHelper.applyThemeToElement(this.host, themeObj);
|
|
@@ -2662,6 +2710,7 @@ const KritzelEditor = class {
|
|
|
2662
2710
|
}
|
|
2663
2711
|
componentDidLoad() {
|
|
2664
2712
|
this.registerCustomSvgIcons();
|
|
2713
|
+
this.registerCustomFonts();
|
|
2665
2714
|
this.listenForMobileKeyboard();
|
|
2666
2715
|
this.setOsSpecificCssVariables();
|
|
2667
2716
|
}
|
|
@@ -2674,6 +2723,7 @@ const KritzelEditor = class {
|
|
|
2674
2723
|
await customElements.whenDefined('kritzel-workspace-manager');
|
|
2675
2724
|
await customElements.whenDefined('kritzel-controls');
|
|
2676
2725
|
await customElements.whenDefined('kritzel-engine');
|
|
2726
|
+
await this.waitForCustomFontsReady();
|
|
2677
2727
|
if (!this.isEngineReady || !this.isControlsReady || !this.isWorkspaceManagerReady || !this.activeWorkspace) {
|
|
2678
2728
|
return;
|
|
2679
2729
|
}
|
|
@@ -2937,6 +2987,15 @@ const KritzelEditor = class {
|
|
|
2937
2987
|
async registerLocales(locales) {
|
|
2938
2988
|
await this.engineRef?.registerLocales(locales);
|
|
2939
2989
|
}
|
|
2990
|
+
/**
|
|
2991
|
+
* Registers custom fonts for the editor runtime.
|
|
2992
|
+
* @param fonts - Mapping from font keys to family names or font definitions.
|
|
2993
|
+
* @remarks This no longer controls the text-tool config tooltip font options.
|
|
2994
|
+
* Configure tooltip fonts via controls[].config.availableFonts.
|
|
2995
|
+
*/
|
|
2996
|
+
async registerFonts(fonts) {
|
|
2997
|
+
await this.registerCustomFonts(fonts);
|
|
2998
|
+
}
|
|
2940
2999
|
/**
|
|
2941
3000
|
* Resolves a term key to its translated string for the active locale.
|
|
2942
3001
|
* @param key - The term key to resolve.
|
|
@@ -3014,6 +3073,25 @@ const KritzelEditor = class {
|
|
|
3014
3073
|
KritzelIconRegistry.register(name, svg);
|
|
3015
3074
|
}
|
|
3016
3075
|
}
|
|
3076
|
+
async registerCustomFonts(fonts = this.customFonts) {
|
|
3077
|
+
KritzelFontRegistry.registerFonts(fonts);
|
|
3078
|
+
const currentVersion = ++this.customFontsLoadVersion;
|
|
3079
|
+
const loadPromise = KritzelFontRegistry.waitForFonts(fonts);
|
|
3080
|
+
this.customFontsReady = loadPromise;
|
|
3081
|
+
await loadPromise;
|
|
3082
|
+
if (currentVersion !== this.customFontsLoadVersion) {
|
|
3083
|
+
await this.waitForCustomFontsReady();
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
async waitForCustomFontsReady() {
|
|
3087
|
+
while (true) {
|
|
3088
|
+
const version = this.customFontsLoadVersion;
|
|
3089
|
+
await this.customFontsReady;
|
|
3090
|
+
if (version === this.customFontsLoadVersion) {
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3017
3095
|
listenForMobileKeyboard() {
|
|
3018
3096
|
KritzelKeyboardHelper.onKeyboardVisibleChanged(isOpen => {
|
|
3019
3097
|
this.isVirtualKeyboardOpen = isOpen;
|
|
@@ -3052,36 +3130,36 @@ const KritzelEditor = class {
|
|
|
3052
3130
|
const isLoggedIn = this.isLoggedIn;
|
|
3053
3131
|
const shouldShowCurrentUser = isLoggedIn;
|
|
3054
3132
|
const shouldShowLoginButton = this.isReady && !!this.loginConfig && !isLoggedIn;
|
|
3055
|
-
return (h(Host, { key: '
|
|
3133
|
+
return (h(Host, { key: '00d652c74feac7b4917772146368125da6deeb1c' }, h("div", { key: 'f8fb86b45b0cdabb5e3ad52de6d6ef31a71a09e4', class: "editor-content", style: {
|
|
3056
3134
|
opacity: this.isEditorVisible ? '1' : '0',
|
|
3057
3135
|
visibility: this.isEditorVisible ? 'visible' : 'hidden',
|
|
3058
3136
|
transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
|
|
3059
|
-
} }, h("div", { key: '
|
|
3137
|
+
} }, h("div", { key: '2378c776d8eecf2614567bed11c6e93fb338e302', class: "top-left-buttons" }, h("kritzel-workspace-manager", { key: 'ce41192540169694482d6f8cca60701bc4427438', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, terms: this.resolvedTerms, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-back-to-content", { key: 'ec269d3e9f589362d8301370778f0c5e4252eead', visible: this.isBackToContentButtonVisible, text: this.resolvedTerms['backToContent.label'] ?? 'Back to content', onBackToContent: () => this.backToContent() })), this.activeNotification && (h("div", { key: '847ed8149d556c934090424ff54b17b6721ccc76', class: "top-center-notification-layer", role: "presentation" }, h("div", { key: '61d8b8e91cda100ffa6620db26ba6dfb2232946a', class: { 'top-center-notification-container': true, 'is-dismissing': this.isNotificationDismissing }, role: "presentation" }, h("kritzel-notification-card", { key: 'b7e132773225ace38e447756110dd39e4661f5fc', notification: this.activeNotification, locale: this.locale, onDismiss: this.dismissNotification, onHoverChange: event => this.handleNotificationHoverChange(event) })))), h("kritzel-engine", { key: '3e4a6d0dbc015ec675fb21a59990c87e9eaa805f', ref: el => {
|
|
3060
3138
|
if (el) {
|
|
3061
3139
|
this.engineRef = el;
|
|
3062
3140
|
}
|
|
3063
|
-
}, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event), onNotificationsChange: event => this.handleNotificationsChange(event) }), h("kritzel-controls", { key: '
|
|
3141
|
+
}, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event), onNotificationsChange: event => this.handleNotificationsChange(event) }), h("kritzel-controls", { key: 'f84607a0a4d0762c1249400f85b7b8454d672c1e', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
|
|
3064
3142
|
if (el) {
|
|
3065
3143
|
this.controlsRef = el;
|
|
3066
3144
|
}
|
|
3067
|
-
}, controls: this.
|
|
3145
|
+
}, controls: this.normalizedControls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: 'e2691e7c730195e197511cb1e4d0fe707677b5ff', class: "bottom-left-buttons" }, h("kritzel-zoom-panel", { key: 'd0ac6624eab49af78d4761c3ad91842834717aad', visible: this.isZoomPanelVisible, disabled: !this.isZoomingEnabled, zoomPercent: this.currentZoomPercent, terms: this.resolvedTerms, onZoomIn: () => this.zoomIn(), onZoomOut: () => this.zoomOut() })), h("div", { key: 'ad3d386ab7e8ad9fdfbb12754db005bc85fa28ce', class: "top-right-buttons" }, h("kritzel-settings", { key: '566024ac6f3d8f7f20238cc1f83882b39dbf698e', ref: el => {
|
|
3068
3146
|
if (el) {
|
|
3069
3147
|
this.settingsRef = el;
|
|
3070
3148
|
}
|
|
3071
|
-
}, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '
|
|
3149
|
+
}, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '4a23ea0c6e070d424a90e9fc87de04e11cff7ade', ref: el => {
|
|
3072
3150
|
if (el) {
|
|
3073
3151
|
this.exportRef = el;
|
|
3074
3152
|
}
|
|
3075
|
-
}, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '
|
|
3153
|
+
}, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: 'feef074b52e552fa2ef7e8258002571aca4c5abd', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: '844c722545363eaf7eec69037a835eae943afeb9', user: this.user, terms: this.resolvedTerms, onClick: () => this.currentUserDialogRef?.open() }), shouldShowCurrentUser && (h("kritzel-current-user-dialog", { key: '8363c1d3230d111cf1ace0ccf805669e592bb533', ref: el => {
|
|
3076
3154
|
if (el) {
|
|
3077
3155
|
this.currentUserDialogRef = el;
|
|
3078
3156
|
this.currentUserDialogRef.addEventListener('logoutRequest', this.handleCurrentUserLogout);
|
|
3079
3157
|
}
|
|
3080
|
-
}, user: this.user, terms: this.resolvedTerms })), shouldShowLoginButton && (h("kritzel-button", { key: '
|
|
3158
|
+
}, user: this.user, terms: this.resolvedTerms })), shouldShowLoginButton && (h("kritzel-button", { key: '68ddf8c3aabc7634b4c1d88f3d2d584fa1f1b150', onButtonClick: () => this.loginDialogRef?.open() }, this.resolvedTerms['login.dialogTitle'] ?? 'Sign in')), h("kritzel-more-menu", { key: '39b938f5792f7a36bbf21ed88a1a5c7717a785a6', items: this.moreMenuItems, visible: this.isMoreMenuVisible, terms: this.resolvedTerms }), h("kritzel-share-dialog", { key: '61ed918499760d874d5d2ec140d3cf59ce94520b', ref: el => {
|
|
3081
3159
|
if (el) {
|
|
3082
3160
|
this.shareDialogRef = el;
|
|
3083
3161
|
}
|
|
3084
|
-
}, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: '
|
|
3162
|
+
}, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: '5f6528a57884bd1494e45755609e710f69041a4d', ref: el => {
|
|
3085
3163
|
if (el) {
|
|
3086
3164
|
this.loginDialogRef = el;
|
|
3087
3165
|
}
|
|
@@ -3100,6 +3178,12 @@ const KritzelEditor = class {
|
|
|
3100
3178
|
"activeWorkspace": [{
|
|
3101
3179
|
"onActiveWorkspaceChange": 0
|
|
3102
3180
|
}],
|
|
3181
|
+
"customFonts": [{
|
|
3182
|
+
"onCustomFontsChange": 0
|
|
3183
|
+
}],
|
|
3184
|
+
"controls": [{
|
|
3185
|
+
"onControlsChange": 0
|
|
3186
|
+
}],
|
|
3103
3187
|
"activeWorkspaceId": [{
|
|
3104
3188
|
"onActiveWorkspaceIdChange": 0
|
|
3105
3189
|
}],
|
|
@@ -21381,7 +21465,7 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
|
|
|
21381
21465
|
* @returns void - This method does not return a value; it updates state and triggers a rerender.
|
|
21382
21466
|
*/
|
|
21383
21467
|
handleContextMenu(event) {
|
|
21384
|
-
if (
|
|
21468
|
+
if (this._core.store.state.activeTool?.toolType !== 'selection') {
|
|
21385
21469
|
return;
|
|
21386
21470
|
}
|
|
21387
21471
|
if (this._core.store.state.skipContextMenu) {
|
|
@@ -21441,7 +21525,7 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
|
|
|
21441
21525
|
*/
|
|
21442
21526
|
open(options) {
|
|
21443
21527
|
const { x, y, objectId } = options;
|
|
21444
|
-
if (this._core.store.state.activeTool
|
|
21528
|
+
if (this._core.store.state.activeTool?.toolType === 'selection') {
|
|
21445
21529
|
const selectionTool = this._core.store.state.activeTool;
|
|
21446
21530
|
selectionTool?.moveHandler?.cancelPendingDrag();
|
|
21447
21531
|
}
|
|
@@ -22256,6 +22340,9 @@ class KritzelObjectMap {
|
|
|
22256
22340
|
*/
|
|
22257
22341
|
onAwarenessChange(callback) {
|
|
22258
22342
|
this._awarenessChangeCallbacks.push(callback);
|
|
22343
|
+
return () => {
|
|
22344
|
+
this._awarenessChangeCallbacks = this._awarenessChangeCallbacks.filter(existingCallback => existingCallback !== callback);
|
|
22345
|
+
};
|
|
22259
22346
|
}
|
|
22260
22347
|
/**
|
|
22261
22348
|
* Registers a callback to be invoked when remote object changes are received.
|
|
@@ -22264,6 +22351,9 @@ class KritzelObjectMap {
|
|
|
22264
22351
|
*/
|
|
22265
22352
|
onObjectsChange(callback) {
|
|
22266
22353
|
this._objectsChangeCallbacks.push(callback);
|
|
22354
|
+
return () => {
|
|
22355
|
+
this._objectsChangeCallbacks = this._objectsChangeCallbacks.filter(existingCallback => existingCallback !== callback);
|
|
22356
|
+
};
|
|
22267
22357
|
}
|
|
22268
22358
|
/**
|
|
22269
22359
|
* Returns the Yjs UndoManager instance for managing undo/redo operations.
|
|
@@ -22460,6 +22550,9 @@ class KritzelObjectMap {
|
|
|
22460
22550
|
callback(states);
|
|
22461
22551
|
}
|
|
22462
22552
|
}, delayMs);
|
|
22553
|
+
if (typeof this._awarenessEmitTimeout.unref === 'function') {
|
|
22554
|
+
this._awarenessEmitTimeout.unref();
|
|
22555
|
+
}
|
|
22463
22556
|
}
|
|
22464
22557
|
};
|
|
22465
22558
|
this._awareness.on('change', this._awarenessChangeHandler);
|
|
@@ -24450,9 +24543,8 @@ class KritzelClipboardManager {
|
|
|
24450
24543
|
const scale = this._core.store.state.scale;
|
|
24451
24544
|
const offset = 25 / scale;
|
|
24452
24545
|
const preparePromises = intent.files.map(async (file, index) => {
|
|
24453
|
-
|
|
24454
|
-
|
|
24455
|
-
return KritzelImage.fromBlob(this._core, compressed, {
|
|
24546
|
+
const preparedFile = await this.prepareImageFile(file);
|
|
24547
|
+
return KritzelImage.fromBlob(this._core, preparedFile, {
|
|
24456
24548
|
translateX: index * offset,
|
|
24457
24549
|
translateY: index * offset,
|
|
24458
24550
|
});
|
|
@@ -24464,6 +24556,12 @@ class KritzelClipboardManager {
|
|
|
24464
24556
|
return null;
|
|
24465
24557
|
}
|
|
24466
24558
|
}
|
|
24559
|
+
async prepareImageFile(file) {
|
|
24560
|
+
if (KritzelImageFileHelper.isGifFile(file)) {
|
|
24561
|
+
return file;
|
|
24562
|
+
}
|
|
24563
|
+
return imageCompression(file, { maxWidthOrHeight: 1200 });
|
|
24564
|
+
}
|
|
24467
24565
|
async materializePlainText(intent) {
|
|
24468
24566
|
const textObject = KritzelText.create(this._core);
|
|
24469
24567
|
const paragraphs = intent.text.split('\n').map(line => {
|
|
@@ -27931,7 +28029,7 @@ const KritzelEngine = class {
|
|
|
27931
28029
|
}
|
|
27932
28030
|
return existingTool;
|
|
27933
28031
|
}
|
|
27934
|
-
const registeredTool = this.core.toolRegistry.registerTool(toolName, toolClass);
|
|
28032
|
+
const registeredTool = this.core.toolRegistry.registerTool(toolName, this.resolveToolClass(toolClass));
|
|
27935
28033
|
if (toolConfig) {
|
|
27936
28034
|
this.applyToolConfig(registeredTool, toolConfig);
|
|
27937
28035
|
}
|
|
@@ -28733,8 +28831,25 @@ const KritzelEngine = class {
|
|
|
28733
28831
|
if (!workspace) {
|
|
28734
28832
|
throw new Error('Cannot export workspace: no active workspace is loaded');
|
|
28735
28833
|
}
|
|
28834
|
+
await this.core.initializeAssetStorage();
|
|
28736
28835
|
const serialized = workspace.serialize({ includeObjects: true });
|
|
28737
|
-
|
|
28836
|
+
const exportMode = this.getWorkspaceExportMode();
|
|
28837
|
+
const { objects, ...workspaceWithoutObjects } = serialized;
|
|
28838
|
+
const payload = {
|
|
28839
|
+
...workspaceWithoutObjects,
|
|
28840
|
+
exportMode,
|
|
28841
|
+
...(objects !== undefined ? { objects } : {}),
|
|
28842
|
+
};
|
|
28843
|
+
if (exportMode === 'portable') {
|
|
28844
|
+
const portableAssets = await this.collectPortableAssets(payload.objects);
|
|
28845
|
+
if (Object.keys(portableAssets).length > 0) {
|
|
28846
|
+
payload.assets = portableAssets;
|
|
28847
|
+
}
|
|
28848
|
+
}
|
|
28849
|
+
else {
|
|
28850
|
+
delete payload.assets;
|
|
28851
|
+
}
|
|
28852
|
+
return JSON.stringify(payload, null, 2);
|
|
28738
28853
|
}
|
|
28739
28854
|
/**
|
|
28740
28855
|
* Imports a workspace from a JSON string into a new workspace.
|
|
@@ -28748,22 +28863,15 @@ const KritzelEngine = class {
|
|
|
28748
28863
|
if (!data.__class__ || data.__class__ !== 'KritzelWorkspace') {
|
|
28749
28864
|
throw new Error('Invalid workspace data: missing or incorrect __class__ identifier');
|
|
28750
28865
|
}
|
|
28866
|
+
await this.core.initializeAssetStorage();
|
|
28867
|
+
await this.restorePortableAssets(data);
|
|
28751
28868
|
if (data.version && data.version !== WORKSPACE_EXPORT_VERSION) {
|
|
28752
28869
|
console.warn(`Workspace version mismatch: expected ${WORKSPACE_EXPORT_VERSION}, got ${data.version}`);
|
|
28753
28870
|
}
|
|
28754
28871
|
// Create a new workspace with a fresh ID but use the imported name
|
|
28755
28872
|
const newWorkspaceId = ObjectHelper.generateUUID();
|
|
28756
|
-
const importedName = data.name
|
|
28757
|
-
|
|
28758
|
-
// Backward compatibility: convert legacy translateX/translateY to centerWorldX/centerWorldY
|
|
28759
|
-
if ('translateX' in importedViewport && !('centerWorldX' in importedViewport)) {
|
|
28760
|
-
const scale = importedViewport.scale ?? 1;
|
|
28761
|
-
importedViewport = {
|
|
28762
|
-
centerWorldX: -(importedViewport.translateX ?? 0) / scale,
|
|
28763
|
-
centerWorldY: -(importedViewport.translateY ?? 0) / scale,
|
|
28764
|
-
scale,
|
|
28765
|
-
};
|
|
28766
|
-
}
|
|
28873
|
+
const importedName = this.getImportedWorkspaceName(data.name);
|
|
28874
|
+
const importedViewport = this.getImportedWorkspaceViewport(data.viewport);
|
|
28767
28875
|
const newWorkspace = new KritzelWorkspace(newWorkspaceId, importedName, importedViewport);
|
|
28768
28876
|
// Save the new workspace
|
|
28769
28877
|
this.core.createWorkspace(newWorkspace);
|
|
@@ -28802,6 +28910,8 @@ const KritzelEngine = class {
|
|
|
28802
28910
|
if (!data.__class__ || data.__class__ !== 'KritzelWorkspace') {
|
|
28803
28911
|
throw new Error('Invalid workspace data: missing or incorrect __class__ identifier');
|
|
28804
28912
|
}
|
|
28913
|
+
await this.core.initializeAssetStorage();
|
|
28914
|
+
await this.restorePortableAssets(data);
|
|
28805
28915
|
if (data.version && data.version !== WORKSPACE_EXPORT_VERSION) {
|
|
28806
28916
|
console.warn(`Workspace version mismatch: expected ${WORKSPACE_EXPORT_VERSION}, got ${data.version}`);
|
|
28807
28917
|
}
|
|
@@ -28828,6 +28938,98 @@ const KritzelEngine = class {
|
|
|
28828
28938
|
this.core.rerender();
|
|
28829
28939
|
return loadedCount;
|
|
28830
28940
|
}
|
|
28941
|
+
getWorkspaceExportMode() {
|
|
28942
|
+
return this.core.assetResolver.hasRemoteProvider ? 'lightweight' : 'portable';
|
|
28943
|
+
}
|
|
28944
|
+
async collectPortableAssets(serializedObjects) {
|
|
28945
|
+
if (!Array.isArray(serializedObjects) || serializedObjects.length === 0) {
|
|
28946
|
+
return {};
|
|
28947
|
+
}
|
|
28948
|
+
const assetIds = new Set();
|
|
28949
|
+
for (const serializedObject of serializedObjects) {
|
|
28950
|
+
if (!serializedObject || typeof serializedObject !== 'object') {
|
|
28951
|
+
continue;
|
|
28952
|
+
}
|
|
28953
|
+
const maybeImage = serializedObject;
|
|
28954
|
+
if (maybeImage.__class__ === 'KritzelImage' && typeof maybeImage.assetId === 'string' && maybeImage.assetId.length > 0) {
|
|
28955
|
+
assetIds.add(maybeImage.assetId);
|
|
28956
|
+
}
|
|
28957
|
+
}
|
|
28958
|
+
const assets = {};
|
|
28959
|
+
for (const assetId of assetIds) {
|
|
28960
|
+
try {
|
|
28961
|
+
const blob = await this.core.assetResolver.fetchBlob(assetId);
|
|
28962
|
+
assets[assetId] = await this.blobToDataUrl(blob);
|
|
28963
|
+
}
|
|
28964
|
+
catch (error) {
|
|
28965
|
+
console.warn(`[Kritzel] Failed to embed asset ${assetId} in portable workspace export:`, error);
|
|
28966
|
+
}
|
|
28967
|
+
}
|
|
28968
|
+
return assets;
|
|
28969
|
+
}
|
|
28970
|
+
async restorePortableAssets(data) {
|
|
28971
|
+
const assets = data.assets;
|
|
28972
|
+
if (!assets || typeof assets !== 'object') {
|
|
28973
|
+
return;
|
|
28974
|
+
}
|
|
28975
|
+
for (const [assetId, dataUrl] of Object.entries(assets)) {
|
|
28976
|
+
if (!assetId || typeof dataUrl !== 'string' || !dataUrl.startsWith('data:')) {
|
|
28977
|
+
continue;
|
|
28978
|
+
}
|
|
28979
|
+
try {
|
|
28980
|
+
const blob = await this.dataUrlToBlob(dataUrl);
|
|
28981
|
+
await this.core.assetResolver.put(blob, {
|
|
28982
|
+
id: assetId,
|
|
28983
|
+
mimeType: blob.type || 'application/octet-stream',
|
|
28984
|
+
kind: 'image',
|
|
28985
|
+
});
|
|
28986
|
+
}
|
|
28987
|
+
catch (error) {
|
|
28988
|
+
console.warn(`[Kritzel] Failed to restore embedded asset ${assetId} from portable workspace import:`, error);
|
|
28989
|
+
}
|
|
28990
|
+
}
|
|
28991
|
+
}
|
|
28992
|
+
blobToDataUrl(blob) {
|
|
28993
|
+
return new Promise((resolve, reject) => {
|
|
28994
|
+
const reader = new FileReader();
|
|
28995
|
+
reader.onload = () => resolve(reader.result);
|
|
28996
|
+
reader.onerror = () => reject(reader.error ?? new Error('Failed to read blob as data URL'));
|
|
28997
|
+
reader.readAsDataURL(blob);
|
|
28998
|
+
});
|
|
28999
|
+
}
|
|
29000
|
+
async dataUrlToBlob(dataUrl) {
|
|
29001
|
+
const response = await fetch(dataUrl);
|
|
29002
|
+
return response.blob();
|
|
29003
|
+
}
|
|
29004
|
+
getImportedWorkspaceName(rawName) {
|
|
29005
|
+
if (typeof rawName === 'string' && rawName.trim().length > 0) {
|
|
29006
|
+
return rawName;
|
|
29007
|
+
}
|
|
29008
|
+
return 'Imported Workspace';
|
|
29009
|
+
}
|
|
29010
|
+
getImportedWorkspaceViewport(rawViewport) {
|
|
29011
|
+
if (!rawViewport || typeof rawViewport !== 'object') {
|
|
29012
|
+
return { centerWorldX: 0, centerWorldY: 0, scale: 1 };
|
|
29013
|
+
}
|
|
29014
|
+
const viewport = rawViewport;
|
|
29015
|
+
if (typeof viewport.centerWorldX === 'number' && typeof viewport.centerWorldY === 'number') {
|
|
29016
|
+
const scale = typeof viewport.scale === 'number' && viewport.scale > 0 ? viewport.scale : 1;
|
|
29017
|
+
return {
|
|
29018
|
+
centerWorldX: viewport.centerWorldX,
|
|
29019
|
+
centerWorldY: viewport.centerWorldY,
|
|
29020
|
+
scale,
|
|
29021
|
+
};
|
|
29022
|
+
}
|
|
29023
|
+
if (typeof viewport.translateX === 'number' || typeof viewport.translateY === 'number') {
|
|
29024
|
+
const scale = typeof viewport.scale === 'number' && viewport.scale > 0 ? viewport.scale : 1;
|
|
29025
|
+
return {
|
|
29026
|
+
centerWorldX: -(typeof viewport.translateX === 'number' ? viewport.translateX : 0) / scale,
|
|
29027
|
+
centerWorldY: -(typeof viewport.translateY === 'number' ? viewport.translateY : 0) / scale,
|
|
29028
|
+
scale,
|
|
29029
|
+
};
|
|
29030
|
+
}
|
|
29031
|
+
return { centerWorldX: 0, centerWorldY: 0, scale: 1 };
|
|
29032
|
+
}
|
|
28831
29033
|
/**
|
|
28832
29034
|
* Exports the current workspace as a JSON file and triggers a browser download.
|
|
28833
29035
|
* @param filename - Optional custom filename (without extension). Defaults to workspace name with timestamp.
|
|
@@ -29112,31 +29314,71 @@ const KritzelEngine = class {
|
|
|
29112
29314
|
this.syncingChange.emit(isSyncing);
|
|
29113
29315
|
}
|
|
29114
29316
|
applyToolConfig(tool, toolConfig) {
|
|
29115
|
-
|
|
29317
|
+
const normalizedToolConfig = this.normalizeToolConfig(toolConfig);
|
|
29318
|
+
Object.entries(normalizedToolConfig).forEach(([key, value]) => {
|
|
29116
29319
|
tool[key] = value;
|
|
29117
29320
|
});
|
|
29118
29321
|
// Resolve palettes map into the flat palette array the UI reads
|
|
29119
|
-
if ('palettes' in
|
|
29120
|
-
const brushConfig =
|
|
29322
|
+
if ('palettes' in normalizedToolConfig && 'type' in normalizedToolConfig) {
|
|
29323
|
+
const brushConfig = normalizedToolConfig;
|
|
29121
29324
|
const resolvedPalette = brushConfig.palettes[brushConfig.type];
|
|
29122
29325
|
if (resolvedPalette) {
|
|
29123
29326
|
tool['palette'] = resolvedPalette;
|
|
29124
29327
|
}
|
|
29125
29328
|
}
|
|
29126
29329
|
// Resolve sizes map into the flat sizes array the UI reads (brush tool uses a map keyed by type)
|
|
29127
|
-
if ('sizes' in
|
|
29128
|
-
const brushConfig =
|
|
29330
|
+
if ('sizes' in normalizedToolConfig && normalizedToolConfig.sizes != null && 'type' in normalizedToolConfig) {
|
|
29331
|
+
const brushConfig = normalizedToolConfig;
|
|
29129
29332
|
const resolvedSizes = brushConfig.sizes?.[brushConfig.type];
|
|
29130
29333
|
if (resolvedSizes) {
|
|
29131
29334
|
tool['sizes'] = resolvedSizes;
|
|
29132
29335
|
}
|
|
29133
29336
|
}
|
|
29134
29337
|
}
|
|
29338
|
+
normalizeToolConfig(toolConfig) {
|
|
29339
|
+
if (!this.isTextToolConfig(toolConfig)) {
|
|
29340
|
+
return toolConfig;
|
|
29341
|
+
}
|
|
29342
|
+
return {
|
|
29343
|
+
...toolConfig,
|
|
29344
|
+
availableFonts: resolveTextToolAvailableFonts(toolConfig.availableFonts),
|
|
29345
|
+
};
|
|
29346
|
+
}
|
|
29347
|
+
isTextToolConfig(toolConfig) {
|
|
29348
|
+
return 'fontFamily' in toolConfig && 'size' in toolConfig && 'color' in toolConfig;
|
|
29349
|
+
}
|
|
29350
|
+
/** Built-in tool classes of this bundle keyed by their tool type. */
|
|
29351
|
+
static BUILT_IN_TOOL_CLASSES = {
|
|
29352
|
+
selection: KritzelSelectionTool,
|
|
29353
|
+
brush: KritzelBrushTool,
|
|
29354
|
+
eraser: KritzelEraserTool,
|
|
29355
|
+
line: KritzelLineTool,
|
|
29356
|
+
shape: KritzelShapeTool,
|
|
29357
|
+
text: KritzelTextTool,
|
|
29358
|
+
image: KritzelImageTool,
|
|
29359
|
+
};
|
|
29360
|
+
/**
|
|
29361
|
+
* Resolves a tool class to the internal built-in class when a foreign copy is passed.
|
|
29362
|
+
* Classes from another compiled copy of the library (dual-package hazard, e.g. built-ins
|
|
29363
|
+
* re-exported by a framework wrapper) would otherwise break `instanceof` checks.
|
|
29364
|
+
*/
|
|
29365
|
+
resolveToolClass(toolClass) {
|
|
29366
|
+
if (toolClass.prototype instanceof KritzelBaseTool) {
|
|
29367
|
+
return toolClass;
|
|
29368
|
+
}
|
|
29369
|
+
try {
|
|
29370
|
+
const probe = new toolClass(this.core);
|
|
29371
|
+
return KritzelEngine.BUILT_IN_TOOL_CLASSES[probe.toolType] ?? toolClass;
|
|
29372
|
+
}
|
|
29373
|
+
catch {
|
|
29374
|
+
return toolClass;
|
|
29375
|
+
}
|
|
29376
|
+
}
|
|
29135
29377
|
get isSelecting() {
|
|
29136
|
-
return this.core.store.state.activeTool
|
|
29378
|
+
return this.core.store.state.activeTool?.toolType === 'selection' && this.core.store.state.isSelecting;
|
|
29137
29379
|
}
|
|
29138
29380
|
get isSelectionActive() {
|
|
29139
|
-
return this.core.store.state.activeTool
|
|
29381
|
+
return this.core.store.state.activeTool?.toolType === 'selection' && this.core.store.selectionGroup !== null;
|
|
29140
29382
|
}
|
|
29141
29383
|
constructor(hostRef) {
|
|
29142
29384
|
registerInstance(this, hostRef);
|
|
@@ -29453,7 +29695,7 @@ const KritzelEngine = class {
|
|
|
29453
29695
|
this.core.store.onStateChange('activeTool', this._handleActiveToolChange.bind(this));
|
|
29454
29696
|
}
|
|
29455
29697
|
_handleActiveToolChange(activeTool) {
|
|
29456
|
-
if (
|
|
29698
|
+
if (activeTool?.toolType !== 'selection') {
|
|
29457
29699
|
this.core.clearSelection();
|
|
29458
29700
|
this.core.store.objects?.remove(o => o instanceof KritzelSelectionBox);
|
|
29459
29701
|
this.core.store.setSelectionBox(null);
|
|
@@ -29462,10 +29704,10 @@ const KritzelEngine = class {
|
|
|
29462
29704
|
this.core.store.state.isResizeHandleSelected = false;
|
|
29463
29705
|
this.core.store.state.isRotationHandleSelected = false;
|
|
29464
29706
|
}
|
|
29465
|
-
if (
|
|
29707
|
+
if (activeTool?.toolType !== 'text') {
|
|
29466
29708
|
this.core.resetActiveText();
|
|
29467
29709
|
}
|
|
29468
|
-
if (
|
|
29710
|
+
if (activeTool?.toolType !== 'shape') {
|
|
29469
29711
|
this.core.resetActiveShape();
|
|
29470
29712
|
}
|
|
29471
29713
|
this.core.store.state.skipContextMenu = false;
|
|
@@ -29699,7 +29941,7 @@ const KritzelEngine = class {
|
|
|
29699
29941
|
borderWidth: object.borderWidth + 'px',
|
|
29700
29942
|
borderStyle: 'solid',
|
|
29701
29943
|
padding: object.padding + 'px',
|
|
29702
|
-
overflow: '
|
|
29944
|
+
overflow: 'visible',
|
|
29703
29945
|
display: 'block',
|
|
29704
29946
|
} })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => el && object.mount(el), style: {
|
|
29705
29947
|
position: 'absolute',
|
|
@@ -30049,7 +30291,7 @@ const KritzelEngine = class {
|
|
|
30049
30291
|
}, this.core.store.selectionGroup?.objects || []);
|
|
30050
30292
|
}
|
|
30051
30293
|
this.hideContextMenu();
|
|
30052
|
-
}, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool
|
|
30294
|
+
}, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool?.toolType === 'eraser' && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed && h("kritzel-watermark", { core: this.core, label: this.core.localizationManager.translate('watermark.poweredBy') })));
|
|
30053
30295
|
}
|
|
30054
30296
|
static get watchers() { return {
|
|
30055
30297
|
"workspace": [{
|
|
@@ -30237,39 +30479,47 @@ const KritzelFontFamily = class {
|
|
|
30237
30479
|
registerInstance(this, hostRef);
|
|
30238
30480
|
this.fontFamilyChange = createEvent(this, "fontFamilyChange");
|
|
30239
30481
|
}
|
|
30240
|
-
fontOptions = [
|
|
30241
|
-
{ value: 'arial', label: 'Arial' },
|
|
30242
|
-
{ value: 'verdana', label: 'Verdana' },
|
|
30243
|
-
{ value: 'helvetica', label: 'Helvetica' },
|
|
30244
|
-
{ value: 'tahoma', label: 'Tahoma' },
|
|
30245
|
-
{ value: 'trebuchet ms', label: 'Trebuchet MS' },
|
|
30246
|
-
{ value: 'times new roman', label: 'Times New Roman' },
|
|
30247
|
-
{ value: 'georgia', label: 'Georgia' },
|
|
30248
|
-
{ value: 'garamond', label: 'Garamond' },
|
|
30249
|
-
{ value: 'courier new', label: 'Courier New' },
|
|
30250
|
-
{ value: 'brush script mt', label: 'Brush Script MT' },
|
|
30251
|
-
];
|
|
30482
|
+
fontOptions = [];
|
|
30252
30483
|
selectedFontFamily;
|
|
30253
30484
|
fontFamilyChange;
|
|
30485
|
+
handleFontOptionsChange() {
|
|
30486
|
+
this.ensureValidSelectedFont(this.resolveFontOptions());
|
|
30487
|
+
}
|
|
30254
30488
|
componentWillLoad() {
|
|
30255
|
-
|
|
30256
|
-
const isValidCurrentFont = this.fontOptions.some(opt => opt.value === this.selectedFontFamily);
|
|
30257
|
-
if (!this.selectedFontFamily || !isValidCurrentFont) {
|
|
30258
|
-
this.selectedFontFamily = this.fontOptions[0].value;
|
|
30259
|
-
}
|
|
30260
|
-
}
|
|
30489
|
+
this.ensureValidSelectedFont(this.resolveFontOptions());
|
|
30261
30490
|
}
|
|
30262
30491
|
handleDropdownValueChange = (event) => {
|
|
30263
30492
|
this.fontFamilyChange.emit(event.detail);
|
|
30264
30493
|
};
|
|
30494
|
+
ensureValidSelectedFont(options) {
|
|
30495
|
+
if (options.length === 0) {
|
|
30496
|
+
return;
|
|
30497
|
+
}
|
|
30498
|
+
const normalizedSelected = this.selectedFontFamily?.trim().toLocaleLowerCase();
|
|
30499
|
+
const isValidCurrentFont = options.some(opt => opt.value.trim().toLocaleLowerCase() === normalizedSelected);
|
|
30500
|
+
if (!normalizedSelected || !isValidCurrentFont) {
|
|
30501
|
+
this.selectedFontFamily = options[0].value;
|
|
30502
|
+
}
|
|
30503
|
+
}
|
|
30504
|
+
resolveFontOptions() {
|
|
30505
|
+
return this.fontOptions;
|
|
30506
|
+
}
|
|
30265
30507
|
render() {
|
|
30266
|
-
const
|
|
30508
|
+
const fontOptions = this.resolveFontOptions();
|
|
30509
|
+
const selectedOption = fontOptions.find(option => option.value === this.selectedFontFamily);
|
|
30510
|
+
const selectedFontFamily = selectedOption?.cssFontFamily ?? this.selectedFontFamily;
|
|
30511
|
+
const dropdownOptions = fontOptions.map(option => ({
|
|
30267
30512
|
value: option.value,
|
|
30268
30513
|
label: option.label,
|
|
30269
|
-
style: { fontFamily: option.value },
|
|
30514
|
+
style: { fontFamily: option.cssFontFamily ?? option.value },
|
|
30270
30515
|
}));
|
|
30271
|
-
return (h(Host, { key: '
|
|
30516
|
+
return (h(Host, { key: '059350f34370f7a291f47a42721ca5d9bb82df49' }, h("kritzel-dropdown", { key: 'fbd8cf1ae463c7e9b76d0ac754a41de54397058e', options: dropdownOptions, value: this.selectedFontFamily, onValueChanged: this.handleDropdownValueChange, selectStyles: { fontFamily: selectedFontFamily } })));
|
|
30272
30517
|
}
|
|
30518
|
+
static get watchers() { return {
|
|
30519
|
+
"fontOptions": [{
|
|
30520
|
+
"handleFontOptionsChange": 0
|
|
30521
|
+
}]
|
|
30522
|
+
}; }
|
|
30273
30523
|
};
|
|
30274
30524
|
KritzelFontFamily.style = kritzelFontFamilyCss();
|
|
30275
30525
|
|
|
@@ -31467,7 +31717,7 @@ const KritzelPortal = class {
|
|
|
31467
31717
|
* This file is auto-generated by the version bump scripts.
|
|
31468
31718
|
* Do not modify manually.
|
|
31469
31719
|
*/
|
|
31470
|
-
const KRITZEL_VERSION = '0.4.
|
|
31720
|
+
const KRITZEL_VERSION = '0.4.2';
|
|
31471
31721
|
|
|
31472
31722
|
const kritzelSettingsCss = () => `:host{display:contents}kritzel-dialog{--kritzel-dialog-body-padding:0;--kritzel-dialog-width-large:800px;--kritzel-dialog-height-large:500px}.footer-button{padding:8px 16px;border-radius:6px;cursor:pointer;font-size:14px}.cancel-button{border:1px solid #ebebeb;background:#fff;color:inherit}.cancel-button:hover{background:#f5f5f5}.settings-content{padding:0}.settings-content h3{margin:0 0 16px 0;font-size:18px;font-weight:600;color:var(--kritzel-settings-content-heading-color, #333333)}.settings-content p{margin:0;font-size:14px;color:var(--kritzel-settings-content-text-color, #666666);line-height:1.5}.settings-group{display:flex;flex-direction:column;gap:24px}.settings-item{display:flex;flex-direction:column;gap:8px}.settings-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.settings-label{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.settings-description{font-size:12px;color:var(--kritzel-settings-description-color, #888888);margin:0;line-height:1.4}.shortcuts-list{display:flex;flex-direction:column;gap:24px}.shortcuts-category{display:flex;flex-direction:column;gap:8px}.shortcuts-category-title{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.shortcuts-group{display:flex;flex-direction:column;gap:4px}.shortcut-item{display:flex;justify-content:space-between;align-items:center;padding:6px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-item-bg, rgba(0, 0, 0, 0.02))}.shortcut-label{font-size:14px;color:var(--kritzel-settings-content-text-color, #666666)}.shortcut-key{font-family:monospace;font-size:12px;padding:2px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-key-bg, #f0f0f0);color:var(--kritzel-settings-shortcut-key-color, #333333);border:1px solid var(--kritzel-settings-shortcut-key-border, #ddd)}`;
|
|
31473
31723
|
|
|
@@ -35182,8 +35432,43 @@ const KritzelToolConfig = class {
|
|
|
35182
35432
|
sizes = [];
|
|
35183
35433
|
currentOpacity = 1;
|
|
35184
35434
|
updateTrigger = 0;
|
|
35435
|
+
getFontOptionsFromTool() {
|
|
35436
|
+
const configuredFonts = resolveTextToolAvailableFonts(this.tool.availableFonts).map(font => {
|
|
35437
|
+
const registeredFont = typeof font === 'string'
|
|
35438
|
+
? {
|
|
35439
|
+
family: font,
|
|
35440
|
+
label: font,
|
|
35441
|
+
cssFontFamily: font,
|
|
35442
|
+
}
|
|
35443
|
+
: {
|
|
35444
|
+
family: font.family,
|
|
35445
|
+
label: font.label ?? font.family,
|
|
35446
|
+
cssFontFamily: font.cssFontFamily ?? font.family,
|
|
35447
|
+
};
|
|
35448
|
+
return {
|
|
35449
|
+
value: registeredFont.family,
|
|
35450
|
+
label: registeredFont.label,
|
|
35451
|
+
cssFontFamily: registeredFont.cssFontFamily,
|
|
35452
|
+
};
|
|
35453
|
+
});
|
|
35454
|
+
const mergedFonts = [...configuredFonts];
|
|
35455
|
+
const seenFonts = new Set(mergedFonts.map(font => font.value.trim().toLocaleLowerCase()));
|
|
35456
|
+
for (const font of KritzelFontRegistry.list()) {
|
|
35457
|
+
const normalizedValue = font.family.trim().toLocaleLowerCase();
|
|
35458
|
+
if (seenFonts.has(normalizedValue)) {
|
|
35459
|
+
continue;
|
|
35460
|
+
}
|
|
35461
|
+
seenFonts.add(normalizedValue);
|
|
35462
|
+
mergedFonts.push({
|
|
35463
|
+
value: font.family,
|
|
35464
|
+
label: font.label,
|
|
35465
|
+
cssFontFamily: font.cssFontFamily,
|
|
35466
|
+
});
|
|
35467
|
+
}
|
|
35468
|
+
return mergedFonts;
|
|
35469
|
+
}
|
|
35185
35470
|
handleSelectionChange() {
|
|
35186
|
-
if (this.tool
|
|
35471
|
+
if (this.tool?.toolType === 'selection') {
|
|
35187
35472
|
this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
|
|
35188
35473
|
if (this.config) {
|
|
35189
35474
|
this.updatePalette();
|
|
@@ -35220,7 +35505,7 @@ const KritzelToolConfig = class {
|
|
|
35220
35505
|
color: KritzelColorHelper.applyOpacity(color, opacity, this.theme),
|
|
35221
35506
|
size,
|
|
35222
35507
|
};
|
|
35223
|
-
if (this.tool
|
|
35508
|
+
if (this.tool.toolType === 'text') {
|
|
35224
35509
|
displayValues.fontFamily = this.tool.fontFamily;
|
|
35225
35510
|
}
|
|
35226
35511
|
this.displayValuesChange.emit(displayValues);
|
|
@@ -35313,7 +35598,7 @@ const KritzelToolConfig = class {
|
|
|
35313
35598
|
case 'shape-fill':
|
|
35314
35599
|
return (h("kritzel-shape-fill", { key: control.type, value: this.getShapeFillValue(), onValueChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
|
|
35315
35600
|
case 'font-family':
|
|
35316
|
-
return (h("kritzel-font-family", { key: control.type, selectedFontFamily: value, onFontFamilyChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
|
|
35601
|
+
return (h("kritzel-font-family", { key: control.type, fontOptions: this.getFontOptionsFromTool(), selectedFontFamily: value, onFontFamilyChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
|
|
35317
35602
|
default:
|
|
35318
35603
|
return null;
|
|
35319
35604
|
}
|