kritzel-stencil 0.3.21 → 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 +2 -2
- package/dist/components/p-BML28BJR.js +0 -1
- package/dist/components/p-BYzaazty.js +0 -1
- package/dist/components/p-CVV-HzFR.js +0 -1
- package/dist/components/p-DWhWFDcC.js +0 -9
- package/dist/stencil/p-60842099.entry.js +0 -9
- package/dist/stencil/p-D35cwCYd.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-Dhio9uis.js';
|
|
2
|
-
import { c as KritzelPath, e as KritzelLine,
|
|
2
|
+
import { c as KritzelPath, e as KritzelLine, R as KritzelColorHelper, T as KritzelDevicesHelper, q as KritzelSelectionTool, n as KritzelTextTool, U as KritzelMouseButton, V as KritzelHTMLHelper, X as DEFAULT_STROKE_SIZES, Y as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, j as KritzelBrushTool, l as KritzelEraserTool, z as DEFAULT_LINE_TOOL_CONFIG, k as KritzelLineTool, o as KritzelShapeTool, y as DEFAULT_TEXT_CONFIG, m as KritzelImageTool, L as KritzelAlignment, B as DEFAULT_ASSET_STORAGE_CONFIG, Z as ObjectHelper, _ as ThemeHelper, E as darkTheme, C as lightTheme, $ as KritzelSelectionGroup, a0 as KritzelSelectionBox, a1 as KritzelIconRegistry, a2 as KritzelKeyboardHelper, a3 as KritzelBaseHandler, s as KritzelWorkspace, f as KritzelGroup, h as KritzelCustomElement, d as KritzelImage, g as KritzelShape, b as KritzelText, M as runMigrations, Q as CURRENT_WORKSPACE_SCHEMA_VERSION, O as WORKSPACE_MIGRATIONS, a4 as KritzelClassHelper, P as CURRENT_APP_STATE_SCHEMA_VERSION, N as APP_STATE_MIGRATIONS, p as KritzelCursorHelper, a5 as imageCompression, t as KritzelAnchorManager, u as KritzelThemeManager, v as KritzelLocalizationManager, w as KritzelLicenseManager, r as KritzelAssetResolver, a6 as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION } from './schema.constants-DMPBDrZh.js';
|
|
3
3
|
import * as Y from 'yjs';
|
|
4
4
|
import 'y-indexeddb';
|
|
5
5
|
import 'y-websocket';
|
|
@@ -1378,71 +1378,6 @@ const KritzelCursorTrail = class {
|
|
|
1378
1378
|
};
|
|
1379
1379
|
KritzelCursorTrail.style = kritzelCursorTrailCss();
|
|
1380
1380
|
|
|
1381
|
-
class KritzelHTMLHelper {
|
|
1382
|
-
static getNumericValueFromStyle(element, property) {
|
|
1383
|
-
const value = window.getComputedStyle(element).getPropertyValue(property);
|
|
1384
|
-
return parseFloat(value) || 0;
|
|
1385
|
-
}
|
|
1386
|
-
static getScrollableParent(element) {
|
|
1387
|
-
if (!element) {
|
|
1388
|
-
return window;
|
|
1389
|
-
}
|
|
1390
|
-
const parent = element.parentNode?.host ?? element.parentElement;
|
|
1391
|
-
if (!parent || parent.tagName === 'BODY') {
|
|
1392
|
-
return window;
|
|
1393
|
-
}
|
|
1394
|
-
const style = window.getComputedStyle(parent);
|
|
1395
|
-
if (style.overflow === 'auto' || style.overflowY === 'auto' || style.overflow === 'scroll' || style.overflowY === 'scroll') {
|
|
1396
|
-
return parent;
|
|
1397
|
-
}
|
|
1398
|
-
return this.getScrollableParent(parent);
|
|
1399
|
-
}
|
|
1400
|
-
static isElementInViewport(element) {
|
|
1401
|
-
if (!element) {
|
|
1402
|
-
return false;
|
|
1403
|
-
}
|
|
1404
|
-
const scrollableParent = this.getScrollableParent(element);
|
|
1405
|
-
const rect = element.getBoundingClientRect();
|
|
1406
|
-
if (scrollableParent === window) {
|
|
1407
|
-
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
1408
|
-
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
1409
|
-
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= viewportHeight && rect.right <= viewportWidth;
|
|
1410
|
-
}
|
|
1411
|
-
const parentRect = scrollableParent.getBoundingClientRect();
|
|
1412
|
-
return rect.top >= parentRect.top && rect.left >= parentRect.left && rect.bottom <= parentRect.bottom && rect.right <= parentRect.right;
|
|
1413
|
-
}
|
|
1414
|
-
static getFocusableElements(root) {
|
|
1415
|
-
if (!root)
|
|
1416
|
-
return [];
|
|
1417
|
-
const focusableElements = [];
|
|
1418
|
-
const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details, [tabindex]:not([tabindex="-1"])';
|
|
1419
|
-
const isVisible = (el) => {
|
|
1420
|
-
const style = window.getComputedStyle(el);
|
|
1421
|
-
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
1422
|
-
};
|
|
1423
|
-
const find = (element) => {
|
|
1424
|
-
// Check if the element itself is focusable
|
|
1425
|
-
if (element instanceof HTMLElement && element.matches(focusableSelector) && !element.hasAttribute('disabled') && isVisible(element)) {
|
|
1426
|
-
focusableElements.push(element);
|
|
1427
|
-
}
|
|
1428
|
-
// Traverse shadow DOM
|
|
1429
|
-
if (element.shadowRoot) {
|
|
1430
|
-
Array.from(element.shadowRoot.children).forEach(find);
|
|
1431
|
-
}
|
|
1432
|
-
// Traverse slotted content
|
|
1433
|
-
if (element.tagName === 'SLOT') {
|
|
1434
|
-
element.assignedElements({ flatten: true }).forEach(find);
|
|
1435
|
-
}
|
|
1436
|
-
// Traverse light DOM children if there is no shadow root
|
|
1437
|
-
if (!element.shadowRoot) {
|
|
1438
|
-
Array.from(element.children).forEach(find);
|
|
1439
|
-
}
|
|
1440
|
-
};
|
|
1441
|
-
find(root);
|
|
1442
|
-
return focusableElements;
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
1381
|
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}`;
|
|
1447
1382
|
|
|
1448
1383
|
const KritzelDialog = class {
|
|
@@ -2204,6 +2139,7 @@ const KritzelEditor = class {
|
|
|
2204
2139
|
showObjectInfo: false,
|
|
2205
2140
|
showSyncProviderInfo: true,
|
|
2206
2141
|
showMigrationInfo: true,
|
|
2142
|
+
showAssetResolverInfo: false,
|
|
2207
2143
|
};
|
|
2208
2144
|
user;
|
|
2209
2145
|
activeUsers;
|
|
@@ -3115,31 +3051,31 @@ const KritzelEditor = class {
|
|
|
3115
3051
|
const isLoggedIn = this.isLoggedIn;
|
|
3116
3052
|
const shouldShowCurrentUser = isLoggedIn;
|
|
3117
3053
|
const shouldShowLoginButton = this.isReady && !!this.loginConfig && !isLoggedIn;
|
|
3118
|
-
return (h(Host, { key: '
|
|
3054
|
+
return (h(Host, { key: '56b172459e6d940229dc1d4f409157e403ad5f27', style: {
|
|
3119
3055
|
opacity: this.isEditorVisible ? '1' : '0',
|
|
3120
3056
|
visibility: this.isEditorVisible ? 'visible' : 'hidden',
|
|
3121
3057
|
transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
|
|
3122
|
-
} }, h("div", { key: '
|
|
3058
|
+
} }, h("div", { key: '93a2195c14402f38416b2d377c684e2650418edb', class: "top-left-buttons" }, 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) }), h("kritzel-back-to-content", { key: '3b90b69a5b83a6e5593d4f752c4094a2a3af8c4d', visible: this.isBackToContentButtonVisible, text: this.resolvedTerms['backToContent.label'] ?? 'Back to content', onBackToContent: () => this.backToContent() })), this.activeNotification && (h("div", { key: '9c2ee1e10212145bf2f97a1a7f27746aa18cfc98', class: "top-center-notification-layer", role: "presentation" }, h("div", { key: 'a77b025329da64e1f1223a2f749aa2fc60e5c469', class: { 'top-center-notification-container': true, 'is-dismissing': this.isNotificationDismissing }, role: "presentation" }, h("kritzel-notification-card", { key: '9ced0bc5213ec8c3387915cd71272a1f56161405', notification: this.activeNotification, locale: this.locale, onDismiss: this.dismissNotification, onHoverChange: event => this.handleNotificationHoverChange(event) })))), h("kritzel-engine", { key: '884b7f088e164a51c49158c409904ca5419f2d55', ref: el => {
|
|
3123
3059
|
if (el) {
|
|
3124
3060
|
this.engineRef = el;
|
|
3125
3061
|
}
|
|
3126
|
-
}, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event), onNotificationsChange: event => this.handleNotificationsChange(event) }), h("kritzel-controls", { key: '
|
|
3062
|
+
}, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event), onNotificationsChange: event => this.handleNotificationsChange(event) }), h("kritzel-controls", { key: '3a7c22f037d551636c53190eb07b318c2b857162', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
|
|
3127
3063
|
if (el) {
|
|
3128
3064
|
this.controlsRef = el;
|
|
3129
3065
|
}
|
|
3130
|
-
}, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: '
|
|
3066
|
+
}, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: 'c0dad9086679397c46f5550c38686a9b7d8bae6c', class: "bottom-left-buttons" }, h("kritzel-zoom-panel", { key: '1639d6d2092ecd3fbc657dfdcfc3f12c02539329', visible: this.isZoomPanelVisible, disabled: !this.isZoomingEnabled, zoomPercent: this.currentZoomPercent, terms: this.resolvedTerms, onZoomIn: () => this.zoomIn(), onZoomOut: () => this.zoomOut() })), h("div", { key: '45313b28a5e4bd75d09980e4765c2241d54fe1df', class: "top-right-buttons" }, h("kritzel-settings", { key: '33737a005cd6580505ee741be0dc40bd69873276', ref: el => {
|
|
3131
3067
|
if (el) {
|
|
3132
3068
|
this.settingsRef = el;
|
|
3133
3069
|
}
|
|
3134
|
-
}, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '
|
|
3070
|
+
}, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '9e13001850b15b9ce9d8a502466ed9fa05ac1518', ref: el => {
|
|
3135
3071
|
if (el) {
|
|
3136
3072
|
this.exportRef = el;
|
|
3137
3073
|
}
|
|
3138
|
-
}, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '
|
|
3074
|
+
}, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: 'f2494af1241ecc068ace09b23cfd405c76bd1273', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: '7f199e3493805977b5e5b8d2c736f31729919f96', user: this.user, terms: this.resolvedTerms }), shouldShowLoginButton && (h("kritzel-button", { key: 'c6c192ddb1245acc771ac550c1fe3e4f9bc08eab', onButtonClick: () => this.loginDialogRef?.open() }, this.resolvedTerms['login.dialogTitle'] ?? 'Sign in')), h("kritzel-more-menu", { key: '869194078a4c90d42c5ebd604bc58b4f55fc4cb6', items: this.moreMenuItems, visible: this.isMoreMenuVisible, terms: this.resolvedTerms }), h("kritzel-share-dialog", { key: '8daed8fd7267aca056b6a53626c721e2f23cead4', ref: el => {
|
|
3139
3075
|
if (el) {
|
|
3140
3076
|
this.shareDialogRef = el;
|
|
3141
3077
|
}
|
|
3142
|
-
}, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: '
|
|
3078
|
+
}, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: 'b65ea0940cee31b152b60881180fab2445c92b0c', ref: el => {
|
|
3143
3079
|
if (el) {
|
|
3144
3080
|
this.loginDialogRef = el;
|
|
3145
3081
|
}
|
|
@@ -21344,7 +21280,7 @@ class KritzelKeyHandler extends KritzelBaseHandler {
|
|
|
21344
21280
|
// of running global canvas shortcuts. Escape is the one exception — it
|
|
21345
21281
|
// still runs through the shortcut system so it can collapse the text
|
|
21346
21282
|
// selection (handled inside the shortcut's action).
|
|
21347
|
-
if ((this._core.store.activeText || this._core.store.activeShape) && event.key !== 'Escape') {
|
|
21283
|
+
if ((this._core.store.activeText || this._core.store.activeShape || this._core.store.activeInteractiveCustomElement) && event.key !== 'Escape') {
|
|
21348
21284
|
return;
|
|
21349
21285
|
}
|
|
21350
21286
|
const shortcut = this.shortcuts.find(s => s.key === event.key && !!s.ctrl === event.ctrlKey && !!s.shift === event.shiftKey && (!s.condition || s.condition(this._core)));
|
|
@@ -21544,120 +21480,6 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
|
|
|
21544
21480
|
}
|
|
21545
21481
|
}
|
|
21546
21482
|
|
|
21547
|
-
/**
|
|
21548
|
-
* Represents a custom HTML element that can be placed and manipulated on the Kritzel canvas.
|
|
21549
|
-
* Extends KritzelBaseObject to inherit common object functionality like positioning,
|
|
21550
|
-
* scaling, and lifecycle management.
|
|
21551
|
-
*/
|
|
21552
|
-
class KritzelCustomElement extends KritzelBaseObject {
|
|
21553
|
-
__class__ = 'KritzelCustomElement';
|
|
21554
|
-
/** The HTML element to be rendered on the canvas. */
|
|
21555
|
-
element;
|
|
21556
|
-
/** Whether the element responds to user interactions. Defaults to true. */
|
|
21557
|
-
isInteractive = true;
|
|
21558
|
-
/**
|
|
21559
|
-
* Creates a new KritzelCustomElement instance.
|
|
21560
|
-
* @param config - Optional configuration object for the custom element.
|
|
21561
|
-
* @param config.element - The HTML element to wrap.
|
|
21562
|
-
* @param config.translateX - Initial X position offset. Defaults to 0.
|
|
21563
|
-
* @param config.translateY - Initial Y position offset. Defaults to 0.
|
|
21564
|
-
* @param config.scale - Initial scale factor. Defaults to 1.
|
|
21565
|
-
* @param config.height - Initial height in pixels. Defaults to 0.
|
|
21566
|
-
* @param config.width - Initial width in pixels. Defaults to 0.
|
|
21567
|
-
*/
|
|
21568
|
-
constructor(config) {
|
|
21569
|
-
super();
|
|
21570
|
-
if (config) {
|
|
21571
|
-
this.translateX = config.translateX || 0;
|
|
21572
|
-
this.translateY = config.translateY || 0;
|
|
21573
|
-
this.rotation = KritzelMathHelper.degreesToRadians(config.rotation ?? 0);
|
|
21574
|
-
this.scale = config.scale || 1;
|
|
21575
|
-
this.element = config.element;
|
|
21576
|
-
this.height = config.height || 0;
|
|
21577
|
-
this.width = config.width || 0;
|
|
21578
|
-
}
|
|
21579
|
-
}
|
|
21580
|
-
/**
|
|
21581
|
-
* Factory method to create a new KritzelCustomElement with proper core binding.
|
|
21582
|
-
* Generates a unique ID and assigns the element to the active workspace.
|
|
21583
|
-
* @param core - The KritzelCore instance for state management and ID generation.
|
|
21584
|
-
* @param config - Optional configuration object for the custom element.
|
|
21585
|
-
* @param config.element - The HTML element to wrap.
|
|
21586
|
-
* @param config.translateX - Initial X position offset.
|
|
21587
|
-
* @param config.translateY - Initial Y position offset.
|
|
21588
|
-
* @param config.scale - Initial scale factor.
|
|
21589
|
-
* @param config.height - Initial height in pixels.
|
|
21590
|
-
* @param config.width - Initial width in pixels.
|
|
21591
|
-
* @returns A new KritzelBaseObject instance bound to the core.
|
|
21592
|
-
*/
|
|
21593
|
-
static create(core, config) {
|
|
21594
|
-
const object = new KritzelCustomElement(config);
|
|
21595
|
-
object._core = core;
|
|
21596
|
-
object.id = object.generateId();
|
|
21597
|
-
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
21598
|
-
object.userId = core.user?.id;
|
|
21599
|
-
return object;
|
|
21600
|
-
}
|
|
21601
|
-
/**
|
|
21602
|
-
* Mounts the custom element to a container element in the DOM.
|
|
21603
|
-
* Clears any existing content in the container and appends this element.
|
|
21604
|
-
* Skips mounting if already mounted to the same container with content attached.
|
|
21605
|
-
* @param element - The container HTML element to mount this custom element into.
|
|
21606
|
-
*/
|
|
21607
|
-
mount(element) {
|
|
21608
|
-
if (element === null) {
|
|
21609
|
-
return;
|
|
21610
|
-
}
|
|
21611
|
-
// If already mounted to the same element and content is still attached, skip
|
|
21612
|
-
if (this.isMounted && this.elementRef === element && this.element.parentElement === element) {
|
|
21613
|
-
return;
|
|
21614
|
-
}
|
|
21615
|
-
this.elementRef = element;
|
|
21616
|
-
this.isMounted = true;
|
|
21617
|
-
// Clear existing content and append the element
|
|
21618
|
-
this.elementRef.innerHTML = '';
|
|
21619
|
-
this.elementRef.appendChild(this.element);
|
|
21620
|
-
}
|
|
21621
|
-
/**
|
|
21622
|
-
* Resizes and repositions the custom element on the canvas.
|
|
21623
|
-
* Updates both the internal state and the DOM element's inline styles.
|
|
21624
|
-
* Syncs changes to Yjs for collaborative editing and cross-tab propagation.
|
|
21625
|
-
* @param x - The new X position (translateX) in canvas coordinates.
|
|
21626
|
-
* @param y - The new Y position (translateY) in canvas coordinates.
|
|
21627
|
-
* @param width - The new width in pixels. Must be greater than 1.
|
|
21628
|
-
* @param height - The new height in pixels. Must be greater than 1.
|
|
21629
|
-
*/
|
|
21630
|
-
resize(x, y, width, height) {
|
|
21631
|
-
if (width <= 1 || height <= 1) {
|
|
21632
|
-
return;
|
|
21633
|
-
}
|
|
21634
|
-
this.width = width;
|
|
21635
|
-
this.height = height;
|
|
21636
|
-
this.translateX = x;
|
|
21637
|
-
this.translateY = y;
|
|
21638
|
-
if (this.element) {
|
|
21639
|
-
this.element.style.width = `${width}px`;
|
|
21640
|
-
this.element.style.height = `${height}px`;
|
|
21641
|
-
}
|
|
21642
|
-
// Update to sync changes to y.js and propagate to other tabs
|
|
21643
|
-
this._core.store.objects.update(this);
|
|
21644
|
-
}
|
|
21645
|
-
/**
|
|
21646
|
-
* Creates a deep copy of this custom element.
|
|
21647
|
-
* The copy receives a new unique ID, is marked as unmounted,
|
|
21648
|
-
* and contains a cloned copy of the underlying HTML element.
|
|
21649
|
-
* @returns A new KritzelCustomElement instance with copied properties and a cloned DOM element.
|
|
21650
|
-
*/
|
|
21651
|
-
copy() {
|
|
21652
|
-
const copiedObject = Object.create(Object.getPrototypeOf(this));
|
|
21653
|
-
Object.assign(copiedObject, this);
|
|
21654
|
-
copiedObject.id = this.generateId();
|
|
21655
|
-
copiedObject.isMounted = false;
|
|
21656
|
-
copiedObject.element = this.element.cloneNode(true);
|
|
21657
|
-
return copiedObject;
|
|
21658
|
-
}
|
|
21659
|
-
}
|
|
21660
|
-
|
|
21661
21483
|
/**
|
|
21662
21484
|
* Handles deserialization/revival of Kritzel objects from plain JavaScript objects.
|
|
21663
21485
|
* This class uses a pattern similar to JSON.parse reviver to reconstruct class instances
|
|
@@ -21805,8 +21627,9 @@ const DEFAULT_ENGINE_CONFIG = {
|
|
|
21805
21627
|
debugInfo: {
|
|
21806
21628
|
showObjectInfo: false,
|
|
21807
21629
|
showViewportInfo: false,
|
|
21808
|
-
showSyncProviderInfo:
|
|
21809
|
-
|
|
21630
|
+
showSyncProviderInfo: false,
|
|
21631
|
+
showAssetResolverInfo: false,
|
|
21632
|
+
showMigrationInfo: false,
|
|
21810
21633
|
},
|
|
21811
21634
|
host: null,
|
|
21812
21635
|
pointerX: 0,
|
|
@@ -22487,7 +22310,8 @@ class KritzelObjectMap {
|
|
|
22487
22310
|
const docName = core.editorId ? `kritzel-workspace-${core.editorId}-${workspaceId}` : `kritzel-workspace-${workspaceId}`;
|
|
22488
22311
|
const finalConfig = config ?? DEFAULT_SYNC_CONFIG;
|
|
22489
22312
|
// Instantiate providers from configuration
|
|
22490
|
-
const
|
|
22313
|
+
const showSyncProviderInfo = !!core.store?.state?.debugInfo?.showSyncProviderInfo;
|
|
22314
|
+
const quiet = !showSyncProviderInfo;
|
|
22491
22315
|
for (const providerConfig of finalConfig.providers) {
|
|
22492
22316
|
let provider;
|
|
22493
22317
|
// Check if it's a class constructor or a factory
|
|
@@ -22501,6 +22325,10 @@ class KritzelObjectMap {
|
|
|
22501
22325
|
}
|
|
22502
22326
|
this._providers.push(provider);
|
|
22503
22327
|
}
|
|
22328
|
+
if (showSyncProviderInfo) {
|
|
22329
|
+
const providerList = this._providers.map(p => `${p.constructor.name} (${p.type})`).join(', ');
|
|
22330
|
+
console.info(`[Kritzel] Workspace sync providers initialized for ${docName}: ${providerList || 'none'}`);
|
|
22331
|
+
}
|
|
22504
22332
|
// captureTimeout is effectively infinite — undo-step boundaries are
|
|
22505
22333
|
// marked explicitly via markUndoBoundary() in insert/remove/reset and
|
|
22506
22334
|
// at stroke/gesture boundaries in the tools. This prevents a single
|
|
@@ -22541,15 +22369,24 @@ class KritzelObjectMap {
|
|
|
22541
22369
|
const networkProviders = this._providers.filter(p => p.type === 'network');
|
|
22542
22370
|
// Await local providers for immediate data availability
|
|
22543
22371
|
const localResults = await Promise.allSettled(localProviders.map(p => p.connect()));
|
|
22372
|
+
if (showSyncProviderInfo) {
|
|
22373
|
+
const connectedLocalCount = localResults.filter(result => result.status === 'fulfilled').length;
|
|
22374
|
+
console.info(`[Kritzel] Workspace local providers connected: ${connectedLocalCount}/${localProviders.length}`);
|
|
22375
|
+
}
|
|
22544
22376
|
localResults.forEach((result, i) => {
|
|
22545
|
-
if (result.status === 'rejected') {
|
|
22377
|
+
if (showSyncProviderInfo && result.status === 'rejected') {
|
|
22546
22378
|
console.error(`[Kritzel] Sync provider "${localProviders[i]?.constructor.name}" failed to connect:`, result.reason);
|
|
22547
22379
|
}
|
|
22548
22380
|
});
|
|
22549
22381
|
// Connect network providers in the background (remote data arrives via Yjs observers)
|
|
22382
|
+
if (showSyncProviderInfo && networkProviders.length > 0) {
|
|
22383
|
+
console.info(`[Kritzel] Workspace network providers connecting in background: ${networkProviders.length}`);
|
|
22384
|
+
}
|
|
22550
22385
|
for (const provider of networkProviders) {
|
|
22551
22386
|
provider.connect().catch(err => {
|
|
22552
|
-
|
|
22387
|
+
if (showSyncProviderInfo) {
|
|
22388
|
+
console.error(`[Kritzel] Network sync provider "${provider.constructor.name}" failed to connect:`, err);
|
|
22389
|
+
}
|
|
22553
22390
|
});
|
|
22554
22391
|
}
|
|
22555
22392
|
this._isReady = true;
|
|
@@ -23440,6 +23277,14 @@ class KritzelStore {
|
|
|
23440
23277
|
const activeShapes = this.objects.filter(o => o instanceof KritzelShape && o.isEditing);
|
|
23441
23278
|
return activeShapes.length > 0 ? activeShapes[0] : null;
|
|
23442
23279
|
}
|
|
23280
|
+
/**
|
|
23281
|
+
* Gets the currently selected custom element whose focused descendant is an input-like element.
|
|
23282
|
+
* @returns The interactive custom element with focused input-like content, or null if none matches
|
|
23283
|
+
*/
|
|
23284
|
+
get activeInteractiveCustomElement() {
|
|
23285
|
+
const interactiveCustomElement = this.selectedObjects.find(object => KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && object.hasFocusedInputElement());
|
|
23286
|
+
return interactiveCustomElement ?? null;
|
|
23287
|
+
}
|
|
23443
23288
|
/**
|
|
23444
23289
|
* Gets the path currently being drawn (not yet completed).
|
|
23445
23290
|
* @returns The incomplete path object, or null if no path is being drawn
|
|
@@ -23609,7 +23454,8 @@ class KritzelAppStateMap {
|
|
|
23609
23454
|
const docName = core.editorId ? `kritzel-app-state-${core.editorId}-${instanceId}` : `kritzel-app-state-${instanceId}`;
|
|
23610
23455
|
const finalConfig = config ?? DEFAULT_SYNC_CONFIG;
|
|
23611
23456
|
// Instantiate providers from configuration
|
|
23612
|
-
const
|
|
23457
|
+
const showSyncProviderInfo = !!core.store.state.debugInfo.showSyncProviderInfo;
|
|
23458
|
+
const quiet = !showSyncProviderInfo;
|
|
23613
23459
|
for (const providerConfig of finalConfig.providers) {
|
|
23614
23460
|
let provider;
|
|
23615
23461
|
// Check if it's a class constructor or a factory
|
|
@@ -23623,6 +23469,10 @@ class KritzelAppStateMap {
|
|
|
23623
23469
|
}
|
|
23624
23470
|
this._providers.push(provider);
|
|
23625
23471
|
}
|
|
23472
|
+
if (showSyncProviderInfo) {
|
|
23473
|
+
const providerList = this._providers.map(p => `${p.constructor.name} (${p.type})`).join(', ');
|
|
23474
|
+
console.info(`[Kritzel] App-state sync providers initialized for ${docName}: ${providerList || 'none'}`);
|
|
23475
|
+
}
|
|
23626
23476
|
// Observe changes to workspaces and sync with application state
|
|
23627
23477
|
this._workspacesObserver = event => {
|
|
23628
23478
|
this.handleWorkspacesChange(event);
|
|
@@ -23635,15 +23485,24 @@ class KritzelAppStateMap {
|
|
|
23635
23485
|
const networkProviders = this._providers.filter(p => p.type === 'network');
|
|
23636
23486
|
// Await local providers for immediate data availability
|
|
23637
23487
|
const localResults = await Promise.allSettled(localProviders.map(p => p.connect()));
|
|
23488
|
+
if (showSyncProviderInfo) {
|
|
23489
|
+
const connectedLocalCount = localResults.filter(result => result.status === 'fulfilled').length;
|
|
23490
|
+
console.info(`[Kritzel] App-state local providers connected: ${connectedLocalCount}/${localProviders.length}`);
|
|
23491
|
+
}
|
|
23638
23492
|
localResults.forEach((result, i) => {
|
|
23639
|
-
if (result.status === 'rejected') {
|
|
23493
|
+
if (showSyncProviderInfo && result.status === 'rejected') {
|
|
23640
23494
|
console.error(`[Kritzel] Sync provider "${localProviders[i]?.constructor.name}" failed to connect:`, result.reason);
|
|
23641
23495
|
}
|
|
23642
23496
|
});
|
|
23643
23497
|
// Connect network providers in the background (remote data arrives via Yjs observers)
|
|
23498
|
+
if (showSyncProviderInfo && networkProviders.length > 0) {
|
|
23499
|
+
console.info(`[Kritzel] App-state network providers connecting in background: ${networkProviders.length}`);
|
|
23500
|
+
}
|
|
23644
23501
|
for (const provider of networkProviders) {
|
|
23645
23502
|
provider.connect().catch(err => {
|
|
23646
|
-
|
|
23503
|
+
if (showSyncProviderInfo) {
|
|
23504
|
+
console.error(`[Kritzel] Network sync provider "${provider.constructor.name}" failed to connect:`, err);
|
|
23505
|
+
}
|
|
23647
23506
|
});
|
|
23648
23507
|
}
|
|
23649
23508
|
this._isReady = true;
|
|
@@ -24739,6 +24598,7 @@ class KritzelCore {
|
|
|
24739
24598
|
this._clipboardManager = new KritzelClipboardManager(this);
|
|
24740
24599
|
this._toolRegistry = new KritzelToolRegistry(this);
|
|
24741
24600
|
this._assetResolver = new KritzelAssetResolver();
|
|
24601
|
+
this._assetResolver.setShowInfo(this._store.state.debugInfo?.showAssetResolverInfo ?? false);
|
|
24742
24602
|
}
|
|
24743
24603
|
/**
|
|
24744
24604
|
* Gets the asset resolver responsible for storing and resolving
|
|
@@ -25110,6 +24970,10 @@ class KritzelCore {
|
|
|
25110
24970
|
this.removeObject(child);
|
|
25111
24971
|
});
|
|
25112
24972
|
}
|
|
24973
|
+
// Unmount custom elements before removal
|
|
24974
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
24975
|
+
object.unmount();
|
|
24976
|
+
}
|
|
25113
24977
|
// Handle anchor cleanup
|
|
25114
24978
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelLine')) {
|
|
25115
24979
|
// If removing a line, clean up its anchor index entries
|
|
@@ -25150,21 +25014,84 @@ class KritzelCore {
|
|
|
25150
25014
|
* @param selectionGroup - The selection group to add
|
|
25151
25015
|
*/
|
|
25152
25016
|
addSelectionGroup(selectionGroup) {
|
|
25153
|
-
this.
|
|
25017
|
+
this.removeLocalSelectionGroups();
|
|
25154
25018
|
this.removeSelectionBox();
|
|
25019
|
+
for (const object of selectionGroup.objects ?? []) {
|
|
25020
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
25021
|
+
const customElementObject = object;
|
|
25022
|
+
if (typeof customElementObject.setIsInteractive === 'function') {
|
|
25023
|
+
customElementObject.setIsInteractive(true);
|
|
25024
|
+
}
|
|
25025
|
+
else {
|
|
25026
|
+
customElementObject.isInteractive = true;
|
|
25027
|
+
}
|
|
25028
|
+
}
|
|
25029
|
+
}
|
|
25155
25030
|
this._store.objects.insert(selectionGroup);
|
|
25156
25031
|
this._store.setSelectionGroup(selectionGroup);
|
|
25157
25032
|
this._kritzelEngine.triggerSelectionChange();
|
|
25158
25033
|
}
|
|
25034
|
+
/**
|
|
25035
|
+
* Returns whether the provided selection group belongs to the local user context.
|
|
25036
|
+
* Local groups are either explicitly owned by the current user or have no user ID.
|
|
25037
|
+
*/
|
|
25038
|
+
isLocalSelectionGroup(selectionGroup) {
|
|
25039
|
+
const localUserId = this._user?.id;
|
|
25040
|
+
return localUserId == null || selectionGroup.userId === localUserId || selectionGroup.userId == null;
|
|
25041
|
+
}
|
|
25042
|
+
/**
|
|
25043
|
+
* Applies deselection teardown side effects to a selection group before removal.
|
|
25044
|
+
*/
|
|
25045
|
+
teardownSelectionGroup(selectionGroup) {
|
|
25046
|
+
selectionGroup.deselectAllChildren?.();
|
|
25047
|
+
for (const object of selectionGroup.objects ?? []) {
|
|
25048
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
25049
|
+
const customElementObject = object;
|
|
25050
|
+
if (typeof customElementObject.setIsInteractive === 'function') {
|
|
25051
|
+
customElementObject.setIsInteractive(false);
|
|
25052
|
+
}
|
|
25053
|
+
else {
|
|
25054
|
+
customElementObject.isInteractive = false;
|
|
25055
|
+
}
|
|
25056
|
+
}
|
|
25057
|
+
}
|
|
25058
|
+
}
|
|
25059
|
+
/**
|
|
25060
|
+
* Removes all local selection groups from the store, including orphaned groups
|
|
25061
|
+
* that are no longer referenced by store.selectionGroup.
|
|
25062
|
+
* @returns True when at least one local selection group was removed
|
|
25063
|
+
*/
|
|
25064
|
+
removeLocalSelectionGroups() {
|
|
25065
|
+
const allSelectionGroupsInStore = this._store.objects
|
|
25066
|
+
.allObjects()
|
|
25067
|
+
.filter((object) => {
|
|
25068
|
+
return object instanceof KritzelSelectionGroup || KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
|
|
25069
|
+
});
|
|
25070
|
+
const allLocalSelectionGroups = allSelectionGroupsInStore.filter(selectionGroup => this.isLocalSelectionGroup(selectionGroup));
|
|
25071
|
+
const currentSelectionGroup = this._store.selectionGroup;
|
|
25072
|
+
if (currentSelectionGroup &&
|
|
25073
|
+
this.isLocalSelectionGroup(currentSelectionGroup) &&
|
|
25074
|
+
!allLocalSelectionGroups.some(group => group.id === currentSelectionGroup.id)) {
|
|
25075
|
+
allLocalSelectionGroups.push(currentSelectionGroup);
|
|
25076
|
+
}
|
|
25077
|
+
if (allLocalSelectionGroups.length === 0) {
|
|
25078
|
+
return false;
|
|
25079
|
+
}
|
|
25080
|
+
for (const selectionGroup of allLocalSelectionGroups) {
|
|
25081
|
+
this.teardownSelectionGroup(selectionGroup);
|
|
25082
|
+
}
|
|
25083
|
+
const localSelectionGroupIds = new Set(allLocalSelectionGroups.map(group => group.id));
|
|
25084
|
+
this._store.objects.remove(object => localSelectionGroupIds.has(object.id));
|
|
25085
|
+
this._store.setSelectionGroup(null);
|
|
25086
|
+
return true;
|
|
25087
|
+
}
|
|
25159
25088
|
/**
|
|
25160
25089
|
* Removes the current selection group from the canvas.
|
|
25161
25090
|
* Clears the cached reference and triggers the selection change event.
|
|
25162
25091
|
*/
|
|
25163
25092
|
removeSelectionGroup() {
|
|
25164
|
-
const
|
|
25165
|
-
if (
|
|
25166
|
-
this._store.objects.remove(object => object.id === selectionGroup.id);
|
|
25167
|
-
this._store.setSelectionGroup(null);
|
|
25093
|
+
const removedAnySelectionGroup = this.removeLocalSelectionGroups();
|
|
25094
|
+
if (removedAnySelectionGroup) {
|
|
25168
25095
|
this._kritzelEngine.triggerSelectionChange();
|
|
25169
25096
|
}
|
|
25170
25097
|
}
|
|
@@ -25468,6 +25395,11 @@ class KritzelCore {
|
|
|
25468
25395
|
(o instanceof KritzelSelectionGroup && (localUserId == null || o.userId === localUserId || o.userId == null)));
|
|
25469
25396
|
this._store.setSelectionBox(null);
|
|
25470
25397
|
this._store.setSelectionGroup(null);
|
|
25398
|
+
for (const object of this._store.allNonSelectionObjects) {
|
|
25399
|
+
if (object.isSelected) {
|
|
25400
|
+
object.isSelected = false;
|
|
25401
|
+
}
|
|
25402
|
+
}
|
|
25471
25403
|
this._store.state.isSelecting = false;
|
|
25472
25404
|
this._store.state.isResizeHandleSelected = false;
|
|
25473
25405
|
this._store.state.isRotationHandleSelected = false;
|
|
@@ -25630,6 +25562,11 @@ class KritzelCore {
|
|
|
25630
25562
|
// During selection phase (no group yet), hide UI for KritzelLine objects
|
|
25631
25563
|
return !(object instanceof KritzelLine);
|
|
25632
25564
|
}
|
|
25565
|
+
// Once a local selection group exists, only the selection-group object
|
|
25566
|
+
// should render group UI (children remain selected but don't render handles).
|
|
25567
|
+
if (!(object instanceof KritzelSelectionGroup) || object.id !== selectionGroup.id) {
|
|
25568
|
+
return false;
|
|
25569
|
+
}
|
|
25633
25570
|
// Show UI if selection contains more than one object
|
|
25634
25571
|
if (selectionGroup.objects.length > 1) {
|
|
25635
25572
|
return true;
|
|
@@ -25915,6 +25852,9 @@ class KritzelSvgExportHelper {
|
|
|
25915
25852
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
|
|
25916
25853
|
return this.imageToSvg(object, imageDataUrls);
|
|
25917
25854
|
}
|
|
25855
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
25856
|
+
return this.customElementToSvg(object, rasterSafeForCanvas);
|
|
25857
|
+
}
|
|
25918
25858
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
|
|
25919
25859
|
return this.groupToSvg(object, theme, imageDataUrls, rasterSafeForCanvas);
|
|
25920
25860
|
}
|
|
@@ -26081,6 +26021,38 @@ class KritzelSvgExportHelper {
|
|
|
26081
26021
|
return `<g transform="${transform}"${opacity}>
|
|
26082
26022
|
<image href="${href}" x="0" y="0" width="${width}" height="${height}" preserveAspectRatio="xMidYMid meet"/>
|
|
26083
26023
|
</g>`;
|
|
26024
|
+
}
|
|
26025
|
+
/**
|
|
26026
|
+
* Converts a KritzelCustomElement to SVG.
|
|
26027
|
+
* SVG mode: embeds HTML in foreignObject (best-effort).
|
|
26028
|
+
* PNG/raster mode: renders placeholder rect with warning.
|
|
26029
|
+
* @param obj - The custom element object
|
|
26030
|
+
* @param rasterSafeForCanvas - If true, render placeholder (for PNG export)
|
|
26031
|
+
* @returns SVG element string
|
|
26032
|
+
*/
|
|
26033
|
+
static customElementToSvg(obj, rasterSafeForCanvas = false) {
|
|
26034
|
+
const transform = this.buildTransform(obj);
|
|
26035
|
+
const opacity = obj.opacity !== 1 ? ` opacity="${obj.opacity}"` : '';
|
|
26036
|
+
const scale = this.getObjectScale(obj);
|
|
26037
|
+
const width = obj.totalWidth / scale;
|
|
26038
|
+
const height = obj.totalHeight / scale;
|
|
26039
|
+
if (rasterSafeForCanvas) {
|
|
26040
|
+
// PNG export: render placeholder rect (foreignObject doesn't rasterize to PNG well)
|
|
26041
|
+
console.warn('[KritzelCustomElement SVG Export] Custom elements do not serialize well to PNG. Use SVG export or screenshot instead.');
|
|
26042
|
+
return `<g transform="${transform}"${opacity}>
|
|
26043
|
+
<rect x="0" y="0" width="${width}" height="${height}" fill="#f0f0f0" stroke="#999" stroke-width="1" />
|
|
26044
|
+
<text x="${width / 2}" y="${height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999">[Custom Element]</text>
|
|
26045
|
+
</g>`;
|
|
26046
|
+
}
|
|
26047
|
+
// SVG export: use foreignObject to embed HTML
|
|
26048
|
+
const html = obj.element?.outerHTML || '<div style="border:1px dashed #ccc">Empty</div>';
|
|
26049
|
+
return `<g transform="${transform}"${opacity}>
|
|
26050
|
+
<foreignObject x="0" y="0" width="${width}" height="${height}">
|
|
26051
|
+
<div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;overflow:hidden;">
|
|
26052
|
+
${html}
|
|
26053
|
+
</div>
|
|
26054
|
+
</foreignObject>
|
|
26055
|
+
</g>`;
|
|
26084
26056
|
}
|
|
26085
26057
|
/**
|
|
26086
26058
|
* Converts a KritzelGroup to SVG by recursively converting children.
|
|
@@ -27152,6 +27124,120 @@ async function toPng(node, options = {}) {
|
|
|
27152
27124
|
return canvas.toDataURL();
|
|
27153
27125
|
}
|
|
27154
27126
|
|
|
27127
|
+
class KritzelWheelHelper {
|
|
27128
|
+
static shouldKeepWheelInCustomElement(ev, customElement) {
|
|
27129
|
+
// Keep Ctrl+wheel available for viewport zoom gestures.
|
|
27130
|
+
if (ev.ctrlKey || customElement.isSelected !== true) {
|
|
27131
|
+
return false;
|
|
27132
|
+
}
|
|
27133
|
+
const path = typeof ev.composedPath === 'function' ? ev.composedPath() : [];
|
|
27134
|
+
const scrollContainer = this.getScrollableContainerFromEventPath(path, customElement);
|
|
27135
|
+
// No scroll container found inside the custom element: let the wheel
|
|
27136
|
+
// event pass through so the viewport can continue handling it.
|
|
27137
|
+
if (!scrollContainer) {
|
|
27138
|
+
return false;
|
|
27139
|
+
}
|
|
27140
|
+
return this.canElementConsumeWheel(scrollContainer, ev.deltaX, ev.deltaY);
|
|
27141
|
+
}
|
|
27142
|
+
static getScrollableContainerFromEventPath(path, customElement) {
|
|
27143
|
+
const potentialRoots = [];
|
|
27144
|
+
if (customElement.element instanceof HTMLElement) {
|
|
27145
|
+
potentialRoots.push(customElement.element);
|
|
27146
|
+
}
|
|
27147
|
+
if (customElement.elementRef instanceof HTMLElement) {
|
|
27148
|
+
potentialRoots.push(customElement.elementRef);
|
|
27149
|
+
}
|
|
27150
|
+
const legacyElementRef = customElement.elmeentRef;
|
|
27151
|
+
if (legacyElementRef instanceof HTMLElement) {
|
|
27152
|
+
potentialRoots.push(legacyElementRef);
|
|
27153
|
+
}
|
|
27154
|
+
for (const root of potentialRoots) {
|
|
27155
|
+
const rootIndex = path.findIndex(entry => entry === root);
|
|
27156
|
+
if (rootIndex === -1) {
|
|
27157
|
+
continue;
|
|
27158
|
+
}
|
|
27159
|
+
for (const entry of path.slice(0, rootIndex + 1)) {
|
|
27160
|
+
if (!(entry instanceof HTMLElement)) {
|
|
27161
|
+
continue;
|
|
27162
|
+
}
|
|
27163
|
+
if (this.isScrollableElement(entry)) {
|
|
27164
|
+
return entry;
|
|
27165
|
+
}
|
|
27166
|
+
}
|
|
27167
|
+
}
|
|
27168
|
+
// Fallback for synthetic/custom wheel events where composedPath is absent
|
|
27169
|
+
// or does not include the custom-element subtree.
|
|
27170
|
+
for (const root of potentialRoots) {
|
|
27171
|
+
if (this.isScrollableElement(root)) {
|
|
27172
|
+
return root;
|
|
27173
|
+
}
|
|
27174
|
+
const firstChild = root.firstElementChild;
|
|
27175
|
+
if (firstChild instanceof HTMLElement && this.isScrollableElement(firstChild)) {
|
|
27176
|
+
return firstChild;
|
|
27177
|
+
}
|
|
27178
|
+
}
|
|
27179
|
+
return null;
|
|
27180
|
+
}
|
|
27181
|
+
static isScrollableElement(element) {
|
|
27182
|
+
const canScrollVertically = element.scrollHeight - element.clientHeight > 0;
|
|
27183
|
+
const canScrollHorizontally = element.scrollWidth - element.clientWidth > 0;
|
|
27184
|
+
if (!canScrollVertically && !canScrollHorizontally) {
|
|
27185
|
+
return false;
|
|
27186
|
+
}
|
|
27187
|
+
const computedStyle = window.getComputedStyle(element);
|
|
27188
|
+
const overflowX = computedStyle.overflowX;
|
|
27189
|
+
const overflowY = computedStyle.overflowY;
|
|
27190
|
+
const allowsVerticalScroll = overflowY !== 'visible' && overflowY !== 'clip';
|
|
27191
|
+
const allowsHorizontalScroll = overflowX !== 'visible' && overflowX !== 'clip';
|
|
27192
|
+
return (canScrollVertically && allowsVerticalScroll) || (canScrollHorizontally && allowsHorizontalScroll);
|
|
27193
|
+
}
|
|
27194
|
+
static canElementConsumeWheel(element, deltaX, deltaY) {
|
|
27195
|
+
const canConsumeVertical = this.canElementConsumeVerticalWheel(element, deltaY);
|
|
27196
|
+
const canConsumeHorizontal = this.canElementConsumeHorizontalWheel(element, deltaX);
|
|
27197
|
+
// Keep wheel events inside the custom element whenever at least one
|
|
27198
|
+
// requested axis can still be consumed by its scroll container.
|
|
27199
|
+
return canConsumeVertical || canConsumeHorizontal;
|
|
27200
|
+
}
|
|
27201
|
+
static canElementConsumeVerticalWheel(element, deltaY) {
|
|
27202
|
+
if (deltaY === 0) {
|
|
27203
|
+
return false;
|
|
27204
|
+
}
|
|
27205
|
+
const maxScrollTop = Math.max(0, element.scrollHeight - element.clientHeight);
|
|
27206
|
+
if (maxScrollTop === 0) {
|
|
27207
|
+
return false;
|
|
27208
|
+
}
|
|
27209
|
+
const epsilon = 1;
|
|
27210
|
+
const scrollingDown = deltaY > 0;
|
|
27211
|
+
const scrollingUp = deltaY < 0;
|
|
27212
|
+
if (scrollingDown) {
|
|
27213
|
+
return element.scrollTop < maxScrollTop - epsilon;
|
|
27214
|
+
}
|
|
27215
|
+
if (scrollingUp) {
|
|
27216
|
+
return element.scrollTop > epsilon;
|
|
27217
|
+
}
|
|
27218
|
+
return false;
|
|
27219
|
+
}
|
|
27220
|
+
static canElementConsumeHorizontalWheel(element, deltaX) {
|
|
27221
|
+
if (deltaX === 0) {
|
|
27222
|
+
return false;
|
|
27223
|
+
}
|
|
27224
|
+
const maxScrollLeft = Math.max(0, element.scrollWidth - element.clientWidth);
|
|
27225
|
+
if (maxScrollLeft === 0) {
|
|
27226
|
+
return false;
|
|
27227
|
+
}
|
|
27228
|
+
const epsilon = 1;
|
|
27229
|
+
const scrollingRight = deltaX > 0;
|
|
27230
|
+
const scrollingLeft = deltaX < 0;
|
|
27231
|
+
if (scrollingRight) {
|
|
27232
|
+
return element.scrollLeft < maxScrollLeft - epsilon;
|
|
27233
|
+
}
|
|
27234
|
+
if (scrollingLeft) {
|
|
27235
|
+
return element.scrollLeft > epsilon;
|
|
27236
|
+
}
|
|
27237
|
+
return false;
|
|
27238
|
+
}
|
|
27239
|
+
}
|
|
27240
|
+
|
|
27155
27241
|
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}`;
|
|
27156
27242
|
|
|
27157
27243
|
const KritzelEngine = class {
|
|
@@ -27340,6 +27426,7 @@ const KritzelEngine = class {
|
|
|
27340
27426
|
onDebugInfoChange(newValue) {
|
|
27341
27427
|
if (newValue) {
|
|
27342
27428
|
this.core.store.state.debugInfo = newValue;
|
|
27429
|
+
this.core.assetResolver.setShowInfo(newValue.showAssetResolverInfo);
|
|
27343
27430
|
}
|
|
27344
27431
|
}
|
|
27345
27432
|
/** When false, non-modified wheel events do not pan the viewport. */
|
|
@@ -27393,6 +27480,12 @@ const KritzelEngine = class {
|
|
|
27393
27480
|
if (this.core.store.state.isContextMenuVisible) {
|
|
27394
27481
|
this.hideContextMenu();
|
|
27395
27482
|
}
|
|
27483
|
+
const hoveredObject = this.core.getObjectFromPointerEvent(ev);
|
|
27484
|
+
if (hoveredObject &&
|
|
27485
|
+
ObjectHelper.isClass(hoveredObject, 'KritzelCustomElement') &&
|
|
27486
|
+
KritzelWheelHelper.shouldKeepWheelInCustomElement(ev, hoveredObject)) {
|
|
27487
|
+
return;
|
|
27488
|
+
}
|
|
27396
27489
|
if (ev.ctrlKey) {
|
|
27397
27490
|
if (this.isZoomingEnabled) {
|
|
27398
27491
|
this.viewport.handleWheel(ev);
|
|
@@ -27409,6 +27502,11 @@ const KritzelEngine = class {
|
|
|
27409
27502
|
if (this.core.store.isDisabled) {
|
|
27410
27503
|
return;
|
|
27411
27504
|
}
|
|
27505
|
+
// Interactive custom-element content should receive native pointer events
|
|
27506
|
+
// whenever the object is marked interactive.
|
|
27507
|
+
if (this.isEmbeddedCustomElementInteraction(ev)) {
|
|
27508
|
+
return;
|
|
27509
|
+
}
|
|
27412
27510
|
if (KritzelDevicesHelper.isTouchDevice()) {
|
|
27413
27511
|
KritzelEventHelper.onLongPress(ev, (event) => this.longpress.emit(event));
|
|
27414
27512
|
}
|
|
@@ -27425,6 +27523,10 @@ const KritzelEngine = class {
|
|
|
27425
27523
|
if (this.core.store.isDisabled) {
|
|
27426
27524
|
return;
|
|
27427
27525
|
}
|
|
27526
|
+
// Ignore drag/move sequences when their pointerdown was intentionally bypassed.
|
|
27527
|
+
if (ev.buttons > 0 && !this.core.store.state.pointers.has(ev.pointerId)) {
|
|
27528
|
+
return;
|
|
27529
|
+
}
|
|
27428
27530
|
if (this.core.store.state.pointers.has(ev.pointerId)) {
|
|
27429
27531
|
this.core.store.state.pointers.set(ev.pointerId, ev);
|
|
27430
27532
|
}
|
|
@@ -27473,6 +27575,56 @@ const KritzelEngine = class {
|
|
|
27473
27575
|
this.viewport.handlePointerUp(ev);
|
|
27474
27576
|
this.core.store.state?.activeTool?.handlePointerUp(ev);
|
|
27475
27577
|
}
|
|
27578
|
+
isEmbeddedCustomElementInteraction(event) {
|
|
27579
|
+
const path = event.composedPath();
|
|
27580
|
+
const objectElement = path.find((entry) => {
|
|
27581
|
+
return entry instanceof HTMLElement && entry.classList.contains('object');
|
|
27582
|
+
});
|
|
27583
|
+
if (!objectElement?.id) {
|
|
27584
|
+
return false;
|
|
27585
|
+
}
|
|
27586
|
+
const object = this.core.store.objects.findById(objectElement.id);
|
|
27587
|
+
if (!object || !KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
27588
|
+
return false;
|
|
27589
|
+
}
|
|
27590
|
+
const isSelected = !!this.core.store.selectionGroup?.objects?.some(selectedObject => selectedObject.id === object.id);
|
|
27591
|
+
if (!isSelected) {
|
|
27592
|
+
return false;
|
|
27593
|
+
}
|
|
27594
|
+
if (object.isInteractive !== true) {
|
|
27595
|
+
return false;
|
|
27596
|
+
}
|
|
27597
|
+
const potentialRoots = [];
|
|
27598
|
+
if (object.element instanceof HTMLElement) {
|
|
27599
|
+
potentialRoots.push(object.element);
|
|
27600
|
+
}
|
|
27601
|
+
if (object.elementRef instanceof HTMLElement) {
|
|
27602
|
+
potentialRoots.push(object.elementRef);
|
|
27603
|
+
}
|
|
27604
|
+
if (potentialRoots.length === 0) {
|
|
27605
|
+
return false;
|
|
27606
|
+
}
|
|
27607
|
+
// Only bypass canvas tool handling when the pointer event came from an
|
|
27608
|
+
// actually interactive descendant inside the custom element subtree.
|
|
27609
|
+
return potentialRoots.some(root => this.isNativeInteractiveEmbeddedTarget(path, root));
|
|
27610
|
+
}
|
|
27611
|
+
isNativeInteractiveEmbeddedTarget(path, customElementRoot) {
|
|
27612
|
+
const interactiveSelector = 'input, button, textarea, select, a[href], [contenteditable="true"], [contenteditable=""]';
|
|
27613
|
+
const rootIndex = path.findIndex(entry => entry === customElementRoot);
|
|
27614
|
+
if (rootIndex === -1) {
|
|
27615
|
+
return false;
|
|
27616
|
+
}
|
|
27617
|
+
for (const entry of path.slice(0, rootIndex)) {
|
|
27618
|
+
if (!(entry instanceof HTMLElement)) {
|
|
27619
|
+
continue;
|
|
27620
|
+
}
|
|
27621
|
+
const interactiveEntry = entry;
|
|
27622
|
+
if (interactiveEntry.matches(interactiveSelector)) {
|
|
27623
|
+
return true;
|
|
27624
|
+
}
|
|
27625
|
+
}
|
|
27626
|
+
return false;
|
|
27627
|
+
}
|
|
27476
27628
|
handlePointerLeave() {
|
|
27477
27629
|
this.core.store.objects?.clearCursorPosition();
|
|
27478
27630
|
}
|
|
@@ -27544,7 +27696,7 @@ const KritzelEngine = class {
|
|
|
27544
27696
|
void this.core.clipboardManager.paste(undefined, undefined, ev);
|
|
27545
27697
|
}
|
|
27546
27698
|
/**
|
|
27547
|
-
|
|
27699
|
+
* Determines if the engine should handle a keyboard/clipboard shortcut event.
|
|
27548
27700
|
* Returns true only if:
|
|
27549
27701
|
* - The event originates from within the engine component, OR
|
|
27550
27702
|
* - The event target is not an interactive element that needs keyboard input
|
|
@@ -28758,6 +28910,8 @@ const KritzelEngine = class {
|
|
|
28758
28910
|
_syncConfigRevision = 0;
|
|
28759
28911
|
_assetStorageConfigRevision = 0;
|
|
28760
28912
|
_isWorkspaceLoading = false;
|
|
28913
|
+
_hasLoggedUnlicensedWelcomeBanner = false;
|
|
28914
|
+
_previousVisibleCustomElements = new Set();
|
|
28761
28915
|
_defaultUndoState = {
|
|
28762
28916
|
canUndo: false,
|
|
28763
28917
|
canRedo: false,
|
|
@@ -28821,6 +28975,14 @@ const KritzelEngine = class {
|
|
|
28821
28975
|
}
|
|
28822
28976
|
disconnectedCallback() {
|
|
28823
28977
|
this.throttledPointerMoveMulti.cancel();
|
|
28978
|
+
// Unmount all remaining custom elements
|
|
28979
|
+
if (this.core.store.allObjects) {
|
|
28980
|
+
this.core.store.allObjects.forEach(object => {
|
|
28981
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
28982
|
+
object.unmount();
|
|
28983
|
+
}
|
|
28984
|
+
});
|
|
28985
|
+
}
|
|
28824
28986
|
// Clear cursor position in awareness before destroying
|
|
28825
28987
|
this.core.store.objects?.clearCursorPosition();
|
|
28826
28988
|
// Clean up current workspace's ObjectMap
|
|
@@ -28877,6 +29039,7 @@ const KritzelEngine = class {
|
|
|
28877
29039
|
await this.initializeSyncAndWorkspace();
|
|
28878
29040
|
if (this.core.store.state.isReady === false) {
|
|
28879
29041
|
this.core.store.state.isReady = true;
|
|
29042
|
+
this.logUnlicensedWelcomeBanner();
|
|
28880
29043
|
this.isEngineReady.emit(this.core.store.state);
|
|
28881
29044
|
}
|
|
28882
29045
|
}, 50);
|
|
@@ -28916,6 +29079,14 @@ const KritzelEngine = class {
|
|
|
28916
29079
|
}
|
|
28917
29080
|
this._isAssetStorageInitialized = true;
|
|
28918
29081
|
}
|
|
29082
|
+
logUnlicensedWelcomeBanner() {
|
|
29083
|
+
if (this.core.licenseManager.isLicensed || this._hasLoggedUnlicensedWelcomeBanner) {
|
|
29084
|
+
return;
|
|
29085
|
+
}
|
|
29086
|
+
this._hasLoggedUnlicensedWelcomeBanner = true;
|
|
29087
|
+
console.info('%c👋 Welcome to Kritzel', 'color: #007AFF; font-weight: 700;');
|
|
29088
|
+
console.info(`This version of Kritzel is not licensed. Get a license at: https://kritzel.io`);
|
|
29089
|
+
}
|
|
28919
29090
|
async doInitializeSyncAndWorkspace() {
|
|
28920
29091
|
// Capture sync config revision to detect prop updates that happen while
|
|
28921
29092
|
// initialization is in-flight.
|
|
@@ -29119,8 +29290,7 @@ const KritzelEngine = class {
|
|
|
29119
29290
|
if (normalizedScale <= this._objectDistanceFadeFarScale) {
|
|
29120
29291
|
return this._objectDistanceFadeMinOpacity;
|
|
29121
29292
|
}
|
|
29122
|
-
const progress = (this._objectDistanceFadeNearScale - normalizedScale) /
|
|
29123
|
-
(this._objectDistanceFadeNearScale - this._objectDistanceFadeFarScale);
|
|
29293
|
+
const progress = (this._objectDistanceFadeNearScale - normalizedScale) / (this._objectDistanceFadeNearScale - this._objectDistanceFadeFarScale);
|
|
29124
29294
|
const smooth = progress * progress * (3 - 2 * progress);
|
|
29125
29295
|
return 1 - smooth * (1 - this._objectDistanceFadeMinOpacity);
|
|
29126
29296
|
}
|
|
@@ -29131,8 +29301,7 @@ const KritzelEngine = class {
|
|
|
29131
29301
|
if (normalizedScale >= this._objectDistanceFadeCloseMaxScale) {
|
|
29132
29302
|
return this._objectDistanceFadeCloseMinOpacity;
|
|
29133
29303
|
}
|
|
29134
|
-
const progress = (normalizedScale - this._objectDistanceFadeCloseStartScale) /
|
|
29135
|
-
(this._objectDistanceFadeCloseMaxScale - this._objectDistanceFadeCloseStartScale);
|
|
29304
|
+
const progress = (normalizedScale - this._objectDistanceFadeCloseStartScale) / (this._objectDistanceFadeCloseMaxScale - this._objectDistanceFadeCloseStartScale);
|
|
29136
29305
|
const smooth = progress * progress * (3 - 2 * progress);
|
|
29137
29306
|
return 1 - smooth * (1 - this._objectDistanceFadeCloseMinOpacity);
|
|
29138
29307
|
}
|
|
@@ -29142,13 +29311,18 @@ const KritzelEngine = class {
|
|
|
29142
29311
|
}
|
|
29143
29312
|
getObjectEffectiveOpacity(object, viewportScale) {
|
|
29144
29313
|
const safeObjectOpacity = Number.isFinite(object.opacity) ? object.opacity : 1;
|
|
29145
|
-
const distanceFadeMultiplier = this.shouldApplyDistanceFade(object)
|
|
29146
|
-
? this.getObjectDistanceFadeMultiplier(object.scale, viewportScale)
|
|
29147
|
-
: 1;
|
|
29314
|
+
const distanceFadeMultiplier = this.shouldApplyDistanceFade(object) ? this.getObjectDistanceFadeMultiplier(object.scale, viewportScale) : 1;
|
|
29148
29315
|
const multiplied = (object.markedForRemoval ? 0.5 : 1) * safeObjectOpacity * distanceFadeMultiplier;
|
|
29149
29316
|
const overridden = ((object.markedForRemoval ? 0.5 : safeObjectOpacity) * distanceFadeMultiplier).toString();
|
|
29150
29317
|
return { multiplied, overridden };
|
|
29151
29318
|
}
|
|
29319
|
+
getSelectionHandleCapabilities(object) {
|
|
29320
|
+
const selectedObjects = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') ? object.objects : [object];
|
|
29321
|
+
return {
|
|
29322
|
+
canRenderResizeHandles: selectedObjects.every(selectedObject => selectedObject.isResizable !== false),
|
|
29323
|
+
canRenderRotationHandle: selectedObjects.every(selectedObject => selectedObject.isRotatable !== false),
|
|
29324
|
+
};
|
|
29325
|
+
}
|
|
29152
29326
|
render() {
|
|
29153
29327
|
if (!this.viewport) {
|
|
29154
29328
|
return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), this.core.localizationManager.translate('engine.loading')))));
|
|
@@ -29162,6 +29336,45 @@ const KritzelEngine = class {
|
|
|
29162
29336
|
const viewportCenterX = this.core.store.state.viewportWidth / 2 + this.core.store.state.translateX;
|
|
29163
29337
|
const viewportCenterY = this.core.store.state.viewportHeight / 2 + this.core.store.state.translateY;
|
|
29164
29338
|
const visibleObjects = this.core.store.objectsInViewport;
|
|
29339
|
+
const getObjectWrapperPointerEvents = (object) => {
|
|
29340
|
+
if (this.core.store.state.isScaling) {
|
|
29341
|
+
return 'none';
|
|
29342
|
+
}
|
|
29343
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup')) {
|
|
29344
|
+
return 'none';
|
|
29345
|
+
}
|
|
29346
|
+
return 'auto';
|
|
29347
|
+
};
|
|
29348
|
+
const getSelectionGroupOverlayPointerEvents = (object) => {
|
|
29349
|
+
if (object.markedForRemoval) {
|
|
29350
|
+
return 'none';
|
|
29351
|
+
}
|
|
29352
|
+
if (!KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup')) {
|
|
29353
|
+
return 'auto';
|
|
29354
|
+
}
|
|
29355
|
+
if (object.objects.length === 1 && KritzelClassHelper.isInstanceOf(object.objects[0], 'KritzelCustomElement')) {
|
|
29356
|
+
return 'none';
|
|
29357
|
+
}
|
|
29358
|
+
return 'auto';
|
|
29359
|
+
};
|
|
29360
|
+
// Track visible custom elements and unmount culled ones
|
|
29361
|
+
const currentVisibleCustomElements = new Set();
|
|
29362
|
+
visibleObjects.forEach(object => {
|
|
29363
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
29364
|
+
currentVisibleCustomElements.add(object.id);
|
|
29365
|
+
}
|
|
29366
|
+
});
|
|
29367
|
+
// Unmount custom elements that left the viewport
|
|
29368
|
+
this._previousVisibleCustomElements.forEach(id => {
|
|
29369
|
+
if (!currentVisibleCustomElements.has(id)) {
|
|
29370
|
+
const object = this.core.store.objects.findById(id);
|
|
29371
|
+
if (object && KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
29372
|
+
object.unmount();
|
|
29373
|
+
}
|
|
29374
|
+
}
|
|
29375
|
+
});
|
|
29376
|
+
// Update tracking set for next render
|
|
29377
|
+
this._previousVisibleCustomElements = currentVisibleCustomElements;
|
|
29165
29378
|
this.core.cursorManager.applyCursor();
|
|
29166
29379
|
if (this.core.store.state.hasViewportChanged) {
|
|
29167
29380
|
this.viewportChange.emit(this.viewport.getViewport());
|
|
@@ -29178,7 +29391,7 @@ const KritzelEngine = class {
|
|
|
29178
29391
|
transformOrigin: 'top left',
|
|
29179
29392
|
position: 'absolute',
|
|
29180
29393
|
zIndex: object.zIndex.toString(),
|
|
29181
|
-
pointerEvents:
|
|
29394
|
+
pointerEvents: getObjectWrapperPointerEvents(object),
|
|
29182
29395
|
} }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
|
|
29183
29396
|
height: object?.totalHeight + 'px',
|
|
29184
29397
|
width: object?.totalWidth + 'px',
|
|
@@ -29267,7 +29480,7 @@ const KritzelEngine = class {
|
|
|
29267
29480
|
transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
|
|
29268
29481
|
transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
|
|
29269
29482
|
opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
|
|
29270
|
-
pointerEvents: object
|
|
29483
|
+
pointerEvents: getSelectionGroupOverlayPointerEvents(object),
|
|
29271
29484
|
} })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => el && object.mount(el), style: {
|
|
29272
29485
|
position: 'absolute',
|
|
29273
29486
|
left: '0',
|
|
@@ -29302,60 +29515,65 @@ const KritzelEngine = class {
|
|
|
29302
29515
|
transform: `scale(${object.scaleFactor})`,
|
|
29303
29516
|
backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
|
|
29304
29517
|
overflow: 'visible',
|
|
29305
|
-
} }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') &&
|
|
29306
|
-
|
|
29307
|
-
|
|
29308
|
-
|
|
29309
|
-
|
|
29310
|
-
|
|
29311
|
-
|
|
29312
|
-
|
|
29313
|
-
|
|
29314
|
-
|
|
29315
|
-
|
|
29316
|
-
|
|
29317
|
-
|
|
29318
|
-
|
|
29319
|
-
|
|
29320
|
-
|
|
29321
|
-
|
|
29322
|
-
|
|
29323
|
-
|
|
29324
|
-
|
|
29325
|
-
|
|
29326
|
-
|
|
29327
|
-
|
|
29328
|
-
|
|
29329
|
-
|
|
29330
|
-
|
|
29331
|
-
|
|
29332
|
-
|
|
29333
|
-
|
|
29334
|
-
|
|
29335
|
-
|
|
29336
|
-
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
|
|
29340
|
-
|
|
29341
|
-
|
|
29518
|
+
} }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') &&
|
|
29519
|
+
(() => {
|
|
29520
|
+
const fillResolved = KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme);
|
|
29521
|
+
const strokeResolved = KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme);
|
|
29522
|
+
const isFilled = !!fillResolved && fillResolved !== 'transparent';
|
|
29523
|
+
const strokeMatchesFill = isFilled && strokeResolved === fillResolved;
|
|
29524
|
+
return (h("div", { ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
|
|
29525
|
+
position: 'absolute',
|
|
29526
|
+
left: '0',
|
|
29527
|
+
top: '0',
|
|
29528
|
+
width: object.totalWidth + 'px',
|
|
29529
|
+
height: object.totalHeight + 'px',
|
|
29530
|
+
transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
|
|
29531
|
+
transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
|
|
29532
|
+
pointerEvents: object.markedForRemoval ? 'none' : 'auto',
|
|
29533
|
+
overflow: 'visible',
|
|
29534
|
+
} }, h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
|
|
29535
|
+
position: 'absolute',
|
|
29536
|
+
top: '0',
|
|
29537
|
+
left: '0',
|
|
29538
|
+
width: '100%',
|
|
29539
|
+
height: '100%',
|
|
29540
|
+
overflow: 'visible',
|
|
29541
|
+
pointerEvents: 'none',
|
|
29542
|
+
}, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: KritzelColorHelper.applyOpacity(object.fillColor, effectiveOpacity, currentTheme), stroke: strokeMatchesFill ? 'none' : KritzelColorHelper.applyOpacity(object.strokeColor, effectiveOpacity, currentTheme), "stroke-width": strokeMatchesFill ? 0 : object.strokeWidth })), h("div", { ref: el => el && object.mountTextEditor(el), style: {
|
|
29543
|
+
position: 'absolute',
|
|
29544
|
+
top: '0',
|
|
29545
|
+
left: '0',
|
|
29546
|
+
width: '100%',
|
|
29547
|
+
height: '100%',
|
|
29548
|
+
display: 'flex',
|
|
29549
|
+
alignItems: 'center',
|
|
29550
|
+
justifyContent: 'center',
|
|
29551
|
+
textAlign: 'center',
|
|
29552
|
+
overflow: 'hidden',
|
|
29553
|
+
pointerEvents: object.isEditing ? 'auto' : 'none',
|
|
29554
|
+
} })));
|
|
29555
|
+
})(), this.core.store.state.debugInfo.showObjectInfo && (h("div", { style: {
|
|
29342
29556
|
pointerEvents: 'none',
|
|
29343
29557
|
position: 'absolute',
|
|
29344
29558
|
left: `${object.totalWidth}px`,
|
|
29345
29559
|
top: '0',
|
|
29346
29560
|
zIndex: (object.zIndex + 2).toString(),
|
|
29347
|
-
} }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
|
|
29561
|
+
} }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isSelected: ", object.isSelected ? 'true' : 'false'), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isInteractive: ", object.isInteractive ? 'true' : 'false'))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
|
|
29348
29562
|
(() => {
|
|
29349
29563
|
const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
|
|
29350
29564
|
const localClientId = this.core.store.objects?.localClientId;
|
|
29351
29565
|
const awarenessStates = this.core.store.objects?.awareness?.getStates();
|
|
29352
|
-
const isRemoteSelection = isSelectionGroup &&
|
|
29353
|
-
|
|
29354
|
-
|
|
29355
|
-
|
|
29356
|
-
|
|
29357
|
-
|
|
29358
|
-
|
|
29566
|
+
const isRemoteSelection = isSelectionGroup &&
|
|
29567
|
+
// Different user
|
|
29568
|
+
((object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
|
|
29569
|
+
// Same user but different client that is still actively connected (e.g. same account on another device)
|
|
29570
|
+
(object.userId != null &&
|
|
29571
|
+
this.core.user?.id != null &&
|
|
29572
|
+
object.userId === this.core.user.id &&
|
|
29573
|
+
object.clientId != null &&
|
|
29574
|
+
localClientId != null &&
|
|
29575
|
+
object.clientId !== localClientId &&
|
|
29576
|
+
awarenessStates?.has(object.clientId) === true));
|
|
29359
29577
|
let remoteUserColor;
|
|
29360
29578
|
if (isRemoteSelection) {
|
|
29361
29579
|
if (awarenessStates) {
|
|
@@ -29374,10 +29592,10 @@ const KritzelEngine = class {
|
|
|
29374
29592
|
}
|
|
29375
29593
|
}
|
|
29376
29594
|
}
|
|
29377
|
-
const selectionBorderColor = remoteUserColor
|
|
29378
|
-
|
|
29379
|
-
const
|
|
29380
|
-
|
|
29595
|
+
const selectionBorderColor = remoteUserColor ?? (KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme) || 'var(--kritzel-selection-border-color, #007AFF)');
|
|
29596
|
+
const selectionHandleStrokeColor = remoteUserColor ?? 'var(--kritzel-selection-handle-stroke-color, #007AFF)';
|
|
29597
|
+
const handleScale = object.scale ?? 1;
|
|
29598
|
+
const { canRenderResizeHandles, canRenderRotationHandle } = this.getSelectionHandleCapabilities(object);
|
|
29381
29599
|
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
|
|
29382
29600
|
zIndex: (object.zIndex + 1).toString(),
|
|
29383
29601
|
height: object?.totalHeight.toString(),
|
|
@@ -29421,50 +29639,50 @@ const KritzelEngine = class {
|
|
|
29421
29639
|
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
29422
29640
|
strokeLinecap: 'square',
|
|
29423
29641
|
} })));
|
|
29424
|
-
})(), !this.isSelecting && !isRemoteSelection && (h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, h("rect", { class: "resize-handle top-left", x: `${(-(baseHandleSize - 1) *
|
|
29642
|
+
})(), !this.isSelecting && !isRemoteSelection && (h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, canRenderResizeHandles && (h("g", null, 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: {
|
|
29425
29643
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29426
29644
|
stroke: selectionHandleStrokeColor,
|
|
29427
|
-
strokeWidth: `calc(2px * ${
|
|
29645
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29428
29646
|
paintOrder: 'fill',
|
|
29429
|
-
} }), h("rect", { class: "resize-handle-overlay top-left", x: `${(-baseHandleTouchSize *
|
|
29647
|
+
} }), 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: {
|
|
29430
29648
|
fill: 'transparent',
|
|
29431
29649
|
paintOrder: 'fill',
|
|
29432
|
-
} }), h("rect", { class: "resize-handle top-right", x: `${object.totalWidth - ((baseHandleSize - 1) *
|
|
29650
|
+
} }), 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: {
|
|
29433
29651
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29434
29652
|
stroke: selectionHandleStrokeColor,
|
|
29435
|
-
strokeWidth: `calc(2px * ${
|
|
29653
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29436
29654
|
paintOrder: 'fill',
|
|
29437
|
-
} }), h("rect", { class: "resize-handle-overlay top-right", x: `${object.totalWidth - (baseHandleTouchSize *
|
|
29655
|
+
} }), 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: {
|
|
29438
29656
|
fill: 'transparent',
|
|
29439
29657
|
paintOrder: 'fill',
|
|
29440
|
-
} }), h("rect", { class: "resize-handle bottom-left", x: `${(-(baseHandleSize - 1) *
|
|
29658
|
+
} }), 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: {
|
|
29441
29659
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29442
29660
|
stroke: selectionHandleStrokeColor,
|
|
29443
|
-
strokeWidth: `calc(2px * ${
|
|
29661
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29444
29662
|
paintOrder: 'fill',
|
|
29445
|
-
} }), h("rect", { class: "resize-handle-overlay bottom-left", x: `${(-baseHandleTouchSize *
|
|
29663
|
+
} }), 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: {
|
|
29446
29664
|
fill: 'transparent',
|
|
29447
29665
|
paintOrder: 'fill',
|
|
29448
|
-
} }), h("rect", { class: "resize-handle bottom-right", x: `${object.totalWidth - ((baseHandleSize - 1) *
|
|
29666
|
+
} }), 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: {
|
|
29449
29667
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29450
29668
|
stroke: selectionHandleStrokeColor,
|
|
29451
|
-
strokeWidth: `calc(2px * ${
|
|
29669
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29452
29670
|
paintOrder: 'fill',
|
|
29453
|
-
} }), h("rect", { class: "resize-handle-overlay bottom-right", x: `${object.totalWidth - (baseHandleTouchSize *
|
|
29671
|
+
} }), 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: {
|
|
29454
29672
|
fill: 'transparent',
|
|
29455
29673
|
paintOrder: 'fill',
|
|
29456
|
-
} }), h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 *
|
|
29674
|
+
} }))), canRenderRotationHandle && (h("g", null, h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * handleScale) / this.core.store.state?.scale), style: {
|
|
29457
29675
|
stroke: selectionBorderColor,
|
|
29458
|
-
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${
|
|
29459
|
-
} }), h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 *
|
|
29676
|
+
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29677
|
+
} }), 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: {
|
|
29460
29678
|
fill: 'var(--kritzel-selection-handle-color, #ffffff)',
|
|
29461
29679
|
stroke: selectionHandleStrokeColor,
|
|
29462
|
-
strokeWidth: `calc(2px * ${
|
|
29680
|
+
strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
|
|
29463
29681
|
paintOrder: 'fill',
|
|
29464
|
-
} }), h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 *
|
|
29682
|
+
} }), 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: {
|
|
29465
29683
|
fill: 'transparent',
|
|
29466
29684
|
paintOrder: 'fill',
|
|
29467
|
-
} }))))), this.core.displaySelectionLineUI(object) && KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, h("g", { class: "selection-line-borders" }, h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
|
|
29685
|
+
} }))))))), this.core.displaySelectionLineUI(object) && KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, h("g", { class: "selection-line-borders" }, h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
|
|
29468
29686
|
stroke: selectionBorderColor,
|
|
29469
29687
|
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
29470
29688
|
strokeLinecap: 'round',
|
|
@@ -29589,7 +29807,7 @@ const KritzelEngine = class {
|
|
|
29589
29807
|
}, this.core.store.selectionGroup?.objects || []);
|
|
29590
29808
|
}
|
|
29591
29809
|
this.hideContextMenu();
|
|
29592
|
-
}, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed &&
|
|
29810
|
+
}, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed && h("kritzel-watermark", { core: this.core, label: this.core.localizationManager.translate('watermark.poweredBy') })));
|
|
29593
29811
|
}
|
|
29594
29812
|
static get watchers() { return {
|
|
29595
29813
|
"workspace": [{
|
|
@@ -30987,7 +31205,7 @@ const KritzelPortal = class {
|
|
|
30987
31205
|
* This file is auto-generated by the version bump scripts.
|
|
30988
31206
|
* Do not modify manually.
|
|
30989
31207
|
*/
|
|
30990
|
-
const KRITZEL_VERSION = '0.3.
|
|
31208
|
+
const KRITZEL_VERSION = '0.3.23';
|
|
30991
31209
|
|
|
30992
31210
|
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)}`;
|
|
30993
31211
|
|
|
@@ -31003,6 +31221,7 @@ const DEFAULT_DEBUG_INFO = {
|
|
|
31003
31221
|
showObjectInfo: false,
|
|
31004
31222
|
showSyncProviderInfo: true,
|
|
31005
31223
|
showMigrationInfo: true,
|
|
31224
|
+
showAssetResolverInfo: false,
|
|
31006
31225
|
};
|
|
31007
31226
|
const SETTINGS_CATEGORY_IDS = ['general', 'viewport', 'shortcuts', 'developer', 'about'];
|
|
31008
31227
|
const KritzelSettings = class {
|
|
@@ -31211,7 +31430,7 @@ const KritzelSettings = class {
|
|
|
31211
31430
|
}
|
|
31212
31431
|
}
|
|
31213
31432
|
render() {
|
|
31214
|
-
return (h(Host, { key: '
|
|
31433
|
+
return (h(Host, { key: '8b96261465efeabb2eb0cf724d29699de5e230a8' }, h("kritzel-dialog", { key: '273a9df290bb97d59000a97f91821e7bad3f3896', isOpen: this.isDialogOpen, dialogTitle: this.t('settings.dialogTitle', 'Settings'), size: "large", contained: true, onDialogClose: this.closeDialog }, h("kritzel-master-detail", { key: '64d17dfaa2a0baf2d4a5d00fe5fc65ad40c96ec6', items: this.categories, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
|
|
31215
31434
|
}
|
|
31216
31435
|
static get watchers() { return {
|
|
31217
31436
|
"settings": [{
|