kritzel-stencil 0.2.10 → 0.2.12
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/kritzel-active-users_42.cjs.entry.js +280 -33
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/stencil.cjs.js +1 -1
- package/dist/collection/classes/core/core.class.js +12 -7
- package/dist/collection/classes/core/viewport.class.js +65 -0
- package/dist/collection/classes/handlers/context-menu.handler.js +7 -6
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +8 -1
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +4 -4
- package/dist/collection/components/shared/kritzel-dialog/kritzel-dialog.css +29 -0
- package/dist/collection/components/shared/kritzel-dialog/kritzel-dialog.js +201 -5
- package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +1 -1
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +1 -1
- package/dist/collection/components/ui/kritzel-current-user-dialog/kritzel-current-user-dialog.js +1 -1
- package/dist/collection/components/ui/kritzel-export/kritzel-export.js +1 -1
- package/dist/collection/components/ui/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
- package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +1 -1
- package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +1 -1
- package/dist/collection/components/ui/kritzel-share-dialog/kritzel-share-dialog.js +2 -2
- package/dist/collection/configs/default-engine-config.js +2 -0
- package/dist/collection/constants/version.js +1 -1
- package/dist/components/index.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-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-workspace-manager.js +1 -1
- package/dist/components/p-BTSOqHMI.js +1 -0
- package/dist/components/{p-B_fA1LTU.js → p-BWB2UGxj.js} +1 -1
- package/dist/components/{p-BpRNLd4z.js → p-Bw1PPSFV.js} +1 -1
- package/dist/components/p-C51_twnc.js +1 -0
- package/dist/components/{p-DykzXVCs.js → p-CS3JA3yn.js} +1 -1
- package/dist/components/p-CrSLn46K.js +1 -0
- package/dist/components/p-CrmWVXea.js +1 -0
- package/dist/components/{p-DQ1fRE9J.js → p-CvCTQQcJ.js} +1 -1
- package/dist/components/{p-CRsnBR8O.js → p-D9BJCr8V.js} +1 -1
- package/dist/components/p-DMfU0hHe.js +1 -0
- package/dist/components/p-DsxW_miC.js +1 -0
- package/dist/components/p-DzxPDPED.js +1 -0
- package/dist/components/{p-nW05C2cx.js → p-Z9_amVdR.js} +1 -1
- package/dist/esm/kritzel-active-users_42.entry.js +280 -33
- package/dist/esm/loader.js +1 -1
- package/dist/esm/stencil.js +1 -1
- package/dist/stencil/p-ddd603ac.entry.js +9 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/viewport.class.d.ts +22 -0
- package/dist/types/components/shared/kritzel-dialog/kritzel-dialog.d.ts +21 -0
- package/dist/types/components.d.ts +11 -0
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/interfaces/engine-state.interface.d.ts +2 -0
- package/package.json +1 -1
- package/dist/components/p-B1V6yEGY.js +0 -1
- package/dist/components/p-BuSOJ7Xd.js +0 -1
- package/dist/components/p-CzYgMB2N.js +0 -1
- package/dist/components/p-DBIK7z89.js +0 -1
- package/dist/components/p-DPxSr1wV.js +0 -1
- package/dist/components/p-Dpr_JQam.js +0 -1
- package/dist/components/p-xHh03blG.js +0 -1
- package/dist/stencil/p-bfff1c18.entry.js +0 -9
|
@@ -870,7 +870,7 @@ class KritzelToolConfigHelper {
|
|
|
870
870
|
}
|
|
871
871
|
}
|
|
872
872
|
|
|
873
|
-
const kritzelControlsCss = () => `:host{display:flex;flex-direction:column;user-select:none;max-width:
|
|
873
|
+
const kritzelControlsCss = () => `:host{display:flex;flex-direction:column;user-select:none;max-width:100%}:host(.mobile){--kritzel-controls-control-hover-background-color:transparent;--kritzel-controls-control-active-background-color:transparent}.kritzel-controls{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--kritzel-controls-gap, 8px);height:100%;padding:var(--kritzel-controls-padding, 8px);background-color:var(--kritzel-controls-background-color, #ffffff);border-radius:var(--kritzel-controls-border-radius, 16px);box-shadow:var(--kritzel-controls-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-controls-border, 1px solid #ebebeb);z-index:10000;position:relative;max-width:100%;overflow:hidden}.kritzel-tools-scroll{display:flex;flex-direction:row;align-items:center;gap:var(--kritzel-controls-gap, 8px);overflow-x:auto;overflow-y:hidden;flex:1 1 auto;min-width:0;padding:4px;margin:-4px;scrollbar-width:none;-ms-overflow-style:none}.kritzel-tools-scroll::-webkit-scrollbar{display:none}.scroll-indicator-left,.scroll-indicator-right{position:absolute;top:0;bottom:0;width:32px;pointer-events:none;opacity:0;transition:opacity 0.2s ease-out;z-index:1}.scroll-indicator-left{left:0;background:linear-gradient(to right, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:var(--kritzel-controls-border-radius, 16px) 0 0 var(--kritzel-controls-border-radius, 16px)}.scroll-indicator-right{right:0;background:linear-gradient(to left, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:0 var(--kritzel-controls-border-radius, 16px) var(--kritzel-controls-border-radius, 16px) 0}.scroll-indicator-left.visible,.scroll-indicator-right.visible{opacity:1}.kritzel-control{display:flex;justify-content:center;align-items:center;color:var(--kritzel-controls-control-color, #000000);border-radius:var(--kritzel-controls-control-border-radius, 12px);padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;font-weight:bold}.kritzel-control:focus,.kritzel-control:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control.selected,.kritzel-control.selected:hover,.kritzel-control.selected:active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control.selected:focus{background-color:var(--kritzel-controls-control-selected-background-color, #007bffe3) !important}.kritzel-control-separator{width:1px;height:24px;background-color:var(--kritzel-controls-border, #ebebeb);margin:0 4px}.kritzel-control-split{position:relative;display:flex;align-items:center;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:var(--kritzel-controls-control-color, #000000)}.kritzel-control-split .kritzel-control-main{display:flex;justify-content:center;align-items:center;padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:inherit}.kritzel-control-split.selected .kritzel-control-main{border-radius:var(--kritzel-controls-control-border-radius, 12px) 0 0 var(--kritzel-controls-control-border-radius, 12px)}.kritzel-control-split .kritzel-control-dropdown{display:flex;justify-content:center;align-items:center;align-self:stretch;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:0 var(--kritzel-controls-control-border-radius, 12px) var(--kritzel-controls-control-border-radius, 12px) 0;color:inherit;width:0;padding:0;opacity:0;overflow:hidden;pointer-events:none;transition:width 0.15s ease-out, padding 0.15s ease-out, opacity 0.15s ease-out}.kritzel-control-split .kritzel-control-dropdown.visible{width:auto;padding:0 6px;opacity:1;pointer-events:auto}.kritzel-control-split .kritzel-control-main:focus,.kritzel-control-split .kritzel-control-main:hover,.kritzel-control-split .kritzel-control-dropdown:focus,.kritzel-control-split .kritzel-control-dropdown:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control-split .kritzel-control-main:active,.kritzel-control-split .kritzel-control-dropdown:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control-split.selected{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control-split.selected .kritzel-control-main:hover,.kritzel-control-split.selected .kritzel-control-dropdown:hover{background-color:rgba(255, 255, 255, 0.15)}.kritzel-submenu-content{display:flex;flex-direction:column;gap:var(--kritzel-submenu-gap, 4px);min-width:140px}.kritzel-submenu-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);border-radius:8px;color:var(--kritzel-controls-control-color, #000000);font-size:14px;text-align:left;white-space:nowrap;-webkit-tap-highlight-color:transparent}.kritzel-submenu-item:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-submenu-item.active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF);color:var(--kritzel-controls-control-selected-color, #ffffff)}.kritzel-submenu-item.active:hover{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF)}.kritzel-config-container{position:relative;display:flex;justify-content:center;align-items:center;height:40px;box-sizing:border-box;-webkit-tap-highlight-color:transparent;flex-shrink:0;width:0;opacity:0;overflow:hidden;pointer-events:none;margin-left:calc(-1 * var(--kritzel-controls-gap, 8px));transition:width 0.2s ease-out, opacity 0.2s ease-out, margin-left 0.2s ease-out}.kritzel-config-container.visible{width:40px;opacity:1;pointer-events:auto;margin-left:0;overflow:visible}.config-gradient-left{position:absolute;top:0;bottom:0;left:-32px;width:32px;background:linear-gradient(to right, transparent, var(--kritzel-controls-background-color, #ffffff));pointer-events:none;z-index:1;opacity:0;transition:opacity 0.2s ease-out}.config-gradient-left.visible{opacity:1}.kritzel-config{display:flex;justify-content:center;align-items:center;cursor:var(--kritzel-global-pointer-cursor, pointer);border-radius:50%}.color-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-global-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.font-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-global-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.no-config{height:24px;width:24px;border-radius:50%;border:1px dashed gray}kritzel-tooltip{z-index:10001}`;
|
|
874
874
|
|
|
875
875
|
const KritzelControls = class {
|
|
876
876
|
constructor(hostRef) {
|
|
@@ -1182,7 +1182,7 @@ const KritzelCurrentUserDialog = class {
|
|
|
1182
1182
|
}
|
|
1183
1183
|
render() {
|
|
1184
1184
|
const displayName = this.getDisplayName();
|
|
1185
|
-
return (h(Host, { key: 'e1dd44cdfdbaebfe886fed0d9feba2ef232b6615' }, h("kritzel-dialog", { key: '
|
|
1185
|
+
return (h(Host, { key: 'e1dd44cdfdbaebfe886fed0d9feba2ef232b6615' }, h("kritzel-dialog", { key: 'cd3daa7abd53c10852d63a2fe53d919414cd8904', dialogTitle: "Account", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small", contained: true }, h("div", { key: '94d0a691ede73135e6cf4ef144c13e52e410ffbe', class: "user-info" }, h("kritzel-avatar", { key: 'e57592d2f3663b593534055be5aae1b224fa8906', user: this.user, size: 80 }), displayName && h("div", { key: '237db2d0608ee49ea70e5282b61a59077f0f4595', class: "user-name" }, displayName), this.user?.email && h("div", { key: 'd821e8171530b92ce6f1781c1145b611d3c533d0', class: "user-email" }, this.user.email)))));
|
|
1186
1186
|
}
|
|
1187
1187
|
};
|
|
1188
1188
|
KritzelCurrentUserDialog.style = kritzelCurrentUserDialogCss();
|
|
@@ -1343,7 +1343,7 @@ class KritzelHTMLHelper {
|
|
|
1343
1343
|
}
|
|
1344
1344
|
}
|
|
1345
1345
|
|
|
1346
|
-
const kritzelDialogCss = () => `:host{display:contents}.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}@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}`;
|
|
1346
|
+
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}`;
|
|
1347
1347
|
|
|
1348
1348
|
const KritzelDialog = class {
|
|
1349
1349
|
constructor(hostRef) {
|
|
@@ -1370,8 +1370,12 @@ const KritzelDialog = class {
|
|
|
1370
1370
|
size = 'medium';
|
|
1371
1371
|
/** Whether to automatically go fullscreen on mobile viewports */
|
|
1372
1372
|
fullscreenOnMobile = true;
|
|
1373
|
+
/** Constrain the dialog to its nearest editor/container ancestor instead of the viewport. */
|
|
1374
|
+
contained = false;
|
|
1373
1375
|
isAnimating = false;
|
|
1374
1376
|
mobileLockedHeight = null;
|
|
1377
|
+
containerRect = null;
|
|
1378
|
+
containerBorderRadius = null;
|
|
1375
1379
|
/** Emitted when the dialog opens */
|
|
1376
1380
|
dialogOpen;
|
|
1377
1381
|
/** Emitted when the dialog closes */
|
|
@@ -1379,6 +1383,9 @@ const KritzelDialog = class {
|
|
|
1379
1383
|
previousOverflow = '';
|
|
1380
1384
|
previousActiveElement = null;
|
|
1381
1385
|
visualViewportListenersAttached = false;
|
|
1386
|
+
containerElement = null;
|
|
1387
|
+
containerResizeObserver = null;
|
|
1388
|
+
containerTrackingFrame = null;
|
|
1382
1389
|
handleIsOpenChange(newValue) {
|
|
1383
1390
|
if (newValue) {
|
|
1384
1391
|
this.openDialog();
|
|
@@ -1428,13 +1435,19 @@ const KritzelDialog = class {
|
|
|
1428
1435
|
}
|
|
1429
1436
|
disconnectedCallback() {
|
|
1430
1437
|
this.removeVisualViewportListeners();
|
|
1438
|
+
this.stopContainerTracking();
|
|
1431
1439
|
this.restoreBodyScroll();
|
|
1432
1440
|
}
|
|
1433
1441
|
openDialog() {
|
|
1434
1442
|
this.isAnimating = true;
|
|
1435
1443
|
this.previousActiveElement = document.activeElement;
|
|
1436
|
-
this.
|
|
1437
|
-
|
|
1444
|
+
if (this.contained) {
|
|
1445
|
+
this.startContainerTracking();
|
|
1446
|
+
}
|
|
1447
|
+
else {
|
|
1448
|
+
this.lockBodyScroll();
|
|
1449
|
+
this.addVisualViewportListeners();
|
|
1450
|
+
}
|
|
1438
1451
|
this.lockMobileViewportHeight();
|
|
1439
1452
|
this.dialogOpen.emit();
|
|
1440
1453
|
if (this.autoFocus) {
|
|
@@ -1449,9 +1462,106 @@ const KritzelDialog = class {
|
|
|
1449
1462
|
closeDialog() {
|
|
1450
1463
|
this.restoreBodyScroll();
|
|
1451
1464
|
this.removeVisualViewportListeners();
|
|
1465
|
+
this.stopContainerTracking();
|
|
1452
1466
|
this.mobileLockedHeight = null;
|
|
1453
1467
|
this.returnFocusToPreviousElement();
|
|
1454
1468
|
}
|
|
1469
|
+
findContainerElement() {
|
|
1470
|
+
// Walk up the composed DOM (crossing shadow roots) and return the first
|
|
1471
|
+
// ancestor that opts into containing dialogs. We accept either an explicit
|
|
1472
|
+
// [data-kritzel-dialog-container] marker or the kritzel-editor host so any
|
|
1473
|
+
// consumer can opt in without modifying the editor itself.
|
|
1474
|
+
let node = this.host;
|
|
1475
|
+
while (node) {
|
|
1476
|
+
if (node instanceof HTMLElement) {
|
|
1477
|
+
if (node.hasAttribute('data-kritzel-dialog-container') || node.tagName === 'KRITZEL-EDITOR') {
|
|
1478
|
+
return node;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
const parent = node.parentNode;
|
|
1482
|
+
if (parent) {
|
|
1483
|
+
node = parent;
|
|
1484
|
+
}
|
|
1485
|
+
else if (node instanceof ShadowRoot) {
|
|
1486
|
+
node = node.host;
|
|
1487
|
+
}
|
|
1488
|
+
else {
|
|
1489
|
+
node = null;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return null;
|
|
1493
|
+
}
|
|
1494
|
+
startContainerTracking() {
|
|
1495
|
+
this.containerElement = this.findContainerElement();
|
|
1496
|
+
if (!this.containerElement) {
|
|
1497
|
+
// No container found — fall back to viewport behavior.
|
|
1498
|
+
this.containerRect = null;
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
this.updateContainerRect();
|
|
1502
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
1503
|
+
this.containerResizeObserver = new ResizeObserver(() => this.updateContainerRect());
|
|
1504
|
+
this.containerResizeObserver.observe(this.containerElement);
|
|
1505
|
+
}
|
|
1506
|
+
window.addEventListener('resize', this.handleContainerTrackingEvent, { passive: true });
|
|
1507
|
+
window.addEventListener('scroll', this.handleContainerTrackingEvent, { capture: true, passive: true });
|
|
1508
|
+
}
|
|
1509
|
+
stopContainerTracking() {
|
|
1510
|
+
if (this.containerResizeObserver) {
|
|
1511
|
+
this.containerResizeObserver.disconnect();
|
|
1512
|
+
this.containerResizeObserver = null;
|
|
1513
|
+
}
|
|
1514
|
+
window.removeEventListener('resize', this.handleContainerTrackingEvent);
|
|
1515
|
+
window.removeEventListener('scroll', this.handleContainerTrackingEvent, { capture: true });
|
|
1516
|
+
if (this.containerTrackingFrame !== null) {
|
|
1517
|
+
cancelAnimationFrame(this.containerTrackingFrame);
|
|
1518
|
+
this.containerTrackingFrame = null;
|
|
1519
|
+
}
|
|
1520
|
+
this.containerElement = null;
|
|
1521
|
+
this.containerRect = null;
|
|
1522
|
+
this.containerBorderRadius = null;
|
|
1523
|
+
}
|
|
1524
|
+
handleContainerTrackingEvent = () => {
|
|
1525
|
+
if (this.containerTrackingFrame !== null)
|
|
1526
|
+
return;
|
|
1527
|
+
this.containerTrackingFrame = requestAnimationFrame(() => {
|
|
1528
|
+
this.containerTrackingFrame = null;
|
|
1529
|
+
this.updateContainerRect();
|
|
1530
|
+
});
|
|
1531
|
+
};
|
|
1532
|
+
updateContainerRect() {
|
|
1533
|
+
if (!this.containerElement)
|
|
1534
|
+
return;
|
|
1535
|
+
const rect = this.containerElement.getBoundingClientRect();
|
|
1536
|
+
const next = { top: rect.top, left: rect.left, width: rect.width, height: rect.height };
|
|
1537
|
+
const prev = this.containerRect;
|
|
1538
|
+
if (!prev || prev.top !== next.top || prev.left !== next.left || prev.width !== next.width || prev.height !== next.height) {
|
|
1539
|
+
this.containerRect = next;
|
|
1540
|
+
}
|
|
1541
|
+
// Look for the nearest visually-rounded ancestor (the container itself or
|
|
1542
|
+
// any ancestor up to the document) so the backdrop matches wrappers that
|
|
1543
|
+
// round their corners around the editor.
|
|
1544
|
+
const radius = this.findVisualBorderRadius(this.containerElement);
|
|
1545
|
+
if (this.containerBorderRadius !== radius) {
|
|
1546
|
+
this.containerBorderRadius = radius;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
findVisualBorderRadius(start) {
|
|
1550
|
+
let node = start;
|
|
1551
|
+
while (node && node !== document.body && node !== document.documentElement) {
|
|
1552
|
+
const computed = window.getComputedStyle(node);
|
|
1553
|
+
const tl = computed.borderTopLeftRadius;
|
|
1554
|
+
const tr = computed.borderTopRightRadius;
|
|
1555
|
+
const br = computed.borderBottomRightRadius;
|
|
1556
|
+
const bl = computed.borderBottomLeftRadius;
|
|
1557
|
+
const isZero = (v) => !v || v === '0px' || v === '0%';
|
|
1558
|
+
if (!(isZero(tl) && isZero(tr) && isZero(br) && isZero(bl))) {
|
|
1559
|
+
return `${tl} ${tr} ${br} ${bl}`;
|
|
1560
|
+
}
|
|
1561
|
+
node = node.parentElement;
|
|
1562
|
+
}
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1455
1565
|
emitClose(reason) {
|
|
1456
1566
|
this.dialogClose.emit({ reason });
|
|
1457
1567
|
}
|
|
@@ -1460,6 +1570,12 @@ const KritzelDialog = class {
|
|
|
1460
1570
|
document.body.style.overflow = 'hidden';
|
|
1461
1571
|
}
|
|
1462
1572
|
lockMobileViewportHeight() {
|
|
1573
|
+
// Skip mobile viewport height locking when contained — the dialog is sized
|
|
1574
|
+
// by its wrapper, not the viewport.
|
|
1575
|
+
if (this.contained) {
|
|
1576
|
+
this.mobileLockedHeight = null;
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1463
1579
|
// Only lock height on mobile when fullscreenOnMobile is enabled.
|
|
1464
1580
|
// Use the smaller dimension so landscape phones (wide but short) are also detected.
|
|
1465
1581
|
const viewportWidth = this.getViewportWidth();
|
|
@@ -1594,15 +1710,73 @@ const KritzelDialog = class {
|
|
|
1594
1710
|
return null;
|
|
1595
1711
|
return (h("div", { class: "dialog-footer" }, h("slot", { name: "footer" })));
|
|
1596
1712
|
}
|
|
1713
|
+
getBackdropStyle() {
|
|
1714
|
+
if (!this.contained || !this.containerRect)
|
|
1715
|
+
return undefined;
|
|
1716
|
+
const { top, left, width, height } = this.containerRect;
|
|
1717
|
+
const style = {
|
|
1718
|
+
top: `${top}px`,
|
|
1719
|
+
left: `${left}px`,
|
|
1720
|
+
right: 'auto',
|
|
1721
|
+
bottom: 'auto',
|
|
1722
|
+
width: `${width}px`,
|
|
1723
|
+
height: `${height}px`,
|
|
1724
|
+
};
|
|
1725
|
+
if (this.containerBorderRadius) {
|
|
1726
|
+
style.borderRadius = this.containerBorderRadius;
|
|
1727
|
+
// Ensure rounded corners actually clip the inner dialog content.
|
|
1728
|
+
style.overflow = 'hidden';
|
|
1729
|
+
}
|
|
1730
|
+
return style;
|
|
1731
|
+
}
|
|
1732
|
+
getDialogContentStyle() {
|
|
1733
|
+
const style = {};
|
|
1734
|
+
// In contained mode, cap the dialog dimensions to the container so the
|
|
1735
|
+
// declared widths/heights of size variants cannot overflow the wrapper.
|
|
1736
|
+
if (this.contained && this.containerRect) {
|
|
1737
|
+
const { width, height } = this.containerRect;
|
|
1738
|
+
if (this.isContainerMobile()) {
|
|
1739
|
+
// Mobile-sized container: behave like fullscreen-on-mobile but scoped
|
|
1740
|
+
// to the container instead of the viewport (works in any orientation).
|
|
1741
|
+
style.width = `${width}px`;
|
|
1742
|
+
style.height = `${height}px`;
|
|
1743
|
+
style.maxWidth = `${width}px`;
|
|
1744
|
+
style.maxHeight = `${height}px`;
|
|
1745
|
+
style.borderRadius = '0';
|
|
1746
|
+
}
|
|
1747
|
+
else {
|
|
1748
|
+
// Leave a small margin so the dialog visibly sits within the container.
|
|
1749
|
+
const maxWidth = Math.max(0, width - 32);
|
|
1750
|
+
const maxHeight = Math.max(0, height - 32);
|
|
1751
|
+
style.maxWidth = `${maxWidth}px`;
|
|
1752
|
+
style.maxHeight = `${maxHeight}px`;
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
if (this.mobileLockedHeight) {
|
|
1756
|
+
style.height = this.mobileLockedHeight;
|
|
1757
|
+
style.maxHeight = this.mobileLockedHeight;
|
|
1758
|
+
}
|
|
1759
|
+
return Object.keys(style).length > 0 ? style : undefined;
|
|
1760
|
+
}
|
|
1761
|
+
isContainerMobile() {
|
|
1762
|
+
if (!this.fullscreenOnMobile || !this.containerRect)
|
|
1763
|
+
return false;
|
|
1764
|
+
// Match the existing viewport media-query threshold: container is "mobile"
|
|
1765
|
+
// when its smaller dimension is <= 576px. This handles both portrait and
|
|
1766
|
+
// landscape wrappers symmetrically.
|
|
1767
|
+
return Math.min(this.containerRect.width, this.containerRect.height) <= 576;
|
|
1768
|
+
}
|
|
1597
1769
|
render() {
|
|
1598
1770
|
if (!this.isOpen)
|
|
1599
1771
|
return null;
|
|
1600
|
-
|
|
1772
|
+
const containerFullscreen = this.contained && this.isContainerMobile();
|
|
1773
|
+
return (h(Host, null, h("div", { class: { backdrop: true, 'is-animating': this.isAnimating, 'contained-fullscreen': containerFullscreen }, style: this.getBackdropStyle(), onClick: this.handleBackdropClick }, h("div", { class: {
|
|
1601
1774
|
'dialog-content': true,
|
|
1602
1775
|
'is-animating': this.isAnimating,
|
|
1603
1776
|
[`size-${this.size}`]: true,
|
|
1604
1777
|
'fullscreen-on-mobile': this.fullscreenOnMobile,
|
|
1605
|
-
|
|
1778
|
+
'contained-fullscreen': containerFullscreen,
|
|
1779
|
+
}, style: this.getDialogContentStyle(), role: "dialog", "aria-modal": "true", "aria-labelledby": this.dialogTitle ? 'dialog-title' : undefined, tabIndex: -1, onClick: this.handleContentClick }, this.renderHeader(), h("div", { class: "dialog-body" }, h("slot", null)), this.renderFooter()))));
|
|
1606
1780
|
}
|
|
1607
1781
|
static get watchers() { return {
|
|
1608
1782
|
"isOpen": [{
|
|
@@ -1895,7 +2069,7 @@ const DEFAULT_SYNC_CONFIG = {
|
|
|
1895
2069
|
],
|
|
1896
2070
|
};
|
|
1897
2071
|
|
|
1898
|
-
const kritzelEditorCss = () => `kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}kritzel-controls{position:absolute;bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}.top-left-buttons{position:absolute;top:var(--kritzel-editor-top-left-buttons-top, 14px);left:var(--kritzel-editor-top-left-buttons-left, 14px);display:flex;align-items:flex-start;gap:8px;z-index:10000}.top-right-buttons{position:absolute;top:var(--kritzel-editor-top-right-buttons-top, 14px);right:var(--kritzel-editor-top-right-buttons-right, 14px);display:flex;align-items:center;gap:8px;z-index:10000}.top-right-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;padding:0;border:var(--kritzel-split-button-border, 1px solid #ebebeb);border-radius:var(--kritzel-split-button-border-radius, 12px);background-color:var(--kritzel-split-button-background-color, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent}.top-right-button:hover{background-color:#f5f5f5}.top-right-button:active{background-color:#ebebeb}`;
|
|
2072
|
+
const kritzelEditorCss = () => `kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:start;line-height:normal}kritzel-controls{position:absolute;left:0;right:0;margin-inline:auto;width:max-content;max-width:calc(100% - 16px);bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}.top-left-buttons{position:absolute;top:var(--kritzel-editor-top-left-buttons-top, 14px);left:var(--kritzel-editor-top-left-buttons-left, 14px);display:flex;align-items:flex-start;gap:8px;z-index:10000}.top-right-buttons{position:absolute;top:var(--kritzel-editor-top-right-buttons-top, 14px);right:var(--kritzel-editor-top-right-buttons-right, 14px);display:flex;align-items:center;gap:8px;z-index:10000}.top-right-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;padding:0;border:var(--kritzel-split-button-border, 1px solid #ebebeb);border-radius:var(--kritzel-split-button-border-radius, 12px);background-color:var(--kritzel-split-button-background-color, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent}.top-right-button:hover{background-color:#f5f5f5}.top-right-button:active{background-color:#ebebeb}`;
|
|
1899
2073
|
|
|
1900
2074
|
const KritzelEditor = class {
|
|
1901
2075
|
constructor(hostRef) {
|
|
@@ -20373,6 +20547,71 @@ class KritzelViewport {
|
|
|
20373
20547
|
this._core.store.state.scale = clampedScale;
|
|
20374
20548
|
this.centerInViewport(object);
|
|
20375
20549
|
}
|
|
20550
|
+
/**
|
|
20551
|
+
* Centers the viewport on a given object and zooms out only if the object
|
|
20552
|
+
* does not fit at the current scale. Never zooms in — if the object already
|
|
20553
|
+
* fits, the scale is left unchanged.
|
|
20554
|
+
* @param object - The object to fit in the viewport
|
|
20555
|
+
*/
|
|
20556
|
+
centerFitInViewportIfNeeded(object) {
|
|
20557
|
+
const scaleX = this._core.store.state.viewportWidth / (object.rotatedBoundingBox.width * 1.1);
|
|
20558
|
+
const scaleY = this._core.store.state.viewportHeight / (object.rotatedBoundingBox.height * 1.1);
|
|
20559
|
+
const newScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
20560
|
+
const clampedScale = Math.max(newScale, this.getEffectiveMinScale());
|
|
20561
|
+
if (clampedScale < this._core.store.state.scale) {
|
|
20562
|
+
this._core.store.state.scale = clampedScale;
|
|
20563
|
+
}
|
|
20564
|
+
this.centerInViewport(object);
|
|
20565
|
+
}
|
|
20566
|
+
/**
|
|
20567
|
+
* Zooms out and centers the viewport on a given object only if the object
|
|
20568
|
+
* does not fit at the current scale. If the object already fits, the
|
|
20569
|
+
* viewport is left completely unchanged.
|
|
20570
|
+
* @param object - The object to check and fit in the viewport
|
|
20571
|
+
*/
|
|
20572
|
+
fitInViewportIfNeeded(object) {
|
|
20573
|
+
const scaleX = this._core.store.state.viewportWidth / (object.rotatedBoundingBox.width * 1.1);
|
|
20574
|
+
const scaleY = this._core.store.state.viewportHeight / (object.rotatedBoundingBox.height * 1.1);
|
|
20575
|
+
const newScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
20576
|
+
const clampedScale = Math.max(newScale, this.getEffectiveMinScale());
|
|
20577
|
+
if (clampedScale < this._core.store.state.scale) {
|
|
20578
|
+
this._core.store.state.scale = clampedScale;
|
|
20579
|
+
this.centerInViewport(object);
|
|
20580
|
+
}
|
|
20581
|
+
}
|
|
20582
|
+
/**
|
|
20583
|
+
* Smoothly brings a given object into view if it is not fully visible within
|
|
20584
|
+
* the current viewport. Zooms out only if the object is too large to fit at
|
|
20585
|
+
* the current scale; never zooms in. If the object is already fully visible,
|
|
20586
|
+
* the viewport is left unchanged.
|
|
20587
|
+
* @param object - The object to bring into view
|
|
20588
|
+
*/
|
|
20589
|
+
bringIntoViewIfNeeded(object) {
|
|
20590
|
+
const { scale, translateX, translateY, viewportWidth, viewportHeight } = this._core.store.state;
|
|
20591
|
+
const bounds = object.rotatedBoundingBox;
|
|
20592
|
+
// Compute the object's bounding box in screen-space coordinates
|
|
20593
|
+
const screenLeft = bounds.x * scale + translateX;
|
|
20594
|
+
const screenTop = bounds.y * scale + translateY;
|
|
20595
|
+
const screenRight = (bounds.x + bounds.width) * scale + translateX;
|
|
20596
|
+
const screenBottom = (bounds.y + bounds.height) * scale + translateY;
|
|
20597
|
+
// If fully visible, no adjustment needed
|
|
20598
|
+
if (screenLeft >= 0 && screenTop >= 0 && screenRight <= viewportWidth && screenBottom <= viewportHeight) {
|
|
20599
|
+
return;
|
|
20600
|
+
}
|
|
20601
|
+
// Calculate the scale needed to fit the object with padding; never zoom in
|
|
20602
|
+
const scaleX = viewportWidth / (bounds.width * 1.1);
|
|
20603
|
+
const scaleY = viewportHeight / (bounds.height * 1.1);
|
|
20604
|
+
const fitScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
20605
|
+
const clampedFitScale = Math.max(fitScale, this.getEffectiveMinScale());
|
|
20606
|
+
const targetScale = Math.min(clampedFitScale, scale);
|
|
20607
|
+
// Animate to center the object at the target scale
|
|
20608
|
+
const objectCenterX = bounds.x + bounds.width / 2;
|
|
20609
|
+
const objectCenterY = bounds.y + bounds.height / 2;
|
|
20610
|
+
const targetTranslateX = viewportWidth / 2 - objectCenterX * targetScale;
|
|
20611
|
+
const targetTranslateY = viewportHeight / 2 - objectCenterY * targetScale;
|
|
20612
|
+
const clamped = this.clampTranslate(targetTranslateX, targetTranslateY);
|
|
20613
|
+
this.animateViewportTo(clamped.translateX, clamped.translateY, targetScale);
|
|
20614
|
+
}
|
|
20376
20615
|
/**
|
|
20377
20616
|
* Handles zoom operations triggered by wheel events with Ctrl key.
|
|
20378
20617
|
* Zooms around the cursor position, respecting scale limits.
|
|
@@ -20823,17 +21062,18 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
|
|
|
20823
21062
|
this._core.rerender();
|
|
20824
21063
|
}
|
|
20825
21064
|
this._core.store.state.contextMenuItems = this._core.store.selectionGroup ? this.objectContextMenuItems : this.globalContextMenuItems;
|
|
20826
|
-
|
|
20827
|
-
|
|
21065
|
+
const clickX = event.clientX - this._core.store.offsetX;
|
|
21066
|
+
const clickY = event.clientY - this._core.store.offsetY;
|
|
21067
|
+
const { translateX, translateY, scale } = this._core.store.state;
|
|
21068
|
+
this._core.store.state.contextMenuWorldX = (clickX - translateX) / scale;
|
|
21069
|
+
this._core.store.state.contextMenuWorldY = (clickY - translateY) / scale;
|
|
21070
|
+
let x = clickX;
|
|
21071
|
+
let y = clickY;
|
|
20828
21072
|
const menuWidthEstimate = 150;
|
|
20829
|
-
const menuHeightEstimate = 200;
|
|
20830
21073
|
const margin = 10;
|
|
20831
21074
|
if (x + menuWidthEstimate > window.innerWidth - margin) {
|
|
20832
21075
|
x = window.innerWidth - menuWidthEstimate - margin;
|
|
20833
21076
|
}
|
|
20834
|
-
if (y + menuHeightEstimate > window.innerHeight - margin) {
|
|
20835
|
-
y = window.innerHeight - menuHeightEstimate - margin;
|
|
20836
|
-
}
|
|
20837
21077
|
x = Math.max(margin, x);
|
|
20838
21078
|
y = Math.max(margin, y);
|
|
20839
21079
|
this._core.store.state.contextMenuX = x;
|
|
@@ -21099,6 +21339,8 @@ const DEFAULT_ENGINE_CONFIG = {
|
|
|
21099
21339
|
contextMenuItems: [],
|
|
21100
21340
|
contextMenuX: 0,
|
|
21101
21341
|
contextMenuY: 0,
|
|
21342
|
+
contextMenuWorldX: 0,
|
|
21343
|
+
contextMenuWorldY: 0,
|
|
21102
21344
|
skipContextMenu: false,
|
|
21103
21345
|
debugInfo: {
|
|
21104
21346
|
showObjectInfo: false,
|
|
@@ -24106,21 +24348,26 @@ class KritzelCore {
|
|
|
24106
24348
|
if (copiedObjects.length === 1) {
|
|
24107
24349
|
selectionGroup.rotation = copiedObjects[0].rotation;
|
|
24108
24350
|
}
|
|
24109
|
-
//
|
|
24110
|
-
|
|
24111
|
-
//
|
|
24351
|
+
// For cross-workspace paste, set the selection group's position before inserting
|
|
24352
|
+
// it into the store. This mirrors the existing pattern where objects have
|
|
24353
|
+
// updatePosition called before addObject, so the correct position is captured
|
|
24354
|
+
// in the single initial insert with no separate Yjs update (and no extra undo step).
|
|
24112
24355
|
if (isDifferentWorkspace) {
|
|
24113
24356
|
if (x !== undefined && y !== undefined) {
|
|
24114
|
-
//
|
|
24357
|
+
// Explicit cursor position provided (e.g. right-click paste)
|
|
24115
24358
|
selectionGroup.updatePosition(x, y);
|
|
24116
24359
|
}
|
|
24117
24360
|
else {
|
|
24118
|
-
//
|
|
24361
|
+
// Ctrl+V paste: center objects in the current viewport
|
|
24119
24362
|
selectionGroup.centerInViewport();
|
|
24120
24363
|
}
|
|
24121
|
-
// Fit the viewport to show the pasted objects
|
|
24122
|
-
this.engine.viewport.centerFitInViewport(selectionGroup);
|
|
24123
24364
|
}
|
|
24365
|
+
// Add the selection group (inserts with the already-adjusted position)
|
|
24366
|
+
this.addSelectionGroup(selectionGroup);
|
|
24367
|
+
// Bring pasted objects into view with a smooth animation if they are not
|
|
24368
|
+
// fully visible. These only mutate in-memory viewport state (scale, translateX/Y)
|
|
24369
|
+
// and do not produce any Yjs writes, so they have no impact on the undo history.
|
|
24370
|
+
this.engine.viewport.bringIntoViewIfNeeded(selectionGroup);
|
|
24124
24371
|
this._store.state.isSelecting = false;
|
|
24125
24372
|
// Defer creating copies for future pastes to next frame to avoid
|
|
24126
24373
|
// doubling the object creation cost in the current paste frame
|
|
@@ -26185,9 +26432,9 @@ const KritzelEngine = class {
|
|
|
26185
26432
|
if (isInsideDialog) {
|
|
26186
26433
|
return false;
|
|
26187
26434
|
}
|
|
26188
|
-
const target =
|
|
26435
|
+
const target = path[0];
|
|
26189
26436
|
// Don't handle if target is an interactive element that needs keyboard input
|
|
26190
|
-
if (target.matches?.('input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
|
|
26437
|
+
if (target instanceof HTMLElement && target.matches?.('input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
|
|
26191
26438
|
return false;
|
|
26192
26439
|
}
|
|
26193
26440
|
// Handle global shortcuts when no interactive element has focus
|
|
@@ -27865,8 +28112,8 @@ const KritzelEngine = class {
|
|
|
27865
28112
|
}, onActionSelected: event => {
|
|
27866
28113
|
if (event.detail.action) {
|
|
27867
28114
|
event.detail.action({
|
|
27868
|
-
x:
|
|
27869
|
-
y:
|
|
28115
|
+
x: this.core.store.state.contextMenuWorldX,
|
|
28116
|
+
y: this.core.store.state.contextMenuWorldY,
|
|
27870
28117
|
}, this.core.store.selectionGroup?.objects || []);
|
|
27871
28118
|
}
|
|
27872
28119
|
this.hideContextMenu();
|
|
@@ -27999,7 +28246,7 @@ const KritzelExport = class {
|
|
|
27999
28246
|
return (h("div", { class: "export-tab-content" }, h("kritzel-input", { label: "Filename", value: this.exportFilename, placeholder: "Enter filename", suffix: ".json", onValueChange: this.handleFilenameChange })));
|
|
28000
28247
|
}
|
|
28001
28248
|
render() {
|
|
28002
|
-
return (h(Host, { key: '5178e66f75b94697c771e2dc6fe7ce317e21cd1a' }, h("kritzel-dialog", { key: '
|
|
28249
|
+
return (h(Host, { key: '5178e66f75b94697c771e2dc6fe7ce317e21cd1a' }, h("kritzel-dialog", { key: 'f80cbe3fa709ed7e046303034b7345ca1f94bc48', isOpen: this.isDialogOpen, dialogTitle: "Export", closable: true, contained: true, onDialogClose: this.closeDialog }, h("div", { key: 'e7968807c2b67ebfc800cb1694b4e34af245ffba', class: "export-content" }, h("kritzel-pill-tabs", { key: 'eac62225c4c42431296f330791a1fb2212f579f5', tabs: this.tabs, value: this.activeTab, onValueChange: this.handleTabChange }), this.activeTab === 'viewport' && this.renderViewportExport(), this.activeTab === 'workspace' && this.renderWorkspaceExport(), h("button", { key: '3489affca39a901c2ef05a0698cdf51c0a7f6d1a', class: "export-primary-button", onClick: this.handleExport }, "Export")))));
|
|
28003
28250
|
}
|
|
28004
28251
|
};
|
|
28005
28252
|
KritzelExport.style = kritzelExportCss();
|
|
@@ -28296,7 +28543,7 @@ const KritzelLoginDialog = class {
|
|
|
28296
28543
|
this.dialogClosed.emit();
|
|
28297
28544
|
};
|
|
28298
28545
|
render() {
|
|
28299
|
-
return (h(Host, { key: '1a664868b840030a773f61c2a0f4388dfb014675' }, h("kritzel-dialog", { key: '
|
|
28546
|
+
return (h(Host, { key: '1a664868b840030a773f61c2a0f4388dfb014675' }, h("kritzel-dialog", { key: '54844ffa772a211515c1ef3e6834ec45f7f3d035', dialogTitle: this.dialogTitle, isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small", contained: true }, h("div", { key: 'd9b981b6904c58bc39173ae37ee5c4c0ee329005', class: "login-content" }, this.subtitle && (h("p", { key: 'd4d200060507d2b8b755796d8313acdfc7e2f587', class: "login-subtitle" }, this.subtitle)), h("div", { key: '3dc1e3c070e62d026eb16ceb48eb63c94bc2bed0', class: "login-providers" }, this.providers.map(provider => (h("button", { key: provider.name, class: {
|
|
28300
28547
|
'provider-button': true,
|
|
28301
28548
|
'is-loading': this.loadingProvider === provider.name,
|
|
28302
28549
|
'is-disabled': this.loadingProvider !== null && this.loadingProvider !== provider.name,
|
|
@@ -28483,7 +28730,7 @@ const KritzelMenu = class {
|
|
|
28483
28730
|
this.itemCloseChildMenu.emit(event.detail);
|
|
28484
28731
|
};
|
|
28485
28732
|
render() {
|
|
28486
|
-
return (h(Host, { key: 'a81ea8a1fe2dc6cb8d9f395cafbcadec3eb4aa45', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: 'bb27d7a923431d79567e79283e505ea4ae02ef36', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (h("kritzel-menu-item", { key: item.id, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
|
|
28733
|
+
return (h(Host, { key: 'a81ea8a1fe2dc6cb8d9f395cafbcadec3eb4aa45', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: 'bb27d7a923431d79567e79283e505ea4ae02ef36', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (h("kritzel-menu-item", { key: item.id, "data-testid": `menu-item-${item.id}`, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
|
|
28487
28734
|
}
|
|
28488
28735
|
};
|
|
28489
28736
|
KritzelMenu.style = kritzelMenuCss();
|
|
@@ -28664,7 +28911,7 @@ const KritzelMoreMenu = class {
|
|
|
28664
28911
|
this.closeMenu();
|
|
28665
28912
|
};
|
|
28666
28913
|
render() {
|
|
28667
|
-
return (h(Host, { key: '0e12ffc8c72566ec92080e6a19bd1d929795bef9', class: { mobile: this.isTouchDevice } }, h("div", { key: 'cc73b51c5aa39522a7ab7ec23d5c0a2732ed7acc', class: { 'more-menu-wrapper': true, visible: this.visible } }, h("button", { key: '
|
|
28914
|
+
return (h(Host, { key: '0e12ffc8c72566ec92080e6a19bd1d929795bef9', class: { mobile: this.isTouchDevice } }, h("div", { key: 'cc73b51c5aa39522a7ab7ec23d5c0a2732ed7acc', class: { 'more-menu-wrapper': true, visible: this.visible } }, h("button", { key: '6b4bda0bcfec9ef9a5506f844c835d8e270b636e', class: "more-menu-button", "data-testid": "more-menu-button", onClick: this.toggleMenu }, h("kritzel-icon", { key: '0de3f4404db14c92b8d81d41514c62eac3b3e0f0', name: this.icon, size: this.iconSize })), h("kritzel-portal", { key: '6aad3b6ac4161c195a15a49b67005e9605253dbc', anchor: this.menuAnchor, offsetY: this.offsetY, onClose: this.closeMenu }, h("kritzel-menu", { key: 'aee02f7da9cbd2b49ee430fedc1a0404991982ba', items: this.visibleItems, onItemSelect: this.handleMenuItemSelect })))));
|
|
28668
28915
|
}
|
|
28669
28916
|
};
|
|
28670
28917
|
KritzelMoreMenu.style = kritzelMoreMenuCss();
|
|
@@ -29167,7 +29414,7 @@ const KritzelPortal = class {
|
|
|
29167
29414
|
* This file is auto-generated by the version bump scripts.
|
|
29168
29415
|
* Do not modify manually.
|
|
29169
29416
|
*/
|
|
29170
|
-
const KRITZEL_VERSION = '0.2.
|
|
29417
|
+
const KRITZEL_VERSION = '0.2.12';
|
|
29171
29418
|
|
|
29172
29419
|
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)}`;
|
|
29173
29420
|
|
|
@@ -29355,7 +29602,7 @@ const KritzelSettings = class {
|
|
|
29355
29602
|
}
|
|
29356
29603
|
}
|
|
29357
29604
|
render() {
|
|
29358
|
-
return (h(Host, { key: 'e86192a8ca49f8618d58ede4d04d321ea238d7d4' }, h("kritzel-dialog", { key: '
|
|
29605
|
+
return (h(Host, { key: 'e86192a8ca49f8618d58ede4d04d321ea238d7d4' }, h("kritzel-dialog", { key: '23a47a8cd9281794bfd2aec7edd6a4ef4b931550', isOpen: this.isDialogOpen, dialogTitle: "Settings", size: "large", contained: true, onDialogClose: this.closeDialog }, h("kritzel-master-detail", { key: '007c8a1c04bd0d692b55d88988b0f8874f9242a4', items: SETTINGS_CATEGORIES, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
|
|
29359
29606
|
}
|
|
29360
29607
|
static get watchers() { return {
|
|
29361
29608
|
"settings": [{
|
|
@@ -29486,9 +29733,9 @@ const KritzelShareDialog = class {
|
|
|
29486
29733
|
this.dialogClosed.emit();
|
|
29487
29734
|
};
|
|
29488
29735
|
render() {
|
|
29489
|
-
return (h(Host, { key: 'bd58f146337b3eca96ca34408a3d30621f01765a' }, h("kritzel-dialog", { key: '
|
|
29736
|
+
return (h(Host, { key: 'bd58f146337b3eca96ca34408a3d30621f01765a' }, h("kritzel-dialog", { key: '0575ac82e19d07cf909556cae2ec433e0057fd5b', dialogTitle: "Share Workspace", size: "small", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, contained: true }, h("div", { key: 'c51d207e31255f45724103bfecbe858f13a721e6', class: "share-content" }, h("div", { key: 'ca6cb7721b9ba834c133b2cb953b208475e34fb5', class: "share-section" }, h("div", { key: '2c76845c903cc1c18cc26b9111d608e732ed12a5', class: "share-row" }, h("div", { key: '7700533f54372bc81d8d795414318a6bf0e93c47', class: "share-label-group" }, h("label", { key: 'a1d80009cb09cfe35bce35ce1151bf0754b052c1', class: "share-label" }, "Link sharing"), h("p", { key: '10c1963e95e658c7fb86174f1dba7565ce40d5a6', class: "share-description" }, this.internalIsPublic
|
|
29490
29737
|
? 'Anyone with the link can access this workspace.'
|
|
29491
|
-
: 'Link sharing is disabled. Only you can access this workspace.')), h("kritzel-slide-toggle", { key: '
|
|
29738
|
+
: 'Link sharing is disabled. Only you can access this workspace.')), h("kritzel-slide-toggle", { key: 'ec62a5ece12be0cea18a16c5d41db0a992309174', checked: this.internalIsPublic, onCheckedChange: this.handleToggleChange, label: "Enable link sharing" }))), this.internalIsPublic && (h("div", { key: '5e826d4c8c37792ba3a74a0189ad313a8ab482e2', class: "share-section" }, h("div", { key: 'f8e35cda32cb34ab21f56335aa27503fd6fe98c4', class: "share-url-container" }, h("input", { key: '47feb20a1843e1d3d8f7d146d71574b187002e8d', type: "text", class: "share-url-input", value: this.getShareUrl(), readOnly: true, onClick: (e) => e.target.select() }), h("button", { key: '052f56f35d057430cbc8fd03da5bef574b173791', class: { 'copy-button': true, 'copy-success': this.copySuccess }, onClick: this.handleCopyUrl, title: this.copySuccess ? 'Copied!' : 'Copy link' }, h("kritzel-icon", { key: '4e1de478f837a352185be2a06e15796dc1fb2f5e', name: this.copySuccess ? 'check' : 'copy', size: 18 })))))))));
|
|
29492
29739
|
}
|
|
29493
29740
|
static get watchers() { return {
|
|
29494
29741
|
"isPublic": [{
|