kritzel-stencil 0.3.30 → 0.3.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/kritzel-active-users_45.cjs.entry.js +256 -113
- package/dist/cjs/{schema.constants-TiseVL4a.js → schema.constants-DItwOm2z.js} +32 -2
- package/dist/collection/classes/handlers/line-handle.handler.js +4 -2
- package/dist/collection/classes/managers/browser-permission.manager.js +4 -4
- package/dist/collection/classes/managers/clipboard.manager.js +36 -104
- package/dist/collection/classes/managers/clipboard.types.js +1 -0
- package/dist/collection/classes/objects/base-object.class.js +7 -0
- package/dist/collection/classes/objects/line.class.js +21 -0
- package/dist/collection/classes/providers/paste-intent/event-paste-intent.provider.js +48 -0
- package/dist/collection/classes/providers/paste-intent/ios-paste-intent.provider.js +16 -0
- package/dist/collection/classes/providers/paste-intent/navigator-paste-intent.provider.js +86 -0
- package/dist/collection/classes/registries/paste-intent-provider.registry.js +26 -0
- package/dist/collection/classes/structures/object-map.structure.js +29 -5
- package/dist/collection/classes/structures/quadtree.structure.js +14 -0
- package/dist/collection/constants/version.js +1 -1
- package/dist/collection/interfaces/paste-intent-provider.interface.js +1 -0
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-awareness-cursors.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/{p-BC7jWR_G.js → p-14NPx-_P.js} +1 -1
- package/dist/components/{p-B4WfPDj0.js → p-BmX2Vb4Z.js} +1 -1
- package/dist/components/{p-pCB0JKlD.js → p-COhjyuRa.js} +1 -1
- package/dist/components/{p-E4tWs1Ga.js → p-DK2ZByiU.js} +2 -2
- package/dist/components/p-DfIknZRl.js +1 -0
- package/dist/components/{p-CPnjRgkl.js → p-Dl3MwBL1.js} +1 -1
- package/dist/components/{p-CRQEFKjb.js → p-FjazwgrY.js} +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-active-users_45.entry.js +256 -113
- package/dist/esm/{schema.constants-7ayQfjzt.js → schema.constants-CH2FWTVr.js} +32 -2
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-CH2FWTVr.js +1 -0
- package/dist/stencil/p-be38d770.entry.js +9 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/managers/clipboard.manager.d.ts +21 -37
- package/dist/types/classes/managers/clipboard.types.d.ts +23 -0
- package/dist/types/classes/objects/line.class.d.ts +11 -0
- package/dist/types/classes/providers/paste-intent/event-paste-intent.provider.d.ts +8 -0
- package/dist/types/classes/providers/paste-intent/ios-paste-intent.provider.d.ts +6 -0
- package/dist/types/classes/providers/paste-intent/navigator-paste-intent.provider.d.ts +9 -0
- package/dist/types/classes/registries/paste-intent-provider.registry.d.ts +10 -0
- package/dist/types/classes/structures/object-map.structure.d.ts +1 -0
- package/dist/types/classes/structures/quadtree.structure.d.ts +8 -0
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/interfaces/paste-intent-provider.interface.d.ts +10 -0
- package/package.json +1 -1
- package/dist/components/p-BNu3Akp5.js +0 -1
- package/dist/stencil/p-0adfecf4.entry.js +0 -9
- package/dist/stencil/p-7ayQfjzt.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{p as e,H as t,c as s,h as i,d as o,t as n}from"./p-B43upypT.js";import{a,C as l}from"./p-CW-VyJgK.js";import{d as r}from"./p-DX2nriaq.js";import{d as c}from"./p-Df3BwVGy.js";import{d as h}from"./p-CdR76C4L.js";import{d as g}from"./p-D0v9WP5w.js";import{d}from"./p-BrAeYciD.js";import{d as p}from"./p-D0RYktBV.js";const u=-1/0,b=1/0,m=-1/0,f=1/0,v={showViewportInfo:!1,showObjectInfo:!1,showSyncProviderInfo:!0,showMigrationInfo:!0,showAssetResolverInfo:!1},w=["general","viewport","shortcuts","developer","about"],y=e(class extends t{constructor(e){super(),!1!==e&&this.__registerHost(),this.__attachShadow(),this.settingsChange=s(this,"settingsChange")}get host(){return this}availableThemes=["light","dark"];availableLocales=[];shortcuts=[];terms={};settings;onSettingsPropChange(e){e&&this.applySettings(e)}isDialogOpen=!1;selectedCategoryId=w[0];scaleMin=1e-4;scaleMax=1e3;lockDrawingScale=!0;theme="light";locale="en";viewportBoundaryLeft=u;viewportBoundaryRight=b;viewportBoundaryTop=m;viewportBoundaryBottom=f;debugInfo={...v};settingsChange;componentWillLoad(){this.settings&&this.applySettings(this.settings)}applySettings(e){"number"==typeof e.scaleMin&&(this.scaleMin=e.scaleMin),"number"==typeof e.scaleMax&&(this.scaleMax=e.scaleMax),"boolean"==typeof e.lockDrawingScale&&(this.lockDrawingScale=e.lockDrawingScale),"string"==typeof e.theme&&(this.theme=e.theme),"string"==typeof e.locale&&(this.locale=e.locale),"number"==typeof e.viewportBoundaryLeft&&(this.viewportBoundaryLeft=e.viewportBoundaryLeft),"number"==typeof e.viewportBoundaryRight&&(this.viewportBoundaryRight=e.viewportBoundaryRight),"number"==typeof e.viewportBoundaryTop&&(this.viewportBoundaryTop=e.viewportBoundaryTop),"number"==typeof e.viewportBoundaryBottom&&(this.viewportBoundaryBottom=e.viewportBoundaryBottom),e.debugInfo&&(this.debugInfo={...v,...e.debugInfo})}emitSettings(){this.settingsChange.emit({scaleMin:this.scaleMin,scaleMax:this.scaleMax,lockDrawingScale:this.lockDrawingScale,theme:this.theme,locale:this.locale,viewportBoundaryLeft:this.viewportBoundaryLeft,viewportBoundaryRight:this.viewportBoundaryRight,viewportBoundaryTop:this.viewportBoundaryTop,viewportBoundaryBottom:this.viewportBoundaryBottom,debugInfo:this.debugInfo})}handleScaleMinChange=e=>{this.scaleMin=e.detail,this.emitSettings()};handleScaleMaxChange=e=>{this.scaleMax=e.detail,this.emitSettings()};handleLockDrawingScaleChange=e=>{this.lockDrawingScale=e.detail,this.emitSettings()};handleThemeChange=e=>{this.theme=e.detail,this.emitSettings()};handleLocaleChange=e=>{this.locale=e.detail,this.emitSettings()};handleViewportBoundaryLeftChange=e=>{this.viewportBoundaryLeft=e.detail??u,this.emitSettings()};handleViewportBoundaryRightChange=e=>{this.viewportBoundaryRight=e.detail??b,this.emitSettings()};handleViewportBoundaryTopChange=e=>{this.viewportBoundaryTop=e.detail??m,this.emitSettings()};handleViewportBoundaryBottomChange=e=>{this.viewportBoundaryBottom=e.detail??f,this.emitSettings()};handleDebugInfoChange=e=>t=>{this.debugInfo={...this.debugInfo,[e]:t.detail},this.emitSettings()};async open(){this.isDialogOpen=!0}closeDialog=()=>{this.isDialogOpen=!1};handleCategorySelect=e=>{this.selectedCategoryId=e.detail.item.id};formatKeyCombo(e){const t=[];return e.ctrl&&t.push("Ctrl"),e.shift&&t.push("Shift"),t.push(this.formatKey(e.key)),t.join("+")}formatKey(e){return{Escape:"Esc",Delete:"Del"," ":"Space"}[e]??e.toUpperCase()}groupShortcutsByCategory(){const e=new Map;for(const t of this.shortcuts){const s=e.get(t.category)||[];s.push(t),e.set(t.category,s)}return e}t(e,t){return this.terms[e]??t}get categories(){const e={general:"settings",viewport:"viewport",shortcuts:"command",developer:"braces",about:"info"},t={general:{key:"settings.categories.general",fallback:"General"},viewport:{key:"settings.categories.viewport",fallback:"Viewport"},shortcuts:{key:"settings.categories.shortcuts",fallback:"Keyboard Shortcuts"},developer:{key:"settings.categories.developer",fallback:"Developer Options"},about:{key:"settings.categories.about",fallback:"About"}};return w.map((s=>({id:s,label:this.t(t[s].key,t[s].fallback),icon:e[s]})))}renderCategoryContent(){switch(this.selectedCategoryId){case"general":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.general.title","General Settings")),i("div",{class:"settings-group"},i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.general.theme.label","Theme")),i("p",{class:"settings-description"},this.t("settings.general.theme.description","Select a registered color theme for the editor interface.")),i("kritzel-dropdown",{options:this.availableThemes.map((e=>({value:e,label:e}))),value:this.theme,onValueChanged:this.handleThemeChange})),this.availableLocales.length>0&&i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.general.language.label","Language")),i("p",{class:"settings-description"},this.t("settings.general.language.description","Select the display language for the editor interface.")),i("kritzel-dropdown",{options:this.availableLocales.map((e=>({value:e.code,label:e.label}))),value:this.locale,onValueChanged:this.handleLocaleChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.general.lockDrawingScale.label","Lock Drawing Scale")),i("p",{class:"settings-description"},this.t("settings.general.lockDrawingScale.description","When enabled, drawn objects maintain a fixed visual size regardless of the current zoom level.")),i("kritzel-slide-toggle",{checked:this.lockDrawingScale,label:this.t("settings.general.lockDrawingScale.label","Lock Drawing Scale"),onCheckedChange:this.handleLockDrawingScaleChange}))));case"viewport":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.viewport.title","Viewport Settings")),i("div",{class:"settings-group"},i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.minZoom.label","Minimum Zoom Level")),i("p",{class:"settings-description"},this.t("settings.viewport.minZoom.description","Sets the minimum zoom level. Lower values allow zooming out further to see more of the canvas.")),i("kritzel-numeric-input",{value:this.scaleMin,min:1e-4,max:1,step:1e-4,onValueChange:this.handleScaleMinChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.maxZoom.label","Maximum Zoom Level")),i("p",{class:"settings-description"},this.t("settings.viewport.maxZoom.description","Sets the maximum zoom level. Higher values allow zooming in closer for detailed work.")),i("kritzel-numeric-input",{value:this.scaleMax,min:1,max:1e3,step:1,onValueChange:this.handleScaleMaxChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryLeft.label","Viewport Boundary Left")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryLeft.description","Left boundary in world coordinates. Set to limit how far left the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryLeft,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryLeftChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryRight.label","Viewport Boundary Right")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryRight.description","Right boundary in world coordinates. Set to limit how far right the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryRight,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryRightChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryTop.label","Viewport Boundary Top")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryTop.description","Top boundary in world coordinates. Set to limit how far up the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryTop,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryTopChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryBottom.label","Viewport Boundary Bottom")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryBottom.description","Bottom boundary in world coordinates. Set to limit how far down the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryBottom,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryBottomChange}))));case"shortcuts":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.shortcuts.title","Keyboard Shortcuts")),i("div",{class:"shortcuts-list"},Array.from(this.groupShortcutsByCategory()).map((([e,t])=>i("div",{class:"shortcuts-category",key:e},i("h4",{class:"shortcuts-category-title"},e),i("div",{class:"shortcuts-group"},t.map((e=>i("div",{class:"shortcut-item",key:e.key+e.label},i("span",{class:"shortcut-label"},e.label),i("kbd",{class:"shortcut-key"},this.formatKeyCombo(e)))))))))));case"developer":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.developer.title","Developer Options")),i("div",{class:"settings-group"},i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showViewportInfo.label","Show Viewport Info")),i("p",{class:"settings-description"},this.t("settings.developer.showViewportInfo.description","Display viewport debug information such as position, zoom level, and boundaries.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showViewportInfo,label:this.t("settings.developer.showViewportInfo.label","Show Viewport Info"),onCheckedChange:this.handleDebugInfoChange("showViewportInfo")})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showObjectInfo.label","Show Object Info")),i("p",{class:"settings-description"},this.t("settings.developer.showObjectInfo.description","Display debug information about objects on the canvas.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showObjectInfo,label:this.t("settings.developer.showObjectInfo.label","Show Object Info"),onCheckedChange:this.handleDebugInfoChange("showObjectInfo")})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showSyncProviderInfo.label","Show Sync Provider Info")),i("p",{class:"settings-description"},this.t("settings.developer.showSyncProviderInfo.description","Display debug information about the sync provider connection status.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showSyncProviderInfo,label:this.t("settings.developer.showSyncProviderInfo.label","Show Sync Provider Info"),onCheckedChange:this.handleDebugInfoChange("showSyncProviderInfo")})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showMigrationInfo.label","Show Migration Info")),i("p",{class:"settings-description"},this.t("settings.developer.showMigrationInfo.description","Display debug information about data migrations.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showMigrationInfo,label:this.t("settings.developer.showMigrationInfo.label","Show Migration Info"),onCheckedChange:this.handleDebugInfoChange("showMigrationInfo")}))));case"about":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.about.title","About")),i("p",null,this.t("settings.about.description","Kritzel - A drawing application")),i("p",{class:"version-info"},"Version ","0.3.30"),i("p",{class:"version-info"},"App-State Schema v",l),i("p",{class:"version-info"},"Workspace Schema v",a));default:return null}}render(){return i(o,{key:"8b96261465efeabb2eb0cf724d29699de5e230a8"},i("kritzel-dialog",{key:"273a9df290bb97d59000a97f91821e7bad3f3896",isOpen:this.isDialogOpen,dialogTitle:this.t("settings.dialogTitle","Settings"),size:"large",contained:!0,onDialogClose:this.closeDialog},i("kritzel-master-detail",{key:"64d17dfaa2a0baf2d4a5d00fe5fc65ad40c96ec6",items:this.categories,selectedItemId:this.selectedCategoryId,onItemSelect:this.handleCategorySelect},this.renderCategoryContent())))}static get watchers(){return{settings:[{onSettingsPropChange:0}]}}static get style(){return":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)}"}},[513,"kritzel-settings",{availableThemes:[16],availableLocales:[16],shortcuts:[16],terms:[16],settings:[16],isDialogOpen:[32],selectedCategoryId:[32],scaleMin:[32],scaleMax:[32],lockDrawingScale:[32],theme:[32],locale:[32],viewportBoundaryLeft:[32],viewportBoundaryRight:[32],viewportBoundaryTop:[32],viewportBoundaryBottom:[32],debugInfo:[32],open:[64]},void 0,{settings:[{onSettingsPropChange:0}]}]);function k(){"undefined"!=typeof customElements&&["kritzel-settings","kritzel-dialog","kritzel-dropdown","kritzel-icon","kritzel-master-detail","kritzel-numeric-input","kritzel-slide-toggle"].forEach((e=>{switch(e){case"kritzel-settings":customElements.get(n(e))||customElements.define(n(e),y);break;case"kritzel-dialog":customElements.get(n(e))||r();break;case"kritzel-dropdown":customElements.get(n(e))||c();break;case"kritzel-icon":customElements.get(n(e))||h();break;case"kritzel-master-detail":customElements.get(n(e))||g();break;case"kritzel-numeric-input":customElements.get(n(e))||d();break;case"kritzel-slide-toggle":customElements.get(n(e))||p()}}))}export{y as K,k as d}
|
|
1
|
+
import{p as e,H as t,c as s,h as i,d as o,t as n}from"./p-B43upypT.js";import{a,C as l}from"./p-CW-VyJgK.js";import{d as r}from"./p-DX2nriaq.js";import{d as c}from"./p-Df3BwVGy.js";import{d as h}from"./p-CdR76C4L.js";import{d as g}from"./p-D0v9WP5w.js";import{d}from"./p-BrAeYciD.js";import{d as p}from"./p-D0RYktBV.js";const u=-1/0,b=1/0,m=-1/0,f=1/0,v={showViewportInfo:!1,showObjectInfo:!1,showSyncProviderInfo:!0,showMigrationInfo:!0,showAssetResolverInfo:!1},w=["general","viewport","shortcuts","developer","about"],y=e(class extends t{constructor(e){super(),!1!==e&&this.__registerHost(),this.__attachShadow(),this.settingsChange=s(this,"settingsChange")}get host(){return this}availableThemes=["light","dark"];availableLocales=[];shortcuts=[];terms={};settings;onSettingsPropChange(e){e&&this.applySettings(e)}isDialogOpen=!1;selectedCategoryId=w[0];scaleMin=1e-4;scaleMax=1e3;lockDrawingScale=!0;theme="light";locale="en";viewportBoundaryLeft=u;viewportBoundaryRight=b;viewportBoundaryTop=m;viewportBoundaryBottom=f;debugInfo={...v};settingsChange;componentWillLoad(){this.settings&&this.applySettings(this.settings)}applySettings(e){"number"==typeof e.scaleMin&&(this.scaleMin=e.scaleMin),"number"==typeof e.scaleMax&&(this.scaleMax=e.scaleMax),"boolean"==typeof e.lockDrawingScale&&(this.lockDrawingScale=e.lockDrawingScale),"string"==typeof e.theme&&(this.theme=e.theme),"string"==typeof e.locale&&(this.locale=e.locale),"number"==typeof e.viewportBoundaryLeft&&(this.viewportBoundaryLeft=e.viewportBoundaryLeft),"number"==typeof e.viewportBoundaryRight&&(this.viewportBoundaryRight=e.viewportBoundaryRight),"number"==typeof e.viewportBoundaryTop&&(this.viewportBoundaryTop=e.viewportBoundaryTop),"number"==typeof e.viewportBoundaryBottom&&(this.viewportBoundaryBottom=e.viewportBoundaryBottom),e.debugInfo&&(this.debugInfo={...v,...e.debugInfo})}emitSettings(){this.settingsChange.emit({scaleMin:this.scaleMin,scaleMax:this.scaleMax,lockDrawingScale:this.lockDrawingScale,theme:this.theme,locale:this.locale,viewportBoundaryLeft:this.viewportBoundaryLeft,viewportBoundaryRight:this.viewportBoundaryRight,viewportBoundaryTop:this.viewportBoundaryTop,viewportBoundaryBottom:this.viewportBoundaryBottom,debugInfo:this.debugInfo})}handleScaleMinChange=e=>{this.scaleMin=e.detail,this.emitSettings()};handleScaleMaxChange=e=>{this.scaleMax=e.detail,this.emitSettings()};handleLockDrawingScaleChange=e=>{this.lockDrawingScale=e.detail,this.emitSettings()};handleThemeChange=e=>{this.theme=e.detail,this.emitSettings()};handleLocaleChange=e=>{this.locale=e.detail,this.emitSettings()};handleViewportBoundaryLeftChange=e=>{this.viewportBoundaryLeft=e.detail??u,this.emitSettings()};handleViewportBoundaryRightChange=e=>{this.viewportBoundaryRight=e.detail??b,this.emitSettings()};handleViewportBoundaryTopChange=e=>{this.viewportBoundaryTop=e.detail??m,this.emitSettings()};handleViewportBoundaryBottomChange=e=>{this.viewportBoundaryBottom=e.detail??f,this.emitSettings()};handleDebugInfoChange=e=>t=>{this.debugInfo={...this.debugInfo,[e]:t.detail},this.emitSettings()};async open(){this.isDialogOpen=!0}closeDialog=()=>{this.isDialogOpen=!1};handleCategorySelect=e=>{this.selectedCategoryId=e.detail.item.id};formatKeyCombo(e){const t=[];return e.ctrl&&t.push("Ctrl"),e.shift&&t.push("Shift"),t.push(this.formatKey(e.key)),t.join("+")}formatKey(e){return{Escape:"Esc",Delete:"Del"," ":"Space"}[e]??e.toUpperCase()}groupShortcutsByCategory(){const e=new Map;for(const t of this.shortcuts){const s=e.get(t.category)||[];s.push(t),e.set(t.category,s)}return e}t(e,t){return this.terms[e]??t}get categories(){const e={general:"settings",viewport:"viewport",shortcuts:"command",developer:"braces",about:"info"},t={general:{key:"settings.categories.general",fallback:"General"},viewport:{key:"settings.categories.viewport",fallback:"Viewport"},shortcuts:{key:"settings.categories.shortcuts",fallback:"Keyboard Shortcuts"},developer:{key:"settings.categories.developer",fallback:"Developer Options"},about:{key:"settings.categories.about",fallback:"About"}};return w.map((s=>({id:s,label:this.t(t[s].key,t[s].fallback),icon:e[s]})))}renderCategoryContent(){switch(this.selectedCategoryId){case"general":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.general.title","General Settings")),i("div",{class:"settings-group"},i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.general.theme.label","Theme")),i("p",{class:"settings-description"},this.t("settings.general.theme.description","Select a registered color theme for the editor interface.")),i("kritzel-dropdown",{options:this.availableThemes.map((e=>({value:e,label:e}))),value:this.theme,onValueChanged:this.handleThemeChange})),this.availableLocales.length>0&&i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.general.language.label","Language")),i("p",{class:"settings-description"},this.t("settings.general.language.description","Select the display language for the editor interface.")),i("kritzel-dropdown",{options:this.availableLocales.map((e=>({value:e.code,label:e.label}))),value:this.locale,onValueChanged:this.handleLocaleChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.general.lockDrawingScale.label","Lock Drawing Scale")),i("p",{class:"settings-description"},this.t("settings.general.lockDrawingScale.description","When enabled, drawn objects maintain a fixed visual size regardless of the current zoom level.")),i("kritzel-slide-toggle",{checked:this.lockDrawingScale,label:this.t("settings.general.lockDrawingScale.label","Lock Drawing Scale"),onCheckedChange:this.handleLockDrawingScaleChange}))));case"viewport":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.viewport.title","Viewport Settings")),i("div",{class:"settings-group"},i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.minZoom.label","Minimum Zoom Level")),i("p",{class:"settings-description"},this.t("settings.viewport.minZoom.description","Sets the minimum zoom level. Lower values allow zooming out further to see more of the canvas.")),i("kritzel-numeric-input",{value:this.scaleMin,min:1e-4,max:1,step:1e-4,onValueChange:this.handleScaleMinChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.maxZoom.label","Maximum Zoom Level")),i("p",{class:"settings-description"},this.t("settings.viewport.maxZoom.description","Sets the maximum zoom level. Higher values allow zooming in closer for detailed work.")),i("kritzel-numeric-input",{value:this.scaleMax,min:1,max:1e3,step:1,onValueChange:this.handleScaleMaxChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryLeft.label","Viewport Boundary Left")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryLeft.description","Left boundary in world coordinates. Set to limit how far left the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryLeft,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryLeftChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryRight.label","Viewport Boundary Right")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryRight.description","Right boundary in world coordinates. Set to limit how far right the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryRight,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryRightChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryTop.label","Viewport Boundary Top")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryTop.description","Top boundary in world coordinates. Set to limit how far up the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryTop,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryTopChange})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.viewport.boundaryBottom.label","Viewport Boundary Bottom")),i("p",{class:"settings-description"},this.t("settings.viewport.boundaryBottom.description","Bottom boundary in world coordinates. Set to limit how far down the viewport can pan.")),i("kritzel-numeric-input",{value:this.viewportBoundaryBottom,step:100,placeholder:this.t("settings.viewport.boundaryPlaceholder","Infinite"),onValueChange:this.handleViewportBoundaryBottomChange}))));case"shortcuts":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.shortcuts.title","Keyboard Shortcuts")),i("div",{class:"shortcuts-list"},Array.from(this.groupShortcutsByCategory()).map((([e,t])=>i("div",{class:"shortcuts-category",key:e},i("h4",{class:"shortcuts-category-title"},e),i("div",{class:"shortcuts-group"},t.map((e=>i("div",{class:"shortcut-item",key:e.key+e.label},i("span",{class:"shortcut-label"},e.label),i("kbd",{class:"shortcut-key"},this.formatKeyCombo(e)))))))))));case"developer":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.developer.title","Developer Options")),i("div",{class:"settings-group"},i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showViewportInfo.label","Show Viewport Info")),i("p",{class:"settings-description"},this.t("settings.developer.showViewportInfo.description","Display viewport debug information such as position, zoom level, and boundaries.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showViewportInfo,label:this.t("settings.developer.showViewportInfo.label","Show Viewport Info"),onCheckedChange:this.handleDebugInfoChange("showViewportInfo")})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showObjectInfo.label","Show Object Info")),i("p",{class:"settings-description"},this.t("settings.developer.showObjectInfo.description","Display debug information about objects on the canvas.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showObjectInfo,label:this.t("settings.developer.showObjectInfo.label","Show Object Info"),onCheckedChange:this.handleDebugInfoChange("showObjectInfo")})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showSyncProviderInfo.label","Show Sync Provider Info")),i("p",{class:"settings-description"},this.t("settings.developer.showSyncProviderInfo.description","Display debug information about the sync provider connection status.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showSyncProviderInfo,label:this.t("settings.developer.showSyncProviderInfo.label","Show Sync Provider Info"),onCheckedChange:this.handleDebugInfoChange("showSyncProviderInfo")})),i("div",{class:"settings-item"},i("label",{class:"settings-label"},this.t("settings.developer.showMigrationInfo.label","Show Migration Info")),i("p",{class:"settings-description"},this.t("settings.developer.showMigrationInfo.description","Display debug information about data migrations.")),i("kritzel-slide-toggle",{checked:this.debugInfo.showMigrationInfo,label:this.t("settings.developer.showMigrationInfo.label","Show Migration Info"),onCheckedChange:this.handleDebugInfoChange("showMigrationInfo")}))));case"about":return i("div",{class:"settings-content"},i("h3",null,this.t("settings.about.title","About")),i("p",null,this.t("settings.about.description","Kritzel - A drawing application")),i("p",{class:"version-info"},"Version ","0.3.32"),i("p",{class:"version-info"},"App-State Schema v",l),i("p",{class:"version-info"},"Workspace Schema v",a));default:return null}}render(){return i(o,{key:"8b96261465efeabb2eb0cf724d29699de5e230a8"},i("kritzel-dialog",{key:"273a9df290bb97d59000a97f91821e7bad3f3896",isOpen:this.isDialogOpen,dialogTitle:this.t("settings.dialogTitle","Settings"),size:"large",contained:!0,onDialogClose:this.closeDialog},i("kritzel-master-detail",{key:"64d17dfaa2a0baf2d4a5d00fe5fc65ad40c96ec6",items:this.categories,selectedItemId:this.selectedCategoryId,onItemSelect:this.handleCategorySelect},this.renderCategoryContent())))}static get watchers(){return{settings:[{onSettingsPropChange:0}]}}static get style(){return":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)}"}},[513,"kritzel-settings",{availableThemes:[16],availableLocales:[16],shortcuts:[16],terms:[16],settings:[16],isDialogOpen:[32],selectedCategoryId:[32],scaleMin:[32],scaleMax:[32],lockDrawingScale:[32],theme:[32],locale:[32],viewportBoundaryLeft:[32],viewportBoundaryRight:[32],viewportBoundaryTop:[32],viewportBoundaryBottom:[32],debugInfo:[32],open:[64]},void 0,{settings:[{onSettingsPropChange:0}]}]);function k(){"undefined"!=typeof customElements&&["kritzel-settings","kritzel-dialog","kritzel-dropdown","kritzel-icon","kritzel-master-detail","kritzel-numeric-input","kritzel-slide-toggle"].forEach((e=>{switch(e){case"kritzel-settings":customElements.get(n(e))||customElements.define(n(e),y);break;case"kritzel-dialog":customElements.get(n(e))||r();break;case"kritzel-dropdown":customElements.get(n(e))||c();break;case"kritzel-icon":customElements.get(n(e))||h();break;case"kritzel-master-detail":customElements.get(n(e))||g();break;case"kritzel-numeric-input":customElements.get(n(e))||d();break;case"kritzel-slide-toggle":customElements.get(n(e))||p()}}))}export{y as K,k as d}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HocuspocusProvider, a as HocuspocusProviderWebsocket } from './schema.constants-
|
|
2
|
-
export { N as APP_STATE_MIGRATIONS, A as AssetNotFoundError, P as CURRENT_APP_STATE_SCHEMA_VERSION, Q as CURRENT_WORKSPACE_SCHEMA_VERSION, B as DEFAULT_ASSET_STORAGE_CONFIG, D as DEFAULT_BRUSH_CONFIG, z as DEFAULT_LINE_TOOL_CONFIG, y as DEFAULT_TEXT_CONFIG, G as DE_LOCALE, F as EN_LOCALE, J as FR_LOCALE, I as IndexedDBAssetProvider, L as KritzelAlignment, t as KritzelAnchorManager, r as KritzelAssetResolver, K as KritzelBaseObject, i as KritzelBaseTool, j as KritzelBrushTool, p as KritzelCursorHelper, h as KritzelCustomElement, x as KritzelCustomElementRendererRegistry, l as KritzelEraserTool, f as KritzelGroup, d as KritzelImage, m as KritzelImageTool, w as KritzelLicenseManager, e as KritzelLine, k as KritzelLineTool, v as KritzelLocalizationManager, c as KritzelPath, q as KritzelSelectionTool, g as KritzelShape, o as KritzelShapeTool, b as KritzelText, n as KritzelTextTool, u as KritzelThemeManager, s as KritzelWorkspace, S as ShapeType, W as WORKSPACE_EXPORT_VERSION, O as WORKSPACE_MIGRATIONS, E as darkTheme, C as lightTheme, M as runMigrations } from './schema.constants-
|
|
1
|
+
import { H as HocuspocusProvider, a as HocuspocusProviderWebsocket } from './schema.constants-CH2FWTVr.js';
|
|
2
|
+
export { N as APP_STATE_MIGRATIONS, A as AssetNotFoundError, P as CURRENT_APP_STATE_SCHEMA_VERSION, Q as CURRENT_WORKSPACE_SCHEMA_VERSION, B as DEFAULT_ASSET_STORAGE_CONFIG, D as DEFAULT_BRUSH_CONFIG, z as DEFAULT_LINE_TOOL_CONFIG, y as DEFAULT_TEXT_CONFIG, G as DE_LOCALE, F as EN_LOCALE, J as FR_LOCALE, I as IndexedDBAssetProvider, L as KritzelAlignment, t as KritzelAnchorManager, r as KritzelAssetResolver, K as KritzelBaseObject, i as KritzelBaseTool, j as KritzelBrushTool, p as KritzelCursorHelper, h as KritzelCustomElement, x as KritzelCustomElementRendererRegistry, l as KritzelEraserTool, f as KritzelGroup, d as KritzelImage, m as KritzelImageTool, w as KritzelLicenseManager, e as KritzelLine, k as KritzelLineTool, v as KritzelLocalizationManager, c as KritzelPath, q as KritzelSelectionTool, g as KritzelShape, o as KritzelShapeTool, b as KritzelText, n as KritzelTextTool, u as KritzelThemeManager, s as KritzelWorkspace, S as ShapeType, W as WORKSPACE_EXPORT_VERSION, O as WORKSPACE_MIGRATIONS, E as darkTheme, C as lightTheme, M as runMigrations } from './schema.constants-CH2FWTVr.js';
|
|
3
3
|
import * as Y from 'yjs';
|
|
4
4
|
import { IndexeddbPersistence } from 'y-indexeddb';
|
|
5
5
|
import { WebsocketProvider } from 'y-websocket';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-Dhio9uis.js';
|
|
2
|
-
import { c as KritzelPath, e as KritzelLine, R as KritzelColorHelper, T as KritzelDevicesHelper, q as KritzelSelectionTool, n as KritzelTextTool, U as KritzelMouseButton, V as KritzelHTMLHelper, X as DEFAULT_STROKE_SIZES, Y as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, j as KritzelBrushTool, l as KritzelEraserTool, z as DEFAULT_LINE_TOOL_CONFIG, k as KritzelLineTool, o as KritzelShapeTool, y as DEFAULT_TEXT_CONFIG, m as KritzelImageTool, L as KritzelAlignment, B as DEFAULT_ASSET_STORAGE_CONFIG, Z as ObjectHelper, _ as ThemeHelper, E as darkTheme, C as lightTheme, $ as KritzelSelectionGroup, a0 as KritzelSelectionBox, a1 as KritzelIconRegistry, a2 as KritzelKeyboardHelper, a3 as KritzelBaseHandler, s as KritzelWorkspace, f as KritzelGroup, h as KritzelCustomElement, d as KritzelImage, g as KritzelShape, b as KritzelText, M as runMigrations, Q as CURRENT_WORKSPACE_SCHEMA_VERSION, O as WORKSPACE_MIGRATIONS, a4 as KritzelClassHelper, P as CURRENT_APP_STATE_SCHEMA_VERSION, N as APP_STATE_MIGRATIONS, p as KritzelCursorHelper, a5 as imageCompression, t as KritzelAnchorManager, u as KritzelThemeManager, v as KritzelLocalizationManager, w as KritzelLicenseManager, r as KritzelAssetResolver, a6 as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION } from './schema.constants-
|
|
2
|
+
import { c as KritzelPath, e as KritzelLine, R as KritzelColorHelper, T as KritzelDevicesHelper, q as KritzelSelectionTool, n as KritzelTextTool, U as KritzelMouseButton, V as KritzelHTMLHelper, X as DEFAULT_STROKE_SIZES, Y as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, j as KritzelBrushTool, l as KritzelEraserTool, z as DEFAULT_LINE_TOOL_CONFIG, k as KritzelLineTool, o as KritzelShapeTool, y as DEFAULT_TEXT_CONFIG, m as KritzelImageTool, L as KritzelAlignment, B as DEFAULT_ASSET_STORAGE_CONFIG, Z as ObjectHelper, _ as ThemeHelper, E as darkTheme, C as lightTheme, $ as KritzelSelectionGroup, a0 as KritzelSelectionBox, a1 as KritzelIconRegistry, a2 as KritzelKeyboardHelper, a3 as KritzelBaseHandler, s as KritzelWorkspace, f as KritzelGroup, h as KritzelCustomElement, d as KritzelImage, g as KritzelShape, b as KritzelText, M as runMigrations, Q as CURRENT_WORKSPACE_SCHEMA_VERSION, O as WORKSPACE_MIGRATIONS, a4 as KritzelClassHelper, P as CURRENT_APP_STATE_SCHEMA_VERSION, N as APP_STATE_MIGRATIONS, p as KritzelCursorHelper, a5 as imageCompression, t as KritzelAnchorManager, u as KritzelThemeManager, v as KritzelLocalizationManager, w as KritzelLicenseManager, r as KritzelAssetResolver, a6 as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION } from './schema.constants-CH2FWTVr.js';
|
|
3
3
|
import * as Y from 'yjs';
|
|
4
4
|
import 'y-indexeddb';
|
|
5
5
|
import 'y-websocket';
|
|
@@ -21896,6 +21896,20 @@ class KritzelQuadtree {
|
|
|
21896
21896
|
}
|
|
21897
21897
|
return false;
|
|
21898
21898
|
}
|
|
21899
|
+
/**
|
|
21900
|
+
* Reindexes an existing object by removing it from its current node and
|
|
21901
|
+
* reinserting it based on its latest bounding box.
|
|
21902
|
+
*
|
|
21903
|
+
* @param object - The updated object to reindex
|
|
21904
|
+
* @returns `true` if the object was found and reinserted, `false` otherwise
|
|
21905
|
+
*/
|
|
21906
|
+
reindex(object) {
|
|
21907
|
+
const removed = this.remove(o => o.id === object.id);
|
|
21908
|
+
if (removed === 0) {
|
|
21909
|
+
return false;
|
|
21910
|
+
}
|
|
21911
|
+
return this.insert(object);
|
|
21912
|
+
}
|
|
21899
21913
|
/**
|
|
21900
21914
|
* Removes objects from the quadtree that match the given predicate.
|
|
21901
21915
|
* Recursively searches through all nodes and removes matching objects.
|
|
@@ -22467,10 +22481,19 @@ class KritzelObjectMap {
|
|
|
22467
22481
|
const objectsToUpdate = [];
|
|
22468
22482
|
const selectionGroupsToUpdate = [];
|
|
22469
22483
|
const objectsToDelete = [];
|
|
22484
|
+
// The reverse anchor index (targetObjectId -> anchored lines) is derived runtime
|
|
22485
|
+
// state that is NOT synced via Yjs. When line anchor connections arrive through a
|
|
22486
|
+
// remote change it must be rebuilt, otherwise getLinesAnchoredTo/updateAnchorsForObject
|
|
22487
|
+
// return stale/empty results on this client (e.g. anchored lines fail to follow a
|
|
22488
|
+
// locally-moved target, leaving selection UI and anchors visually offset).
|
|
22489
|
+
let anchorIndexNeedsRebuild = false;
|
|
22470
22490
|
changedKeys.forEach(key => {
|
|
22471
22491
|
const change = event.changes.keys.get(key);
|
|
22472
22492
|
if (change && change.action === 'delete') {
|
|
22473
22493
|
objectsToDelete.push(key);
|
|
22494
|
+
if (this._idMap.get(key) instanceof KritzelLine) {
|
|
22495
|
+
anchorIndexNeedsRebuild = true;
|
|
22496
|
+
}
|
|
22474
22497
|
}
|
|
22475
22498
|
else {
|
|
22476
22499
|
const serialized = this._objectsMap?.get(key);
|
|
@@ -22482,6 +22505,9 @@ class KritzelObjectMap {
|
|
|
22482
22505
|
}
|
|
22483
22506
|
else {
|
|
22484
22507
|
objectsToUpdate.push(object);
|
|
22508
|
+
if (object instanceof KritzelLine) {
|
|
22509
|
+
anchorIndexNeedsRebuild = true;
|
|
22510
|
+
}
|
|
22485
22511
|
}
|
|
22486
22512
|
}
|
|
22487
22513
|
}
|
|
@@ -22508,7 +22534,7 @@ class KritzelObjectMap {
|
|
|
22508
22534
|
if (previous && typeof object.adoptTransientStateFrom === 'function') {
|
|
22509
22535
|
object.adoptTransientStateFrom(previous);
|
|
22510
22536
|
}
|
|
22511
|
-
this.quadtree.
|
|
22537
|
+
this.quadtree.reindex(object);
|
|
22512
22538
|
this._idMap.set(object.id, object);
|
|
22513
22539
|
updatedObjects.push(object);
|
|
22514
22540
|
}
|
|
@@ -22527,7 +22553,7 @@ class KritzelObjectMap {
|
|
|
22527
22553
|
if (previous && typeof object.adoptTransientStateFrom === 'function') {
|
|
22528
22554
|
object.adoptTransientStateFrom(previous);
|
|
22529
22555
|
}
|
|
22530
|
-
this.quadtree.
|
|
22556
|
+
this.quadtree.reindex(object);
|
|
22531
22557
|
this._idMap.set(object.id, object);
|
|
22532
22558
|
}
|
|
22533
22559
|
else {
|
|
@@ -22544,7 +22570,7 @@ class KritzelObjectMap {
|
|
|
22544
22570
|
object.refreshObjectDimensions(undefined, true);
|
|
22545
22571
|
object.captureUnchangedSnapshots();
|
|
22546
22572
|
// Update quadtree again with corrected dimensions
|
|
22547
|
-
this.quadtree.
|
|
22573
|
+
this.quadtree.reindex(object);
|
|
22548
22574
|
});
|
|
22549
22575
|
// If regular objects were changed but their SelectionGroup wasn't explicitly updated,
|
|
22550
22576
|
// we still need to refresh that SelectionGroup's dimensions
|
|
@@ -22562,10 +22588,16 @@ class KritzelObjectMap {
|
|
|
22562
22588
|
selectionGroup.refreshObjectDimensions(undefined, true);
|
|
22563
22589
|
selectionGroup.captureUnchangedSnapshots();
|
|
22564
22590
|
// Update quadtree with corrected dimensions
|
|
22565
|
-
this.quadtree.
|
|
22591
|
+
this.quadtree.reindex(selectionGroup);
|
|
22566
22592
|
}
|
|
22567
22593
|
}
|
|
22568
22594
|
}
|
|
22595
|
+
// Rebuild the anchor index if any line anchor connections may have changed, so that
|
|
22596
|
+
// subsequent local operations (moving a target, refreshing selection UI) resolve the
|
|
22597
|
+
// correct anchored lines on this client.
|
|
22598
|
+
if (anchorIndexNeedsRebuild) {
|
|
22599
|
+
this._core?.anchorManager.rebuildIndex();
|
|
22600
|
+
}
|
|
22569
22601
|
// Invalidate the store's selection cache so it fetches the updated SelectionGroup
|
|
22570
22602
|
this._core?.store.invalidateSelectionCache();
|
|
22571
22603
|
this._core?.rerender();
|
|
@@ -22807,7 +22839,12 @@ class KritzelObjectMap {
|
|
|
22807
22839
|
if (!existed) {
|
|
22808
22840
|
return false;
|
|
22809
22841
|
}
|
|
22810
|
-
this.
|
|
22842
|
+
if (this._localOnlyMode || options.skipReindex) {
|
|
22843
|
+
this.quadtree.update(object);
|
|
22844
|
+
}
|
|
22845
|
+
else {
|
|
22846
|
+
this.quadtree.reindex(object);
|
|
22847
|
+
}
|
|
22811
22848
|
this._idMap.set(object.id, object);
|
|
22812
22849
|
if (!this._localOnlyMode && this._objectsMap && this.isPersistable(object)) {
|
|
22813
22850
|
const serialized = object.serialize();
|
|
@@ -23996,17 +24033,17 @@ class KritzelBrowserPermissionManager {
|
|
|
23996
24033
|
*/
|
|
23997
24034
|
constructor(_core) {
|
|
23998
24035
|
this.registerRequestPermissionHandler('clipboard-read', async () => {
|
|
23999
|
-
// Firefox and Safari open native paste menus when
|
|
24036
|
+
// Firefox and Safari open native paste menus when the clipboard is read
|
|
24000
24037
|
// proactively, so rely on the permission state instead of an eager read.
|
|
24001
24038
|
if (this._isFirefox || this._isSafari) {
|
|
24002
24039
|
return 'granted';
|
|
24003
24040
|
}
|
|
24004
24041
|
try {
|
|
24005
|
-
await navigator.
|
|
24006
|
-
return 'granted';
|
|
24042
|
+
const status = await navigator.permissions.query({ name: 'clipboard-read' });
|
|
24043
|
+
return status.state === 'denied' ? 'denied' : 'granted';
|
|
24007
24044
|
}
|
|
24008
24045
|
catch {
|
|
24009
|
-
return '
|
|
24046
|
+
return 'granted';
|
|
24010
24047
|
}
|
|
24011
24048
|
});
|
|
24012
24049
|
}
|
|
@@ -24045,37 +24082,141 @@ class KritzelBrowserPermissionManager {
|
|
|
24045
24082
|
}
|
|
24046
24083
|
}
|
|
24047
24084
|
|
|
24048
|
-
|
|
24049
|
-
/**
|
|
24050
|
-
* Manages clipboard operations (copy/cut/paste) for a core instance.
|
|
24051
|
-
*
|
|
24052
|
-
* The system clipboard is the single source of truth: copy serializes the current
|
|
24053
|
-
* selection into a Kritzel payload, paste reads + revives it. No copied objects are
|
|
24054
|
-
* cached on the engine state.
|
|
24055
|
-
*/
|
|
24056
|
-
class KritzelClipboardManager {
|
|
24085
|
+
class KritzelPasteIntentProviderRegistry {
|
|
24057
24086
|
_core;
|
|
24058
|
-
|
|
24059
|
-
|
|
24060
|
-
|
|
24061
|
-
*/
|
|
24062
|
-
_pasteOffset = 0;
|
|
24063
|
-
constructor(core) {
|
|
24064
|
-
this._core = core;
|
|
24087
|
+
_providers = [];
|
|
24088
|
+
constructor(_core) {
|
|
24089
|
+
this._core = _core;
|
|
24065
24090
|
}
|
|
24066
|
-
|
|
24067
|
-
|
|
24068
|
-
|
|
24069
|
-
|
|
24070
|
-
|
|
24071
|
-
|
|
24072
|
-
|
|
24073
|
-
|
|
24091
|
+
register(provider) {
|
|
24092
|
+
this._providers.push(provider);
|
|
24093
|
+
}
|
|
24094
|
+
async resolve(event) {
|
|
24095
|
+
const context = {
|
|
24096
|
+
core: this._core,
|
|
24097
|
+
event,
|
|
24098
|
+
};
|
|
24099
|
+
for (const provider of this._providers) {
|
|
24100
|
+
if (!provider.canHandle(context)) {
|
|
24101
|
+
continue;
|
|
24102
|
+
}
|
|
24103
|
+
const intent = await provider.getPasteIntent(context);
|
|
24104
|
+
if (intent.type !== 'unknown') {
|
|
24105
|
+
return intent;
|
|
24106
|
+
}
|
|
24074
24107
|
}
|
|
24075
|
-
return
|
|
24108
|
+
return { type: 'unknown' };
|
|
24076
24109
|
}
|
|
24077
|
-
|
|
24078
|
-
|
|
24110
|
+
}
|
|
24111
|
+
|
|
24112
|
+
const CLIPBOARD_PAYLOAD_PREFIX = 'kritzel-clipboard/v1:';
|
|
24113
|
+
|
|
24114
|
+
class KritzelEventPasteIntentProvider {
|
|
24115
|
+
canHandle(context) {
|
|
24116
|
+
return !!context.event?.clipboardData;
|
|
24117
|
+
}
|
|
24118
|
+
async getPasteIntent(context) {
|
|
24119
|
+
const data = context.event?.clipboardData;
|
|
24120
|
+
if (!data) {
|
|
24121
|
+
return { type: 'unknown' };
|
|
24122
|
+
}
|
|
24123
|
+
const imageFiles = Array.from(data.files ?? []).filter(file => file.type.startsWith('image/'));
|
|
24124
|
+
if (imageFiles.length > 0) {
|
|
24125
|
+
return { type: 'image_files', files: imageFiles };
|
|
24126
|
+
}
|
|
24127
|
+
if (data.types.includes('text/plain')) {
|
|
24128
|
+
const textIntent = this.determineTextPasteIntent(data.getData('text/plain'));
|
|
24129
|
+
if (textIntent) {
|
|
24130
|
+
return textIntent;
|
|
24131
|
+
}
|
|
24132
|
+
}
|
|
24133
|
+
return { type: 'unknown' };
|
|
24134
|
+
}
|
|
24135
|
+
parseClipboardPayload(text) {
|
|
24136
|
+
if (!text || !text.startsWith(CLIPBOARD_PAYLOAD_PREFIX)) {
|
|
24137
|
+
return null;
|
|
24138
|
+
}
|
|
24139
|
+
try {
|
|
24140
|
+
const parsed = JSON.parse(text.slice(CLIPBOARD_PAYLOAD_PREFIX.length));
|
|
24141
|
+
if (parsed?.version !== 1 || !Array.isArray(parsed.objects)) {
|
|
24142
|
+
return null;
|
|
24143
|
+
}
|
|
24144
|
+
return parsed;
|
|
24145
|
+
}
|
|
24146
|
+
catch {
|
|
24147
|
+
return null;
|
|
24148
|
+
}
|
|
24149
|
+
}
|
|
24150
|
+
determineTextPasteIntent(text) {
|
|
24151
|
+
const payload = this.parseClipboardPayload(text);
|
|
24152
|
+
if (payload) {
|
|
24153
|
+
return { type: 'kritzel_objects', payload };
|
|
24154
|
+
}
|
|
24155
|
+
if (text && text.trim().length > 0) {
|
|
24156
|
+
return { type: 'plain_text', text };
|
|
24157
|
+
}
|
|
24158
|
+
return null;
|
|
24159
|
+
}
|
|
24160
|
+
}
|
|
24161
|
+
|
|
24162
|
+
class KritzelNavigatorPasteIntentProvider {
|
|
24163
|
+
canHandle(context) {
|
|
24164
|
+
return !context.event?.clipboardData && typeof navigator !== 'undefined' && !!navigator.clipboard;
|
|
24165
|
+
}
|
|
24166
|
+
async getPasteIntent(context) {
|
|
24167
|
+
if (typeof navigator === 'undefined' || !navigator.clipboard) {
|
|
24168
|
+
return { type: 'unknown' };
|
|
24169
|
+
}
|
|
24170
|
+
const { clipboard } = navigator;
|
|
24171
|
+
const permissionState = await context.core.permissionManager.checkPermission('clipboard-read');
|
|
24172
|
+
if (permissionState !== 'granted') {
|
|
24173
|
+
const requestedState = await context.core.permissionManager.requestPermission('clipboard-read');
|
|
24174
|
+
if (requestedState !== 'granted') {
|
|
24175
|
+
return { type: 'unknown' };
|
|
24176
|
+
}
|
|
24177
|
+
}
|
|
24178
|
+
if (clipboard.read) {
|
|
24179
|
+
try {
|
|
24180
|
+
const items = await clipboard.read();
|
|
24181
|
+
const { imageFiles, text } = await this.processClipboardItems(items);
|
|
24182
|
+
if (imageFiles.length > 0) {
|
|
24183
|
+
return { type: 'image_files', files: imageFiles };
|
|
24184
|
+
}
|
|
24185
|
+
if (text !== null) {
|
|
24186
|
+
const textIntent = this.determineTextPasteIntent(text);
|
|
24187
|
+
if (textIntent) {
|
|
24188
|
+
return textIntent;
|
|
24189
|
+
}
|
|
24190
|
+
}
|
|
24191
|
+
}
|
|
24192
|
+
catch {
|
|
24193
|
+
// Fall back to readText below when read() is denied or unavailable at runtime.
|
|
24194
|
+
}
|
|
24195
|
+
}
|
|
24196
|
+
if (clipboard.readText) {
|
|
24197
|
+
const textIntent = this.determineTextPasteIntent(await clipboard.readText());
|
|
24198
|
+
if (textIntent) {
|
|
24199
|
+
return textIntent;
|
|
24200
|
+
}
|
|
24201
|
+
}
|
|
24202
|
+
return { type: 'unknown' };
|
|
24203
|
+
}
|
|
24204
|
+
async processClipboardItems(items) {
|
|
24205
|
+
const imageFiles = [];
|
|
24206
|
+
let text = null;
|
|
24207
|
+
await Promise.all(items.map(async (item) => {
|
|
24208
|
+
const imageType = item.types.find(type => type.startsWith('image/'));
|
|
24209
|
+
if (imageType) {
|
|
24210
|
+
const blob = await item.getType(imageType);
|
|
24211
|
+
imageFiles.push(new File([blob], 'pasted-image', { type: imageType }));
|
|
24212
|
+
return;
|
|
24213
|
+
}
|
|
24214
|
+
if (text === null && item.types.includes('text/plain')) {
|
|
24215
|
+
const blob = await item.getType('text/plain');
|
|
24216
|
+
text = await blob.text();
|
|
24217
|
+
}
|
|
24218
|
+
}));
|
|
24219
|
+
return { imageFiles, text };
|
|
24079
24220
|
}
|
|
24080
24221
|
parseClipboardPayload(text) {
|
|
24081
24222
|
if (!text || !text.startsWith(CLIPBOARD_PAYLOAD_PREFIX)) {
|
|
@@ -24102,6 +24243,79 @@ class KritzelClipboardManager {
|
|
|
24102
24243
|
}
|
|
24103
24244
|
return null;
|
|
24104
24245
|
}
|
|
24246
|
+
}
|
|
24247
|
+
|
|
24248
|
+
class KritzelIosPasteIntentProvider {
|
|
24249
|
+
canHandle(context) {
|
|
24250
|
+
return !context.event?.clipboardData && KritzelDevicesHelper.isIOS();
|
|
24251
|
+
}
|
|
24252
|
+
async getPasteIntent(context) {
|
|
24253
|
+
// On iOS Safari, eventless programmatic clipboard reads are commonly unavailable
|
|
24254
|
+
// (e.g. the context-menu paste calls engine.paste() without a native ClipboardEvent).
|
|
24255
|
+
// Fall back to the in-memory session buffer so internal object copy/paste still works.
|
|
24256
|
+
const payload = context.core.clipboardManager.sessionClipboardPayload;
|
|
24257
|
+
if (payload) {
|
|
24258
|
+
return { type: 'kritzel_objects', payload };
|
|
24259
|
+
}
|
|
24260
|
+
return { type: 'unknown' };
|
|
24261
|
+
}
|
|
24262
|
+
}
|
|
24263
|
+
|
|
24264
|
+
/**
|
|
24265
|
+
* Manages clipboard operations (copy/cut/paste) for a core instance.
|
|
24266
|
+
*
|
|
24267
|
+
* The system clipboard is the preferred source of truth: copy serializes the current
|
|
24268
|
+
* selection into a Kritzel payload, paste reads + revives it.
|
|
24269
|
+
*
|
|
24270
|
+
* A copy also mirrors the payload into an in-memory session buffer. On platforms where
|
|
24271
|
+
* eventless programmatic clipboard access is unavailable (notably iOS Safari, where the
|
|
24272
|
+
* context menu triggers copy/paste without a native ClipboardEvent), the session buffer
|
|
24273
|
+
* is used as the fallback source so internal object copy/paste keeps working.
|
|
24274
|
+
*/
|
|
24275
|
+
class KritzelClipboardManager {
|
|
24276
|
+
_core;
|
|
24277
|
+
_pasteIntentRegistry;
|
|
24278
|
+
/**
|
|
24279
|
+
* In-memory mirror of the most recent copy payload. Acts as the fallback clipboard
|
|
24280
|
+
* source when the system clipboard cannot be read programmatically (e.g. iOS Safari
|
|
24281
|
+
* context-menu paste). Reset is not required; a new copy overwrites it.
|
|
24282
|
+
*/
|
|
24283
|
+
_sessionClipboardPayload = null;
|
|
24284
|
+
/**
|
|
24285
|
+
* In-memory cascade offset (world units) applied to successive pastes of the same
|
|
24286
|
+
* clipboard content so they don't stack exactly on top of each other. Reset on copy/cut.
|
|
24287
|
+
*/
|
|
24288
|
+
_pasteOffset = 0;
|
|
24289
|
+
constructor(core) {
|
|
24290
|
+
this._core = core;
|
|
24291
|
+
this._pasteIntentRegistry = new KritzelPasteIntentProviderRegistry(this._core);
|
|
24292
|
+
// Provider order is intentional: iOS eventless path should short-circuit,
|
|
24293
|
+
// native paste events remain preferred, and async navigator APIs are fallback.
|
|
24294
|
+
this._pasteIntentRegistry.register(new KritzelIosPasteIntentProvider());
|
|
24295
|
+
this._pasteIntentRegistry.register(new KritzelEventPasteIntentProvider());
|
|
24296
|
+
this._pasteIntentRegistry.register(new KritzelNavigatorPasteIntentProvider());
|
|
24297
|
+
}
|
|
24298
|
+
/**
|
|
24299
|
+
* The most recent copy payload mirrored in memory, used as a fallback clipboard
|
|
24300
|
+
* source when the system clipboard cannot be read programmatically.
|
|
24301
|
+
*/
|
|
24302
|
+
get sessionClipboardPayload() {
|
|
24303
|
+
return this._sessionClipboardPayload;
|
|
24304
|
+
}
|
|
24305
|
+
/**
|
|
24306
|
+
* Serializes an object for the clipboard payload. Groups additionally embed their
|
|
24307
|
+
* (recursively serialized) children under `__children__` so the payload is self-contained.
|
|
24308
|
+
*/
|
|
24309
|
+
serializeForClipboard(object) {
|
|
24310
|
+
const serialized = (typeof object.serialize === 'function' ? object.serialize() : object);
|
|
24311
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
|
|
24312
|
+
serialized.__children__ = object.children.map(child => this.serializeForClipboard(child));
|
|
24313
|
+
}
|
|
24314
|
+
return serialized;
|
|
24315
|
+
}
|
|
24316
|
+
serializeClipboardPayload(payload) {
|
|
24317
|
+
return `${CLIPBOARD_PAYLOAD_PREFIX}${JSON.stringify(payload)}`;
|
|
24318
|
+
}
|
|
24105
24319
|
async writeBrowserClipboardPayload(payload, event) {
|
|
24106
24320
|
const serialized = this.serializeClipboardPayload(payload);
|
|
24107
24321
|
if (event?.clipboardData) {
|
|
@@ -24181,80 +24395,6 @@ class KritzelClipboardManager {
|
|
|
24181
24395
|
}
|
|
24182
24396
|
}
|
|
24183
24397
|
}
|
|
24184
|
-
/**
|
|
24185
|
-
* Evaluates the clipboard event to determine exactly what the user is trying to paste.
|
|
24186
|
-
* Returns a PasteIntent covering the 3 main cases: Kritzel objects, Images, or Plain text.
|
|
24187
|
-
*/
|
|
24188
|
-
async determinePasteIntent(event) {
|
|
24189
|
-
if (event?.clipboardData) {
|
|
24190
|
-
const data = event.clipboardData;
|
|
24191
|
-
const imageFiles = Array.from(data.files ?? []).filter(file => file.type.startsWith('image/'));
|
|
24192
|
-
if (imageFiles.length > 0) {
|
|
24193
|
-
return { type: 'image_files', files: imageFiles };
|
|
24194
|
-
}
|
|
24195
|
-
if (data.types.includes('text/plain')) {
|
|
24196
|
-
const textIntent = this.determineTextPasteIntent(data.getData('text/plain'));
|
|
24197
|
-
if (textIntent)
|
|
24198
|
-
return textIntent;
|
|
24199
|
-
}
|
|
24200
|
-
return { type: 'unknown' };
|
|
24201
|
-
}
|
|
24202
|
-
if (typeof navigator === 'undefined' || !navigator.clipboard) {
|
|
24203
|
-
return { type: 'unknown' };
|
|
24204
|
-
}
|
|
24205
|
-
const { clipboard } = navigator;
|
|
24206
|
-
const permissionState = await this._core.permissionManager.checkPermission('clipboard-read');
|
|
24207
|
-
if (permissionState !== 'granted') {
|
|
24208
|
-
const requestedState = await this._core.permissionManager.requestPermission('clipboard-read');
|
|
24209
|
-
if (requestedState !== 'granted') {
|
|
24210
|
-
return { type: 'unknown' };
|
|
24211
|
-
}
|
|
24212
|
-
}
|
|
24213
|
-
if (clipboard.read) {
|
|
24214
|
-
try {
|
|
24215
|
-
const items = await clipboard.read();
|
|
24216
|
-
const { imageFiles, text } = await this.processClipboardItems(items);
|
|
24217
|
-
if (imageFiles.length > 0) {
|
|
24218
|
-
return { type: 'image_files', files: imageFiles };
|
|
24219
|
-
}
|
|
24220
|
-
if (text !== null) {
|
|
24221
|
-
const textIntent = this.determineTextPasteIntent(text);
|
|
24222
|
-
if (textIntent)
|
|
24223
|
-
return textIntent;
|
|
24224
|
-
}
|
|
24225
|
-
}
|
|
24226
|
-
catch {
|
|
24227
|
-
// Fall back to readText below when read() is denied or unavailable at runtime.
|
|
24228
|
-
}
|
|
24229
|
-
}
|
|
24230
|
-
if (clipboard.readText) {
|
|
24231
|
-
const textIntent = this.determineTextPasteIntent(await clipboard.readText());
|
|
24232
|
-
if (textIntent)
|
|
24233
|
-
return textIntent;
|
|
24234
|
-
}
|
|
24235
|
-
return { type: 'unknown' };
|
|
24236
|
-
}
|
|
24237
|
-
/**
|
|
24238
|
-
* Helper to parse clipboard items in parallel
|
|
24239
|
-
*/
|
|
24240
|
-
async processClipboardItems(items) {
|
|
24241
|
-
const imageFiles = [];
|
|
24242
|
-
let text = null;
|
|
24243
|
-
// Process items concurrently
|
|
24244
|
-
await Promise.all(items.map(async (item) => {
|
|
24245
|
-
const imageType = item.types.find(type => type.startsWith('image/'));
|
|
24246
|
-
if (imageType) {
|
|
24247
|
-
const blob = await item.getType(imageType);
|
|
24248
|
-
imageFiles.push(new File([blob], 'pasted-image', { type: imageType }));
|
|
24249
|
-
return;
|
|
24250
|
-
}
|
|
24251
|
-
if (text === null && item.types.includes('text/plain')) {
|
|
24252
|
-
const blob = await item.getType('text/plain');
|
|
24253
|
-
text = await blob.text();
|
|
24254
|
-
}
|
|
24255
|
-
}));
|
|
24256
|
-
return { imageFiles, text };
|
|
24257
|
-
}
|
|
24258
24398
|
/**
|
|
24259
24399
|
* Copies currently selected objects into internal clipboard state.
|
|
24260
24400
|
*/
|
|
@@ -24270,6 +24410,9 @@ class KritzelClipboardManager {
|
|
|
24270
24410
|
};
|
|
24271
24411
|
// A fresh copy resets the cascade so the first paste lands at the default offset.
|
|
24272
24412
|
this._pasteOffset = 0;
|
|
24413
|
+
// Mirror the payload in memory so eventless paste still works where the system
|
|
24414
|
+
// clipboard is not programmatically accessible (e.g. iOS Safari context menu).
|
|
24415
|
+
this._sessionClipboardPayload = payload;
|
|
24273
24416
|
void this.writeBrowserClipboardPayload(payload, event);
|
|
24274
24417
|
}
|
|
24275
24418
|
/**
|
|
@@ -24328,7 +24471,7 @@ class KritzelClipboardManager {
|
|
|
24328
24471
|
* Pastes objects from clipboard with optional explicit world coordinates.
|
|
24329
24472
|
*/
|
|
24330
24473
|
async paste(x, y, event) {
|
|
24331
|
-
const pasteIntent = await this.
|
|
24474
|
+
const pasteIntent = await this._pasteIntentRegistry.resolve(event);
|
|
24332
24475
|
let objects = null;
|
|
24333
24476
|
if (pasteIntent.type === 'kritzel_objects') {
|
|
24334
24477
|
objects = this.materializeKritzelObjects(pasteIntent);
|
|
@@ -31237,7 +31380,7 @@ const KritzelPortal = class {
|
|
|
31237
31380
|
* This file is auto-generated by the version bump scripts.
|
|
31238
31381
|
* Do not modify manually.
|
|
31239
31382
|
*/
|
|
31240
|
-
const KRITZEL_VERSION = '0.3.
|
|
31383
|
+
const KRITZEL_VERSION = '0.3.32';
|
|
31241
31384
|
|
|
31242
31385
|
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)}`;
|
|
31243
31386
|
|
|
@@ -549,6 +549,13 @@ class KritzelBaseObject {
|
|
|
549
549
|
this.resizing = false;
|
|
550
550
|
this.markedForRemoval = false;
|
|
551
551
|
this.isVisible = true;
|
|
552
|
+
// Reset known transient geometry caches if present on subclasses.
|
|
553
|
+
if ('_adjustedPoints' in this) {
|
|
554
|
+
this._adjustedPoints = null;
|
|
555
|
+
}
|
|
556
|
+
if ('_clipInfo' in this) {
|
|
557
|
+
this._clipInfo = null;
|
|
558
|
+
}
|
|
552
559
|
return this;
|
|
553
560
|
}
|
|
554
561
|
/**
|
|
@@ -18371,6 +18378,27 @@ class KritzelLine extends KritzelBaseObject {
|
|
|
18371
18378
|
calculateBoundingBox() {
|
|
18372
18379
|
return KritzelLine.calculateBoundingBox(this.startX, this.startY, this.endX, this.endY, this.controlX, this.controlY, this.strokeWidth);
|
|
18373
18380
|
}
|
|
18381
|
+
/**
|
|
18382
|
+
* Serializes the line while excluding transient cache fields.
|
|
18383
|
+
* @returns A serializable line object without runtime caches
|
|
18384
|
+
*/
|
|
18385
|
+
serialize() {
|
|
18386
|
+
const serialized = super.serialize();
|
|
18387
|
+
delete serialized._adjustedPoints;
|
|
18388
|
+
delete serialized._clipInfo;
|
|
18389
|
+
return serialized;
|
|
18390
|
+
}
|
|
18391
|
+
/**
|
|
18392
|
+
* Deserializes and resets transient caches so geometry is recomputed lazily.
|
|
18393
|
+
* @param object - The serialized line object
|
|
18394
|
+
* @returns This instance cast to type T
|
|
18395
|
+
*/
|
|
18396
|
+
deserialize(object) {
|
|
18397
|
+
const result = super.deserialize(object);
|
|
18398
|
+
this._adjustedPoints = null;
|
|
18399
|
+
this._clipInfo = null;
|
|
18400
|
+
return result;
|
|
18401
|
+
}
|
|
18374
18402
|
/**
|
|
18375
18403
|
* Recalculates and updates the width, height, x, y, and translation properties
|
|
18376
18404
|
* based on the current endpoint positions and stroke width.
|
|
@@ -24305,8 +24333,10 @@ class KritzelLineHandleHandler extends KritzelBaseHandler {
|
|
|
24305
24333
|
// Adjust translateX/Y to compensate for the bounding box shift
|
|
24306
24334
|
line.translateX = newTranslateX;
|
|
24307
24335
|
line.translateY = newTranslateY;
|
|
24308
|
-
// Clear
|
|
24309
|
-
|
|
24336
|
+
// Clear transient caches so geometry and anchor clipping recompute on demand.
|
|
24337
|
+
const linePrivate = line;
|
|
24338
|
+
linePrivate._adjustedPoints = null;
|
|
24339
|
+
linePrivate._clipInfo = null;
|
|
24310
24340
|
this._core.store.objects.update(line);
|
|
24311
24341
|
}
|
|
24312
24342
|
/**
|