kritzel-stencil 0.2.11 → 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 +93 -20
- 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-engine/kritzel-engine.js +4 -4
- package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +1 -1
- package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +1 -1
- 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-editor.js +1 -1
- package/dist/components/kritzel-engine.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-split-button.js +1 -1
- package/dist/components/kritzel-workspace-manager.js +1 -1
- 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-DqJ9KC24.js → p-CS3JA3yn.js} +1 -1
- 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-DzxPDPED.js +1 -0
- package/dist/esm/kritzel-active-users_42.entry.js +93 -20
- 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/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-xHh03blG.js +0 -1
- package/dist/stencil/p-836d973c.entry.js +0 -9
|
@@ -20569,6 +20569,71 @@ class KritzelViewport {
|
|
|
20569
20569
|
this._core.store.state.scale = clampedScale;
|
|
20570
20570
|
this.centerInViewport(object);
|
|
20571
20571
|
}
|
|
20572
|
+
/**
|
|
20573
|
+
* Centers the viewport on a given object and zooms out only if the object
|
|
20574
|
+
* does not fit at the current scale. Never zooms in — if the object already
|
|
20575
|
+
* fits, the scale is left unchanged.
|
|
20576
|
+
* @param object - The object to fit in the viewport
|
|
20577
|
+
*/
|
|
20578
|
+
centerFitInViewportIfNeeded(object) {
|
|
20579
|
+
const scaleX = this._core.store.state.viewportWidth / (object.rotatedBoundingBox.width * 1.1);
|
|
20580
|
+
const scaleY = this._core.store.state.viewportHeight / (object.rotatedBoundingBox.height * 1.1);
|
|
20581
|
+
const newScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
20582
|
+
const clampedScale = Math.max(newScale, this.getEffectiveMinScale());
|
|
20583
|
+
if (clampedScale < this._core.store.state.scale) {
|
|
20584
|
+
this._core.store.state.scale = clampedScale;
|
|
20585
|
+
}
|
|
20586
|
+
this.centerInViewport(object);
|
|
20587
|
+
}
|
|
20588
|
+
/**
|
|
20589
|
+
* Zooms out and centers the viewport on a given object only if the object
|
|
20590
|
+
* does not fit at the current scale. If the object already fits, the
|
|
20591
|
+
* viewport is left completely unchanged.
|
|
20592
|
+
* @param object - The object to check and fit in the viewport
|
|
20593
|
+
*/
|
|
20594
|
+
fitInViewportIfNeeded(object) {
|
|
20595
|
+
const scaleX = this._core.store.state.viewportWidth / (object.rotatedBoundingBox.width * 1.1);
|
|
20596
|
+
const scaleY = this._core.store.state.viewportHeight / (object.rotatedBoundingBox.height * 1.1);
|
|
20597
|
+
const newScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
20598
|
+
const clampedScale = Math.max(newScale, this.getEffectiveMinScale());
|
|
20599
|
+
if (clampedScale < this._core.store.state.scale) {
|
|
20600
|
+
this._core.store.state.scale = clampedScale;
|
|
20601
|
+
this.centerInViewport(object);
|
|
20602
|
+
}
|
|
20603
|
+
}
|
|
20604
|
+
/**
|
|
20605
|
+
* Smoothly brings a given object into view if it is not fully visible within
|
|
20606
|
+
* the current viewport. Zooms out only if the object is too large to fit at
|
|
20607
|
+
* the current scale; never zooms in. If the object is already fully visible,
|
|
20608
|
+
* the viewport is left unchanged.
|
|
20609
|
+
* @param object - The object to bring into view
|
|
20610
|
+
*/
|
|
20611
|
+
bringIntoViewIfNeeded(object) {
|
|
20612
|
+
const { scale, translateX, translateY, viewportWidth, viewportHeight } = this._core.store.state;
|
|
20613
|
+
const bounds = object.rotatedBoundingBox;
|
|
20614
|
+
// Compute the object's bounding box in screen-space coordinates
|
|
20615
|
+
const screenLeft = bounds.x * scale + translateX;
|
|
20616
|
+
const screenTop = bounds.y * scale + translateY;
|
|
20617
|
+
const screenRight = (bounds.x + bounds.width) * scale + translateX;
|
|
20618
|
+
const screenBottom = (bounds.y + bounds.height) * scale + translateY;
|
|
20619
|
+
// If fully visible, no adjustment needed
|
|
20620
|
+
if (screenLeft >= 0 && screenTop >= 0 && screenRight <= viewportWidth && screenBottom <= viewportHeight) {
|
|
20621
|
+
return;
|
|
20622
|
+
}
|
|
20623
|
+
// Calculate the scale needed to fit the object with padding; never zoom in
|
|
20624
|
+
const scaleX = viewportWidth / (bounds.width * 1.1);
|
|
20625
|
+
const scaleY = viewportHeight / (bounds.height * 1.1);
|
|
20626
|
+
const fitScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
20627
|
+
const clampedFitScale = Math.max(fitScale, this.getEffectiveMinScale());
|
|
20628
|
+
const targetScale = Math.min(clampedFitScale, scale);
|
|
20629
|
+
// Animate to center the object at the target scale
|
|
20630
|
+
const objectCenterX = bounds.x + bounds.width / 2;
|
|
20631
|
+
const objectCenterY = bounds.y + bounds.height / 2;
|
|
20632
|
+
const targetTranslateX = viewportWidth / 2 - objectCenterX * targetScale;
|
|
20633
|
+
const targetTranslateY = viewportHeight / 2 - objectCenterY * targetScale;
|
|
20634
|
+
const clamped = this.clampTranslate(targetTranslateX, targetTranslateY);
|
|
20635
|
+
this.animateViewportTo(clamped.translateX, clamped.translateY, targetScale);
|
|
20636
|
+
}
|
|
20572
20637
|
/**
|
|
20573
20638
|
* Handles zoom operations triggered by wheel events with Ctrl key.
|
|
20574
20639
|
* Zooms around the cursor position, respecting scale limits.
|
|
@@ -21019,17 +21084,18 @@ class KritzelContextMenuHandler extends workspace_migrations.KritzelBaseHandler
|
|
|
21019
21084
|
this._core.rerender();
|
|
21020
21085
|
}
|
|
21021
21086
|
this._core.store.state.contextMenuItems = this._core.store.selectionGroup ? this.objectContextMenuItems : this.globalContextMenuItems;
|
|
21022
|
-
|
|
21023
|
-
|
|
21087
|
+
const clickX = event.clientX - this._core.store.offsetX;
|
|
21088
|
+
const clickY = event.clientY - this._core.store.offsetY;
|
|
21089
|
+
const { translateX, translateY, scale } = this._core.store.state;
|
|
21090
|
+
this._core.store.state.contextMenuWorldX = (clickX - translateX) / scale;
|
|
21091
|
+
this._core.store.state.contextMenuWorldY = (clickY - translateY) / scale;
|
|
21092
|
+
let x = clickX;
|
|
21093
|
+
let y = clickY;
|
|
21024
21094
|
const menuWidthEstimate = 150;
|
|
21025
|
-
const menuHeightEstimate = 200;
|
|
21026
21095
|
const margin = 10;
|
|
21027
21096
|
if (x + menuWidthEstimate > window.innerWidth - margin) {
|
|
21028
21097
|
x = window.innerWidth - menuWidthEstimate - margin;
|
|
21029
21098
|
}
|
|
21030
|
-
if (y + menuHeightEstimate > window.innerHeight - margin) {
|
|
21031
|
-
y = window.innerHeight - menuHeightEstimate - margin;
|
|
21032
|
-
}
|
|
21033
21099
|
x = Math.max(margin, x);
|
|
21034
21100
|
y = Math.max(margin, y);
|
|
21035
21101
|
this._core.store.state.contextMenuX = x;
|
|
@@ -21295,6 +21361,8 @@ const DEFAULT_ENGINE_CONFIG = {
|
|
|
21295
21361
|
contextMenuItems: [],
|
|
21296
21362
|
contextMenuX: 0,
|
|
21297
21363
|
contextMenuY: 0,
|
|
21364
|
+
contextMenuWorldX: 0,
|
|
21365
|
+
contextMenuWorldY: 0,
|
|
21298
21366
|
skipContextMenu: false,
|
|
21299
21367
|
debugInfo: {
|
|
21300
21368
|
showObjectInfo: false,
|
|
@@ -24302,21 +24370,26 @@ class KritzelCore {
|
|
|
24302
24370
|
if (copiedObjects.length === 1) {
|
|
24303
24371
|
selectionGroup.rotation = copiedObjects[0].rotation;
|
|
24304
24372
|
}
|
|
24305
|
-
//
|
|
24306
|
-
|
|
24307
|
-
//
|
|
24373
|
+
// For cross-workspace paste, set the selection group's position before inserting
|
|
24374
|
+
// it into the store. This mirrors the existing pattern where objects have
|
|
24375
|
+
// updatePosition called before addObject, so the correct position is captured
|
|
24376
|
+
// in the single initial insert with no separate Yjs update (and no extra undo step).
|
|
24308
24377
|
if (isDifferentWorkspace) {
|
|
24309
24378
|
if (x !== undefined && y !== undefined) {
|
|
24310
|
-
//
|
|
24379
|
+
// Explicit cursor position provided (e.g. right-click paste)
|
|
24311
24380
|
selectionGroup.updatePosition(x, y);
|
|
24312
24381
|
}
|
|
24313
24382
|
else {
|
|
24314
|
-
//
|
|
24383
|
+
// Ctrl+V paste: center objects in the current viewport
|
|
24315
24384
|
selectionGroup.centerInViewport();
|
|
24316
24385
|
}
|
|
24317
|
-
// Fit the viewport to show the pasted objects
|
|
24318
|
-
this.engine.viewport.centerFitInViewport(selectionGroup);
|
|
24319
24386
|
}
|
|
24387
|
+
// Add the selection group (inserts with the already-adjusted position)
|
|
24388
|
+
this.addSelectionGroup(selectionGroup);
|
|
24389
|
+
// Bring pasted objects into view with a smooth animation if they are not
|
|
24390
|
+
// fully visible. These only mutate in-memory viewport state (scale, translateX/Y)
|
|
24391
|
+
// and do not produce any Yjs writes, so they have no impact on the undo history.
|
|
24392
|
+
this.engine.viewport.bringIntoViewIfNeeded(selectionGroup);
|
|
24320
24393
|
this._store.state.isSelecting = false;
|
|
24321
24394
|
// Defer creating copies for future pastes to next frame to avoid
|
|
24322
24395
|
// doubling the object creation cost in the current paste frame
|
|
@@ -26381,9 +26454,9 @@ const KritzelEngine = class {
|
|
|
26381
26454
|
if (isInsideDialog) {
|
|
26382
26455
|
return false;
|
|
26383
26456
|
}
|
|
26384
|
-
const target =
|
|
26457
|
+
const target = path[0];
|
|
26385
26458
|
// Don't handle if target is an interactive element that needs keyboard input
|
|
26386
|
-
if (target.matches?.('input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
|
|
26459
|
+
if (target instanceof HTMLElement && target.matches?.('input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
|
|
26387
26460
|
return false;
|
|
26388
26461
|
}
|
|
26389
26462
|
// Handle global shortcuts when no interactive element has focus
|
|
@@ -28061,8 +28134,8 @@ const KritzelEngine = class {
|
|
|
28061
28134
|
}, onActionSelected: event => {
|
|
28062
28135
|
if (event.detail.action) {
|
|
28063
28136
|
event.detail.action({
|
|
28064
|
-
x:
|
|
28065
|
-
y:
|
|
28137
|
+
x: this.core.store.state.contextMenuWorldX,
|
|
28138
|
+
y: this.core.store.state.contextMenuWorldY,
|
|
28066
28139
|
}, this.core.store.selectionGroup?.objects || []);
|
|
28067
28140
|
}
|
|
28068
28141
|
this.hideContextMenu();
|
|
@@ -28679,7 +28752,7 @@ const KritzelMenu = class {
|
|
|
28679
28752
|
this.itemCloseChildMenu.emit(event.detail);
|
|
28680
28753
|
};
|
|
28681
28754
|
render() {
|
|
28682
|
-
return (index.h(index.Host, { key: 'a81ea8a1fe2dc6cb8d9f395cafbcadec3eb4aa45', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && index.h("div", { key: 'bb27d7a923431d79567e79283e505ea4ae02ef36', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (index.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 })))));
|
|
28755
|
+
return (index.h(index.Host, { key: 'a81ea8a1fe2dc6cb8d9f395cafbcadec3eb4aa45', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && index.h("div", { key: 'bb27d7a923431d79567e79283e505ea4ae02ef36', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (index.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 })))));
|
|
28683
28756
|
}
|
|
28684
28757
|
};
|
|
28685
28758
|
KritzelMenu.style = kritzelMenuCss();
|
|
@@ -28860,7 +28933,7 @@ const KritzelMoreMenu = class {
|
|
|
28860
28933
|
this.closeMenu();
|
|
28861
28934
|
};
|
|
28862
28935
|
render() {
|
|
28863
|
-
return (index.h(index.Host, { key: '0e12ffc8c72566ec92080e6a19bd1d929795bef9', class: { mobile: this.isTouchDevice } }, index.h("div", { key: 'cc73b51c5aa39522a7ab7ec23d5c0a2732ed7acc', class: { 'more-menu-wrapper': true, visible: this.visible } }, index.h("button", { key: '
|
|
28936
|
+
return (index.h(index.Host, { key: '0e12ffc8c72566ec92080e6a19bd1d929795bef9', class: { mobile: this.isTouchDevice } }, index.h("div", { key: 'cc73b51c5aa39522a7ab7ec23d5c0a2732ed7acc', class: { 'more-menu-wrapper': true, visible: this.visible } }, index.h("button", { key: '6b4bda0bcfec9ef9a5506f844c835d8e270b636e', class: "more-menu-button", "data-testid": "more-menu-button", onClick: this.toggleMenu }, index.h("kritzel-icon", { key: '0de3f4404db14c92b8d81d41514c62eac3b3e0f0', name: this.icon, size: this.iconSize })), index.h("kritzel-portal", { key: '6aad3b6ac4161c195a15a49b67005e9605253dbc', anchor: this.menuAnchor, offsetY: this.offsetY, onClose: this.closeMenu }, index.h("kritzel-menu", { key: 'aee02f7da9cbd2b49ee430fedc1a0404991982ba', items: this.visibleItems, onItemSelect: this.handleMenuItemSelect })))));
|
|
28864
28937
|
}
|
|
28865
28938
|
};
|
|
28866
28939
|
KritzelMoreMenu.style = kritzelMoreMenuCss();
|
|
@@ -29363,7 +29436,7 @@ const KritzelPortal = class {
|
|
|
29363
29436
|
* This file is auto-generated by the version bump scripts.
|
|
29364
29437
|
* Do not modify manually.
|
|
29365
29438
|
*/
|
|
29366
|
-
const KRITZEL_VERSION = '0.2.
|
|
29439
|
+
const KRITZEL_VERSION = '0.2.12';
|
|
29367
29440
|
|
|
29368
29441
|
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)}`;
|
|
29369
29442
|
|
|
@@ -789,21 +789,26 @@ export class KritzelCore {
|
|
|
789
789
|
if (copiedObjects.length === 1) {
|
|
790
790
|
selectionGroup.rotation = copiedObjects[0].rotation;
|
|
791
791
|
}
|
|
792
|
-
//
|
|
793
|
-
|
|
794
|
-
//
|
|
792
|
+
// For cross-workspace paste, set the selection group's position before inserting
|
|
793
|
+
// it into the store. This mirrors the existing pattern where objects have
|
|
794
|
+
// updatePosition called before addObject, so the correct position is captured
|
|
795
|
+
// in the single initial insert with no separate Yjs update (and no extra undo step).
|
|
795
796
|
if (isDifferentWorkspace) {
|
|
796
797
|
if (x !== undefined && y !== undefined) {
|
|
797
|
-
//
|
|
798
|
+
// Explicit cursor position provided (e.g. right-click paste)
|
|
798
799
|
selectionGroup.updatePosition(x, y);
|
|
799
800
|
}
|
|
800
801
|
else {
|
|
801
|
-
//
|
|
802
|
+
// Ctrl+V paste: center objects in the current viewport
|
|
802
803
|
selectionGroup.centerInViewport();
|
|
803
804
|
}
|
|
804
|
-
// Fit the viewport to show the pasted objects
|
|
805
|
-
this.engine.viewport.centerFitInViewport(selectionGroup);
|
|
806
805
|
}
|
|
806
|
+
// Add the selection group (inserts with the already-adjusted position)
|
|
807
|
+
this.addSelectionGroup(selectionGroup);
|
|
808
|
+
// Bring pasted objects into view with a smooth animation if they are not
|
|
809
|
+
// fully visible. These only mutate in-memory viewport state (scale, translateX/Y)
|
|
810
|
+
// and do not produce any Yjs writes, so they have no impact on the undo history.
|
|
811
|
+
this.engine.viewport.bringIntoViewIfNeeded(selectionGroup);
|
|
807
812
|
this._store.state.isSelecting = false;
|
|
808
813
|
// Defer creating copies for future pastes to next frame to avoid
|
|
809
814
|
// doubling the object creation cost in the current paste frame
|
|
@@ -429,6 +429,71 @@ export class KritzelViewport {
|
|
|
429
429
|
this._core.store.state.scale = clampedScale;
|
|
430
430
|
this.centerInViewport(object);
|
|
431
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Centers the viewport on a given object and zooms out only if the object
|
|
434
|
+
* does not fit at the current scale. Never zooms in — if the object already
|
|
435
|
+
* fits, the scale is left unchanged.
|
|
436
|
+
* @param object - The object to fit in the viewport
|
|
437
|
+
*/
|
|
438
|
+
centerFitInViewportIfNeeded(object) {
|
|
439
|
+
const scaleX = this._core.store.state.viewportWidth / (object.rotatedBoundingBox.width * 1.1);
|
|
440
|
+
const scaleY = this._core.store.state.viewportHeight / (object.rotatedBoundingBox.height * 1.1);
|
|
441
|
+
const newScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
442
|
+
const clampedScale = Math.max(newScale, this.getEffectiveMinScale());
|
|
443
|
+
if (clampedScale < this._core.store.state.scale) {
|
|
444
|
+
this._core.store.state.scale = clampedScale;
|
|
445
|
+
}
|
|
446
|
+
this.centerInViewport(object);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Zooms out and centers the viewport on a given object only if the object
|
|
450
|
+
* does not fit at the current scale. If the object already fits, the
|
|
451
|
+
* viewport is left completely unchanged.
|
|
452
|
+
* @param object - The object to check and fit in the viewport
|
|
453
|
+
*/
|
|
454
|
+
fitInViewportIfNeeded(object) {
|
|
455
|
+
const scaleX = this._core.store.state.viewportWidth / (object.rotatedBoundingBox.width * 1.1);
|
|
456
|
+
const scaleY = this._core.store.state.viewportHeight / (object.rotatedBoundingBox.height * 1.1);
|
|
457
|
+
const newScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
458
|
+
const clampedScale = Math.max(newScale, this.getEffectiveMinScale());
|
|
459
|
+
if (clampedScale < this._core.store.state.scale) {
|
|
460
|
+
this._core.store.state.scale = clampedScale;
|
|
461
|
+
this.centerInViewport(object);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Smoothly brings a given object into view if it is not fully visible within
|
|
466
|
+
* the current viewport. Zooms out only if the object is too large to fit at
|
|
467
|
+
* the current scale; never zooms in. If the object is already fully visible,
|
|
468
|
+
* the viewport is left unchanged.
|
|
469
|
+
* @param object - The object to bring into view
|
|
470
|
+
*/
|
|
471
|
+
bringIntoViewIfNeeded(object) {
|
|
472
|
+
const { scale, translateX, translateY, viewportWidth, viewportHeight } = this._core.store.state;
|
|
473
|
+
const bounds = object.rotatedBoundingBox;
|
|
474
|
+
// Compute the object's bounding box in screen-space coordinates
|
|
475
|
+
const screenLeft = bounds.x * scale + translateX;
|
|
476
|
+
const screenTop = bounds.y * scale + translateY;
|
|
477
|
+
const screenRight = (bounds.x + bounds.width) * scale + translateX;
|
|
478
|
+
const screenBottom = (bounds.y + bounds.height) * scale + translateY;
|
|
479
|
+
// If fully visible, no adjustment needed
|
|
480
|
+
if (screenLeft >= 0 && screenTop >= 0 && screenRight <= viewportWidth && screenBottom <= viewportHeight) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
// Calculate the scale needed to fit the object with padding; never zoom in
|
|
484
|
+
const scaleX = viewportWidth / (bounds.width * 1.1);
|
|
485
|
+
const scaleY = viewportHeight / (bounds.height * 1.1);
|
|
486
|
+
const fitScale = Math.min(scaleX, scaleY, this._core.store.state.scaleMax);
|
|
487
|
+
const clampedFitScale = Math.max(fitScale, this.getEffectiveMinScale());
|
|
488
|
+
const targetScale = Math.min(clampedFitScale, scale);
|
|
489
|
+
// Animate to center the object at the target scale
|
|
490
|
+
const objectCenterX = bounds.x + bounds.width / 2;
|
|
491
|
+
const objectCenterY = bounds.y + bounds.height / 2;
|
|
492
|
+
const targetTranslateX = viewportWidth / 2 - objectCenterX * targetScale;
|
|
493
|
+
const targetTranslateY = viewportHeight / 2 - objectCenterY * targetScale;
|
|
494
|
+
const clamped = this.clampTranslate(targetTranslateX, targetTranslateY);
|
|
495
|
+
this.animateViewportTo(clamped.translateX, clamped.translateY, targetScale);
|
|
496
|
+
}
|
|
432
497
|
/**
|
|
433
498
|
* Handles zoom operations triggered by wheel events with Ctrl key.
|
|
434
499
|
* Zooms around the cursor position, respecting scale limits.
|
|
@@ -72,17 +72,18 @@ export class KritzelContextMenuHandler extends KritzelBaseHandler {
|
|
|
72
72
|
this._core.rerender();
|
|
73
73
|
}
|
|
74
74
|
this._core.store.state.contextMenuItems = this._core.store.selectionGroup ? this.objectContextMenuItems : this.globalContextMenuItems;
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
const clickX = event.clientX - this._core.store.offsetX;
|
|
76
|
+
const clickY = event.clientY - this._core.store.offsetY;
|
|
77
|
+
const { translateX, translateY, scale } = this._core.store.state;
|
|
78
|
+
this._core.store.state.contextMenuWorldX = (clickX - translateX) / scale;
|
|
79
|
+
this._core.store.state.contextMenuWorldY = (clickY - translateY) / scale;
|
|
80
|
+
let x = clickX;
|
|
81
|
+
let y = clickY;
|
|
77
82
|
const menuWidthEstimate = 150;
|
|
78
|
-
const menuHeightEstimate = 200;
|
|
79
83
|
const margin = 10;
|
|
80
84
|
if (x + menuWidthEstimate > window.innerWidth - margin) {
|
|
81
85
|
x = window.innerWidth - menuWidthEstimate - margin;
|
|
82
86
|
}
|
|
83
|
-
if (y + menuHeightEstimate > window.innerHeight - margin) {
|
|
84
|
-
y = window.innerHeight - menuHeightEstimate - margin;
|
|
85
|
-
}
|
|
86
87
|
x = Math.max(margin, x);
|
|
87
88
|
y = Math.max(margin, y);
|
|
88
89
|
this._core.store.state.contextMenuX = x;
|
|
@@ -341,9 +341,9 @@ export class KritzelEngine {
|
|
|
341
341
|
if (isInsideDialog) {
|
|
342
342
|
return false;
|
|
343
343
|
}
|
|
344
|
-
const target =
|
|
344
|
+
const target = path[0];
|
|
345
345
|
// Don't handle if target is an interactive element that needs keyboard input
|
|
346
|
-
if (target.matches?.('input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
|
|
346
|
+
if (target instanceof HTMLElement && target.matches?.('input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
|
|
347
347
|
return false;
|
|
348
348
|
}
|
|
349
349
|
// Handle global shortcuts when no interactive element has focus
|
|
@@ -2006,8 +2006,8 @@ export class KritzelEngine {
|
|
|
2006
2006
|
}, onActionSelected: event => {
|
|
2007
2007
|
if (event.detail.action) {
|
|
2008
2008
|
event.detail.action({
|
|
2009
|
-
x:
|
|
2010
|
-
y:
|
|
2009
|
+
x: this.core.store.state.contextMenuWorldX,
|
|
2010
|
+
y: this.core.store.state.contextMenuWorldY,
|
|
2011
2011
|
}, this.core.store.selectionGroup?.objects || []);
|
|
2012
2012
|
}
|
|
2013
2013
|
this.hideContextMenu();
|
|
@@ -51,7 +51,7 @@ export class KritzelMenu {
|
|
|
51
51
|
this.itemCloseChildMenu.emit(event.detail);
|
|
52
52
|
};
|
|
53
53
|
render() {
|
|
54
|
-
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 })))));
|
|
54
|
+
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 })))));
|
|
55
55
|
}
|
|
56
56
|
static get is() { return "kritzel-menu"; }
|
|
57
57
|
static get encapsulation() { return "shadow"; }
|
|
@@ -55,7 +55,7 @@ export class KritzelMoreMenu {
|
|
|
55
55
|
this.closeMenu();
|
|
56
56
|
};
|
|
57
57
|
render() {
|
|
58
|
-
return (h(Host, { key: '0e12ffc8c72566ec92080e6a19bd1d929795bef9', class: { mobile: this.isTouchDevice } }, h("div", { key: 'cc73b51c5aa39522a7ab7ec23d5c0a2732ed7acc', class: { 'more-menu-wrapper': true, visible: this.visible } }, h("button", { key: '
|
|
58
|
+
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 })))));
|
|
59
59
|
}
|
|
60
60
|
static get is() { return "kritzel-more-menu"; }
|
|
61
61
|
static get encapsulation() { return "shadow"; }
|
package/dist/components/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{g as getAssetPath,r as render,s as setAssetPath,a as setNonce,b as setPlatformOptions}from"./p-BWj1eE2b.js";export{A as AssetNotFoundError,I as IndexedDBAssetProvider,i as KritzelAssetResolver,d as KritzelBrushTool,b as KritzelGroup,a as KritzelImage,e as KritzelLineTool,h as KritzelSelectionTool,c as KritzelShape,g as KritzelShapeTool,K as KritzelText,f as KritzelTextTool,S as ShapeType}from"./p-D9-C4GfD.js";export{a as KritzelLine,K as KritzelPath}from"./p-C4bAtxyk.js";export{A as APP_STATE_MIGRATIONS,I as IndexedDBSyncProvider,d as KritzelAlignment,c as KritzelAnchorManager,b as KritzelCursorHelper,K as KritzelEraserTool,a as KritzelImageTool,W as WORKSPACE_MIGRATIONS,r as runMigrations}from"./p-B_fA1LTU.js";import*as t from"yjs";import{WebsocketProvider as o}from"y-websocket";import{H as n,a as m}from"./kritzel-editor.js";export{d as DEFAULT_ASSET_STORAGE_CONFIG,D as DEFAULT_BRUSH_CONFIG,c as DEFAULT_LINE_TOOL_CONFIG,b as DEFAULT_TEXT_CONFIG,KritzelEditor,defineCustomElement as defineCustomElementKritzelEditor}from"./kritzel-editor.js";export{K as KritzelWorkspace,W as WORKSPACE_EXPORT_VERSION}from"./p-DhMlShij.js";export{K as KritzelThemeManager,d as darkTheme,l as lightTheme}from"./p-DjAiIBXv.js";export{C as CURRENT_APP_STATE_SCHEMA_VERSION,a as CURRENT_WORKSPACE_SCHEMA_VERSION}from"./p-CW-VyJgK.js";export{KritzelActiveUsers,defineCustomElement as defineCustomElementKritzelActiveUsers}from"./kritzel-active-users.js";export{KritzelAvatar,defineCustomElement as defineCustomElementKritzelAvatar}from"./kritzel-avatar.js";export{KritzelAwarenessCursors,defineCustomElement as defineCustomElementKritzelAwarenessCursors}from"./kritzel-awareness-cursors.js";export{KritzelBackToContent,defineCustomElement as defineCustomElementKritzelBackToContent}from"./kritzel-back-to-content.js";export{KritzelBrushStyle,defineCustomElement as defineCustomElementKritzelBrushStyle}from"./kritzel-brush-style.js";export{KritzelButton,defineCustomElement as defineCustomElementKritzelButton}from"./kritzel-button.js";export{KritzelColor,defineCustomElement as defineCustomElementKritzelColor}from"./kritzel-color.js";export{KritzelColorPalette,defineCustomElement as defineCustomElementKritzelColorPalette}from"./kritzel-color-palette.js";export{KritzelContextMenu,defineCustomElement as defineCustomElementKritzelContextMenu}from"./kritzel-context-menu.js";export{KritzelControls,defineCustomElement as defineCustomElementKritzelControls}from"./kritzel-controls.js";export{KritzelCurrentUser,defineCustomElement as defineCustomElementKritzelCurrentUser}from"./kritzel-current-user.js";export{KritzelCurrentUserDialog,defineCustomElement as defineCustomElementKritzelCurrentUserDialog}from"./kritzel-current-user-dialog.js";export{KritzelCursorTrail,defineCustomElement as defineCustomElementKritzelCursorTrail}from"./kritzel-cursor-trail.js";export{KritzelDialog,defineCustomElement as defineCustomElementKritzelDialog}from"./kritzel-dialog.js";export{KritzelDropdown,defineCustomElement as defineCustomElementKritzelDropdown}from"./kritzel-dropdown.js";export{KritzelEngine,defineCustomElement as defineCustomElementKritzelEngine}from"./kritzel-engine.js";export{KritzelExport,defineCustomElement as defineCustomElementKritzelExport}from"./kritzel-export.js";export{KritzelFont,defineCustomElement as defineCustomElementKritzelFont}from"./kritzel-font.js";export{KritzelFontFamily,defineCustomElement as defineCustomElementKritzelFontFamily}from"./kritzel-font-family.js";export{KritzelFontSize,defineCustomElement as defineCustomElementKritzelFontSize}from"./kritzel-font-size.js";export{KritzelIcon,defineCustomElement as defineCustomElementKritzelIcon}from"./kritzel-icon.js";export{KritzelInput,defineCustomElement as defineCustomElementKritzelInput}from"./kritzel-input.js";export{KritzelLineEndings,defineCustomElement as defineCustomElementKritzelLineEndings}from"./kritzel-line-endings.js";export{KritzelLoginDialog,defineCustomElement as defineCustomElementKritzelLoginDialog}from"./kritzel-login-dialog.js";export{KritzelMasterDetail,defineCustomElement as defineCustomElementKritzelMasterDetail}from"./kritzel-master-detail.js";export{KritzelMenu,defineCustomElement as defineCustomElementKritzelMenu}from"./kritzel-menu.js";export{KritzelMenuItem,defineCustomElement as defineCustomElementKritzelMenuItem}from"./kritzel-menu-item.js";export{KritzelMoreMenu,defineCustomElement as defineCustomElementKritzelMoreMenu}from"./kritzel-more-menu.js";export{KritzelNumericInput,defineCustomElement as defineCustomElementKritzelNumericInput}from"./kritzel-numeric-input.js";export{KritzelOpacitySlider,defineCustomElement as defineCustomElementKritzelOpacitySlider}from"./kritzel-opacity-slider.js";export{KritzelPillTabs,defineCustomElement as defineCustomElementKritzelPillTabs}from"./kritzel-pill-tabs.js";export{KritzelPortal,defineCustomElement as defineCustomElementKritzelPortal}from"./kritzel-portal.js";export{KritzelSettings,defineCustomElement as defineCustomElementKritzelSettings}from"./kritzel-settings.js";export{KritzelShapeFill,defineCustomElement as defineCustomElementKritzelShapeFill}from"./kritzel-shape-fill.js";export{KritzelShareDialog,defineCustomElement as defineCustomElementKritzelShareDialog}from"./kritzel-share-dialog.js";export{KritzelSlideToggle,defineCustomElement as defineCustomElementKritzelSlideToggle}from"./kritzel-slide-toggle.js";export{KritzelSplitButton,defineCustomElement as defineCustomElementKritzelSplitButton}from"./kritzel-split-button.js";export{KritzelStrokeSize,defineCustomElement as defineCustomElementKritzelStrokeSize}from"./kritzel-stroke-size.js";export{KritzelToolConfig,defineCustomElement as defineCustomElementKritzelToolConfig}from"./kritzel-tool-config.js";export{KritzelTooltip,defineCustomElement as defineCustomElementKritzelTooltip}from"./kritzel-tooltip.js";export{KritzelUtilityPanel,defineCustomElement as defineCustomElementKritzelUtilityPanel}from"./kritzel-utility-panel.js";export{KritzelWorkspaceManager,defineCustomElement as defineCustomElementKritzelWorkspaceManager}from"./kritzel-workspace-manager.js";const u=Math.floor,z=127,p=Number.MAX_SAFE_INTEGER;class E{constructor(){this.cpos=0,this.cbuf=new Uint8Array(100),this.bufs=[]}}const y=()=>new E,k=e=>{const t=new Uint8Array((e=>{let t=e.cpos;for(let s=0;s<e.bufs.length;s++)t+=e.bufs[s].length;return t})(e));let s=0;for(let i=0;i<e.bufs.length;i++){const o=e.bufs[i];t.set(o,s),s+=o.length}return t.set(new Uint8Array(e.cbuf.buffer,0,e.cpos),s),t},w=(e,t)=>{const s=e.cbuf.length;e.cpos===s&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(2*s),e.cpos=0),e.cbuf[e.cpos++]=t},x=(e,t)=>{for(;t>z;)w(e,128|z&t),t=u(t/128);w(e,z&t)},T=(e,t)=>{x(e,t.byteLength),((e,t)=>{const s=e.cbuf.length,i=e.cpos,o=((e,t)=>e<t?e:t)(s-i,t.length),n=t.length-o;e.cbuf.set(t.subarray(0,o),i),e.cpos+=o,n>0&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(((e,t)=>e>t?e:t)(2*s,n)),e.cbuf.set(t.subarray(o)),e.cpos=n)})(e,t)},j=e=>Error(e),P=j("Unexpected end of array"),v=j("Integer out of Range");class U{constructor(e){this.arr=e,this.pos=0}}const M=e=>((e,t)=>{const s=new Uint8Array(e.arr.buffer,e.pos+e.arr.byteOffset,t);return e.pos+=t,s})(e,_(e)),_=e=>{let t=0,s=1;const i=e.arr.length;for(;e.pos<i;){const i=e.arr[e.pos++];if(t+=(i&z)*s,s*=128,i<128)return t;if(t>p)throw v}throw P};class F{type="local";doc;channel;_synced=!1;constructor(e,t,s){this.doc=t,this.channel=new BroadcastChannel(e),this.channel.onmessage=e=>{this.handleMessage(e.data)},this.doc.on("update",this.handleDocUpdate),this.broadcastSync(),setTimeout((()=>{this._synced=!0}),100),s?.quiet||console.info("BroadcastChannel Provider initialized: "+e)}handleDocUpdate=(e,t)=>{if(t!==this){const t=y();x(t,0),T(t,e),this.channel.postMessage(k(t))}};handleMessage(e){const s=(e=>new U(e))(new Uint8Array(e));switch(_(s)){case 0:const e=M(s);t.applyUpdate(this.doc,e,this);break;case 1:this.broadcastSync();break;case 2:const i=M(s),o=t.encodeStateAsUpdate(this.doc,i);if(o.length>0){const e=y();x(e,0),T(e,o),this.channel.postMessage(k(e))}}}broadcastSync(){const e=y();x(e,2),T(e,t.encodeStateVector(this.doc)),this.channel.postMessage(k(e))}async connect(){if(!this._synced)return new Promise((e=>{const t=()=>{this._synced?e():setTimeout(t,50)};t()}))}disconnect(){}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.doc.off("update",this.handleDocUpdate),this.channel.close()}}class ${type="network";provider;isConnected=!1;_quiet=!1;get awareness(){return this.provider.awareness}constructor(e,t,s){const i=s?.url||"ws://localhost:1234",n=s?.roomName||e;this.provider=new o(i,n,t,{params:s?.params,protocols:s?.protocols,WebSocketPolyfill:s?.WebSocketPolyfill,awareness:s?.awareness,maxBackoffTime:s?.maxBackoffTime,disableBc:!0}),this._quiet=s?.quiet??!1,this.setupEventListeners(),this._quiet||console.info(`WebSocket Provider initialized: ${i}/${n}`)}static with(e){return{create:(t,s,i)=>{const o=i?{...e,...i}:e;return new $(t,s,o)}}}setupEventListeners(){this.provider.on("status",(({status:e})=>{"connected"===e?(this.isConnected=!0,this._quiet||console.info("WebSocket connected")):"disconnected"===e&&(this.isConnected=!1,this._quiet||console.info("WebSocket disconnected"))})),this.provider.on("sync",(e=>{e&&!this._quiet&&console.info("WebSocket synced")}))}async connect(){if(!this.isConnected)return new Promise(((e,t)=>{const s=setTimeout((()=>{t(Error("WebSocket connection timeout"))}),1e4),i=({status:t})=>{"connected"===t&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())};this.provider.on("status",i),this.provider.wsconnected&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())}))}disconnect(){this.provider&&this.provider.disconnect(),this.isConnected=!1}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.provider&&this.provider.destroy(),this.isConnected=!1}}class O{type="network";provider;isConnected=!1;isSynced=!1;usesSharedSocket=!1;isDestroyed=!1;connectTimeout=null;pendingConnectReject=null;connectionTimeoutMs;_connectionStatus="disconnected";visibilityHandler=null;onlineHandler=null;get awareness(){return this.provider.awareness}get connectionStatus(){return this._connectionStatus}static sharedWebSocketProvider=null;constructor(e,t,s){const i=s?.name||e,o=s?.url||"ws://localhost:1234";this.connectionTimeoutMs=s?.connectionTimeout??1e4;const r=s?.websocketProvider||O.sharedWebSocketProvider,l={};void 0!==s?.delay&&(l.delay=s.delay),void 0!==s?.factor&&(l.factor=s.factor),void 0!==s?.maxAttempts&&(l.maxAttempts=s.maxAttempts),void 0!==s?.minDelay&&(l.minDelay=s.minDelay),void 0!==s?.maxDelay&&(l.maxDelay=s.maxDelay);const a=()=>{this.isDestroyed||(this.isConnected=!0,this._connectionStatus="connected",s?.quiet||console.info("Hocuspocus connected: "+i),s?.onConnect&&s.onConnect())},c=()=>{this.isDestroyed||(this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected",s?.quiet||console.info("Hocuspocus disconnected: "+i),s?.onDisconnect&&s.onDisconnect())},m=()=>{this.isDestroyed||(this.isSynced=!0,this._connectionStatus="synced",s?.quiet||console.info("Hocuspocus synced: "+i),s?.onSynced&&s.onSynced())},d=e=>{this.isDestroyed||("connecting"===e.status&&(this._connectionStatus="connecting"),s?.onStatus&&s.onStatus(e))};if(r){this.usesSharedSocket=!0;const e={websocketProvider:r,name:i,document:t,token:s?.token||null,onStatus:d,onConnect:a,onDisconnect:c,onSynced:m,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),this.provider=new n(e),this.provider.attach(),s?.quiet||console.info("Hocuspocus Provider initialized (multiplexed): "+i)}else{this.usesSharedSocket=!1;const e={url:o,name:i,document:t,token:s?.token||null,autoConnect:!1,onStatus:d,onConnect:a,onDisconnect:c,onSynced:m,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),s?.WebSocketPolyfill&&(e.WebSocketPolyfill=s.WebSocketPolyfill),this.provider=new n(e),s?.quiet||console.info(`Hocuspocus Provider initialized: ${o}/${i}`)}this.setupBrowserEventListeners()}setupBrowserEventListeners(){"undefined"!=typeof document&&(this.visibilityHandler=()=>{"visible"!==document.visibilityState||this.isConnected||this.isDestroyed||this.provider.connect()},document.addEventListener("visibilitychange",this.visibilityHandler)),"undefined"!=typeof window&&(this.onlineHandler=()=>{this.isConnected||this.isDestroyed||this.provider.connect()},window.addEventListener("online",this.onlineHandler))}removeBrowserEventListeners(){this.visibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.onlineHandler&&"undefined"!=typeof window&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null)}static createSharedWebSocket(e){if(O.sharedWebSocketProvider)return console.warn("Shared WebSocket already exists. Returning existing instance."),O.sharedWebSocketProvider;const t={url:e.url};return e.WebSocketPolyfill&&(t.WebSocketPolyfill=e.WebSocketPolyfill),e.onConnect&&(t.onConnect=e.onConnect),e.onDisconnect&&(t.onDisconnect=e.onDisconnect),e.onStatus&&(t.onStatus=e.onStatus),O.sharedWebSocketProvider=new m(t),console.info("Shared Hocuspocus WebSocket created: "+e.url),O.sharedWebSocketProvider}static destroySharedWebSocket(){O.sharedWebSocketProvider&&(O.sharedWebSocketProvider.destroy(),O.sharedWebSocketProvider=null,console.info("Shared Hocuspocus WebSocket destroyed"))}static getSharedWebSocket(){return O.sharedWebSocketProvider}static with(e){return{create:(t,s,i)=>{const o=i?{...e,...i}:e;return new O(t,s,o)}}}async connect(){if(!this.isSynced&&!this.isDestroyed)return this._connectionStatus="connecting",new Promise(((e,t)=>{this.pendingConnectReject=t,this.connectTimeout=setTimeout((()=>{this.pendingConnectReject=null,this.connectTimeout=null,t(Error("Hocuspocus connection timeout"))}),this.connectionTimeoutMs);const s=()=>{this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),this.isDestroyed||e()};if(this.provider.on("synced",s),this.provider.isSynced)return this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),void e();this.isConnected||this.usesSharedSocket||this.provider.connect()}))}async reconnect(){return this.disconnect(),this.connect()}disconnect(){this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.provider&&(this.usesSharedSocket?this.provider.detach():this.provider.disconnect()),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}destroy(){this.isDestroyed=!0,this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.removeBrowserEventListeners(),this.provider&&this.provider.destroy(),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}}class B{type="remote";name="HttpAssetProvider";_options;constructor(e){this._options=e}static with(e){return{create:()=>new B(e)}}async init(){this._options.quiet||console.info("HttpAssetProvider initialized")}destroy(){}canResolve(e){return!0}async put(e,t){const s=t.id??this.generateUuid(),i={...t,id:s},o=await(this._options.headers?.())??{},n=await this._options.uploadUrl(i),r=this._options.upload??this.defaultUpload;return{id:(await r(n,e,i,o)).id??s,kind:t.kind??"file",mimeType:t.mimeType,size:e.size,createdAt:Date.now(),width:t.width,height:t.height,durationMs:t.durationMs,originalFilename:t.originalFilename}}async resolve(e){return this._options.resolveUrl(e)}async fetch(e){const t=await this._options.resolveUrl(e),s=await(this._options.headers?.())??{},i=await fetch(t,{headers:s});if(!i.ok)throw Error(`[HttpAssetProvider] Failed to fetch asset ${e}: ${i.status} ${i.statusText}`);return i.blob()}async delete(e){if(!this._options.deleteUrl)return;const t=await this._options.deleteUrl(e),s=await(this._options.headers?.())??{},i=await fetch(t,{method:"DELETE",headers:s});if(!i.ok)throw Error(`[HttpAssetProvider] Failed to delete asset ${e}: ${i.status} ${i.statusText}`);this._options.quiet||console.info("HttpAssetProvider: deleted asset "+e)}defaultUpload=async(e,t,s,i)=>{const o=new FormData;o.append("metadata",JSON.stringify(s)),o.append("file",t,s.originalFilename||`${s.id}.${this.extensionFromMime(s.mimeType)}`);const n=await fetch(e,{method:"POST",headers:i,body:o});if(!n.ok)throw Error(`[HttpAssetProvider] Upload failed: ${n.status} ${n.statusText}`);return(n.headers.get("content-type")||"").includes("application/json")?await n.json():{}};extensionFromMime(e){const t=e.indexOf("/");return t>=0?e.slice(t+1):"bin"}generateUuid(){if("undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID)return crypto.randomUUID();const e=crypto.getRandomValues(new Uint8Array(16));e[6]=15&e[6]|64,e[8]=63&e[8]|128;const t=Array.from(e,(e=>e.toString(16).padStart(2,"0"))).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}}class H{type="remote";name="PresignedAssetProvider";_options;constructor(e){this._options=e}static with(e){return{create:()=>new H(e)}}async init(){this._options.quiet||console.info("PresignedAssetProvider initialized")}destroy(){}canResolve(e){return!0}async put(e,t){const s=await this._options.getUploadDescriptor(t),i=s.method??"PUT",o={...s.headers??{}};let n;if(o["Content-Type"]||o["content-type"]||(o["Content-Type"]=t.mimeType),"POST"===i&&s.fields){const t=new FormData;for(const[e,i]of Object.entries(s.fields))t.append(e,i);t.append("file",e),n=t,delete o["Content-Type"],delete o["content-type"]}else n=e;const r=await fetch(s.url,{method:i,headers:o,body:n});if(!r.ok)throw Error(`[PresignedAssetProvider] Upload failed: ${r.status} ${r.statusText}`);return{id:s.id,kind:t.kind??"file",mimeType:t.mimeType,size:e.size,createdAt:Date.now(),width:t.width,height:t.height,durationMs:t.durationMs,originalFilename:t.originalFilename}}async resolve(e){return this._options.getDownloadUrl(e)}async fetch(e){const t=await this._options.getDownloadUrl(e),s=await fetch(t);if(!s.ok)throw Error(`[PresignedAssetProvider] Failed to fetch asset ${e}: ${s.status} ${s.statusText}`);return s.blob()}async delete(e){this._options.deleteAsset&&(await this._options.deleteAsset(e),this._options.quiet||console.info("PresignedAssetProvider: deleted asset "+e))}}export{F as BroadcastSyncProvider,O as HocuspocusSyncProvider,B as HttpAssetProvider,H as PresignedAssetProvider,$ as WebSocketSyncProvider}
|
|
1
|
+
export{g as getAssetPath,r as render,s as setAssetPath,a as setNonce,b as setPlatformOptions}from"./p-BWj1eE2b.js";export{A as AssetNotFoundError,I as IndexedDBAssetProvider,i as KritzelAssetResolver,d as KritzelBrushTool,b as KritzelGroup,a as KritzelImage,e as KritzelLineTool,h as KritzelSelectionTool,c as KritzelShape,g as KritzelShapeTool,K as KritzelText,f as KritzelTextTool,S as ShapeType}from"./p-D9-C4GfD.js";export{a as KritzelLine,K as KritzelPath}from"./p-C4bAtxyk.js";export{A as APP_STATE_MIGRATIONS,I as IndexedDBSyncProvider,d as KritzelAlignment,c as KritzelAnchorManager,b as KritzelCursorHelper,K as KritzelEraserTool,a as KritzelImageTool,W as WORKSPACE_MIGRATIONS,r as runMigrations}from"./p-BWB2UGxj.js";import*as t from"yjs";import{WebsocketProvider as o}from"y-websocket";import{H as n,a as m}from"./kritzel-editor.js";export{d as DEFAULT_ASSET_STORAGE_CONFIG,D as DEFAULT_BRUSH_CONFIG,c as DEFAULT_LINE_TOOL_CONFIG,b as DEFAULT_TEXT_CONFIG,KritzelEditor,defineCustomElement as defineCustomElementKritzelEditor}from"./kritzel-editor.js";export{K as KritzelWorkspace,W as WORKSPACE_EXPORT_VERSION}from"./p-DhMlShij.js";export{K as KritzelThemeManager,d as darkTheme,l as lightTheme}from"./p-DjAiIBXv.js";export{C as CURRENT_APP_STATE_SCHEMA_VERSION,a as CURRENT_WORKSPACE_SCHEMA_VERSION}from"./p-CW-VyJgK.js";export{KritzelActiveUsers,defineCustomElement as defineCustomElementKritzelActiveUsers}from"./kritzel-active-users.js";export{KritzelAvatar,defineCustomElement as defineCustomElementKritzelAvatar}from"./kritzel-avatar.js";export{KritzelAwarenessCursors,defineCustomElement as defineCustomElementKritzelAwarenessCursors}from"./kritzel-awareness-cursors.js";export{KritzelBackToContent,defineCustomElement as defineCustomElementKritzelBackToContent}from"./kritzel-back-to-content.js";export{KritzelBrushStyle,defineCustomElement as defineCustomElementKritzelBrushStyle}from"./kritzel-brush-style.js";export{KritzelButton,defineCustomElement as defineCustomElementKritzelButton}from"./kritzel-button.js";export{KritzelColor,defineCustomElement as defineCustomElementKritzelColor}from"./kritzel-color.js";export{KritzelColorPalette,defineCustomElement as defineCustomElementKritzelColorPalette}from"./kritzel-color-palette.js";export{KritzelContextMenu,defineCustomElement as defineCustomElementKritzelContextMenu}from"./kritzel-context-menu.js";export{KritzelControls,defineCustomElement as defineCustomElementKritzelControls}from"./kritzel-controls.js";export{KritzelCurrentUser,defineCustomElement as defineCustomElementKritzelCurrentUser}from"./kritzel-current-user.js";export{KritzelCurrentUserDialog,defineCustomElement as defineCustomElementKritzelCurrentUserDialog}from"./kritzel-current-user-dialog.js";export{KritzelCursorTrail,defineCustomElement as defineCustomElementKritzelCursorTrail}from"./kritzel-cursor-trail.js";export{KritzelDialog,defineCustomElement as defineCustomElementKritzelDialog}from"./kritzel-dialog.js";export{KritzelDropdown,defineCustomElement as defineCustomElementKritzelDropdown}from"./kritzel-dropdown.js";export{KritzelEngine,defineCustomElement as defineCustomElementKritzelEngine}from"./kritzel-engine.js";export{KritzelExport,defineCustomElement as defineCustomElementKritzelExport}from"./kritzel-export.js";export{KritzelFont,defineCustomElement as defineCustomElementKritzelFont}from"./kritzel-font.js";export{KritzelFontFamily,defineCustomElement as defineCustomElementKritzelFontFamily}from"./kritzel-font-family.js";export{KritzelFontSize,defineCustomElement as defineCustomElementKritzelFontSize}from"./kritzel-font-size.js";export{KritzelIcon,defineCustomElement as defineCustomElementKritzelIcon}from"./kritzel-icon.js";export{KritzelInput,defineCustomElement as defineCustomElementKritzelInput}from"./kritzel-input.js";export{KritzelLineEndings,defineCustomElement as defineCustomElementKritzelLineEndings}from"./kritzel-line-endings.js";export{KritzelLoginDialog,defineCustomElement as defineCustomElementKritzelLoginDialog}from"./kritzel-login-dialog.js";export{KritzelMasterDetail,defineCustomElement as defineCustomElementKritzelMasterDetail}from"./kritzel-master-detail.js";export{KritzelMenu,defineCustomElement as defineCustomElementKritzelMenu}from"./kritzel-menu.js";export{KritzelMenuItem,defineCustomElement as defineCustomElementKritzelMenuItem}from"./kritzel-menu-item.js";export{KritzelMoreMenu,defineCustomElement as defineCustomElementKritzelMoreMenu}from"./kritzel-more-menu.js";export{KritzelNumericInput,defineCustomElement as defineCustomElementKritzelNumericInput}from"./kritzel-numeric-input.js";export{KritzelOpacitySlider,defineCustomElement as defineCustomElementKritzelOpacitySlider}from"./kritzel-opacity-slider.js";export{KritzelPillTabs,defineCustomElement as defineCustomElementKritzelPillTabs}from"./kritzel-pill-tabs.js";export{KritzelPortal,defineCustomElement as defineCustomElementKritzelPortal}from"./kritzel-portal.js";export{KritzelSettings,defineCustomElement as defineCustomElementKritzelSettings}from"./kritzel-settings.js";export{KritzelShapeFill,defineCustomElement as defineCustomElementKritzelShapeFill}from"./kritzel-shape-fill.js";export{KritzelShareDialog,defineCustomElement as defineCustomElementKritzelShareDialog}from"./kritzel-share-dialog.js";export{KritzelSlideToggle,defineCustomElement as defineCustomElementKritzelSlideToggle}from"./kritzel-slide-toggle.js";export{KritzelSplitButton,defineCustomElement as defineCustomElementKritzelSplitButton}from"./kritzel-split-button.js";export{KritzelStrokeSize,defineCustomElement as defineCustomElementKritzelStrokeSize}from"./kritzel-stroke-size.js";export{KritzelToolConfig,defineCustomElement as defineCustomElementKritzelToolConfig}from"./kritzel-tool-config.js";export{KritzelTooltip,defineCustomElement as defineCustomElementKritzelTooltip}from"./kritzel-tooltip.js";export{KritzelUtilityPanel,defineCustomElement as defineCustomElementKritzelUtilityPanel}from"./kritzel-utility-panel.js";export{KritzelWorkspaceManager,defineCustomElement as defineCustomElementKritzelWorkspaceManager}from"./kritzel-workspace-manager.js";const u=Math.floor,z=127,p=Number.MAX_SAFE_INTEGER;class E{constructor(){this.cpos=0,this.cbuf=new Uint8Array(100),this.bufs=[]}}const y=()=>new E,k=e=>{const t=new Uint8Array((e=>{let t=e.cpos;for(let s=0;s<e.bufs.length;s++)t+=e.bufs[s].length;return t})(e));let s=0;for(let i=0;i<e.bufs.length;i++){const o=e.bufs[i];t.set(o,s),s+=o.length}return t.set(new Uint8Array(e.cbuf.buffer,0,e.cpos),s),t},w=(e,t)=>{const s=e.cbuf.length;e.cpos===s&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(2*s),e.cpos=0),e.cbuf[e.cpos++]=t},x=(e,t)=>{for(;t>z;)w(e,128|z&t),t=u(t/128);w(e,z&t)},T=(e,t)=>{x(e,t.byteLength),((e,t)=>{const s=e.cbuf.length,i=e.cpos,o=((e,t)=>e<t?e:t)(s-i,t.length),n=t.length-o;e.cbuf.set(t.subarray(0,o),i),e.cpos+=o,n>0&&(e.bufs.push(e.cbuf),e.cbuf=new Uint8Array(((e,t)=>e>t?e:t)(2*s,n)),e.cbuf.set(t.subarray(o)),e.cpos=n)})(e,t)},j=e=>Error(e),P=j("Unexpected end of array"),v=j("Integer out of Range");class U{constructor(e){this.arr=e,this.pos=0}}const M=e=>((e,t)=>{const s=new Uint8Array(e.arr.buffer,e.pos+e.arr.byteOffset,t);return e.pos+=t,s})(e,F(e)),F=e=>{let t=0,s=1;const i=e.arr.length;for(;e.pos<i;){const i=e.arr[e.pos++];if(t+=(i&z)*s,s*=128,i<128)return t;if(t>p)throw v}throw P};class _{type="local";doc;channel;_synced=!1;constructor(e,t,s){this.doc=t,this.channel=new BroadcastChannel(e),this.channel.onmessage=e=>{this.handleMessage(e.data)},this.doc.on("update",this.handleDocUpdate),this.broadcastSync(),setTimeout((()=>{this._synced=!0}),100),s?.quiet||console.info("BroadcastChannel Provider initialized: "+e)}handleDocUpdate=(e,t)=>{if(t!==this){const t=y();x(t,0),T(t,e),this.channel.postMessage(k(t))}};handleMessage(e){const s=(e=>new U(e))(new Uint8Array(e));switch(F(s)){case 0:const e=M(s);t.applyUpdate(this.doc,e,this);break;case 1:this.broadcastSync();break;case 2:const i=M(s),o=t.encodeStateAsUpdate(this.doc,i);if(o.length>0){const e=y();x(e,0),T(e,o),this.channel.postMessage(k(e))}}}broadcastSync(){const e=y();x(e,2),T(e,t.encodeStateVector(this.doc)),this.channel.postMessage(k(e))}async connect(){if(!this._synced)return new Promise((e=>{const t=()=>{this._synced?e():setTimeout(t,50)};t()}))}disconnect(){}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.doc.off("update",this.handleDocUpdate),this.channel.close()}}class ${type="network";provider;isConnected=!1;_quiet=!1;get awareness(){return this.provider.awareness}constructor(e,t,s){const i=s?.url||"ws://localhost:1234",n=s?.roomName||e;this.provider=new o(i,n,t,{params:s?.params,protocols:s?.protocols,WebSocketPolyfill:s?.WebSocketPolyfill,awareness:s?.awareness,maxBackoffTime:s?.maxBackoffTime,disableBc:!0}),this._quiet=s?.quiet??!1,this.setupEventListeners(),this._quiet||console.info(`WebSocket Provider initialized: ${i}/${n}`)}static with(e){return{create:(t,s,i)=>{const o=i?{...e,...i}:e;return new $(t,s,o)}}}setupEventListeners(){this.provider.on("status",(({status:e})=>{"connected"===e?(this.isConnected=!0,this._quiet||console.info("WebSocket connected")):"disconnected"===e&&(this.isConnected=!1,this._quiet||console.info("WebSocket disconnected"))})),this.provider.on("sync",(e=>{e&&!this._quiet&&console.info("WebSocket synced")}))}async connect(){if(!this.isConnected)return new Promise(((e,t)=>{const s=setTimeout((()=>{t(Error("WebSocket connection timeout"))}),1e4),i=({status:t})=>{"connected"===t&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())};this.provider.on("status",i),this.provider.wsconnected&&(clearTimeout(s),this.provider.off("status",i),this.isConnected=!0,e())}))}disconnect(){this.provider&&this.provider.disconnect(),this.isConnected=!1}async reconnect(){return this.disconnect(),this.connect()}destroy(){this.provider&&this.provider.destroy(),this.isConnected=!1}}class O{type="network";provider;isConnected=!1;isSynced=!1;usesSharedSocket=!1;isDestroyed=!1;connectTimeout=null;pendingConnectReject=null;connectionTimeoutMs;_connectionStatus="disconnected";visibilityHandler=null;onlineHandler=null;get awareness(){return this.provider.awareness}get connectionStatus(){return this._connectionStatus}static sharedWebSocketProvider=null;constructor(e,t,s){const i=s?.name||e,o=s?.url||"ws://localhost:1234";this.connectionTimeoutMs=s?.connectionTimeout??1e4;const r=s?.websocketProvider||O.sharedWebSocketProvider,l={};void 0!==s?.delay&&(l.delay=s.delay),void 0!==s?.factor&&(l.factor=s.factor),void 0!==s?.maxAttempts&&(l.maxAttempts=s.maxAttempts),void 0!==s?.minDelay&&(l.minDelay=s.minDelay),void 0!==s?.maxDelay&&(l.maxDelay=s.maxDelay);const a=()=>{this.isDestroyed||(this.isConnected=!0,this._connectionStatus="connected",s?.quiet||console.info("Hocuspocus connected: "+i),s?.onConnect&&s.onConnect())},c=()=>{this.isDestroyed||(this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected",s?.quiet||console.info("Hocuspocus disconnected: "+i),s?.onDisconnect&&s.onDisconnect())},m=()=>{this.isDestroyed||(this.isSynced=!0,this._connectionStatus="synced",s?.quiet||console.info("Hocuspocus synced: "+i),s?.onSynced&&s.onSynced())},d=e=>{this.isDestroyed||("connecting"===e.status&&(this._connectionStatus="connecting"),s?.onStatus&&s.onStatus(e))};if(r){this.usesSharedSocket=!0;const e={websocketProvider:r,name:i,document:t,token:s?.token||null,onStatus:d,onConnect:a,onDisconnect:c,onSynced:m,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),this.provider=new n(e),this.provider.attach(),s?.quiet||console.info("Hocuspocus Provider initialized (multiplexed): "+i)}else{this.usesSharedSocket=!1;const e={url:o,name:i,document:t,token:s?.token||null,autoConnect:!1,onStatus:d,onConnect:a,onDisconnect:c,onSynced:m,...l};void 0!==s?.forceSyncInterval&&(e.forceSyncInterval=s.forceSyncInterval),s?.onAuthenticationFailed&&(e.onAuthenticationFailed=s.onAuthenticationFailed),s?.WebSocketPolyfill&&(e.WebSocketPolyfill=s.WebSocketPolyfill),this.provider=new n(e),s?.quiet||console.info(`Hocuspocus Provider initialized: ${o}/${i}`)}this.setupBrowserEventListeners()}setupBrowserEventListeners(){"undefined"!=typeof document&&(this.visibilityHandler=()=>{"visible"!==document.visibilityState||this.isConnected||this.isDestroyed||this.provider.connect()},document.addEventListener("visibilitychange",this.visibilityHandler)),"undefined"!=typeof window&&(this.onlineHandler=()=>{this.isConnected||this.isDestroyed||this.provider.connect()},window.addEventListener("online",this.onlineHandler))}removeBrowserEventListeners(){this.visibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.onlineHandler&&"undefined"!=typeof window&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null)}static createSharedWebSocket(e){if(O.sharedWebSocketProvider)return console.warn("Shared WebSocket already exists. Returning existing instance."),O.sharedWebSocketProvider;const t={url:e.url};return e.WebSocketPolyfill&&(t.WebSocketPolyfill=e.WebSocketPolyfill),e.onConnect&&(t.onConnect=e.onConnect),e.onDisconnect&&(t.onDisconnect=e.onDisconnect),e.onStatus&&(t.onStatus=e.onStatus),O.sharedWebSocketProvider=new m(t),console.info("Shared Hocuspocus WebSocket created: "+e.url),O.sharedWebSocketProvider}static destroySharedWebSocket(){O.sharedWebSocketProvider&&(O.sharedWebSocketProvider.destroy(),O.sharedWebSocketProvider=null,console.info("Shared Hocuspocus WebSocket destroyed"))}static getSharedWebSocket(){return O.sharedWebSocketProvider}static with(e){return{create:(t,s,i)=>{const o=i?{...e,...i}:e;return new O(t,s,o)}}}async connect(){if(!this.isSynced&&!this.isDestroyed)return this._connectionStatus="connecting",new Promise(((e,t)=>{this.pendingConnectReject=t,this.connectTimeout=setTimeout((()=>{this.pendingConnectReject=null,this.connectTimeout=null,t(Error("Hocuspocus connection timeout"))}),this.connectionTimeoutMs);const s=()=>{this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),this.isDestroyed||e()};if(this.provider.on("synced",s),this.provider.isSynced)return this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject=null,this.provider.off("synced",s),void e();this.isConnected||this.usesSharedSocket||this.provider.connect()}))}async reconnect(){return this.disconnect(),this.connect()}disconnect(){this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.provider&&(this.usesSharedSocket?this.provider.detach():this.provider.disconnect()),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}destroy(){this.isDestroyed=!0,this.connectTimeout&&(clearTimeout(this.connectTimeout),this.connectTimeout=null),this.pendingConnectReject&&(this.pendingConnectReject=null),this.removeBrowserEventListeners(),this.provider&&this.provider.destroy(),this.isConnected=!1,this.isSynced=!1,this._connectionStatus="disconnected"}}class B{type="remote";name="HttpAssetProvider";_options;constructor(e){this._options=e}static with(e){return{create:()=>new B(e)}}async init(){this._options.quiet||console.info("HttpAssetProvider initialized")}destroy(){}canResolve(e){return!0}async put(e,t){const s=t.id??this.generateUuid(),i={...t,id:s},o=await(this._options.headers?.())??{},n=await this._options.uploadUrl(i),r=this._options.upload??this.defaultUpload;return{id:(await r(n,e,i,o)).id??s,kind:t.kind??"file",mimeType:t.mimeType,size:e.size,createdAt:Date.now(),width:t.width,height:t.height,durationMs:t.durationMs,originalFilename:t.originalFilename}}async resolve(e){return this._options.resolveUrl(e)}async fetch(e){const t=await this._options.resolveUrl(e),s=await(this._options.headers?.())??{},i=await fetch(t,{headers:s});if(!i.ok)throw Error(`[HttpAssetProvider] Failed to fetch asset ${e}: ${i.status} ${i.statusText}`);return i.blob()}async delete(e){if(!this._options.deleteUrl)return;const t=await this._options.deleteUrl(e),s=await(this._options.headers?.())??{},i=await fetch(t,{method:"DELETE",headers:s});if(!i.ok)throw Error(`[HttpAssetProvider] Failed to delete asset ${e}: ${i.status} ${i.statusText}`);this._options.quiet||console.info("HttpAssetProvider: deleted asset "+e)}defaultUpload=async(e,t,s,i)=>{const o=new FormData;o.append("metadata",JSON.stringify(s)),o.append("file",t,s.originalFilename||`${s.id}.${this.extensionFromMime(s.mimeType)}`);const n=await fetch(e,{method:"POST",headers:i,body:o});if(!n.ok)throw Error(`[HttpAssetProvider] Upload failed: ${n.status} ${n.statusText}`);return(n.headers.get("content-type")||"").includes("application/json")?await n.json():{}};extensionFromMime(e){const t=e.indexOf("/");return t>=0?e.slice(t+1):"bin"}generateUuid(){if("undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID)return crypto.randomUUID();const e=crypto.getRandomValues(new Uint8Array(16));e[6]=15&e[6]|64,e[8]=63&e[8]|128;const t=Array.from(e,(e=>e.toString(16).padStart(2,"0"))).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}}class H{type="remote";name="PresignedAssetProvider";_options;constructor(e){this._options=e}static with(e){return{create:()=>new H(e)}}async init(){this._options.quiet||console.info("PresignedAssetProvider initialized")}destroy(){}canResolve(e){return!0}async put(e,t){const s=await this._options.getUploadDescriptor(t),i=s.method??"PUT",o={...s.headers??{}};let n;if(o["Content-Type"]||o["content-type"]||(o["Content-Type"]=t.mimeType),"POST"===i&&s.fields){const t=new FormData;for(const[e,i]of Object.entries(s.fields))t.append(e,i);t.append("file",e),n=t,delete o["Content-Type"],delete o["content-type"]}else n=e;const r=await fetch(s.url,{method:i,headers:o,body:n});if(!r.ok)throw Error(`[PresignedAssetProvider] Upload failed: ${r.status} ${r.statusText}`);return{id:s.id,kind:t.kind??"file",mimeType:t.mimeType,size:e.size,createdAt:Date.now(),width:t.width,height:t.height,durationMs:t.durationMs,originalFilename:t.originalFilename}}async resolve(e){return this._options.getDownloadUrl(e)}async fetch(e){const t=await this._options.getDownloadUrl(e),s=await fetch(t);if(!s.ok)throw Error(`[PresignedAssetProvider] Failed to fetch asset ${e}: ${s.status} ${s.statusText}`);return s.blob()}async delete(e){this._options.deleteAsset&&(await this._options.deleteAsset(e),this._options.quiet||console.info("PresignedAssetProvider: deleted asset "+e))}}export{_ as BroadcastSyncProvider,O as HocuspocusSyncProvider,B as HttpAssetProvider,H as PresignedAssetProvider,$ as WebSocketSyncProvider}
|