kritzel-stencil 0.1.76 → 0.1.77

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.
Files changed (40) hide show
  1. package/dist/cjs/index.cjs.js +2 -330
  2. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +36 -18
  3. package/dist/cjs/{workspace.migrations-DkmVO6dE.js → workspace.migrations-OULs44dI.js} +331 -2
  4. package/dist/collection/classes/objects/selection-group.class.js +2 -0
  5. package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.css +6 -1
  6. package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +5 -2
  7. package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +2 -0
  8. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +12 -6
  9. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +18 -8
  10. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.css +1 -0
  11. package/dist/collection/constants/version.js +1 -1
  12. package/dist/components/index.js +1 -1
  13. package/dist/components/kritzel-awareness-cursors.js +1 -1
  14. package/dist/components/kritzel-controls.js +1 -1
  15. package/dist/components/kritzel-editor.js +1 -1
  16. package/dist/components/kritzel-engine.js +1 -1
  17. package/dist/components/kritzel-settings.js +1 -1
  18. package/dist/components/kritzel-tool-config.js +1 -1
  19. package/dist/components/kritzel-utility-panel.js +1 -1
  20. package/dist/components/{p-DvIEvoZu.js → p-BK1hLBTd.js} +1 -1
  21. package/dist/components/{p-jdYmu4SA.js → p-BdGcOXa5.js} +2 -2
  22. package/dist/components/{p-CsoDfhD5.js → p-C_X8stam.js} +1 -1
  23. package/dist/components/p-WotNmY5q.js +1 -0
  24. package/dist/components/{p-31FVoNWR.js → p-XS5J5W5_.js} +1 -1
  25. package/dist/components/{p-CJ2eHeoV.js → p-_CqLIbO6.js} +1 -1
  26. package/dist/components/{p-2OYw6GJ7.js → p-_LbtY-TA.js} +1 -1
  27. package/dist/esm/index.js +2 -331
  28. package/dist/esm/kritzel-active-users_42.entry.js +36 -18
  29. package/dist/esm/{workspace.migrations-D48_Bqvh.js → workspace.migrations-D6whgl7G.js} +331 -1
  30. package/dist/stencil/index.esm.js +1 -1
  31. package/dist/stencil/p-8fe1ec39.entry.js +9 -0
  32. package/dist/stencil/p-D6whgl7G.js +1 -0
  33. package/dist/stencil/stencil.esm.js +1 -1
  34. package/dist/types/classes/objects/selection-group.class.d.ts +1 -0
  35. package/dist/types/components.d.ts +8 -2
  36. package/dist/types/constants/version.d.ts +1 -1
  37. package/package.json +1 -1
  38. package/dist/components/p-xNwOWoiT.js +0 -1
  39. package/dist/stencil/p-775a7246.entry.js +0 -9
  40. package/dist/stencil/p-D48_Bqvh.js +0 -1
@@ -1 +1 @@
1
- import{p as e,H as t,c as s,h as i,d as o,t as r}from"./p-pebXO4LU.js";import{h as a,d as l,e as n,g as h,f as p}from"./p-CJ2eHeoV.js";import{a as c}from"./p-CjazGGq3.js";import{d}from"./p-C1uR_ZNW.js";import{d as m}from"./p-BEJQ2kP7.js";import{d as f}from"./p-GYI7sDxr.js";import{d as y}from"./p-HLbqRJGs.js";import{d as u}from"./p-TyR-YTXm.js";import{d as g}from"./p-CZhyKp-f.js";import{d as k}from"./p-CHmi1QWx.js";import{d as z}from"./p-CFhp1W9F.js";import{d as C}from"./p-C7SBI_0T.js";import{d as x}from"./p-JdNoaqqb.js";import{d as b}from"./p-BiouZo1q.js";class v{static getToolConfig(e){return e instanceof a?e.getToolConfig():e instanceof l?{type:"brush",colorProperty:"color",sizeProperty:"size",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"stroke-size",propertyName:"size"}]}:e instanceof n?{type:"line",colorProperty:"color",sizeProperty:"size",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"stroke-size",propertyName:"size"},{type:"line-endings",propertyName:"arrows",additionalProps:{}}]}:e instanceof h?{type:"shape",colorProperty:"strokeColor",sizeProperty:"strokeWidth",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"stroke-size",propertyName:"strokeWidth"},{type:"shape-fill",propertyName:"fillColor",additionalProps:{}}]}:e instanceof p?{type:"text",colorProperty:"fontColor",sizeProperty:"fontSize",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"font-size",propertyName:"fontSize",additionalProps:{}},{type:"font-family",propertyName:"fontFamily"}]}:null}}const E=e(class extends t{constructor(e){super(),!1!==e&&this.__registerHost(),this.__attachShadow(),this.toolChange=s(this,"toolChange"),this.displayValuesChange=s(this,"displayValuesChange")}tool;handleToolChange(e,t){const s=v.getToolConfig(e);if(t&&e&&"shape"===s?.type){const i=v.getToolConfig(t);"shape"===i?.type&&[s.colorProperty,s.sizeProperty,s.opacityProperty,"fillColor"].forEach((s=>{s&&void 0!==t[s]&&(e[s]=t[s])}))}this.config=s,this.config&&(this.updatePalette(),this.currentOpacity=e[this.config.opacityProperty]??1,this.emitDisplayValues())}isExpanded=!1;theme;onThemeChange(){this.emitDisplayValues()}toolChange;displayValuesChange;config;palette=[];currentOpacity=1;updateTrigger=0;handleSelectionChange(){this.tool instanceof a&&(this.config=v.getToolConfig(this.tool),this.config&&(this.updatePalette(),this.currentOpacity=this.tool[this.config.opacityProperty]??1,this.emitDisplayValues()))}componentWillLoad(){this.config=v.getToolConfig(this.tool),this.config&&(this.updatePalette(),this.currentOpacity=this.tool[this.config.opacityProperty]??1,this.emitDisplayValues())}emitDisplayValues(){if(!this.config)return;const e=this.tool[this.config.sizeProperty],t={color:c.applyOpacity(this.tool[this.config.colorProperty],this.currentOpacity,this.theme),size:e};this.tool instanceof p&&(t.fontFamily=this.tool.fontFamily),this.displayValuesChange.emit(t)}updatePalette(){this.config&&(this.palette="none"===this.config.paletteSource?[]:this.tool.palette||[])}handleToggleExpand=()=>{this.isExpanded=!this.isExpanded};handleColorChange=e=>{if(this.tool[this.config.colorProperty]=e.detail,"shape"===this.config.type||"selection"===this.config.type){const t=this.tool;("string"==typeof t.fillColor?"transparent"===t.fillColor:"transparent"===t.fillColor.light&&"transparent"===t.fillColor.dark)||(t.fillColor=e.detail)}this.emitDisplayValues(),this.toolChange.emit(this.tool),this.updateTrigger++};handleSizeChange=e=>{this.tool[this.config.sizeProperty]=e.detail,this.emitDisplayValues(),this.toolChange.emit(this.tool),this.updateTrigger++};handleOpacityChange=e=>{this.tool[this.config.opacityProperty]=e.detail,this.currentOpacity=e.detail,this.emitDisplayValues(),this.toolChange.emit(this.tool)};handlePropertyChange=(e,t)=>{if("shape"!==this.config.type&&"selection"!==this.config.type||"fillColor"!==e)this.tool[e]=t,"fontFamily"===e&&this.emitDisplayValues();else{const e="filled"===t?this.tool[this.config.colorProperty]:{light:"transparent",dark:"transparent"};this.tool.fillColor=e,"filled"===t&&(this.tool[this.config.colorProperty]=e)}this.toolChange.emit(this.tool),this.updateTrigger++};getShapeFillValue(){const e=this.tool.fillColor;return("string"==typeof e?"transparent"===e:"transparent"===e.light&&"transparent"===e.dark)?"transparent":"filled"}renderControl(e){const t=this.tool[e.propertyName];switch(e.type){case"stroke-size":return i("kritzel-stroke-size",{key:e.type,selectedSize:t,onSizeChange:this.handleSizeChange});case"font-size":return i("kritzel-font-size",{key:e.type,selectedSize:t,fontFamily:this.tool.fontFamily,onSizeChange:this.handleSizeChange});case"line-endings":return i("kritzel-line-endings",{key:e.type,value:t,onValueChange:t=>this.handlePropertyChange(e.propertyName,t.detail)});case"shape-fill":return i("kritzel-shape-fill",{key:e.type,value:this.getShapeFillValue(),onValueChange:t=>this.handlePropertyChange(e.propertyName,t.detail)});case"font-family":return i("kritzel-font-family",{key:e.type,selectedFontFamily:t,onFontFamilyChange:t=>this.handlePropertyChange(e.propertyName,t.detail)});default:return null}}render(){if(!this.config)return null;const e=this.palette.length>6||"text"===this.config.type,t=this.palette.length>0,s=this.config.controls.find((e=>"stroke-size"===e.type||"font-size"===e.type)),r=this.config.controls.filter((e=>"stroke-size"!==e.type&&"font-size"!==e.type));return i(o,null,i("div",{style:{display:"flex",flexDirection:"row",gap:"8px",width:"100%"}},i("div",{style:{display:"flex",flexDirection:"column",gap:"12px",flex:"1"}},t&&i("kritzel-color-palette",{colors:this.palette,selectedColor:this.tool[this.config.colorProperty],isExpanded:this.isExpanded,isOpaque:!0,opacity:this.currentOpacity,theme:this.theme,onColorChange:this.handleColorChange}),s&&this.renderControl(s),i("kritzel-opacity-slider",{value:this.tool[this.config.opacityProperty],previewColor:this.tool[this.config.colorProperty],onValueChange:this.handleOpacityChange}),r.map((e=>[i("div",{class:"divider"}),this.renderControl(e)]))),e&&i("div",{style:{display:"flex",alignItems:"flex-start"}},i("button",{class:"expand-toggle",onClick:this.handleToggleExpand,title:this.isExpanded?"Collapse":"Expand"},i("kritzel-icon",{name:this.isExpanded?"chevron-up":"chevron-down"})))))}static get watchers(){return{tool:[{handleToolChange:0}],theme:[{onThemeChange:0}]}}static get style(){return".expand-toggle{background:none;border:none;cursor:var(--kritzel-global-pointer-cursor, pointer);padding:0;margin:0;display:flex;align-items:center;justify-content:center;width:32px;height:32px;color:var(--kritzel-icon-color, currentColor);transition:transform 0.2s ease}.expand-toggle:hover{opacity:0.7}.expand-toggle:focus{outline:none}.expand-toggle:focus-visible{outline:2px solid var(--kritzel-focus-color, #007acc);outline-offset:2px}.expand-toggle:active{transform:scale(0.95)}.divider{height:1px;background-color:var(--kritzel-divider-color, #e0e0e0);margin:4px 0;width:100%}"}},[513,"kritzel-tool-config",{tool:[1040],isExpanded:[1028,"is-expanded"],theme:[1],config:[32],palette:[32],currentOpacity:[32],updateTrigger:[32]},[[4,"objectsSelectionChange","handleSelectionChange"]],{tool:[{handleToolChange:0}],theme:[{onThemeChange:0}]}]);function P(){"undefined"!=typeof customElements&&["kritzel-tool-config","kritzel-color","kritzel-color-palette","kritzel-dropdown","kritzel-font","kritzel-font-family","kritzel-font-size","kritzel-icon","kritzel-line-endings","kritzel-opacity-slider","kritzel-shape-fill","kritzel-stroke-size"].forEach((e=>{switch(e){case"kritzel-tool-config":customElements.get(r(e))||customElements.define(r(e),E);break;case"kritzel-color":customElements.get(r(e))||d();break;case"kritzel-color-palette":customElements.get(r(e))||m();break;case"kritzel-dropdown":customElements.get(r(e))||f();break;case"kritzel-font":customElements.get(r(e))||y();break;case"kritzel-font-family":customElements.get(r(e))||u();break;case"kritzel-font-size":customElements.get(r(e))||g();break;case"kritzel-icon":customElements.get(r(e))||k();break;case"kritzel-line-endings":customElements.get(r(e))||z();break;case"kritzel-opacity-slider":customElements.get(r(e))||C();break;case"kritzel-shape-fill":customElements.get(r(e))||x();break;case"kritzel-stroke-size":customElements.get(r(e))||b()}}))}export{v as K,E as a,P as d}
1
+ import{p as e,H as t,c as s,h as i,d as o,t as r}from"./p-pebXO4LU.js";import{h as a,d as l,e as n,g as h,f as p}from"./p-_CqLIbO6.js";import{a as c}from"./p-CjazGGq3.js";import{d}from"./p-C1uR_ZNW.js";import{d as m}from"./p-BEJQ2kP7.js";import{d as f}from"./p-GYI7sDxr.js";import{d as y}from"./p-HLbqRJGs.js";import{d as u}from"./p-TyR-YTXm.js";import{d as g}from"./p-CZhyKp-f.js";import{d as k}from"./p-CHmi1QWx.js";import{d as z}from"./p-CFhp1W9F.js";import{d as C}from"./p-C7SBI_0T.js";import{d as x}from"./p-JdNoaqqb.js";import{d as b}from"./p-BiouZo1q.js";class v{static getToolConfig(e){return e instanceof a?e.getToolConfig():e instanceof l?{type:"brush",colorProperty:"color",sizeProperty:"size",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"stroke-size",propertyName:"size"}]}:e instanceof n?{type:"line",colorProperty:"color",sizeProperty:"size",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"stroke-size",propertyName:"size"},{type:"line-endings",propertyName:"arrows",additionalProps:{}}]}:e instanceof h?{type:"shape",colorProperty:"strokeColor",sizeProperty:"strokeWidth",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"stroke-size",propertyName:"strokeWidth"},{type:"shape-fill",propertyName:"fillColor",additionalProps:{}}]}:e instanceof p?{type:"text",colorProperty:"fontColor",sizeProperty:"fontSize",opacityProperty:"opacity",paletteSource:"palette",controls:[{type:"font-size",propertyName:"fontSize",additionalProps:{}},{type:"font-family",propertyName:"fontFamily"}]}:null}}const E=e(class extends t{constructor(e){super(),!1!==e&&this.__registerHost(),this.__attachShadow(),this.toolChange=s(this,"toolChange"),this.displayValuesChange=s(this,"displayValuesChange")}tool;handleToolChange(e,t){const s=v.getToolConfig(e);if(t&&e&&"shape"===s?.type){const i=v.getToolConfig(t);"shape"===i?.type&&[s.colorProperty,s.sizeProperty,s.opacityProperty,"fillColor"].forEach((s=>{s&&void 0!==t[s]&&(e[s]=t[s])}))}this.config=s,this.config&&(this.updatePalette(),this.currentOpacity=e[this.config.opacityProperty]??1,this.emitDisplayValues())}isExpanded=!1;theme;onThemeChange(){this.emitDisplayValues()}toolChange;displayValuesChange;config;palette=[];currentOpacity=1;updateTrigger=0;handleSelectionChange(){this.tool instanceof a&&(this.config=v.getToolConfig(this.tool),this.config&&(this.updatePalette(),this.currentOpacity=this.tool[this.config.opacityProperty]??1,this.emitDisplayValues()))}componentWillLoad(){this.config=v.getToolConfig(this.tool),this.config&&(this.updatePalette(),this.currentOpacity=this.tool[this.config.opacityProperty]??1,this.emitDisplayValues())}emitDisplayValues(){if(!this.config)return;const e=this.tool[this.config.sizeProperty],t={color:c.applyOpacity(this.tool[this.config.colorProperty],this.currentOpacity,this.theme),size:e};this.tool instanceof p&&(t.fontFamily=this.tool.fontFamily),this.displayValuesChange.emit(t)}updatePalette(){this.config&&(this.palette="none"===this.config.paletteSource?[]:this.tool.palette||[])}handleToggleExpand=()=>{this.isExpanded=!this.isExpanded};handleColorChange=e=>{if(this.tool[this.config.colorProperty]=e.detail,"shape"===this.config.type||"selection"===this.config.type){const t=this.tool;("string"==typeof t.fillColor?"transparent"===t.fillColor:"transparent"===t.fillColor.light&&"transparent"===t.fillColor.dark)||(t.fillColor=e.detail)}this.emitDisplayValues(),this.toolChange.emit(this.tool),this.updateTrigger++};handleSizeChange=e=>{this.tool[this.config.sizeProperty]=e.detail,this.emitDisplayValues(),this.toolChange.emit(this.tool),this.updateTrigger++};handleOpacityChange=e=>{this.tool[this.config.opacityProperty]=e.detail,this.currentOpacity=e.detail,this.emitDisplayValues(),this.toolChange.emit(this.tool)};handlePropertyChange=(e,t)=>{if("shape"!==this.config.type&&"selection"!==this.config.type||"fillColor"!==e)this.tool[e]=t,"fontFamily"===e&&this.emitDisplayValues();else{const e="filled"===t?this.tool[this.config.colorProperty]:{light:"transparent",dark:"transparent"};this.tool.fillColor=e,"filled"===t&&(this.tool[this.config.colorProperty]=e)}this.toolChange.emit(this.tool),this.updateTrigger++};getShapeFillValue(){const e=this.tool.fillColor;return("string"==typeof e?"transparent"===e:"transparent"===e.light&&"transparent"===e.dark)?"transparent":"filled"}renderControl(e){const t=this.tool[e.propertyName];switch(e.type){case"stroke-size":return i("kritzel-stroke-size",{key:e.type,selectedSize:t,onSizeChange:this.handleSizeChange});case"font-size":return i("kritzel-font-size",{key:e.type,selectedSize:t,fontFamily:this.tool.fontFamily,onSizeChange:this.handleSizeChange});case"line-endings":return i("kritzel-line-endings",{key:e.type,value:t,onValueChange:t=>this.handlePropertyChange(e.propertyName,t.detail)});case"shape-fill":return i("kritzel-shape-fill",{key:e.type,value:this.getShapeFillValue(),onValueChange:t=>this.handlePropertyChange(e.propertyName,t.detail)});case"font-family":return i("kritzel-font-family",{key:e.type,selectedFontFamily:t,onFontFamilyChange:t=>this.handlePropertyChange(e.propertyName,t.detail)});default:return null}}render(){if(!this.config)return null;const e=this.palette.length>6||"text"===this.config.type,t=this.palette.length>0,s=this.config.controls.find((e=>"stroke-size"===e.type||"font-size"===e.type)),r=this.config.controls.filter((e=>"stroke-size"!==e.type&&"font-size"!==e.type));return i(o,null,i("div",{style:{display:"flex",flexDirection:"row",gap:"8px",width:"100%"}},i("div",{style:{display:"flex",flexDirection:"column",gap:"12px",flex:"1"}},t&&i("kritzel-color-palette",{colors:this.palette,selectedColor:this.tool[this.config.colorProperty],isExpanded:this.isExpanded,isOpaque:!0,opacity:this.currentOpacity,theme:this.theme,onColorChange:this.handleColorChange}),s&&this.renderControl(s),i("kritzel-opacity-slider",{value:this.tool[this.config.opacityProperty],previewColor:this.tool[this.config.colorProperty],onValueChange:this.handleOpacityChange}),r.map((e=>[i("div",{class:"divider"}),this.renderControl(e)]))),e&&i("div",{style:{display:"flex",alignItems:"flex-start"}},i("button",{class:"expand-toggle",onClick:this.handleToggleExpand,title:this.isExpanded?"Collapse":"Expand"},i("kritzel-icon",{name:this.isExpanded?"chevron-up":"chevron-down"})))))}static get watchers(){return{tool:[{handleToolChange:0}],theme:[{onThemeChange:0}]}}static get style(){return".expand-toggle{background:none;border:none;cursor:var(--kritzel-global-pointer-cursor, pointer);padding:0;margin:0;display:flex;align-items:center;justify-content:center;width:32px;height:32px;color:var(--kritzel-icon-color, currentColor);transition:transform 0.2s ease}.expand-toggle:hover{opacity:0.7}.expand-toggle:focus{outline:none}.expand-toggle:focus-visible{outline:2px solid var(--kritzel-focus-color, #007acc);outline-offset:2px}.expand-toggle:active{transform:scale(0.95)}.divider{height:1px;background-color:var(--kritzel-divider-color, #e0e0e0);margin:4px 0;width:100%}"}},[513,"kritzel-tool-config",{tool:[1040],isExpanded:[1028,"is-expanded"],theme:[1],config:[32],palette:[32],currentOpacity:[32],updateTrigger:[32]},[[4,"objectsSelectionChange","handleSelectionChange"]],{tool:[{handleToolChange:0}],theme:[{onThemeChange:0}]}]);function P(){"undefined"!=typeof customElements&&["kritzel-tool-config","kritzel-color","kritzel-color-palette","kritzel-dropdown","kritzel-font","kritzel-font-family","kritzel-font-size","kritzel-icon","kritzel-line-endings","kritzel-opacity-slider","kritzel-shape-fill","kritzel-stroke-size"].forEach((e=>{switch(e){case"kritzel-tool-config":customElements.get(r(e))||customElements.define(r(e),E);break;case"kritzel-color":customElements.get(r(e))||d();break;case"kritzel-color-palette":customElements.get(r(e))||m();break;case"kritzel-dropdown":customElements.get(r(e))||f();break;case"kritzel-font":customElements.get(r(e))||y();break;case"kritzel-font-family":customElements.get(r(e))||u();break;case"kritzel-font-size":customElements.get(r(e))||g();break;case"kritzel-icon":customElements.get(r(e))||k();break;case"kritzel-line-endings":customElements.get(r(e))||z();break;case"kritzel-opacity-slider":customElements.get(r(e))||C();break;case"kritzel-shape-fill":customElements.get(r(e))||x();break;case"kritzel-stroke-size":customElements.get(r(e))||b()}}))}export{v as K,E as a,P as d}
package/dist/esm/index.js CHANGED
@@ -1,5 +1,4 @@
1
- import { H as HocuspocusProvider, a as HocuspocusProviderWebsocket } from './workspace.migrations-D48_Bqvh.js';
2
- export { A as APP_STATE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, w as CURRENT_WORKSPACE_SCHEMA_VERSION, D as DEFAULT_BRUSH_CONFIG, s as DEFAULT_LINE_TOOL_CONFIG, r as DEFAULT_TEXT_CONFIG, I as IndexedDBSyncProvider, v as KritzelAlignment, p as KritzelAnchorManager, g as KritzelBrushTool, m as KritzelCursorHelper, i as KritzelEraserTool, e as KritzelGroup, c as KritzelImage, j as KritzelImageTool, d as KritzelLine, h as KritzelLineTool, b as KritzelPath, n as KritzelSelectionTool, f as KritzelShape, l as KritzelShapeTool, K as KritzelText, k as KritzelTextTool, q as KritzelThemeManager, o as KritzelWorkspace, S as ShapeType, W as WORKSPACE_EXPORT_VERSION, y as WORKSPACE_MIGRATIONS, u as darkTheme, t as lightTheme, x as runMigrations } from './workspace.migrations-D48_Bqvh.js';
1
+ export { A as APP_STATE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, v as CURRENT_WORKSPACE_SCHEMA_VERSION, D as DEFAULT_BRUSH_CONFIG, r as DEFAULT_LINE_TOOL_CONFIG, q as DEFAULT_TEXT_CONFIG, H as HocuspocusSyncProvider, I as IndexedDBSyncProvider, u as KritzelAlignment, o as KritzelAnchorManager, f as KritzelBrushTool, l as KritzelCursorHelper, h as KritzelEraserTool, d as KritzelGroup, b as KritzelImage, i as KritzelImageTool, c as KritzelLine, g as KritzelLineTool, a as KritzelPath, m as KritzelSelectionTool, e as KritzelShape, k as KritzelShapeTool, K as KritzelText, j as KritzelTextTool, p as KritzelThemeManager, n as KritzelWorkspace, S as ShapeType, W as WORKSPACE_EXPORT_VERSION, x as WORKSPACE_MIGRATIONS, t as darkTheme, s as lightTheme, w as runMigrations } from './workspace.migrations-D6whgl7G.js';
3
2
  import * as Y from 'yjs';
4
3
  import { WebsocketProvider } from 'y-websocket';
5
4
  import 'y-indexeddb';
@@ -536,332 +535,4 @@ class WebSocketSyncProvider {
536
535
  }
537
536
  }
538
537
 
539
- /**
540
- * Hocuspocus sync provider for real-time collaboration
541
- * Supports multiplexing - multiple documents can share the same WebSocket connection
542
- */
543
- class HocuspocusSyncProvider {
544
- type = 'network';
545
- provider;
546
- isConnected = false;
547
- isSynced = false;
548
- usesSharedSocket = false;
549
- isDestroyed = false;
550
- connectTimeout = null;
551
- pendingConnectReject = null;
552
- connectionTimeoutMs;
553
- _connectionStatus = 'disconnected';
554
- visibilityHandler = null;
555
- onlineHandler = null;
556
- get awareness() {
557
- return this.provider.awareness;
558
- }
559
- get connectionStatus() {
560
- return this._connectionStatus;
561
- }
562
- // Static shared WebSocket instance for multiplexing
563
- static sharedWebSocketProvider = null;
564
- constructor(docName, doc, options) {
565
- const name = options?.name || docName;
566
- const url = options?.url || 'ws://localhost:1234';
567
- this.connectionTimeoutMs = options?.connectionTimeout ?? 10000;
568
- // Use provided websocketProvider or the static shared one
569
- const websocketProvider = options?.websocketProvider || HocuspocusSyncProvider.sharedWebSocketProvider;
570
- // Build reconnect config from options
571
- const reconnectConfig = {};
572
- if (options?.delay !== undefined)
573
- reconnectConfig.delay = options.delay;
574
- if (options?.factor !== undefined)
575
- reconnectConfig.factor = options.factor;
576
- if (options?.maxAttempts !== undefined)
577
- reconnectConfig.maxAttempts = options.maxAttempts;
578
- if (options?.minDelay !== undefined)
579
- reconnectConfig.minDelay = options.minDelay;
580
- if (options?.maxDelay !== undefined)
581
- reconnectConfig.maxDelay = options.maxDelay;
582
- const onConnect = () => {
583
- if (this.isDestroyed) {
584
- return;
585
- }
586
- this.isConnected = true;
587
- this._connectionStatus = 'connected';
588
- if (!options?.quiet) {
589
- console.info(`Hocuspocus connected: ${name}`);
590
- }
591
- if (options?.onConnect) {
592
- options.onConnect();
593
- }
594
- };
595
- const onDisconnect = () => {
596
- if (this.isDestroyed) {
597
- return;
598
- }
599
- this.isConnected = false;
600
- this.isSynced = false;
601
- this._connectionStatus = 'disconnected';
602
- if (!options?.quiet) {
603
- console.info(`Hocuspocus disconnected: ${name}`);
604
- }
605
- if (options?.onDisconnect) {
606
- options.onDisconnect();
607
- }
608
- };
609
- const onSynced = () => {
610
- if (this.isDestroyed) {
611
- return;
612
- }
613
- this.isSynced = true;
614
- this._connectionStatus = 'synced';
615
- if (!options?.quiet) {
616
- console.info(`Hocuspocus synced: ${name}`);
617
- }
618
- if (options?.onSynced) {
619
- options.onSynced();
620
- }
621
- };
622
- const onStatus = (data) => {
623
- if (this.isDestroyed) {
624
- return;
625
- }
626
- if (data.status === 'connecting') {
627
- this._connectionStatus = 'connecting';
628
- }
629
- if (options?.onStatus) {
630
- options.onStatus(data);
631
- }
632
- };
633
- if (websocketProvider) {
634
- // Multiplexing mode - use shared WebSocket connection
635
- this.usesSharedSocket = true;
636
- const config = {
637
- websocketProvider,
638
- name,
639
- document: doc,
640
- token: options?.token || null,
641
- onStatus,
642
- onConnect,
643
- onDisconnect,
644
- onSynced,
645
- ...reconnectConfig,
646
- };
647
- // Add optional settings
648
- if (options?.forceSyncInterval !== undefined) {
649
- config.forceSyncInterval = options.forceSyncInterval;
650
- }
651
- if (options?.onAuthenticationFailed) {
652
- config.onAuthenticationFailed = options.onAuthenticationFailed;
653
- }
654
- this.provider = new HocuspocusProvider(config);
655
- // Must call attach() explicitly when using shared socket
656
- this.provider.attach();
657
- if (!options?.quiet) {
658
- console.info(`Hocuspocus Provider initialized (multiplexed): ${name}`);
659
- }
660
- }
661
- else {
662
- // Standalone mode - create own WebSocket connection
663
- this.usesSharedSocket = false;
664
- const config = {
665
- url,
666
- name,
667
- document: doc,
668
- token: options?.token || null,
669
- autoConnect: false,
670
- onStatus,
671
- onConnect,
672
- onDisconnect,
673
- onSynced,
674
- ...reconnectConfig,
675
- };
676
- // Add optional settings
677
- if (options?.forceSyncInterval !== undefined) {
678
- config.forceSyncInterval = options.forceSyncInterval;
679
- }
680
- if (options?.onAuthenticationFailed) {
681
- config.onAuthenticationFailed = options.onAuthenticationFailed;
682
- }
683
- if (options?.WebSocketPolyfill) {
684
- config.WebSocketPolyfill = options.WebSocketPolyfill;
685
- }
686
- this.provider = new HocuspocusProvider(config);
687
- if (!options?.quiet) {
688
- console.info(`Hocuspocus Provider initialized: ${url}/${name}`);
689
- }
690
- }
691
- this.setupBrowserEventListeners();
692
- }
693
- setupBrowserEventListeners() {
694
- if (typeof document !== 'undefined') {
695
- this.visibilityHandler = () => {
696
- if (document.visibilityState === 'visible' && !this.isConnected && !this.isDestroyed) {
697
- this.provider.connect();
698
- }
699
- };
700
- document.addEventListener('visibilitychange', this.visibilityHandler);
701
- }
702
- if (typeof window !== 'undefined') {
703
- this.onlineHandler = () => {
704
- if (!this.isConnected && !this.isDestroyed) {
705
- this.provider.connect();
706
- }
707
- };
708
- window.addEventListener('online', this.onlineHandler);
709
- }
710
- }
711
- removeBrowserEventListeners() {
712
- if (this.visibilityHandler && typeof document !== 'undefined') {
713
- document.removeEventListener('visibilitychange', this.visibilityHandler);
714
- this.visibilityHandler = null;
715
- }
716
- if (this.onlineHandler && typeof window !== 'undefined') {
717
- window.removeEventListener('online', this.onlineHandler);
718
- this.onlineHandler = null;
719
- }
720
- }
721
- /**
722
- * Create a shared WebSocket connection for multiplexing
723
- * Call this once to create a shared connection that multiple providers can use
724
- */
725
- static createSharedWebSocket(options) {
726
- if (HocuspocusSyncProvider.sharedWebSocketProvider) {
727
- console.warn('Shared WebSocket already exists. Returning existing instance.');
728
- return HocuspocusSyncProvider.sharedWebSocketProvider;
729
- }
730
- const config = {
731
- url: options.url,
732
- };
733
- if (options.WebSocketPolyfill) {
734
- config.WebSocketPolyfill = options.WebSocketPolyfill;
735
- }
736
- if (options.onConnect) {
737
- config.onConnect = options.onConnect;
738
- }
739
- if (options.onDisconnect) {
740
- config.onDisconnect = options.onDisconnect;
741
- }
742
- if (options.onStatus) {
743
- config.onStatus = options.onStatus;
744
- }
745
- HocuspocusSyncProvider.sharedWebSocketProvider = new HocuspocusProviderWebsocket(config);
746
- console.info(`Shared Hocuspocus WebSocket created: ${options.url}`);
747
- return HocuspocusSyncProvider.sharedWebSocketProvider;
748
- }
749
- /**
750
- * Destroy the shared WebSocket connection
751
- * Call this when you're done with all multiplexed providers
752
- */
753
- static destroySharedWebSocket() {
754
- if (HocuspocusSyncProvider.sharedWebSocketProvider) {
755
- HocuspocusSyncProvider.sharedWebSocketProvider.destroy();
756
- HocuspocusSyncProvider.sharedWebSocketProvider = null;
757
- console.info('Shared Hocuspocus WebSocket destroyed');
758
- }
759
- }
760
- /**
761
- * Get the shared WebSocket provider instance (if it exists)
762
- */
763
- static getSharedWebSocket() {
764
- return HocuspocusSyncProvider.sharedWebSocketProvider;
765
- }
766
- /**
767
- * Static factory method for creating HocuspocusSyncProvider with configuration options
768
- * Returns a ProviderFactory that can be used in sync configuration
769
- */
770
- static with(options) {
771
- return {
772
- create: (docName, doc, runtimeOptions) => {
773
- const mergedOptions = runtimeOptions ? { ...options, ...runtimeOptions } : options;
774
- return new HocuspocusSyncProvider(docName, doc, mergedOptions);
775
- },
776
- };
777
- }
778
- async connect() {
779
- if (this.isSynced || this.isDestroyed) {
780
- return;
781
- }
782
- this._connectionStatus = 'connecting';
783
- return new Promise((resolve, reject) => {
784
- // Store reject function so we can cancel the connection if destroyed
785
- this.pendingConnectReject = reject;
786
- this.connectTimeout = setTimeout(() => {
787
- this.pendingConnectReject = null;
788
- this.connectTimeout = null;
789
- reject(new Error('Hocuspocus connection timeout'));
790
- }, this.connectionTimeoutMs);
791
- const syncHandler = () => {
792
- if (this.connectTimeout) {
793
- clearTimeout(this.connectTimeout);
794
- this.connectTimeout = null;
795
- }
796
- this.pendingConnectReject = null;
797
- this.provider.off('synced', syncHandler);
798
- if (!this.isDestroyed) {
799
- resolve();
800
- }
801
- };
802
- this.provider.on('synced', syncHandler);
803
- // If already synced, resolve immediately
804
- if (this.provider.isSynced) {
805
- if (this.connectTimeout) {
806
- clearTimeout(this.connectTimeout);
807
- this.connectTimeout = null;
808
- }
809
- this.pendingConnectReject = null;
810
- this.provider.off('synced', syncHandler);
811
- resolve();
812
- return;
813
- }
814
- // Connect if not already connected (standalone mode only)
815
- if (!this.isConnected && !this.usesSharedSocket) {
816
- this.provider.connect();
817
- }
818
- });
819
- }
820
- async reconnect() {
821
- this.disconnect();
822
- return this.connect();
823
- }
824
- disconnect() {
825
- // Cancel any pending connection attempt
826
- if (this.connectTimeout) {
827
- clearTimeout(this.connectTimeout);
828
- this.connectTimeout = null;
829
- }
830
- if (this.pendingConnectReject) {
831
- this.pendingConnectReject = null; // Don't reject, just abandon the promise
832
- }
833
- if (this.provider) {
834
- if (this.usesSharedSocket) {
835
- // Detach from shared socket instead of disconnecting
836
- this.provider.detach();
837
- }
838
- else {
839
- this.provider.disconnect();
840
- }
841
- }
842
- this.isConnected = false;
843
- this.isSynced = false;
844
- this._connectionStatus = 'disconnected';
845
- }
846
- destroy() {
847
- // Mark as destroyed first to prevent any callbacks from doing work
848
- this.isDestroyed = true;
849
- // Cancel any pending connection attempt
850
- if (this.connectTimeout) {
851
- clearTimeout(this.connectTimeout);
852
- this.connectTimeout = null;
853
- }
854
- if (this.pendingConnectReject) {
855
- this.pendingConnectReject = null; // Don't reject, just abandon the promise
856
- }
857
- this.removeBrowserEventListeners();
858
- if (this.provider) {
859
- this.provider.destroy();
860
- }
861
- this.isConnected = false;
862
- this.isSynced = false;
863
- this._connectionStatus = 'disconnected';
864
- }
865
- }
866
-
867
- export { BroadcastSyncProvider, HocuspocusSyncProvider, WebSocketSyncProvider };
538
+ export { BroadcastSyncProvider, WebSocketSyncProvider };
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-MV-81ybv.js';
2
- import { b as KritzelPath, d as KritzelLine, z as KritzelColorHelper, n as KritzelSelectionTool, g as KritzelBrushTool, h as KritzelLineTool, l as KritzelShapeTool, k as KritzelTextTool, B as KritzelDevicesHelper, E as KritzelMouseButton, F as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, i as KritzelEraserTool, s as DEFAULT_LINE_TOOL_CONFIG, r as DEFAULT_TEXT_CONFIG, j as KritzelImageTool, v as KritzelAlignment, I as IndexedDBSyncProvider, G as KritzelSelectionGroup, J as KritzelSelectionBox, L as KritzelIconRegistry, M as KritzelKeyboardHelper, N as KritzelBaseHandler, O as KritzelToolRegistry, P as KritzelBaseObject, o as KritzelWorkspace, e as KritzelGroup, c as KritzelImage, f as KritzelShape, K as KritzelText, x as runMigrations, w as CURRENT_WORKSPACE_SCHEMA_VERSION, y as WORKSPACE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, A as APP_STATE_MIGRATIONS, Q as ObjectHelper, m as KritzelCursorHelper, p as KritzelAnchorManager, q as KritzelThemeManager, R as KritzelClassHelper, T as KritzelEventHelper, U as KritzelBaseTool, W as WORKSPACE_EXPORT_VERSION } from './workspace.migrations-D48_Bqvh.js';
2
+ import { a as KritzelPath, c as KritzelLine, y as KritzelColorHelper, m as KritzelSelectionTool, f as KritzelBrushTool, g as KritzelLineTool, k as KritzelShapeTool, j as KritzelTextTool, z as KritzelDevicesHelper, B as KritzelMouseButton, E as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, h as KritzelEraserTool, r as DEFAULT_LINE_TOOL_CONFIG, q as DEFAULT_TEXT_CONFIG, i as KritzelImageTool, u as KritzelAlignment, H as HocuspocusSyncProvider, I as IndexedDBSyncProvider, F as KritzelSelectionGroup, G as KritzelSelectionBox, J as KritzelIconRegistry, L as KritzelKeyboardHelper, M as KritzelBaseHandler, N as KritzelToolRegistry, O as KritzelBaseObject, n as KritzelWorkspace, d as KritzelGroup, b as KritzelImage, e as KritzelShape, K as KritzelText, w as runMigrations, v as CURRENT_WORKSPACE_SCHEMA_VERSION, x as WORKSPACE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, A as APP_STATE_MIGRATIONS, P as ObjectHelper, l as KritzelCursorHelper, o as KritzelAnchorManager, p as KritzelThemeManager, Q as KritzelClassHelper, R as KritzelEventHelper, T as KritzelBaseTool, W as WORKSPACE_EXPORT_VERSION } from './workspace.migrations-D6whgl7G.js';
3
3
  import * as Y from 'yjs';
4
4
  import 'y-websocket';
5
5
  import 'y-indexeddb';
@@ -154,7 +154,7 @@ const KritzelAvatar = class {
154
154
  };
155
155
  KritzelAvatar.style = kritzelAvatarCss();
156
156
 
157
- const kritzelAwarenessCursorsCss = () => `:host{display:block;position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:9500}.awareness-cursor{position:absolute;top:0;left:0;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform}.awareness-cursor.stale{opacity:0}.awareness-cursor.tracking-object{transition-duration:0ms}.cursor-arrow{filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.cursor-label{position:absolute;left:16px;top:16px;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;user-select:none}.edge-indicator{position:absolute;top:-12px;left:-12px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform;pointer-events:auto;user-select:none;cursor:pointer}.edge-indicator.stale{opacity:0}.edge-indicator.tracking-object{transition-duration:0ms}.edge-arrow{position:absolute;filter:drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3))}.edge-label{position:absolute;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;opacity:0;transform-origin:center;transition:opacity 150ms ease}.edge-indicator:hover .edge-label{opacity:1}.remote-selection-box{position:absolute;top:0;left:0;border-width:2px;border-style:solid;pointer-events:none;will-change:transform, width, height;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, width var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, height var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out}`;
157
+ const kritzelAwarenessCursorsCss = () => `:host{display:block;position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:1}.awareness-cursor{position:absolute;top:0;left:0;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform}.awareness-cursor.stale{opacity:0}.awareness-cursor.tracking-object{transition-duration:0ms}.cursor-arrow{filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.cursor-label{position:absolute;left:16px;top:16px;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;user-select:none}.edge-indicator{position:absolute;top:-12px;left:-12px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, opacity 300ms ease;will-change:transform;pointer-events:auto;user-select:none;cursor:pointer}.edge-indicator.stale{opacity:0}.edge-indicator.tracking-object{transition-duration:0ms}.edge-arrow{position:absolute;filter:drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3));transition:opacity 300ms ease}.edge-arrow.stale{opacity:0}.edge-label{position:absolute;white-space:nowrap;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;font-size:var(--kritzel-awareness-cursor-label-font-size, 12px);color:var(--kritzel-awareness-cursor-label-text-color, #ffffff);padding:2px 8px;border-radius:4px;line-height:1.4;font-weight:500;pointer-events:none;opacity:0;transform-origin:center;transition:opacity 150ms ease}.edge-indicator:hover .edge-label{opacity:1}.remote-selection-box{position:absolute;top:0;left:0;border-width:2px;border-style:solid;pointer-events:none;will-change:transform, width, height;transition:transform var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, width var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out, height var(--kritzel-awareness-cursor-transition-duration, 100ms) ease-out}`;
158
158
 
159
159
  const STALE_THRESHOLD_MS = 10_000;
160
160
  const REMOVE_THRESHOLD_MS = 30_000;
@@ -236,6 +236,9 @@ const KritzelAwarenessCursors = class {
236
236
  updated.delete(clientId);
237
237
  changed = true;
238
238
  }
239
+ else if (!changed && now - cursor.lastCursorMove > STALE_THRESHOLD_MS) {
240
+ changed = true;
241
+ }
239
242
  }
240
243
  if (changed) {
241
244
  this.remoteCursors = updated;
@@ -331,7 +334,7 @@ const KritzelAwarenessCursors = class {
331
334
  }
332
335
  render() {
333
336
  const cursors = Array.from(this.remoteCursors.values());
334
- return (h(Host, { key: '4dd962322c7e955b9038c55cb10f8ffda1e0b246' }, cursors.map(remoteCursor => {
337
+ return (h(Host, { key: '5a28def6e024249c4309c087502cde9f219f5421' }, cursors.map(remoteCursor => {
335
338
  if (!remoteCursor.cursor)
336
339
  return null;
337
340
  // When a remote user is actively drawing, derive cursor position from
@@ -407,7 +410,7 @@ const KritzelAwarenessCursors = class {
407
410
  const displayName = this.getUserDisplayName(cursor.user);
408
411
  return (h("div", { key: `edge-${cursor.clientId}`, class: { 'edge-indicator': true, stale, 'tracking-object': trackingObject }, style: {
409
412
  transform: `translate(${clamped.x}px, ${clamped.y}px)`,
410
- } }, h("svg", { class: "edge-arrow", width: "16", height: "16", viewBox: "0 0 16 16", style: { transform: `rotate(${arrowDeg}deg)` } }, h("path", { d: "M8 1L14 13H2L8 1Z", fill: color, stroke: "#ffffff", "stroke-width": "1.5", "stroke-linejoin": "round" })), h("span", { class: "edge-label", style: {
413
+ } }, h("svg", { class: { 'edge-arrow': true, stale }, width: "16", height: "16", viewBox: "0 0 16 16", style: { transform: `rotate(${arrowDeg}deg)` } }, h("path", { d: "M8 1L14 13H2L8 1Z", fill: color, stroke: "#ffffff", "stroke-width": "1.5", "stroke-linejoin": "round" })), h("span", { class: "edge-label", style: {
411
414
  backgroundColor: color,
412
415
  transform: `translate(${labelX}px, ${labelY}px)`,
413
416
  } }, displayName)));
@@ -1832,7 +1835,7 @@ const DEFAULT_SHAPE_CONFIG = {
1832
1835
  const ABSOLUTE_SCALE_MAX = 1000;
1833
1836
  const ABSOLUTE_SCALE_MIN = 0.0001;
1834
1837
 
1835
- 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}.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}.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}`;
1838
+ 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}`;
1836
1839
 
1837
1840
  const KritzelEditor = class {
1838
1841
  constructor(hostRef) {
@@ -1866,7 +1869,11 @@ const KritzelEditor = class {
1866
1869
  showSyncProviderInfo: true,
1867
1870
  showMigrationInfo: true,
1868
1871
  };
1869
- user;
1872
+ user = {
1873
+ id: `guest-1`,
1874
+ displayName: 'Guest',
1875
+ isGuest: false,
1876
+ };
1870
1877
  activeUsers;
1871
1878
  controls = [
1872
1879
  {
@@ -2011,7 +2018,8 @@ const KritzelEditor = class {
2011
2018
  isControlsVisible = true;
2012
2019
  isUtilityPanelVisible = true;
2013
2020
  syncConfig = {
2014
- providers: [IndexedDBSyncProvider]
2021
+ appStateId: 'kritzel-app-test',
2022
+ providers: [HocuspocusSyncProvider, IndexedDBSyncProvider]
2015
2023
  };
2016
2024
  /** Optional login configuration. When provided, a "Sign in" button is shown that opens a login dialog with the configured providers. */
2017
2025
  loginConfig;
@@ -2528,7 +2536,7 @@ const KritzelEditor = class {
2528
2536
  const isLoggedIn = this.isLoggedIn;
2529
2537
  const shouldShowCurrentUser = isLoggedIn;
2530
2538
  const shouldShowLoginButton = !!this.loginConfig && !isLoggedIn;
2531
- return (h(Host, { key: 'd1944655652eb2939e3696ed70050baaca0871e2' }, h("div", { key: 'ce5dfd9b8f8d9927e9a6ace4056f9053163c7e0a', class: "top-left-buttons" }, h("kritzel-workspace-manager", { key: 'e127a667c6e4e853bb4f0c9ffd0edaa6d80d9dfa', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-back-to-content", { key: 'a9abb378f3c79f356d2164cbddf6badba10188a8', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), h("kritzel-engine", { key: 'c5f764580f3623eeb9381e54769a891a48c04620', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, scaleMin: this.scaleMin, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.currentTheme, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), h("kritzel-controls", { key: '2479b6979d5b2b6c55a873bd1d8468b5fd967f72', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, theme: this.currentTheme, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: 'ec6ac72ba154abe0738259464f20cae9e7dbdd9e', class: "top-right-buttons" }, h("kritzel-settings", { key: 'f68f791d673b30331e55f358b9c71b3e2a9a8388', ref: el => (this.settingsRef = el), shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: 'dfe5a051caccee504df4f347705303fa1f812556', ref: el => (this.exportRef = el), workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '48983a14d3902cd238cf0d9ed302ed561a655a9a', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: '589bdc895741a2d17f60c4b549d14fe8fff74c17', user: this.user }), shouldShowLoginButton && h("kritzel-button", { key: '50414a9d7ade623678c767ce63c49f5e99336bed', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), h("kritzel-more-menu", { key: 'db3069ee0b093acd238750df81c6f426139c9b87', items: this.moreMenuItems }), h("kritzel-share-dialog", { key: 'e16057838f00b2c3f239e794b4310bd2690d16e2', ref: el => (this.shareDialogRef = el), isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: 'a6d1fc06c983542c6af95e7bb4b2b2d522a03605', ref: el => (this.loginDialogRef = el), providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
2539
+ return (h(Host, { key: 'b52c23bf28392a0061034c0909aadb7abf4d86a7' }, h("div", { key: '7bf75101bef73a2c8481258060e3236a8ca939b4', class: "top-left-buttons" }, h("kritzel-workspace-manager", { key: '69adc1756e00ed56c9980e78929543ad4ecc7b0e', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-back-to-content", { key: 'd802fe454738919d9108a807eb379b2f31e94ab6', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), h("kritzel-engine", { key: '2d3ce8937285956d978f3947ffa86872e156b04d', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, scaleMin: this.scaleMin, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.currentTheme, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), h("kritzel-controls", { key: '6d9b0640b205143c7dc21572616624ef707cfe06', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, theme: this.currentTheme, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: 'c65f16c40d78d8e3eb585e870e414f496e816e82', class: "top-right-buttons" }, h("kritzel-settings", { key: 'a84d5de344011a32be1b4178acc3a5fff246d702', ref: el => (this.settingsRef = el), shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '67748d0376f4e7ac39edfc61c1c2cd639664ad78', ref: el => (this.exportRef = el), workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '1155b8784de2353ae208a2910844bad1e945a891', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: 'fb8951eed7f7f5c9117bb0027e9af1aae95088ed', user: this.user }), shouldShowLoginButton && h("kritzel-button", { key: 'd4288b1577082c207696331de4d9fcb1e749fa2a', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), h("kritzel-more-menu", { key: '66f0990868bf034a172e6e8db3162a1af0637cf8', items: this.moreMenuItems }), h("kritzel-share-dialog", { key: 'ce3ab2b6db71bf0a4998c16f04521ee39c1715b7', ref: el => (this.shareDialogRef = el), isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: 'd3ec7461c2e6a8fcdac4ce13a51f80835888cb44', ref: el => (this.loginDialogRef = el), providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
2532
2540
  }
2533
2541
  static get watchers() { return {
2534
2542
  "isEngineReady": [{
@@ -26999,18 +27007,28 @@ const KritzelEngine = class {
26999
27007
  zIndex: (object.zIndex + 2).toString(),
27000
27008
  } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
27001
27009
  (() => {
27002
- const isRemoteSelection = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') &&
27003
- object.userId != null &&
27004
- this.core.user?.id != null &&
27005
- object.userId !== this.core.user.id;
27010
+ const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
27011
+ const localClientId = this.core.store.state.objects?.localClientId;
27012
+ const isRemoteSelection = isSelectionGroup && (
27013
+ // Different user
27014
+ (object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
27015
+ // Same user but different client (e.g. same account in two browser tabs)
27016
+ (object.clientId != null && localClientId != null && object.clientId !== localClientId));
27006
27017
  let remoteUserColor;
27007
27018
  if (isRemoteSelection) {
27008
27019
  const awarenessStates = this.core.store.state.objects?.awareness?.getStates();
27009
27020
  if (awarenessStates) {
27010
- for (const state of awarenessStates.values()) {
27011
- if (state.user?.id === object.userId) {
27012
- remoteUserColor = state.user.color;
27013
- break;
27021
+ // Try direct lookup by clientId first (most precise)
27022
+ if (isSelectionGroup && object.clientId != null) {
27023
+ remoteUserColor = awarenessStates.get(object.clientId)?.user?.color;
27024
+ }
27025
+ // Fall back to userId match (for selection groups without clientId)
27026
+ if (!remoteUserColor) {
27027
+ for (const state of awarenessStates.values()) {
27028
+ if (state.user?.id === object.userId) {
27029
+ remoteUserColor = state.user.color;
27030
+ break;
27031
+ }
27014
27032
  }
27015
27033
  }
27016
27034
  }
@@ -28499,7 +28517,7 @@ const KritzelPortal = class {
28499
28517
  * This file is auto-generated by the version bump scripts.
28500
28518
  * Do not modify manually.
28501
28519
  */
28502
- const KRITZEL_VERSION = '0.1.76';
28520
+ const KRITZEL_VERSION = '0.1.77';
28503
28521
 
28504
28522
  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)}`;
28505
28523
 
@@ -29344,7 +29362,7 @@ const KritzelTooltip = class {
29344
29362
  };
29345
29363
  KritzelTooltip.style = kritzelTooltipCss();
29346
29364
 
29347
- const kritzelUtilityPanelCss = () => `:host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:var(--kritzel-utility-panel-background-color, #e2e2e2);width:fit-content;user-select:none}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-utility-panel-button-color, #333333);--kritzel-icon-color:var(--kritzel-utility-panel-button-color, #333333);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-utility-panel-button-border-radius, 8px)}.utility-button:hover,.utility-button:focus-visible{background-color:var(--kritzel-utility-panel-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.utility-button:disabled{opacity:0.4;cursor:not-allowed;pointer-events:none}.utility-separator{width:1px;height:16px;background-color:var(--kritzel-utility-panel-separator-color, hsl(0, 0%, 0%, 8%))}`;
29365
+ const kritzelUtilityPanelCss = () => `:host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:var(--kritzel-utility-panel-background-color, #e2e2e2);width:fit-content;user-select:none;z-index:10000}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-utility-panel-button-color, #333333);--kritzel-icon-color:var(--kritzel-utility-panel-button-color, #333333);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-utility-panel-button-border-radius, 8px)}.utility-button:hover,.utility-button:focus-visible{background-color:var(--kritzel-utility-panel-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.utility-button:disabled{opacity:0.4;cursor:not-allowed;pointer-events:none}.utility-separator{width:1px;height:16px;background-color:var(--kritzel-utility-panel-separator-color, hsl(0, 0%, 0%, 8%))}`;
29348
29366
 
29349
29367
  const KritzelUtilityPanel = class {
29350
29368
  constructor(hostRef) {