kritzel-stencil 0.3.22 → 0.3.23
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 +3 -1
- package/dist/cjs/kritzel-active-users_45.cjs.entry.js +507 -288
- package/dist/cjs/{schema.constants-IBG5VW_J.js → schema.constants-Lr_zNkox.js} +713 -47
- package/dist/collection/classes/core/core.class.js +83 -5
- package/dist/collection/classes/core/store.class.js +9 -0
- package/dist/collection/classes/handlers/key.handler.js +1 -1
- package/dist/collection/classes/handlers/selection.handler.js +13 -9
- package/dist/collection/classes/objects/base-object.class.js +20 -8
- package/dist/collection/classes/objects/custom-element.class.js +330 -8
- package/dist/collection/classes/objects/image.class.js +0 -1
- package/dist/collection/classes/objects/selection-group.class.js +12 -0
- package/dist/collection/classes/providers/assets/asset-resolver.class.js +24 -14
- package/dist/collection/classes/providers/assets/indexeddb-asset-provider.class.js +0 -8
- package/dist/collection/classes/registries/custom-element-renderer.registry.js +52 -0
- package/dist/collection/classes/structures/app-state-map.structure.js +17 -3
- package/dist/collection/classes/structures/object-map.structure.js +17 -3
- package/dist/collection/classes/tools/selection-tool.class.js +34 -6
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +9 -8
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +211 -78
- package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +2 -1
- package/dist/collection/configs/default-engine-config.js +3 -2
- package/dist/collection/constants/version.js +1 -1
- package/dist/collection/helpers/html.helper.js +52 -0
- package/dist/collection/helpers/object.helper.js +3 -0
- package/dist/collection/helpers/svg-export.helper.js +35 -0
- package/dist/collection/helpers/wheel.helper.js +113 -0
- package/dist/collection/index.js +3 -0
- package/dist/collection/interfaces/custom-element-renderer.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-current-user-dialog.js +1 -1
- package/dist/components/kritzel-current-user.js +1 -1
- package/dist/components/kritzel-dialog.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-export.js +1 -1
- package/dist/components/kritzel-login-dialog.js +1 -1
- package/dist/components/kritzel-menu-item.js +1 -1
- package/dist/components/kritzel-menu.js +1 -1
- package/dist/components/kritzel-more-menu.js +1 -1
- package/dist/components/kritzel-portal.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-share-dialog.js +1 -1
- package/dist/components/kritzel-split-button.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/kritzel-tooltip.js +1 -1
- package/dist/components/kritzel-workspace-manager.js +1 -1
- package/dist/components/{p-BwuemYET.js → p-B4WfPDj0.js} +1 -1
- package/dist/components/p-BNu3Akp5.js +1 -0
- package/dist/components/p-BYveczcb.js +1 -0
- package/dist/components/{p-D28ZylHn.js → p-BixEMVtW.js} +1 -1
- package/dist/components/{p-Ndib1Jb3.js → p-BntMEYss.js} +1 -1
- package/dist/components/p-C48bv_0f.js +9 -0
- package/dist/components/{p-BO1CnEOT.js → p-CPMpf9ku.js} +1 -1
- package/dist/components/{p-BhODnvMO.js → p-CZQz_mul.js} +1 -1
- package/dist/components/{p-COj8EVzL.js → p-Ckpa5tHF.js} +1 -1
- package/dist/components/{p-BPoDE87Q.js → p-DJ3KI725.js} +1 -1
- package/dist/components/{p-DRsD38Nl.js → p-DPlEzPKO.js} +1 -1
- package/dist/components/{p-C-RiEw9X.js → p-DSd5xTAH.js} +1 -1
- package/dist/components/{p-CbMLbDou.js → p-DTqMF94b.js} +1 -1
- package/dist/components/{p-CHrSFOSI.js → p-DX2nriaq.js} +1 -1
- package/dist/components/{p-BAN5dnHX.js → p-Dd-pMvlr.js} +1 -1
- package/dist/components/{p-C5TZjIE1.js → p-M9m9-OEY.js} +1 -1
- package/dist/components/p-WUdQqYnu.js +1 -0
- package/dist/components/{p-YFR180v-.js → p-XDNjFYRB.js} +1 -1
- package/dist/components/{p-CJEIUs0x.js → p-X_pyPCe8.js} +1 -1
- package/dist/components/{p-CpR9lc-o.js → p-meY80XnF.js} +1 -1
- package/dist/components/{p-6Ca7Eolf.js → p-y5T0_Wvi.js} +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-active-users_45.entry.js +500 -281
- package/dist/esm/{schema.constants-D35cwCYd.js → schema.constants-DMPBDrZh.js} +711 -47
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-27d41f6f.entry.js +9 -0
- package/dist/stencil/p-DMPBDrZh.js +1 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/core.class.d.ts +15 -0
- package/dist/types/classes/core/store.class.d.ts +6 -0
- package/dist/types/classes/objects/base-object.class.d.ts +3 -2
- package/dist/types/classes/objects/custom-element.class.d.ts +87 -21
- package/dist/types/classes/objects/image.class.d.ts +0 -1
- package/dist/types/classes/objects/selection-group.class.d.ts +1 -0
- package/dist/types/classes/providers/assets/asset-resolver.class.d.ts +3 -0
- package/dist/types/classes/providers/assets/indexeddb-asset-provider.class.d.ts +0 -1
- package/dist/types/classes/registries/custom-element-renderer.registry.d.ts +32 -0
- package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +7 -1
- package/dist/types/components.d.ts +2 -2
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/helpers/html.helper.d.ts +2 -0
- package/dist/types/helpers/object.helper.d.ts +1 -0
- package/dist/types/helpers/svg-export.helper.d.ts +9 -0
- package/dist/types/helpers/wheel.helper.d.ts +9 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/interfaces/asset-storage-config.interface.d.ts +0 -4
- package/dist/types/interfaces/custom-element-renderer.interface.d.ts +40 -0
- package/dist/types/interfaces/debug-info.interface.d.ts +1 -0
- package/dist/types/interfaces/object.interface.d.ts +0 -1
- package/package.json +1 -1
- package/dist/components/p-BML28BJR.js +0 -1
- package/dist/components/p-CVV-HzFR.js +0 -1
- package/dist/components/p-DWhWFDcC.js +0 -9
- package/dist/components/p-Dd_EODkk.js +0 -1
- package/dist/stencil/p-D35cwCYd.js +0 -1
- package/dist/stencil/p-fcbf7965.entry.js +0 -9
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var index = require('./index-Xav9JFHg.js');
|
|
4
|
-
var schema_constants = require('./schema.constants-
|
|
4
|
+
var schema_constants = require('./schema.constants-Lr_zNkox.js');
|
|
5
5
|
var Y = require('yjs');
|
|
6
6
|
require('y-indexeddb');
|
|
7
7
|
require('y-websocket');
|
|
@@ -1400,71 +1400,6 @@ const KritzelCursorTrail = class {
|
|
|
1400
1400
|
};
|
|
1401
1401
|
KritzelCursorTrail.style = kritzelCursorTrailCss();
|
|
1402
1402
|
|
|
1403
|
-
class KritzelHTMLHelper {
|
|
1404
|
-
static getNumericValueFromStyle(element, property) {
|
|
1405
|
-
const value = window.getComputedStyle(element).getPropertyValue(property);
|
|
1406
|
-
return parseFloat(value) || 0;
|
|
1407
|
-
}
|
|
1408
|
-
static getScrollableParent(element) {
|
|
1409
|
-
if (!element) {
|
|
1410
|
-
return window;
|
|
1411
|
-
}
|
|
1412
|
-
const parent = element.parentNode?.host ?? element.parentElement;
|
|
1413
|
-
if (!parent || parent.tagName === 'BODY') {
|
|
1414
|
-
return window;
|
|
1415
|
-
}
|
|
1416
|
-
const style = window.getComputedStyle(parent);
|
|
1417
|
-
if (style.overflow === 'auto' || style.overflowY === 'auto' || style.overflow === 'scroll' || style.overflowY === 'scroll') {
|
|
1418
|
-
return parent;
|
|
1419
|
-
}
|
|
1420
|
-
return this.getScrollableParent(parent);
|
|
1421
|
-
}
|
|
1422
|
-
static isElementInViewport(element) {
|
|
1423
|
-
if (!element) {
|
|
1424
|
-
return false;
|
|
1425
|
-
}
|
|
1426
|
-
const scrollableParent = this.getScrollableParent(element);
|
|
1427
|
-
const rect = element.getBoundingClientRect();
|
|
1428
|
-
if (scrollableParent === window) {
|
|
1429
|
-
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
1430
|
-
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
1431
|
-
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= viewportHeight && rect.right <= viewportWidth;
|
|
1432
|
-
}
|
|
1433
|
-
const parentRect = scrollableParent.getBoundingClientRect();
|
|
1434
|
-
return rect.top >= parentRect.top && rect.left >= parentRect.left && rect.bottom <= parentRect.bottom && rect.right <= parentRect.right;
|
|
1435
|
-
}
|
|
1436
|
-
static getFocusableElements(root) {
|
|
1437
|
-
if (!root)
|
|
1438
|
-
return [];
|
|
1439
|
-
const focusableElements = [];
|
|
1440
|
-
const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details, [tabindex]:not([tabindex="-1"])';
|
|
1441
|
-
const isVisible = (el) => {
|
|
1442
|
-
const style = window.getComputedStyle(el);
|
|
1443
|
-
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
1444
|
-
};
|
|
1445
|
-
const find = (element) => {
|
|
1446
|
-
// Check if the element itself is focusable
|
|
1447
|
-
if (element instanceof HTMLElement && element.matches(focusableSelector) && !element.hasAttribute('disabled') && isVisible(element)) {
|
|
1448
|
-
focusableElements.push(element);
|
|
1449
|
-
}
|
|
1450
|
-
// Traverse shadow DOM
|
|
1451
|
-
if (element.shadowRoot) {
|
|
1452
|
-
Array.from(element.shadowRoot.children).forEach(find);
|
|
1453
|
-
}
|
|
1454
|
-
// Traverse slotted content
|
|
1455
|
-
if (element.tagName === 'SLOT') {
|
|
1456
|
-
element.assignedElements({ flatten: true }).forEach(find);
|
|
1457
|
-
}
|
|
1458
|
-
// Traverse light DOM children if there is no shadow root
|
|
1459
|
-
if (!element.shadowRoot) {
|
|
1460
|
-
Array.from(element.children).forEach(find);
|
|
1461
|
-
}
|
|
1462
|
-
};
|
|
1463
|
-
find(root);
|
|
1464
|
-
return focusableElements;
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
1403
|
const kritzelDialogCss = () => `:host{display:contents}.dialog-content{text-align:start;line-height:normal}.backdrop{position:fixed;top:0;left:0;right:0;bottom:0;z-index:10002;display:flex;align-items:center;justify-content:center;background-color:var(--kritzel-dialog-backdrop-color, rgba(0, 0, 0, 0.5));opacity:1;transition:opacity 150ms ease-out}.backdrop.is-animating{opacity:0}.dialog-content{position:relative;display:flex;flex-direction:column;background-color:var(--kritzel-dialog-background-color, #ffffff);border-radius:var(--kritzel-dialog-border-radius, 12px);box-shadow:var(--kritzel-dialog-box-shadow, 0 4px 20px rgba(0, 0, 0, 0.15));border:var(--kritzel-dialog-border, 1px solid #ebebeb);max-height:var(--kritzel-dialog-max-height, 90vh);max-width:var(--kritzel-dialog-max-width, 90vw);overflow:hidden;transform:scale(1);opacity:1;transition:transform 200ms ease-out, opacity 200ms ease-out;font-family:var(--kritzel-dialog-font-family, sans-serif)}.dialog-content.is-animating{transform:scale(0.95);opacity:0}.dialog-content.size-small{width:var(--kritzel-dialog-width-small, 320px);height:var(--kritzel-dialog-height-small, auto)}.dialog-content.size-medium{width:var(--kritzel-dialog-width-medium, 480px);height:var(--kritzel-dialog-height-medium, auto)}.dialog-content.size-large{width:var(--kritzel-dialog-width-large, 640px);height:var(--kritzel-dialog-height-large, auto)}.dialog-content.size-fullscreen{width:100vw;height:100vh;height:100dvh;max-width:100vw;max-height:100vh;max-height:100dvh;border-radius:0}.backdrop.contained-fullscreen{background-color:transparent}.dialog-content.contained-fullscreen{border-radius:0}.dialog-content.contained-fullscreen .dialog-body{display:flex;flex-direction:column}.dialog-content.contained-fullscreen .dialog-body ::slotted(*){flex:1;min-height:0}@media (max-width: 576px), (max-height: 576px) and (orientation: landscape){.backdrop:has(.fullscreen-on-mobile){background-color:transparent}.dialog-content.fullscreen-on-mobile{width:100vw;height:100vh;height:100dvh;max-width:100vw;max-height:100vh;max-height:100dvh;border-radius:0}.dialog-content.fullscreen-on-mobile .dialog-body{display:flex;flex-direction:column}.dialog-content.fullscreen-on-mobile .dialog-body ::slotted(*){flex:1;min-height:0}}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--kritzel-dialog-header-padding, 16px 20px);border-bottom:var(--kritzel-dialog-header-border, 1px solid #ebebeb);gap:12px}.dialog-title{margin:0;font-size:var(--kritzel-dialog-title-font-size, 18px);font-weight:var(--kritzel-dialog-title-font-weight, 600);color:var(--kritzel-dialog-title-color, #1a1a1a);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.close-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:none;border-radius:var(--kritzel-dialog-close-button-border-radius, 6px);background-color:var(--kritzel-dialog-close-button-background, transparent);color:var(--kritzel-dialog-close-button-color, #666666);cursor:var(--kritzel-global-pointer-cursor, pointer);transition:background-color 150ms ease, color 150ms ease;flex-shrink:0;-webkit-tap-highlight-color:transparent}.close-button:hover{background-color:var(--kritzel-dialog-close-button-hover-background, #f5f5f5);color:var(--kritzel-dialog-close-button-hover-color, #1a1a1a)}.close-button:active{background-color:var(--kritzel-dialog-close-button-active-background, #ebebeb)}.close-button:focus-visible{outline:revert;outline-offset:revert}.dialog-body{padding:var(--kritzel-dialog-body-padding, 20px);overflow-y:auto;flex:1;min-height:0;scrollbar-color:var(--kritzel-global-scrollbar-thumb-color, #ebebeb) transparent;scrollbar-width:thin}.dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--kritzel-dialog-footer-gap, 8px);padding:var(--kritzel-dialog-footer-padding, 16px 20px);border-top:var(--kritzel-dialog-footer-border, 1px solid #ebebeb)}::slotted([slot='header']){flex:1}::slotted([slot='footer']){display:contents}`;
|
|
1469
1404
|
|
|
1470
1405
|
const KritzelDialog = class {
|
|
@@ -1747,7 +1682,7 @@ const KritzelDialog = class {
|
|
|
1747
1682
|
const dialogContent = this.host.shadowRoot?.querySelector('.dialog-content');
|
|
1748
1683
|
if (!dialogContent)
|
|
1749
1684
|
return;
|
|
1750
|
-
const focusableElements = KritzelHTMLHelper.getFocusableElements(dialogContent);
|
|
1685
|
+
const focusableElements = schema_constants.KritzelHTMLHelper.getFocusableElements(dialogContent);
|
|
1751
1686
|
const slotElements = this.getSlottedFocusableElements();
|
|
1752
1687
|
const allFocusable = [...focusableElements, ...slotElements];
|
|
1753
1688
|
if (allFocusable.length > 0) {
|
|
@@ -1764,7 +1699,7 @@ const KritzelDialog = class {
|
|
|
1764
1699
|
const assigned = slot.assignedElements({ flatten: true });
|
|
1765
1700
|
assigned.forEach(el => {
|
|
1766
1701
|
// Use KritzelHTMLHelper to find focusable elements including those in nested shadow DOMs
|
|
1767
|
-
const elements = KritzelHTMLHelper.getFocusableElements(el);
|
|
1702
|
+
const elements = schema_constants.KritzelHTMLHelper.getFocusableElements(el);
|
|
1768
1703
|
focusable.push(...elements);
|
|
1769
1704
|
});
|
|
1770
1705
|
});
|
|
@@ -2226,6 +2161,7 @@ const KritzelEditor = class {
|
|
|
2226
2161
|
showObjectInfo: false,
|
|
2227
2162
|
showSyncProviderInfo: true,
|
|
2228
2163
|
showMigrationInfo: true,
|
|
2164
|
+
showAssetResolverInfo: false,
|
|
2229
2165
|
};
|
|
2230
2166
|
user;
|
|
2231
2167
|
activeUsers;
|
|
@@ -3137,31 +3073,31 @@ const KritzelEditor = class {
|
|
|
3137
3073
|
const isLoggedIn = this.isLoggedIn;
|
|
3138
3074
|
const shouldShowCurrentUser = isLoggedIn;
|
|
3139
3075
|
const shouldShowLoginButton = this.isReady && !!this.loginConfig && !isLoggedIn;
|
|
3140
|
-
return (index.h(index.Host, { key: '
|
|
3076
|
+
return (index.h(index.Host, { key: '56b172459e6d940229dc1d4f409157e403ad5f27', style: {
|
|
3141
3077
|
opacity: this.isEditorVisible ? '1' : '0',
|
|
3142
3078
|
visibility: this.isEditorVisible ? 'visible' : 'hidden',
|
|
3143
3079
|
transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
|
|
3144
|
-
} }, index.h("div", { key: '
|
|
3080
|
+
} }, index.h("div", { key: '93a2195c14402f38416b2d377c684e2650418edb', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: '1b42b21bc35e1fc56202e19a78053e46d87ca51a', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, terms: this.resolvedTerms, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: '3b90b69a5b83a6e5593d4f752c4094a2a3af8c4d', visible: this.isBackToContentButtonVisible, text: this.resolvedTerms['backToContent.label'] ?? 'Back to content', onBackToContent: () => this.backToContent() })), this.activeNotification && (index.h("div", { key: '9c2ee1e10212145bf2f97a1a7f27746aa18cfc98', class: "top-center-notification-layer", role: "presentation" }, index.h("div", { key: 'a77b025329da64e1f1223a2f749aa2fc60e5c469', class: { 'top-center-notification-container': true, 'is-dismissing': this.isNotificationDismissing }, role: "presentation" }, index.h("kritzel-notification-card", { key: '9ced0bc5213ec8c3387915cd71272a1f56161405', notification: this.activeNotification, locale: this.locale, onDismiss: this.dismissNotification, onHoverChange: event => this.handleNotificationHoverChange(event) })))), index.h("kritzel-engine", { key: '884b7f088e164a51c49158c409904ca5419f2d55', ref: el => {
|
|
3145
3081
|
if (el) {
|
|
3146
3082
|
this.engineRef = el;
|
|
3147
3083
|
}
|
|
3148
|
-
}, 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) }), index.h("kritzel-controls", { key: '
|
|
3084
|
+
}, 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) }), index.h("kritzel-controls", { key: '3a7c22f037d551636c53190eb07b318c2b857162', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
|
|
3149
3085
|
if (el) {
|
|
3150
3086
|
this.controlsRef = el;
|
|
3151
3087
|
}
|
|
3152
|
-
}, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: '
|
|
3088
|
+
}, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: 'c0dad9086679397c46f5550c38686a9b7d8bae6c', class: "bottom-left-buttons" }, index.h("kritzel-zoom-panel", { key: '1639d6d2092ecd3fbc657dfdcfc3f12c02539329', visible: this.isZoomPanelVisible, disabled: !this.isZoomingEnabled, zoomPercent: this.currentZoomPercent, terms: this.resolvedTerms, onZoomIn: () => this.zoomIn(), onZoomOut: () => this.zoomOut() })), index.h("div", { key: '45313b28a5e4bd75d09980e4765c2241d54fe1df', class: "top-right-buttons" }, index.h("kritzel-settings", { key: '33737a005cd6580505ee741be0dc40bd69873276', ref: el => {
|
|
3153
3089
|
if (el) {
|
|
3154
3090
|
this.settingsRef = el;
|
|
3155
3091
|
}
|
|
3156
|
-
}, 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) }), index.h("kritzel-export", { key: '
|
|
3092
|
+
}, 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) }), index.h("kritzel-export", { key: '9e13001850b15b9ce9d8a502466ed9fa05ac1518', ref: el => {
|
|
3157
3093
|
if (el) {
|
|
3158
3094
|
this.exportRef = el;
|
|
3159
3095
|
}
|
|
3160
|
-
}, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: '
|
|
3096
|
+
}, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: 'f2494af1241ecc068ace09b23cfd405c76bd1273', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: '7f199e3493805977b5e5b8d2c736f31729919f96', user: this.user, terms: this.resolvedTerms }), shouldShowLoginButton && (index.h("kritzel-button", { key: 'c6c192ddb1245acc771ac550c1fe3e4f9bc08eab', onButtonClick: () => this.loginDialogRef?.open() }, this.resolvedTerms['login.dialogTitle'] ?? 'Sign in')), index.h("kritzel-more-menu", { key: '869194078a4c90d42c5ebd604bc58b4f55fc4cb6', items: this.moreMenuItems, visible: this.isMoreMenuVisible, terms: this.resolvedTerms }), index.h("kritzel-share-dialog", { key: '8daed8fd7267aca056b6a53626c721e2f23cead4', ref: el => {
|
|
3161
3097
|
if (el) {
|
|
3162
3098
|
this.shareDialogRef = el;
|
|
3163
3099
|
}
|
|
3164
|
-
}, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: '
|
|
3100
|
+
}, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: 'b65ea0940cee31b152b60881180fab2445c92b0c', ref: el => {
|
|
3165
3101
|
if (el) {
|
|
3166
3102
|
this.loginDialogRef = el;
|
|
3167
3103
|
}
|
|
@@ -21366,7 +21302,7 @@ class KritzelKeyHandler extends schema_constants.KritzelBaseHandler {
|
|
|
21366
21302
|
// of running global canvas shortcuts. Escape is the one exception — it
|
|
21367
21303
|
// still runs through the shortcut system so it can collapse the text
|
|
21368
21304
|
// selection (handled inside the shortcut's action).
|
|
21369
|
-
if ((this._core.store.activeText || this._core.store.activeShape) && event.key !== 'Escape') {
|
|
21305
|
+
if ((this._core.store.activeText || this._core.store.activeShape || this._core.store.activeInteractiveCustomElement) && event.key !== 'Escape') {
|
|
21370
21306
|
return;
|
|
21371
21307
|
}
|
|
21372
21308
|
const shortcut = this.shortcuts.find(s => s.key === event.key && !!s.ctrl === event.ctrlKey && !!s.shift === event.shiftKey && (!s.condition || s.condition(this._core)));
|
|
@@ -21566,120 +21502,6 @@ class KritzelContextMenuHandler extends schema_constants.KritzelBaseHandler {
|
|
|
21566
21502
|
}
|
|
21567
21503
|
}
|
|
21568
21504
|
|
|
21569
|
-
/**
|
|
21570
|
-
* Represents a custom HTML element that can be placed and manipulated on the Kritzel canvas.
|
|
21571
|
-
* Extends KritzelBaseObject to inherit common object functionality like positioning,
|
|
21572
|
-
* scaling, and lifecycle management.
|
|
21573
|
-
*/
|
|
21574
|
-
class KritzelCustomElement extends schema_constants.KritzelBaseObject {
|
|
21575
|
-
__class__ = 'KritzelCustomElement';
|
|
21576
|
-
/** The HTML element to be rendered on the canvas. */
|
|
21577
|
-
element;
|
|
21578
|
-
/** Whether the element responds to user interactions. Defaults to true. */
|
|
21579
|
-
isInteractive = true;
|
|
21580
|
-
/**
|
|
21581
|
-
* Creates a new KritzelCustomElement instance.
|
|
21582
|
-
* @param config - Optional configuration object for the custom element.
|
|
21583
|
-
* @param config.element - The HTML element to wrap.
|
|
21584
|
-
* @param config.translateX - Initial X position offset. Defaults to 0.
|
|
21585
|
-
* @param config.translateY - Initial Y position offset. Defaults to 0.
|
|
21586
|
-
* @param config.scale - Initial scale factor. Defaults to 1.
|
|
21587
|
-
* @param config.height - Initial height in pixels. Defaults to 0.
|
|
21588
|
-
* @param config.width - Initial width in pixels. Defaults to 0.
|
|
21589
|
-
*/
|
|
21590
|
-
constructor(config) {
|
|
21591
|
-
super();
|
|
21592
|
-
if (config) {
|
|
21593
|
-
this.translateX = config.translateX || 0;
|
|
21594
|
-
this.translateY = config.translateY || 0;
|
|
21595
|
-
this.rotation = schema_constants.KritzelMathHelper.degreesToRadians(config.rotation ?? 0);
|
|
21596
|
-
this.scale = config.scale || 1;
|
|
21597
|
-
this.element = config.element;
|
|
21598
|
-
this.height = config.height || 0;
|
|
21599
|
-
this.width = config.width || 0;
|
|
21600
|
-
}
|
|
21601
|
-
}
|
|
21602
|
-
/**
|
|
21603
|
-
* Factory method to create a new KritzelCustomElement with proper core binding.
|
|
21604
|
-
* Generates a unique ID and assigns the element to the active workspace.
|
|
21605
|
-
* @param core - The KritzelCore instance for state management and ID generation.
|
|
21606
|
-
* @param config - Optional configuration object for the custom element.
|
|
21607
|
-
* @param config.element - The HTML element to wrap.
|
|
21608
|
-
* @param config.translateX - Initial X position offset.
|
|
21609
|
-
* @param config.translateY - Initial Y position offset.
|
|
21610
|
-
* @param config.scale - Initial scale factor.
|
|
21611
|
-
* @param config.height - Initial height in pixels.
|
|
21612
|
-
* @param config.width - Initial width in pixels.
|
|
21613
|
-
* @returns A new KritzelBaseObject instance bound to the core.
|
|
21614
|
-
*/
|
|
21615
|
-
static create(core, config) {
|
|
21616
|
-
const object = new KritzelCustomElement(config);
|
|
21617
|
-
object._core = core;
|
|
21618
|
-
object.id = object.generateId();
|
|
21619
|
-
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
21620
|
-
object.userId = core.user?.id;
|
|
21621
|
-
return object;
|
|
21622
|
-
}
|
|
21623
|
-
/**
|
|
21624
|
-
* Mounts the custom element to a container element in the DOM.
|
|
21625
|
-
* Clears any existing content in the container and appends this element.
|
|
21626
|
-
* Skips mounting if already mounted to the same container with content attached.
|
|
21627
|
-
* @param element - The container HTML element to mount this custom element into.
|
|
21628
|
-
*/
|
|
21629
|
-
mount(element) {
|
|
21630
|
-
if (element === null) {
|
|
21631
|
-
return;
|
|
21632
|
-
}
|
|
21633
|
-
// If already mounted to the same element and content is still attached, skip
|
|
21634
|
-
if (this.isMounted && this.elementRef === element && this.element.parentElement === element) {
|
|
21635
|
-
return;
|
|
21636
|
-
}
|
|
21637
|
-
this.elementRef = element;
|
|
21638
|
-
this.isMounted = true;
|
|
21639
|
-
// Clear existing content and append the element
|
|
21640
|
-
this.elementRef.innerHTML = '';
|
|
21641
|
-
this.elementRef.appendChild(this.element);
|
|
21642
|
-
}
|
|
21643
|
-
/**
|
|
21644
|
-
* Resizes and repositions the custom element on the canvas.
|
|
21645
|
-
* Updates both the internal state and the DOM element's inline styles.
|
|
21646
|
-
* Syncs changes to Yjs for collaborative editing and cross-tab propagation.
|
|
21647
|
-
* @param x - The new X position (translateX) in canvas coordinates.
|
|
21648
|
-
* @param y - The new Y position (translateY) in canvas coordinates.
|
|
21649
|
-
* @param width - The new width in pixels. Must be greater than 1.
|
|
21650
|
-
* @param height - The new height in pixels. Must be greater than 1.
|
|
21651
|
-
*/
|
|
21652
|
-
resize(x, y, width, height) {
|
|
21653
|
-
if (width <= 1 || height <= 1) {
|
|
21654
|
-
return;
|
|
21655
|
-
}
|
|
21656
|
-
this.width = width;
|
|
21657
|
-
this.height = height;
|
|
21658
|
-
this.translateX = x;
|
|
21659
|
-
this.translateY = y;
|
|
21660
|
-
if (this.element) {
|
|
21661
|
-
this.element.style.width = `${width}px`;
|
|
21662
|
-
this.element.style.height = `${height}px`;
|
|
21663
|
-
}
|
|
21664
|
-
// Update to sync changes to y.js and propagate to other tabs
|
|
21665
|
-
this._core.store.objects.update(this);
|
|
21666
|
-
}
|
|
21667
|
-
/**
|
|
21668
|
-
* Creates a deep copy of this custom element.
|
|
21669
|
-
* The copy receives a new unique ID, is marked as unmounted,
|
|
21670
|
-
* and contains a cloned copy of the underlying HTML element.
|
|
21671
|
-
* @returns A new KritzelCustomElement instance with copied properties and a cloned DOM element.
|
|
21672
|
-
*/
|
|
21673
|
-
copy() {
|
|
21674
|
-
const copiedObject = Object.create(Object.getPrototypeOf(this));
|
|
21675
|
-
Object.assign(copiedObject, this);
|
|
21676
|
-
copiedObject.id = this.generateId();
|
|
21677
|
-
copiedObject.isMounted = false;
|
|
21678
|
-
copiedObject.element = this.element.cloneNode(true);
|
|
21679
|
-
return copiedObject;
|
|
21680
|
-
}
|
|
21681
|
-
}
|
|
21682
|
-
|
|
21683
21505
|
/**
|
|
21684
21506
|
* Handles deserialization/revival of Kritzel objects from plain JavaScript objects.
|
|
21685
21507
|
* This class uses a pattern similar to JSON.parse reviver to reconstruct class instances
|
|
@@ -21740,7 +21562,7 @@ class KritzelReviver {
|
|
|
21740
21562
|
revivedObj = schema_constants.KritzelImage.create(this._core).deserialize(obj);
|
|
21741
21563
|
break;
|
|
21742
21564
|
case 'KritzelCustomElement':
|
|
21743
|
-
revivedObj = KritzelCustomElement.create(this._core).deserialize(obj);
|
|
21565
|
+
revivedObj = schema_constants.KritzelCustomElement.create(this._core).deserialize(obj);
|
|
21744
21566
|
break;
|
|
21745
21567
|
case 'KritzelSelectionGroup':
|
|
21746
21568
|
revivedObj = schema_constants.KritzelSelectionGroup.create(this._core).deserialize(obj);
|
|
@@ -21827,8 +21649,9 @@ const DEFAULT_ENGINE_CONFIG = {
|
|
|
21827
21649
|
debugInfo: {
|
|
21828
21650
|
showObjectInfo: false,
|
|
21829
21651
|
showViewportInfo: false,
|
|
21830
|
-
showSyncProviderInfo:
|
|
21831
|
-
|
|
21652
|
+
showSyncProviderInfo: false,
|
|
21653
|
+
showAssetResolverInfo: false,
|
|
21654
|
+
showMigrationInfo: false,
|
|
21832
21655
|
},
|
|
21833
21656
|
host: null,
|
|
21834
21657
|
pointerX: 0,
|
|
@@ -22509,7 +22332,8 @@ class KritzelObjectMap {
|
|
|
22509
22332
|
const docName = core.editorId ? `kritzel-workspace-${core.editorId}-${workspaceId}` : `kritzel-workspace-${workspaceId}`;
|
|
22510
22333
|
const finalConfig = config ?? DEFAULT_SYNC_CONFIG;
|
|
22511
22334
|
// Instantiate providers from configuration
|
|
22512
|
-
const
|
|
22335
|
+
const showSyncProviderInfo = !!core.store?.state?.debugInfo?.showSyncProviderInfo;
|
|
22336
|
+
const quiet = !showSyncProviderInfo;
|
|
22513
22337
|
for (const providerConfig of finalConfig.providers) {
|
|
22514
22338
|
let provider;
|
|
22515
22339
|
// Check if it's a class constructor or a factory
|
|
@@ -22523,6 +22347,10 @@ class KritzelObjectMap {
|
|
|
22523
22347
|
}
|
|
22524
22348
|
this._providers.push(provider);
|
|
22525
22349
|
}
|
|
22350
|
+
if (showSyncProviderInfo) {
|
|
22351
|
+
const providerList = this._providers.map(p => `${p.constructor.name} (${p.type})`).join(', ');
|
|
22352
|
+
console.info(`[Kritzel] Workspace sync providers initialized for ${docName}: ${providerList || 'none'}`);
|
|
22353
|
+
}
|
|
22526
22354
|
// captureTimeout is effectively infinite — undo-step boundaries are
|
|
22527
22355
|
// marked explicitly via markUndoBoundary() in insert/remove/reset and
|
|
22528
22356
|
// at stroke/gesture boundaries in the tools. This prevents a single
|
|
@@ -22563,15 +22391,24 @@ class KritzelObjectMap {
|
|
|
22563
22391
|
const networkProviders = this._providers.filter(p => p.type === 'network');
|
|
22564
22392
|
// Await local providers for immediate data availability
|
|
22565
22393
|
const localResults = await Promise.allSettled(localProviders.map(p => p.connect()));
|
|
22394
|
+
if (showSyncProviderInfo) {
|
|
22395
|
+
const connectedLocalCount = localResults.filter(result => result.status === 'fulfilled').length;
|
|
22396
|
+
console.info(`[Kritzel] Workspace local providers connected: ${connectedLocalCount}/${localProviders.length}`);
|
|
22397
|
+
}
|
|
22566
22398
|
localResults.forEach((result, i) => {
|
|
22567
|
-
if (result.status === 'rejected') {
|
|
22399
|
+
if (showSyncProviderInfo && result.status === 'rejected') {
|
|
22568
22400
|
console.error(`[Kritzel] Sync provider "${localProviders[i]?.constructor.name}" failed to connect:`, result.reason);
|
|
22569
22401
|
}
|
|
22570
22402
|
});
|
|
22571
22403
|
// Connect network providers in the background (remote data arrives via Yjs observers)
|
|
22404
|
+
if (showSyncProviderInfo && networkProviders.length > 0) {
|
|
22405
|
+
console.info(`[Kritzel] Workspace network providers connecting in background: ${networkProviders.length}`);
|
|
22406
|
+
}
|
|
22572
22407
|
for (const provider of networkProviders) {
|
|
22573
22408
|
provider.connect().catch(err => {
|
|
22574
|
-
|
|
22409
|
+
if (showSyncProviderInfo) {
|
|
22410
|
+
console.error(`[Kritzel] Network sync provider "${provider.constructor.name}" failed to connect:`, err);
|
|
22411
|
+
}
|
|
22575
22412
|
});
|
|
22576
22413
|
}
|
|
22577
22414
|
this._isReady = true;
|
|
@@ -23462,6 +23299,14 @@ class KritzelStore {
|
|
|
23462
23299
|
const activeShapes = this.objects.filter(o => o instanceof schema_constants.KritzelShape && o.isEditing);
|
|
23463
23300
|
return activeShapes.length > 0 ? activeShapes[0] : null;
|
|
23464
23301
|
}
|
|
23302
|
+
/**
|
|
23303
|
+
* Gets the currently selected custom element whose focused descendant is an input-like element.
|
|
23304
|
+
* @returns The interactive custom element with focused input-like content, or null if none matches
|
|
23305
|
+
*/
|
|
23306
|
+
get activeInteractiveCustomElement() {
|
|
23307
|
+
const interactiveCustomElement = this.selectedObjects.find(object => schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && object.hasFocusedInputElement());
|
|
23308
|
+
return interactiveCustomElement ?? null;
|
|
23309
|
+
}
|
|
23465
23310
|
/**
|
|
23466
23311
|
* Gets the path currently being drawn (not yet completed).
|
|
23467
23312
|
* @returns The incomplete path object, or null if no path is being drawn
|
|
@@ -23631,7 +23476,8 @@ class KritzelAppStateMap {
|
|
|
23631
23476
|
const docName = core.editorId ? `kritzel-app-state-${core.editorId}-${instanceId}` : `kritzel-app-state-${instanceId}`;
|
|
23632
23477
|
const finalConfig = config ?? DEFAULT_SYNC_CONFIG;
|
|
23633
23478
|
// Instantiate providers from configuration
|
|
23634
|
-
const
|
|
23479
|
+
const showSyncProviderInfo = !!core.store.state.debugInfo.showSyncProviderInfo;
|
|
23480
|
+
const quiet = !showSyncProviderInfo;
|
|
23635
23481
|
for (const providerConfig of finalConfig.providers) {
|
|
23636
23482
|
let provider;
|
|
23637
23483
|
// Check if it's a class constructor or a factory
|
|
@@ -23645,6 +23491,10 @@ class KritzelAppStateMap {
|
|
|
23645
23491
|
}
|
|
23646
23492
|
this._providers.push(provider);
|
|
23647
23493
|
}
|
|
23494
|
+
if (showSyncProviderInfo) {
|
|
23495
|
+
const providerList = this._providers.map(p => `${p.constructor.name} (${p.type})`).join(', ');
|
|
23496
|
+
console.info(`[Kritzel] App-state sync providers initialized for ${docName}: ${providerList || 'none'}`);
|
|
23497
|
+
}
|
|
23648
23498
|
// Observe changes to workspaces and sync with application state
|
|
23649
23499
|
this._workspacesObserver = event => {
|
|
23650
23500
|
this.handleWorkspacesChange(event);
|
|
@@ -23657,15 +23507,24 @@ class KritzelAppStateMap {
|
|
|
23657
23507
|
const networkProviders = this._providers.filter(p => p.type === 'network');
|
|
23658
23508
|
// Await local providers for immediate data availability
|
|
23659
23509
|
const localResults = await Promise.allSettled(localProviders.map(p => p.connect()));
|
|
23510
|
+
if (showSyncProviderInfo) {
|
|
23511
|
+
const connectedLocalCount = localResults.filter(result => result.status === 'fulfilled').length;
|
|
23512
|
+
console.info(`[Kritzel] App-state local providers connected: ${connectedLocalCount}/${localProviders.length}`);
|
|
23513
|
+
}
|
|
23660
23514
|
localResults.forEach((result, i) => {
|
|
23661
|
-
if (result.status === 'rejected') {
|
|
23515
|
+
if (showSyncProviderInfo && result.status === 'rejected') {
|
|
23662
23516
|
console.error(`[Kritzel] Sync provider "${localProviders[i]?.constructor.name}" failed to connect:`, result.reason);
|
|
23663
23517
|
}
|
|
23664
23518
|
});
|
|
23665
23519
|
// Connect network providers in the background (remote data arrives via Yjs observers)
|
|
23520
|
+
if (showSyncProviderInfo && networkProviders.length > 0) {
|
|
23521
|
+
console.info(`[Kritzel] App-state network providers connecting in background: ${networkProviders.length}`);
|
|
23522
|
+
}
|
|
23666
23523
|
for (const provider of networkProviders) {
|
|
23667
23524
|
provider.connect().catch(err => {
|
|
23668
|
-
|
|
23525
|
+
if (showSyncProviderInfo) {
|
|
23526
|
+
console.error(`[Kritzel] Network sync provider "${provider.constructor.name}" failed to connect:`, err);
|
|
23527
|
+
}
|
|
23669
23528
|
});
|
|
23670
23529
|
}
|
|
23671
23530
|
this._isReady = true;
|
|
@@ -24761,6 +24620,7 @@ class KritzelCore {
|
|
|
24761
24620
|
this._clipboardManager = new KritzelClipboardManager(this);
|
|
24762
24621
|
this._toolRegistry = new KritzelToolRegistry(this);
|
|
24763
24622
|
this._assetResolver = new schema_constants.KritzelAssetResolver();
|
|
24623
|
+
this._assetResolver.setShowInfo(this._store.state.debugInfo?.showAssetResolverInfo ?? false);
|
|
24764
24624
|
}
|
|
24765
24625
|
/**
|
|
24766
24626
|
* Gets the asset resolver responsible for storing and resolving
|
|
@@ -25132,6 +24992,10 @@ class KritzelCore {
|
|
|
25132
24992
|
this.removeObject(child);
|
|
25133
24993
|
});
|
|
25134
24994
|
}
|
|
24995
|
+
// Unmount custom elements before removal
|
|
24996
|
+
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
24997
|
+
object.unmount();
|
|
24998
|
+
}
|
|
25135
24999
|
// Handle anchor cleanup
|
|
25136
25000
|
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelLine')) {
|
|
25137
25001
|
// If removing a line, clean up its anchor index entries
|
|
@@ -25172,21 +25036,84 @@ class KritzelCore {
|
|
|
25172
25036
|
* @param selectionGroup - The selection group to add
|
|
25173
25037
|
*/
|
|
25174
25038
|
addSelectionGroup(selectionGroup) {
|
|
25175
|
-
this.
|
|
25039
|
+
this.removeLocalSelectionGroups();
|
|
25176
25040
|
this.removeSelectionBox();
|
|
25041
|
+
for (const object of selectionGroup.objects ?? []) {
|
|
25042
|
+
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
25043
|
+
const customElementObject = object;
|
|
25044
|
+
if (typeof customElementObject.setIsInteractive === 'function') {
|
|
25045
|
+
customElementObject.setIsInteractive(true);
|
|
25046
|
+
}
|
|
25047
|
+
else {
|
|
25048
|
+
customElementObject.isInteractive = true;
|
|
25049
|
+
}
|
|
25050
|
+
}
|
|
25051
|
+
}
|
|
25177
25052
|
this._store.objects.insert(selectionGroup);
|
|
25178
25053
|
this._store.setSelectionGroup(selectionGroup);
|
|
25179
25054
|
this._kritzelEngine.triggerSelectionChange();
|
|
25180
25055
|
}
|
|
25056
|
+
/**
|
|
25057
|
+
* Returns whether the provided selection group belongs to the local user context.
|
|
25058
|
+
* Local groups are either explicitly owned by the current user or have no user ID.
|
|
25059
|
+
*/
|
|
25060
|
+
isLocalSelectionGroup(selectionGroup) {
|
|
25061
|
+
const localUserId = this._user?.id;
|
|
25062
|
+
return localUserId == null || selectionGroup.userId === localUserId || selectionGroup.userId == null;
|
|
25063
|
+
}
|
|
25064
|
+
/**
|
|
25065
|
+
* Applies deselection teardown side effects to a selection group before removal.
|
|
25066
|
+
*/
|
|
25067
|
+
teardownSelectionGroup(selectionGroup) {
|
|
25068
|
+
selectionGroup.deselectAllChildren?.();
|
|
25069
|
+
for (const object of selectionGroup.objects ?? []) {
|
|
25070
|
+
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
25071
|
+
const customElementObject = object;
|
|
25072
|
+
if (typeof customElementObject.setIsInteractive === 'function') {
|
|
25073
|
+
customElementObject.setIsInteractive(false);
|
|
25074
|
+
}
|
|
25075
|
+
else {
|
|
25076
|
+
customElementObject.isInteractive = false;
|
|
25077
|
+
}
|
|
25078
|
+
}
|
|
25079
|
+
}
|
|
25080
|
+
}
|
|
25081
|
+
/**
|
|
25082
|
+
* Removes all local selection groups from the store, including orphaned groups
|
|
25083
|
+
* that are no longer referenced by store.selectionGroup.
|
|
25084
|
+
* @returns True when at least one local selection group was removed
|
|
25085
|
+
*/
|
|
25086
|
+
removeLocalSelectionGroups() {
|
|
25087
|
+
const allSelectionGroupsInStore = this._store.objects
|
|
25088
|
+
.allObjects()
|
|
25089
|
+
.filter((object) => {
|
|
25090
|
+
return object instanceof schema_constants.KritzelSelectionGroup || schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
|
|
25091
|
+
});
|
|
25092
|
+
const allLocalSelectionGroups = allSelectionGroupsInStore.filter(selectionGroup => this.isLocalSelectionGroup(selectionGroup));
|
|
25093
|
+
const currentSelectionGroup = this._store.selectionGroup;
|
|
25094
|
+
if (currentSelectionGroup &&
|
|
25095
|
+
this.isLocalSelectionGroup(currentSelectionGroup) &&
|
|
25096
|
+
!allLocalSelectionGroups.some(group => group.id === currentSelectionGroup.id)) {
|
|
25097
|
+
allLocalSelectionGroups.push(currentSelectionGroup);
|
|
25098
|
+
}
|
|
25099
|
+
if (allLocalSelectionGroups.length === 0) {
|
|
25100
|
+
return false;
|
|
25101
|
+
}
|
|
25102
|
+
for (const selectionGroup of allLocalSelectionGroups) {
|
|
25103
|
+
this.teardownSelectionGroup(selectionGroup);
|
|
25104
|
+
}
|
|
25105
|
+
const localSelectionGroupIds = new Set(allLocalSelectionGroups.map(group => group.id));
|
|
25106
|
+
this._store.objects.remove(object => localSelectionGroupIds.has(object.id));
|
|
25107
|
+
this._store.setSelectionGroup(null);
|
|
25108
|
+
return true;
|
|
25109
|
+
}
|
|
25181
25110
|
/**
|
|
25182
25111
|
* Removes the current selection group from the canvas.
|
|
25183
25112
|
* Clears the cached reference and triggers the selection change event.
|
|
25184
25113
|
*/
|
|
25185
25114
|
removeSelectionGroup() {
|
|
25186
|
-
const
|
|
25187
|
-
if (
|
|
25188
|
-
this._store.objects.remove(object => object.id === selectionGroup.id);
|
|
25189
|
-
this._store.setSelectionGroup(null);
|
|
25115
|
+
const removedAnySelectionGroup = this.removeLocalSelectionGroups();
|
|
25116
|
+
if (removedAnySelectionGroup) {
|
|
25190
25117
|
this._kritzelEngine.triggerSelectionChange();
|
|
25191
25118
|
}
|
|
25192
25119
|
}
|
|
@@ -25490,6 +25417,11 @@ class KritzelCore {
|
|
|
25490
25417
|
(o instanceof schema_constants.KritzelSelectionGroup && (localUserId == null || o.userId === localUserId || o.userId == null)));
|
|
25491
25418
|
this._store.setSelectionBox(null);
|
|
25492
25419
|
this._store.setSelectionGroup(null);
|
|
25420
|
+
for (const object of this._store.allNonSelectionObjects) {
|
|
25421
|
+
if (object.isSelected) {
|
|
25422
|
+
object.isSelected = false;
|
|
25423
|
+
}
|
|
25424
|
+
}
|
|
25493
25425
|
this._store.state.isSelecting = false;
|
|
25494
25426
|
this._store.state.isResizeHandleSelected = false;
|
|
25495
25427
|
this._store.state.isRotationHandleSelected = false;
|
|
@@ -25652,6 +25584,11 @@ class KritzelCore {
|
|
|
25652
25584
|
// During selection phase (no group yet), hide UI for KritzelLine objects
|
|
25653
25585
|
return !(object instanceof schema_constants.KritzelLine);
|
|
25654
25586
|
}
|
|
25587
|
+
// Once a local selection group exists, only the selection-group object
|
|
25588
|
+
// should render group UI (children remain selected but don't render handles).
|
|
25589
|
+
if (!(object instanceof schema_constants.KritzelSelectionGroup) || object.id !== selectionGroup.id) {
|
|
25590
|
+
return false;
|
|
25591
|
+
}
|
|
25655
25592
|
// Show UI if selection contains more than one object
|
|
25656
25593
|
if (selectionGroup.objects.length > 1) {
|
|
25657
25594
|
return true;
|
|
@@ -25937,6 +25874,9 @@ class KritzelSvgExportHelper {
|
|
|
25937
25874
|
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
|
|
25938
25875
|
return this.imageToSvg(object, imageDataUrls);
|
|
25939
25876
|
}
|
|
25877
|
+
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
25878
|
+
return this.customElementToSvg(object, rasterSafeForCanvas);
|
|
25879
|
+
}
|
|
25940
25880
|
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
|
|
25941
25881
|
return this.groupToSvg(object, theme, imageDataUrls, rasterSafeForCanvas);
|
|
25942
25882
|
}
|
|
@@ -26103,6 +26043,38 @@ class KritzelSvgExportHelper {
|
|
|
26103
26043
|
return `<g transform="${transform}"${opacity}>
|
|
26104
26044
|
<image href="${href}" x="0" y="0" width="${width}" height="${height}" preserveAspectRatio="xMidYMid meet"/>
|
|
26105
26045
|
</g>`;
|
|
26046
|
+
}
|
|
26047
|
+
/**
|
|
26048
|
+
* Converts a KritzelCustomElement to SVG.
|
|
26049
|
+
* SVG mode: embeds HTML in foreignObject (best-effort).
|
|
26050
|
+
* PNG/raster mode: renders placeholder rect with warning.
|
|
26051
|
+
* @param obj - The custom element object
|
|
26052
|
+
* @param rasterSafeForCanvas - If true, render placeholder (for PNG export)
|
|
26053
|
+
* @returns SVG element string
|
|
26054
|
+
*/
|
|
26055
|
+
static customElementToSvg(obj, rasterSafeForCanvas = false) {
|
|
26056
|
+
const transform = this.buildTransform(obj);
|
|
26057
|
+
const opacity = obj.opacity !== 1 ? ` opacity="${obj.opacity}"` : '';
|
|
26058
|
+
const scale = this.getObjectScale(obj);
|
|
26059
|
+
const width = obj.totalWidth / scale;
|
|
26060
|
+
const height = obj.totalHeight / scale;
|
|
26061
|
+
if (rasterSafeForCanvas) {
|
|
26062
|
+
// PNG export: render placeholder rect (foreignObject doesn't rasterize to PNG well)
|
|
26063
|
+
console.warn('[KritzelCustomElement SVG Export] Custom elements do not serialize well to PNG. Use SVG export or screenshot instead.');
|
|
26064
|
+
return `<g transform="${transform}"${opacity}>
|
|
26065
|
+
<rect x="0" y="0" width="${width}" height="${height}" fill="#f0f0f0" stroke="#999" stroke-width="1" />
|
|
26066
|
+
<text x="${width / 2}" y="${height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999">[Custom Element]</text>
|
|
26067
|
+
</g>`;
|
|
26068
|
+
}
|
|
26069
|
+
// SVG export: use foreignObject to embed HTML
|
|
26070
|
+
const html = obj.element?.outerHTML || '<div style="border:1px dashed #ccc">Empty</div>';
|
|
26071
|
+
return `<g transform="${transform}"${opacity}>
|
|
26072
|
+
<foreignObject x="0" y="0" width="${width}" height="${height}">
|
|
26073
|
+
<div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;overflow:hidden;">
|
|
26074
|
+
${html}
|
|
26075
|
+
</div>
|
|
26076
|
+
</foreignObject>
|
|
26077
|
+
</g>`;
|
|
26106
26078
|
}
|
|
26107
26079
|
/**
|
|
26108
26080
|
* Converts a KritzelGroup to SVG by recursively converting children.
|
|
@@ -27174,6 +27146,120 @@ async function toPng(node, options = {}) {
|
|
|
27174
27146
|
return canvas.toDataURL();
|
|
27175
27147
|
}
|
|
27176
27148
|
|
|
27149
|
+
class KritzelWheelHelper {
|
|
27150
|
+
static shouldKeepWheelInCustomElement(ev, customElement) {
|
|
27151
|
+
// Keep Ctrl+wheel available for viewport zoom gestures.
|
|
27152
|
+
if (ev.ctrlKey || customElement.isSelected !== true) {
|
|
27153
|
+
return false;
|
|
27154
|
+
}
|
|
27155
|
+
const path = typeof ev.composedPath === 'function' ? ev.composedPath() : [];
|
|
27156
|
+
const scrollContainer = this.getScrollableContainerFromEventPath(path, customElement);
|
|
27157
|
+
// No scroll container found inside the custom element: let the wheel
|
|
27158
|
+
// event pass through so the viewport can continue handling it.
|
|
27159
|
+
if (!scrollContainer) {
|
|
27160
|
+
return false;
|
|
27161
|
+
}
|
|
27162
|
+
return this.canElementConsumeWheel(scrollContainer, ev.deltaX, ev.deltaY);
|
|
27163
|
+
}
|
|
27164
|
+
static getScrollableContainerFromEventPath(path, customElement) {
|
|
27165
|
+
const potentialRoots = [];
|
|
27166
|
+
if (customElement.element instanceof HTMLElement) {
|
|
27167
|
+
potentialRoots.push(customElement.element);
|
|
27168
|
+
}
|
|
27169
|
+
if (customElement.elementRef instanceof HTMLElement) {
|
|
27170
|
+
potentialRoots.push(customElement.elementRef);
|
|
27171
|
+
}
|
|
27172
|
+
const legacyElementRef = customElement.elmeentRef;
|
|
27173
|
+
if (legacyElementRef instanceof HTMLElement) {
|
|
27174
|
+
potentialRoots.push(legacyElementRef);
|
|
27175
|
+
}
|
|
27176
|
+
for (const root of potentialRoots) {
|
|
27177
|
+
const rootIndex = path.findIndex(entry => entry === root);
|
|
27178
|
+
if (rootIndex === -1) {
|
|
27179
|
+
continue;
|
|
27180
|
+
}
|
|
27181
|
+
for (const entry of path.slice(0, rootIndex + 1)) {
|
|
27182
|
+
if (!(entry instanceof HTMLElement)) {
|
|
27183
|
+
continue;
|
|
27184
|
+
}
|
|
27185
|
+
if (this.isScrollableElement(entry)) {
|
|
27186
|
+
return entry;
|
|
27187
|
+
}
|
|
27188
|
+
}
|
|
27189
|
+
}
|
|
27190
|
+
// Fallback for synthetic/custom wheel events where composedPath is absent
|
|
27191
|
+
// or does not include the custom-element subtree.
|
|
27192
|
+
for (const root of potentialRoots) {
|
|
27193
|
+
if (this.isScrollableElement(root)) {
|
|
27194
|
+
return root;
|
|
27195
|
+
}
|
|
27196
|
+
const firstChild = root.firstElementChild;
|
|
27197
|
+
if (firstChild instanceof HTMLElement && this.isScrollableElement(firstChild)) {
|
|
27198
|
+
return firstChild;
|
|
27199
|
+
}
|
|
27200
|
+
}
|
|
27201
|
+
return null;
|
|
27202
|
+
}
|
|
27203
|
+
static isScrollableElement(element) {
|
|
27204
|
+
const canScrollVertically = element.scrollHeight - element.clientHeight > 0;
|
|
27205
|
+
const canScrollHorizontally = element.scrollWidth - element.clientWidth > 0;
|
|
27206
|
+
if (!canScrollVertically && !canScrollHorizontally) {
|
|
27207
|
+
return false;
|
|
27208
|
+
}
|
|
27209
|
+
const computedStyle = window.getComputedStyle(element);
|
|
27210
|
+
const overflowX = computedStyle.overflowX;
|
|
27211
|
+
const overflowY = computedStyle.overflowY;
|
|
27212
|
+
const allowsVerticalScroll = overflowY !== 'visible' && overflowY !== 'clip';
|
|
27213
|
+
const allowsHorizontalScroll = overflowX !== 'visible' && overflowX !== 'clip';
|
|
27214
|
+
return (canScrollVertically && allowsVerticalScroll) || (canScrollHorizontally && allowsHorizontalScroll);
|
|
27215
|
+
}
|
|
27216
|
+
static canElementConsumeWheel(element, deltaX, deltaY) {
|
|
27217
|
+
const canConsumeVertical = this.canElementConsumeVerticalWheel(element, deltaY);
|
|
27218
|
+
const canConsumeHorizontal = this.canElementConsumeHorizontalWheel(element, deltaX);
|
|
27219
|
+
// Keep wheel events inside the custom element whenever at least one
|
|
27220
|
+
// requested axis can still be consumed by its scroll container.
|
|
27221
|
+
return canConsumeVertical || canConsumeHorizontal;
|
|
27222
|
+
}
|
|
27223
|
+
static canElementConsumeVerticalWheel(element, deltaY) {
|
|
27224
|
+
if (deltaY === 0) {
|
|
27225
|
+
return false;
|
|
27226
|
+
}
|
|
27227
|
+
const maxScrollTop = Math.max(0, element.scrollHeight - element.clientHeight);
|
|
27228
|
+
if (maxScrollTop === 0) {
|
|
27229
|
+
return false;
|
|
27230
|
+
}
|
|
27231
|
+
const epsilon = 1;
|
|
27232
|
+
const scrollingDown = deltaY > 0;
|
|
27233
|
+
const scrollingUp = deltaY < 0;
|
|
27234
|
+
if (scrollingDown) {
|
|
27235
|
+
return element.scrollTop < maxScrollTop - epsilon;
|
|
27236
|
+
}
|
|
27237
|
+
if (scrollingUp) {
|
|
27238
|
+
return element.scrollTop > epsilon;
|
|
27239
|
+
}
|
|
27240
|
+
return false;
|
|
27241
|
+
}
|
|
27242
|
+
static canElementConsumeHorizontalWheel(element, deltaX) {
|
|
27243
|
+
if (deltaX === 0) {
|
|
27244
|
+
return false;
|
|
27245
|
+
}
|
|
27246
|
+
const maxScrollLeft = Math.max(0, element.scrollWidth - element.clientWidth);
|
|
27247
|
+
if (maxScrollLeft === 0) {
|
|
27248
|
+
return false;
|
|
27249
|
+
}
|
|
27250
|
+
const epsilon = 1;
|
|
27251
|
+
const scrollingRight = deltaX > 0;
|
|
27252
|
+
const scrollingLeft = deltaX < 0;
|
|
27253
|
+
if (scrollingRight) {
|
|
27254
|
+
return element.scrollLeft < maxScrollLeft - epsilon;
|
|
27255
|
+
}
|
|
27256
|
+
if (scrollingLeft) {
|
|
27257
|
+
return element.scrollLeft > epsilon;
|
|
27258
|
+
}
|
|
27259
|
+
return false;
|
|
27260
|
+
}
|
|
27261
|
+
}
|
|
27262
|
+
|
|
27177
27263
|
const kritzelEngineCss = () => `:host{display:block;position:relative;height:100%;width:100%;overflow:hidden;background-color:var(--kritzel-engine-background-color, #ffffff)}:host,:host *{touch-action:none;user-select:none}.ProseMirror{outline:none}p,h1,h2,h3,h4,h5,h6,blockquote,pre{margin:0;padding:0}.workspace-loading-overlay{position:absolute;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;gap:10px;background-color:var(--kritzel-engine-loading-overlay-background, rgba(255, 255, 255, 0.6));color:var(--kritzel-engine-loading-overlay-color, #333);font-family:var(--kritzel-font-family, sans-serif);font-size:1.25rem;pointer-events:all;animation:workspace-loading-fade-in 200ms ease-out var(--kritzel-engine-loading-overlay-delay, 300ms) forwards;opacity:0}.workspace-loading-spinner{width:20px;height:20px;box-sizing:border-box;display:block;flex-shrink:0;border:2px solid var(--kritzel-engine-loading-overlay-spinner-color, #cccccc);border-top-color:var(--kritzel-engine-loading-overlay-spinner-active-color, #333333);border-radius:50%;animation:workspace-loading-spin 0.6s linear infinite}@keyframes workspace-loading-spin{to{transform:rotate(360deg)}}@keyframes workspace-loading-fade-in{to{opacity:1}}.debug-panel{position:absolute;pointer-events:none;top:0;right:0}.origin{position:relative;top:0;left:0;height:0;width:0;pointer-events:none;-webkit-transform-origin:top left;-moz-transform-origin:top left;transform-origin:top left;overflow:visible}.object{overflow:visible}.PlaygroundEditorTheme__quote{margin:0;margin-left:20px;margin-bottom:10px;font-size:15px;color:rgb(101, 103, 107);border-left-color:rgb(206, 208, 212);border-left-width:4px;border-left-style:solid;padding-left:16px}`;
|
|
27178
27264
|
|
|
27179
27265
|
const KritzelEngine = class {
|
|
@@ -27362,6 +27448,7 @@ const KritzelEngine = class {
|
|
|
27362
27448
|
onDebugInfoChange(newValue) {
|
|
27363
27449
|
if (newValue) {
|
|
27364
27450
|
this.core.store.state.debugInfo = newValue;
|
|
27451
|
+
this.core.assetResolver.setShowInfo(newValue.showAssetResolverInfo);
|
|
27365
27452
|
}
|
|
27366
27453
|
}
|
|
27367
27454
|
/** When false, non-modified wheel events do not pan the viewport. */
|
|
@@ -27415,6 +27502,12 @@ const KritzelEngine = class {
|
|
|
27415
27502
|
if (this.core.store.state.isContextMenuVisible) {
|
|
27416
27503
|
this.hideContextMenu();
|
|
27417
27504
|
}
|
|
27505
|
+
const hoveredObject = this.core.getObjectFromPointerEvent(ev);
|
|
27506
|
+
if (hoveredObject &&
|
|
27507
|
+
schema_constants.ObjectHelper.isClass(hoveredObject, 'KritzelCustomElement') &&
|
|
27508
|
+
KritzelWheelHelper.shouldKeepWheelInCustomElement(ev, hoveredObject)) {
|
|
27509
|
+
return;
|
|
27510
|
+
}
|
|
27418
27511
|
if (ev.ctrlKey) {
|
|
27419
27512
|
if (this.isZoomingEnabled) {
|
|
27420
27513
|
this.viewport.handleWheel(ev);
|
|
@@ -27431,6 +27524,11 @@ const KritzelEngine = class {
|
|
|
27431
27524
|
if (this.core.store.isDisabled) {
|
|
27432
27525
|
return;
|
|
27433
27526
|
}
|
|
27527
|
+
// Interactive custom-element content should receive native pointer events
|
|
27528
|
+
// whenever the object is marked interactive.
|
|
27529
|
+
if (this.isEmbeddedCustomElementInteraction(ev)) {
|
|
27530
|
+
return;
|
|
27531
|
+
}
|
|
27434
27532
|
if (schema_constants.KritzelDevicesHelper.isTouchDevice()) {
|
|
27435
27533
|
schema_constants.KritzelEventHelper.onLongPress(ev, (event) => this.longpress.emit(event));
|
|
27436
27534
|
}
|
|
@@ -27447,6 +27545,10 @@ const KritzelEngine = class {
|
|
|
27447
27545
|
if (this.core.store.isDisabled) {
|
|
27448
27546
|
return;
|
|
27449
27547
|
}
|
|
27548
|
+
// Ignore drag/move sequences when their pointerdown was intentionally bypassed.
|
|
27549
|
+
if (ev.buttons > 0 && !this.core.store.state.pointers.has(ev.pointerId)) {
|
|
27550
|
+
return;
|
|
27551
|
+
}
|
|
27450
27552
|
if (this.core.store.state.pointers.has(ev.pointerId)) {
|
|
27451
27553
|
this.core.store.state.pointers.set(ev.pointerId, ev);
|
|
27452
27554
|
}
|
|
@@ -27495,6 +27597,56 @@ const KritzelEngine = class {
|
|
|
27495
27597
|
this.viewport.handlePointerUp(ev);
|
|
27496
27598
|
this.core.store.state?.activeTool?.handlePointerUp(ev);
|
|
27497
27599
|
}
|
|
27600
|
+
isEmbeddedCustomElementInteraction(event) {
|
|
27601
|
+
const path = event.composedPath();
|
|
27602
|
+
const objectElement = path.find((entry) => {
|
|
27603
|
+
return entry instanceof HTMLElement && entry.classList.contains('object');
|
|
27604
|
+
});
|
|
27605
|
+
if (!objectElement?.id) {
|
|
27606
|
+
return false;
|
|
27607
|
+
}
|
|
27608
|
+
const object = this.core.store.objects.findById(objectElement.id);
|
|
27609
|
+
if (!object || !schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
27610
|
+
return false;
|
|
27611
|
+
}
|
|
27612
|
+
const isSelected = !!this.core.store.selectionGroup?.objects?.some(selectedObject => selectedObject.id === object.id);
|
|
27613
|
+
if (!isSelected) {
|
|
27614
|
+
return false;
|
|
27615
|
+
}
|
|
27616
|
+
if (object.isInteractive !== true) {
|
|
27617
|
+
return false;
|
|
27618
|
+
}
|
|
27619
|
+
const potentialRoots = [];
|
|
27620
|
+
if (object.element instanceof HTMLElement) {
|
|
27621
|
+
potentialRoots.push(object.element);
|
|
27622
|
+
}
|
|
27623
|
+
if (object.elementRef instanceof HTMLElement) {
|
|
27624
|
+
potentialRoots.push(object.elementRef);
|
|
27625
|
+
}
|
|
27626
|
+
if (potentialRoots.length === 0) {
|
|
27627
|
+
return false;
|
|
27628
|
+
}
|
|
27629
|
+
// Only bypass canvas tool handling when the pointer event came from an
|
|
27630
|
+
// actually interactive descendant inside the custom element subtree.
|
|
27631
|
+
return potentialRoots.some(root => this.isNativeInteractiveEmbeddedTarget(path, root));
|
|
27632
|
+
}
|
|
27633
|
+
isNativeInteractiveEmbeddedTarget(path, customElementRoot) {
|
|
27634
|
+
const interactiveSelector = 'input, button, textarea, select, a[href], [contenteditable="true"], [contenteditable=""]';
|
|
27635
|
+
const rootIndex = path.findIndex(entry => entry === customElementRoot);
|
|
27636
|
+
if (rootIndex === -1) {
|
|
27637
|
+
return false;
|
|
27638
|
+
}
|
|
27639
|
+
for (const entry of path.slice(0, rootIndex)) {
|
|
27640
|
+
if (!(entry instanceof HTMLElement)) {
|
|
27641
|
+
continue;
|
|
27642
|
+
}
|
|
27643
|
+
const interactiveEntry = entry;
|
|
27644
|
+
if (interactiveEntry.matches(interactiveSelector)) {
|
|
27645
|
+
return true;
|
|
27646
|
+
}
|
|
27647
|
+
}
|
|
27648
|
+
return false;
|
|
27649
|
+
}
|
|
27498
27650
|
handlePointerLeave() {
|
|
27499
27651
|
this.core.store.objects?.clearCursorPosition();
|
|
27500
27652
|
}
|
|
@@ -27566,7 +27718,7 @@ const KritzelEngine = class {
|
|
|
27566
27718
|
void this.core.clipboardManager.paste(undefined, undefined, ev);
|
|
27567
27719
|
}
|
|
27568
27720
|
/**
|
|
27569
|
-
|
|
27721
|
+
* Determines if the engine should handle a keyboard/clipboard shortcut event.
|
|
27570
27722
|
* Returns true only if:
|
|
27571
27723
|
* - The event originates from within the engine component, OR
|
|
27572
27724
|
* - The event target is not an interactive element that needs keyboard input
|
|
@@ -28780,6 +28932,8 @@ const KritzelEngine = class {
|
|
|
28780
28932
|
_syncConfigRevision = 0;
|
|
28781
28933
|
_assetStorageConfigRevision = 0;
|
|
28782
28934
|
_isWorkspaceLoading = false;
|
|
28935
|
+
_hasLoggedUnlicensedWelcomeBanner = false;
|
|
28936
|
+
_previousVisibleCustomElements = new Set();
|
|
28783
28937
|
_defaultUndoState = {
|
|
28784
28938
|
canUndo: false,
|
|
28785
28939
|
canRedo: false,
|
|
@@ -28843,6 +28997,14 @@ const KritzelEngine = class {
|
|
|
28843
28997
|
}
|
|
28844
28998
|
disconnectedCallback() {
|
|
28845
28999
|
this.throttledPointerMoveMulti.cancel();
|
|
29000
|
+
// Unmount all remaining custom elements
|
|
29001
|
+
if (this.core.store.allObjects) {
|
|
29002
|
+
this.core.store.allObjects.forEach(object => {
|
|
29003
|
+
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
29004
|
+
object.unmount();
|
|
29005
|
+
}
|
|
29006
|
+
});
|
|
29007
|
+
}
|
|
28846
29008
|
// Clear cursor position in awareness before destroying
|
|
28847
29009
|
this.core.store.objects?.clearCursorPosition();
|
|
28848
29010
|
// Clean up current workspace's ObjectMap
|
|
@@ -28899,6 +29061,7 @@ const KritzelEngine = class {
|
|
|
28899
29061
|
await this.initializeSyncAndWorkspace();
|
|
28900
29062
|
if (this.core.store.state.isReady === false) {
|
|
28901
29063
|
this.core.store.state.isReady = true;
|
|
29064
|
+
this.logUnlicensedWelcomeBanner();
|
|
28902
29065
|
this.isEngineReady.emit(this.core.store.state);
|
|
28903
29066
|
}
|
|
28904
29067
|
}, 50);
|
|
@@ -28938,6 +29101,14 @@ const KritzelEngine = class {
|
|
|
28938
29101
|
}
|
|
28939
29102
|
this._isAssetStorageInitialized = true;
|
|
28940
29103
|
}
|
|
29104
|
+
logUnlicensedWelcomeBanner() {
|
|
29105
|
+
if (this.core.licenseManager.isLicensed || this._hasLoggedUnlicensedWelcomeBanner) {
|
|
29106
|
+
return;
|
|
29107
|
+
}
|
|
29108
|
+
this._hasLoggedUnlicensedWelcomeBanner = true;
|
|
29109
|
+
console.info('%c👋 Welcome to Kritzel', 'color: #007AFF; font-weight: 700;');
|
|
29110
|
+
console.info(`This version of Kritzel is not licensed. Get a license at: https://kritzel.io`);
|
|
29111
|
+
}
|
|
28941
29112
|
async doInitializeSyncAndWorkspace() {
|
|
28942
29113
|
// Capture sync config revision to detect prop updates that happen while
|
|
28943
29114
|
// initialization is in-flight.
|
|
@@ -29141,8 +29312,7 @@ const KritzelEngine = class {
|
|
|
29141
29312
|
if (normalizedScale <= this._objectDistanceFadeFarScale) {
|
|
29142
29313
|
return this._objectDistanceFadeMinOpacity;
|
|
29143
29314
|
}
|
|
29144
|
-
const progress = (this._objectDistanceFadeNearScale - normalizedScale) /
|
|
29145
|
-
(this._objectDistanceFadeNearScale - this._objectDistanceFadeFarScale);
|
|
29315
|
+
const progress = (this._objectDistanceFadeNearScale - normalizedScale) / (this._objectDistanceFadeNearScale - this._objectDistanceFadeFarScale);
|
|
29146
29316
|
const smooth = progress * progress * (3 - 2 * progress);
|
|
29147
29317
|
return 1 - smooth * (1 - this._objectDistanceFadeMinOpacity);
|
|
29148
29318
|
}
|
|
@@ -29153,8 +29323,7 @@ const KritzelEngine = class {
|
|
|
29153
29323
|
if (normalizedScale >= this._objectDistanceFadeCloseMaxScale) {
|
|
29154
29324
|
return this._objectDistanceFadeCloseMinOpacity;
|
|
29155
29325
|
}
|
|
29156
|
-
const progress = (normalizedScale - this._objectDistanceFadeCloseStartScale) /
|
|
29157
|
-
(this._objectDistanceFadeCloseMaxScale - this._objectDistanceFadeCloseStartScale);
|
|
29326
|
+
const progress = (normalizedScale - this._objectDistanceFadeCloseStartScale) / (this._objectDistanceFadeCloseMaxScale - this._objectDistanceFadeCloseStartScale);
|
|
29158
29327
|
const smooth = progress * progress * (3 - 2 * progress);
|
|
29159
29328
|
return 1 - smooth * (1 - this._objectDistanceFadeCloseMinOpacity);
|
|
29160
29329
|
}
|
|
@@ -29164,13 +29333,18 @@ const KritzelEngine = class {
|
|
|
29164
29333
|
}
|
|
29165
29334
|
getObjectEffectiveOpacity(object, viewportScale) {
|
|
29166
29335
|
const safeObjectOpacity = Number.isFinite(object.opacity) ? object.opacity : 1;
|
|
29167
|
-
const distanceFadeMultiplier = this.shouldApplyDistanceFade(object)
|
|
29168
|
-
? this.getObjectDistanceFadeMultiplier(object.scale, viewportScale)
|
|
29169
|
-
: 1;
|
|
29336
|
+
const distanceFadeMultiplier = this.shouldApplyDistanceFade(object) ? this.getObjectDistanceFadeMultiplier(object.scale, viewportScale) : 1;
|
|
29170
29337
|
const multiplied = (object.markedForRemoval ? 0.5 : 1) * safeObjectOpacity * distanceFadeMultiplier;
|
|
29171
29338
|
const overridden = ((object.markedForRemoval ? 0.5 : safeObjectOpacity) * distanceFadeMultiplier).toString();
|
|
29172
29339
|
return { multiplied, overridden };
|
|
29173
29340
|
}
|
|
29341
|
+
getSelectionHandleCapabilities(object) {
|
|
29342
|
+
const selectedObjects = schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') ? object.objects : [object];
|
|
29343
|
+
return {
|
|
29344
|
+
canRenderResizeHandles: selectedObjects.every(selectedObject => selectedObject.isResizable !== false),
|
|
29345
|
+
canRenderRotationHandle: selectedObjects.every(selectedObject => selectedObject.isRotatable !== false),
|
|
29346
|
+
};
|
|
29347
|
+
}
|
|
29174
29348
|
render() {
|
|
29175
29349
|
if (!this.viewport) {
|
|
29176
29350
|
return (index.h(index.Host, null, this.core.store.state.isLoading && (index.h("div", { class: "workspace-loading-overlay" }, index.h("span", { class: "workspace-loading-spinner" }), this.core.localizationManager.translate('engine.loading')))));
|
|
@@ -29184,6 +29358,45 @@ const KritzelEngine = class {
|
|
|
29184
29358
|
const viewportCenterX = this.core.store.state.viewportWidth / 2 + this.core.store.state.translateX;
|
|
29185
29359
|
const viewportCenterY = this.core.store.state.viewportHeight / 2 + this.core.store.state.translateY;
|
|
29186
29360
|
const visibleObjects = this.core.store.objectsInViewport;
|
|
29361
|
+
const getObjectWrapperPointerEvents = (object) => {
|
|
29362
|
+
if (this.core.store.state.isScaling) {
|
|
29363
|
+
return 'none';
|
|
29364
|
+
}
|
|
29365
|
+
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup')) {
|
|
29366
|
+
return 'none';
|
|
29367
|
+
}
|
|
29368
|
+
return 'auto';
|
|
29369
|
+
};
|
|
29370
|
+
const getSelectionGroupOverlayPointerEvents = (object) => {
|
|
29371
|
+
if (object.markedForRemoval) {
|
|
29372
|
+
return 'none';
|
|
29373
|
+
}
|
|
29374
|
+
if (!schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup')) {
|
|
29375
|
+
return 'auto';
|
|
29376
|
+
}
|
|
29377
|
+
if (object.objects.length === 1 && schema_constants.KritzelClassHelper.isInstanceOf(object.objects[0], 'KritzelCustomElement')) {
|
|
29378
|
+
return 'none';
|
|
29379
|
+
}
|
|
29380
|
+
return 'auto';
|
|
29381
|
+
};
|
|
29382
|
+
// Track visible custom elements and unmount culled ones
|
|
29383
|
+
const currentVisibleCustomElements = new Set();
|
|
29384
|
+
visibleObjects.forEach(object => {
|
|
29385
|
+
if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
29386
|
+
currentVisibleCustomElements.add(object.id);
|
|
29387
|
+
}
|
|
29388
|
+
});
|
|
29389
|
+
// Unmount custom elements that left the viewport
|
|
29390
|
+
this._previousVisibleCustomElements.forEach(id => {
|
|
29391
|
+
if (!currentVisibleCustomElements.has(id)) {
|
|
29392
|
+
const object = this.core.store.objects.findById(id);
|
|
29393
|
+
if (object && schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
29394
|
+
object.unmount();
|
|
29395
|
+
}
|
|
29396
|
+
}
|
|
29397
|
+
});
|
|
29398
|
+
// Update tracking set for next render
|
|
29399
|
+
this._previousVisibleCustomElements = currentVisibleCustomElements;
|
|
29187
29400
|
this.core.cursorManager.applyCursor();
|
|
29188
29401
|
if (this.core.store.state.hasViewportChanged) {
|
|
29189
29402
|
this.viewportChange.emit(this.viewport.getViewport());
|
|
@@ -29200,7 +29413,7 @@ const KritzelEngine = class {
|
|
|
29200
29413
|
transformOrigin: 'top left',
|
|
29201
29414
|
position: 'absolute',
|
|
29202
29415
|
zIndex: object.zIndex.toString(),
|
|
29203
|
-
pointerEvents:
|
|
29416
|
+
pointerEvents: getObjectWrapperPointerEvents(object),
|
|
29204
29417
|
} }, schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (index.h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
|
|
29205
29418
|
height: object?.totalHeight + 'px',
|
|
29206
29419
|
width: object?.totalWidth + 'px',
|
|
@@ -29289,7 +29502,7 @@ const KritzelEngine = class {
|
|
|
29289
29502
|
transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
|
|
29290
29503
|
transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
|
|
29291
29504
|
opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
|
|
29292
|
-
pointerEvents: object
|
|
29505
|
+
pointerEvents: getSelectionGroupOverlayPointerEvents(object),
|
|
29293
29506
|
} })), schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (index.h("div", { ref: el => el && object.mount(el), style: {
|
|
29294
29507
|
position: 'absolute',
|
|
29295
29508
|
left: '0',
|
|
@@ -29324,60 +29537,65 @@ const KritzelEngine = class {
|
|
|
29324
29537
|
transform: `scale(${object.scaleFactor})`,
|
|
29325
29538
|
backgroundColor: schema_constants.KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
|
|
29326
29539
|
overflow: 'visible',
|
|
29327
|
-
} }))), schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelShape') &&
|
|
29328
|
-
|
|
29329
|
-
|
|
29330
|
-
|
|
29331
|
-
|
|
29332
|
-
|
|
29333
|
-
|
|
29334
|
-
|
|
29335
|
-
|
|
29336
|
-
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
|
|
29340
|
-
|
|
29341
|
-
|
|
29342
|
-
|
|
29343
|
-
|
|
29344
|
-
|
|
29345
|
-
|
|
29346
|
-
|
|
29347
|
-
|
|
29348
|
-
|
|
29349
|
-
|
|
29350
|
-
|
|
29351
|
-
|
|
29352
|
-
|
|
29353
|
-
|
|
29354
|
-
|
|
29355
|
-
|
|
29356
|
-
|
|
29357
|
-
|
|
29358
|
-
|
|
29359
|
-
|
|
29360
|
-
|
|
29361
|
-
|
|
29362
|
-
|
|
29363
|
-
|
|
29540
|
+
} }))), schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelShape') &&
|
|
29541
|
+
(() => {
|
|
29542
|
+
const fillResolved = schema_constants.KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme);
|
|
29543
|
+
const strokeResolved = schema_constants.KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme);
|
|
29544
|
+
const isFilled = !!fillResolved && fillResolved !== 'transparent';
|
|
29545
|
+
const strokeMatchesFill = isFilled && strokeResolved === fillResolved;
|
|
29546
|
+
return (index.h("div", { ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
|
|
29547
|
+
position: 'absolute',
|
|
29548
|
+
left: '0',
|
|
29549
|
+
top: '0',
|
|
29550
|
+
width: object.totalWidth + 'px',
|
|
29551
|
+
height: object.totalHeight + 'px',
|
|
29552
|
+
transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
|
|
29553
|
+
transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
|
|
29554
|
+
pointerEvents: object.markedForRemoval ? 'none' : 'auto',
|
|
29555
|
+
overflow: 'visible',
|
|
29556
|
+
} }, index.h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
|
|
29557
|
+
position: 'absolute',
|
|
29558
|
+
top: '0',
|
|
29559
|
+
left: '0',
|
|
29560
|
+
width: '100%',
|
|
29561
|
+
height: '100%',
|
|
29562
|
+
overflow: 'visible',
|
|
29563
|
+
pointerEvents: 'none',
|
|
29564
|
+
}, viewBox: object.viewBox, preserveAspectRatio: "none" }, index.h("path", { d: object.getSvgPath(), fill: schema_constants.KritzelColorHelper.applyOpacity(object.fillColor, effectiveOpacity, currentTheme), stroke: strokeMatchesFill ? 'none' : schema_constants.KritzelColorHelper.applyOpacity(object.strokeColor, effectiveOpacity, currentTheme), "stroke-width": strokeMatchesFill ? 0 : object.strokeWidth })), index.h("div", { ref: el => el && object.mountTextEditor(el), style: {
|
|
29565
|
+
position: 'absolute',
|
|
29566
|
+
top: '0',
|
|
29567
|
+
left: '0',
|
|
29568
|
+
width: '100%',
|
|
29569
|
+
height: '100%',
|
|
29570
|
+
display: 'flex',
|
|
29571
|
+
alignItems: 'center',
|
|
29572
|
+
justifyContent: 'center',
|
|
29573
|
+
textAlign: 'center',
|
|
29574
|
+
overflow: 'hidden',
|
|
29575
|
+
pointerEvents: object.isEditing ? 'auto' : 'none',
|
|
29576
|
+
} })));
|
|
29577
|
+
})(), this.core.store.state.debugInfo.showObjectInfo && (index.h("div", { style: {
|
|
29364
29578
|
pointerEvents: 'none',
|
|
29365
29579
|
position: 'absolute',
|
|
29366
29580
|
left: `${object.totalWidth}px`,
|
|
29367
29581
|
top: '0',
|
|
29368
29582
|
zIndex: (object.zIndex + 2).toString(),
|
|
29369
|
-
} }, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (index.h("div", null, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
|
|
29583
|
+
} }, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isSelected: ", object.isSelected ? 'true' : 'false'), schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (index.h("div", null, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isInteractive: ", object.isInteractive ? 'true' : 'false'))), schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (index.h("div", null, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
|
|
29370
29584
|
(() => {
|
|
29371
29585
|
const isSelectionGroup = schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
|
|
29372
29586
|
const localClientId = this.core.store.objects?.localClientId;
|
|
29373
29587
|
const awarenessStates = this.core.store.objects?.awareness?.getStates();
|
|
29374
|
-
const isRemoteSelection = isSelectionGroup &&
|
|
29375
|
-
|
|
29376
|
-
|
|
29377
|
-
|
|
29378
|
-
|
|
29379
|
-
|
|
29380
|
-
|
|
29588
|
+
const isRemoteSelection = isSelectionGroup &&
|
|
29589
|
+
// Different user
|
|
29590
|
+
((object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
|
|
29591
|
+
// Same user but different client that is still actively connected (e.g. same account on another device)
|
|
29592
|
+
(object.userId != null &&
|
|
29593
|
+
this.core.user?.id != null &&
|
|
29594
|
+
object.userId === this.core.user.id &&
|
|
29595
|
+
object.clientId != null &&
|
|
29596
|
+
localClientId != null &&
|
|
29597
|
+
object.clientId !== localClientId &&
|
|
29598
|
+
awarenessStates?.has(object.clientId) === true));
|
|
29381
29599
|
let remoteUserColor;
|
|
29382
29600
|
if (isRemoteSelection) {
|
|
29383
29601
|
if (awarenessStates) {
|
|
@@ -29396,10 +29614,10 @@ const KritzelEngine = class {
|
|
|
29396
29614
|
}
|
|
29397
29615
|
}
|
|
29398
29616
|
}
|
|
29399
|
-
const selectionBorderColor = remoteUserColor
|
|
29400
|
-
|
|
29401
|
-
const
|
|
29402
|
-
|
|
29617
|
+
const selectionBorderColor = remoteUserColor ?? (schema_constants.KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme) || 'var(--kritzel-selection-border-color, #007AFF)');
|
|
29618
|
+
const selectionHandleStrokeColor = remoteUserColor ?? 'var(--kritzel-selection-handle-stroke-color, #007AFF)';
|
|
29619
|
+
const handleScale = object.scale ?? 1;
|
|
29620
|
+
const { canRenderResizeHandles, canRenderRotationHandle } = this.getSelectionHandleCapabilities(object);
|
|
29403
29621
|
return (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
|
|
29404
29622
|
zIndex: (object.zIndex + 1).toString(),
|
|
29405
29623
|
height: object?.totalHeight.toString(),
|
|
@@ -29443,50 +29661,50 @@ const KritzelEngine = class {
|
|
|
29443
29661
|
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
29444
29662
|
strokeLinecap: 'square',
|
|
29445
29663
|
} })));
|
|
29446
|
-
})(), !this.isSelecting && !isRemoteSelection && (index.h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, index.h("rect", { class: "resize-handle top-left", x: `${(-(baseHandleSize - 1) *
|
|
29664
|
+
})(), !this.isSelecting && !isRemoteSelection && (index.h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, canRenderResizeHandles && (index.h("g", null, index.h("rect", { class: "resize-handle top-left", x: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29447
29665
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29448
29666
|
stroke: selectionHandleStrokeColor,
|
|
29449
|
-
strokeWidth: `calc(2px * ${
|
|
29667
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29450
29668
|
paintOrder: 'fill',
|
|
29451
|
-
} }), index.h("rect", { class: "resize-handle-overlay top-left", x: `${(-baseHandleTouchSize *
|
|
29669
|
+
} }), index.h("rect", { class: "resize-handle-overlay top-left", x: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29452
29670
|
fill: 'transparent',
|
|
29453
29671
|
paintOrder: 'fill',
|
|
29454
|
-
} }), index.h("rect", { class: "resize-handle top-right", x: `${object.totalWidth - ((baseHandleSize - 1) *
|
|
29672
|
+
} }), index.h("rect", { class: "resize-handle top-right", x: `${object.totalWidth - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29455
29673
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29456
29674
|
stroke: selectionHandleStrokeColor,
|
|
29457
|
-
strokeWidth: `calc(2px * ${
|
|
29675
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29458
29676
|
paintOrder: 'fill',
|
|
29459
|
-
} }), index.h("rect", { class: "resize-handle-overlay top-right", x: `${object.totalWidth - (baseHandleTouchSize *
|
|
29677
|
+
} }), index.h("rect", { class: "resize-handle-overlay top-right", x: `${object.totalWidth - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29460
29678
|
fill: 'transparent',
|
|
29461
29679
|
paintOrder: 'fill',
|
|
29462
|
-
} }), index.h("rect", { class: "resize-handle bottom-left", x: `${(-(baseHandleSize - 1) *
|
|
29680
|
+
} }), index.h("rect", { class: "resize-handle bottom-left", x: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29463
29681
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29464
29682
|
stroke: selectionHandleStrokeColor,
|
|
29465
|
-
strokeWidth: `calc(2px * ${
|
|
29683
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29466
29684
|
paintOrder: 'fill',
|
|
29467
|
-
} }), index.h("rect", { class: "resize-handle-overlay bottom-left", x: `${(-baseHandleTouchSize *
|
|
29685
|
+
} }), index.h("rect", { class: "resize-handle-overlay bottom-left", x: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29468
29686
|
fill: 'transparent',
|
|
29469
29687
|
paintOrder: 'fill',
|
|
29470
|
-
} }), index.h("rect", { class: "resize-handle bottom-right", x: `${object.totalWidth - ((baseHandleSize - 1) *
|
|
29688
|
+
} }), index.h("rect", { class: "resize-handle bottom-right", x: `${object.totalWidth - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29471
29689
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29472
29690
|
stroke: selectionHandleStrokeColor,
|
|
29473
|
-
strokeWidth: `calc(2px * ${
|
|
29691
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29474
29692
|
paintOrder: 'fill',
|
|
29475
|
-
} }), index.h("rect", { class: "resize-handle-overlay bottom-right", x: `${object.totalWidth - (baseHandleTouchSize *
|
|
29693
|
+
} }), index.h("rect", { class: "resize-handle-overlay bottom-right", x: `${object.totalWidth - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29476
29694
|
fill: 'transparent',
|
|
29477
29695
|
paintOrder: 'fill',
|
|
29478
|
-
} }), index.h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 *
|
|
29696
|
+
} }))), canRenderRotationHandle && (index.h("g", null, index.h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * handleScale) / this.core.store.state?.scale), style: {
|
|
29479
29697
|
stroke: selectionBorderColor,
|
|
29480
|
-
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${
|
|
29481
|
-
} }), index.h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 *
|
|
29698
|
+
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29699
|
+
} }), index.h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * handleScale) / this.core.store.state?.scale), r: `${((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29482
29700
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29483
29701
|
stroke: selectionHandleStrokeColor,
|
|
29484
|
-
strokeWidth: `calc(2px * ${
|
|
29702
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29485
29703
|
paintOrder: 'fill',
|
|
29486
|
-
} }), index.h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 *
|
|
29704
|
+
} }), index.h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * handleScale) / this.core.store.state?.scale), r: `${(baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, style: {
|
|
29487
29705
|
fill: 'transparent',
|
|
29488
29706
|
paintOrder: 'fill',
|
|
29489
|
-
} }))))), this.core.displaySelectionLineUI(object) && schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (index.h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, index.h("g", { class: "selection-line-borders" }, index.h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
|
|
29707
|
+
} }))))))), this.core.displaySelectionLineUI(object) && schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (index.h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, index.h("g", { class: "selection-line-borders" }, index.h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
|
|
29490
29708
|
stroke: selectionBorderColor,
|
|
29491
29709
|
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
29492
29710
|
strokeLinecap: 'round',
|
|
@@ -29611,7 +29829,7 @@ const KritzelEngine = class {
|
|
|
29611
29829
|
}, this.core.store.selectionGroup?.objects || []);
|
|
29612
29830
|
}
|
|
29613
29831
|
this.hideContextMenu();
|
|
29614
|
-
}, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && index.h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof schema_constants.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed &&
|
|
29832
|
+
}, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && index.h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof schema_constants.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed && index.h("kritzel-watermark", { core: this.core, label: this.core.localizationManager.translate('watermark.poweredBy') })));
|
|
29615
29833
|
}
|
|
29616
29834
|
static get watchers() { return {
|
|
29617
29835
|
"workspace": [{
|
|
@@ -30801,7 +31019,7 @@ const KritzelPortal = class {
|
|
|
30801
31019
|
this.calculatePosition();
|
|
30802
31020
|
}
|
|
30803
31021
|
handleWindowScroll() {
|
|
30804
|
-
const isInViewport = KritzelHTMLHelper.isElementInViewport(this.anchor);
|
|
31022
|
+
const isInViewport = schema_constants.KritzelHTMLHelper.isElementInViewport(this.anchor);
|
|
30805
31023
|
if (!isInViewport) {
|
|
30806
31024
|
this.anchor?.blur();
|
|
30807
31025
|
this.closePortal();
|
|
@@ -30827,7 +31045,7 @@ const KritzelPortal = class {
|
|
|
30827
31045
|
return activeEl;
|
|
30828
31046
|
}
|
|
30829
31047
|
trapFocus(event) {
|
|
30830
|
-
const focusableElements = KritzelHTMLHelper.getFocusableElements(this.host);
|
|
31048
|
+
const focusableElements = schema_constants.KritzelHTMLHelper.getFocusableElements(this.host);
|
|
30831
31049
|
if (focusableElements.length === 0)
|
|
30832
31050
|
return;
|
|
30833
31051
|
const firstFocusable = focusableElements[0];
|
|
@@ -30853,7 +31071,7 @@ const KritzelPortal = class {
|
|
|
30853
31071
|
const firstAssigned = slotEl?.assignedElements({ flatten: true })[0];
|
|
30854
31072
|
if (!firstAssigned)
|
|
30855
31073
|
return null;
|
|
30856
|
-
const focusable = KritzelHTMLHelper.getFocusableElements(firstAssigned);
|
|
31074
|
+
const focusable = schema_constants.KritzelHTMLHelper.getFocusableElements(firstAssigned);
|
|
30857
31075
|
return focusable[0] ?? firstAssigned;
|
|
30858
31076
|
}
|
|
30859
31077
|
get lastAddedPortal() {
|
|
@@ -31009,7 +31227,7 @@ const KritzelPortal = class {
|
|
|
31009
31227
|
* This file is auto-generated by the version bump scripts.
|
|
31010
31228
|
* Do not modify manually.
|
|
31011
31229
|
*/
|
|
31012
|
-
const KRITZEL_VERSION = '0.3.
|
|
31230
|
+
const KRITZEL_VERSION = '0.3.23';
|
|
31013
31231
|
|
|
31014
31232
|
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)}`;
|
|
31015
31233
|
|
|
@@ -31025,6 +31243,7 @@ const DEFAULT_DEBUG_INFO = {
|
|
|
31025
31243
|
showObjectInfo: false,
|
|
31026
31244
|
showSyncProviderInfo: true,
|
|
31027
31245
|
showMigrationInfo: true,
|
|
31246
|
+
showAssetResolverInfo: false,
|
|
31028
31247
|
};
|
|
31029
31248
|
const SETTINGS_CATEGORY_IDS = ['general', 'viewport', 'shortcuts', 'developer', 'about'];
|
|
31030
31249
|
const KritzelSettings = class {
|
|
@@ -31233,7 +31452,7 @@ const KritzelSettings = class {
|
|
|
31233
31452
|
}
|
|
31234
31453
|
}
|
|
31235
31454
|
render() {
|
|
31236
|
-
return (index.h(index.Host, { key: '
|
|
31455
|
+
return (index.h(index.Host, { key: '8b96261465efeabb2eb0cf724d29699de5e230a8' }, index.h("kritzel-dialog", { key: '273a9df290bb97d59000a97f91821e7bad3f3896', isOpen: this.isDialogOpen, dialogTitle: this.t('settings.dialogTitle', 'Settings'), size: "large", contained: true, onDialogClose: this.closeDialog }, index.h("kritzel-master-detail", { key: '64d17dfaa2a0baf2d4a5d00fe5fc65ad40c96ec6', items: this.categories, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
|
|
31237
31456
|
}
|
|
31238
31457
|
static get watchers() { return {
|
|
31239
31458
|
"settings": [{
|
|
@@ -31858,7 +32077,7 @@ const KritzelTooltip = class {
|
|
|
31858
32077
|
}
|
|
31859
32078
|
}
|
|
31860
32079
|
async focusContent() {
|
|
31861
|
-
const focusableElements = KritzelHTMLHelper.getFocusableElements(this.host);
|
|
32080
|
+
const focusableElements = schema_constants.KritzelHTMLHelper.getFocusableElements(this.host);
|
|
31862
32081
|
if (focusableElements.length > 0) {
|
|
31863
32082
|
focusableElements[0].focus();
|
|
31864
32083
|
}
|